// plik: ntpc.c
// Zobacz:
// https://en.wikipedia.org/wiki/Network_Time_Protocol
//
// https://github.com/SanketDG/c-projects/blob/master/ntp-client.c
// https://www.cbk.poznan.pl/
//
// Kompilacja: cygwin
// gcc ntpc.c -o ntpc
// $ ./ntpc
// Usage: ./ntpc <server> [port]
//
// $ ./ntpc 150.254.183.15
// Time: Sat Mar 30 09:28:12 2019
//
// ./ntpc vega.cbk.poznan.pl
//
// ./ntpc 150.254.183.15 123
//---------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <time.h>
#include <unistd.h>
// Difference between Jan 1, 1900 and Jan 1, 1970
#define UNIX_OFFSET 2208988800L
#define NTP_DEFAULT_PORT "123"
// Flags 00|100|011 for li=0, vn=4, mode=3
#define NTP_FLAGS 0x23
typedef struct {
uint8_t flags;
uint8_t stratum;
uint8_t poll;
uint8_t precision;
uint32_t root_delay;
uint32_t root_dispersion;
uint8_t referenceID[4];
uint32_t ref_ts_secs;
uint32_t ref_ts_frac;
uint32_t origin_ts_secs;
uint32_t origin_ts_frac;
uint32_t recv_ts_secs; // This is what we need mostly to get current time.
uint32_t recv_ts_fracs;
uint32_t transmit_ts_secs;
uint32_t transmit_ts_frac;
} ntp_packet;
int main(int argc, char *argv[]) {
char *server;
char *port = NTP_DEFAULT_PORT;
int server_sock, status;
struct addrinfo hints, *servinfo, *ap;
socklen_t addrlen = sizeof(struct sockaddr_storage);
if(argc < 2) {
printf("Usage: %s <server> [port]\n", argv
[0]);
}
server = argv[1]; // if it is supplied as argument
if(argc == 3) {
// Port is also passed in as argument
port = argv[2];
}
ntp_packet packet = { .flags = NTP_FLAGS }; // populate the struct
hints = (struct addrinfo) { .ai_family = AF_UNSPEC, .ai_socktype = SOCK_DGRAM };
// Get the info of the NTP server
if((status = getaddrinfo(server, port, &hints, &servinfo)) != 0) {
fprintf(stderr
, "getaddrinfo() error: %s\n", gai_strerror
(status
));
}
// Initalize the socket
for(ap = servinfo; ap != NULL; ap = ap->ai_next) {
server_sock = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol);
if(server_sock == -1)
continue;
break;
}
if (ap == NULL) {
fprintf(stderr
, "socket() error\n");
}
// Send the structure to the server
if((status = sendto(server_sock, &packet, sizeof(packet), 0, ap->ai_addr, addrlen)) == -1) {
}
// Recive the structure from the server
if((status = recvfrom(server_sock, &packet, sizeof(packet), 0, ap->ai_addr, &addrlen)) == -1) {
}
freeaddrinfo(servinfo);
close(server_sock);
// Convert from network's to host's endian order
packet.recv_ts_secs = ntohl(packet.recv_ts_secs);
// The number of seconds we get back from the server is equal to the no. of
// seconds since Jan 1, 1900. Since Unix time starts from Jan 1, 1970, we
// subtract 70 years worth of seconds from Jan 1, 1990.
time_t time_struct = (time_t) packet.recv_ts_secs - UNIX_OFFSET;
time_t rawtime;
struct tm * timeinfo;
}