-
Notifications
You must be signed in to change notification settings - Fork 4
/
ntp-client.c
126 lines (85 loc) · 2.87 KB
/
ntp-client.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#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]);
exit(1);
}
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));
exit(2);
}
// 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");
exit(2);
}
// Send the structure to the server
if((status = sendto(server_sock, &packet, sizeof(packet), 0, ap->ai_addr, addrlen)) == -1) {
perror("sendto() error");
exit(2);
}
// Send the structure to the server
if((status = recvfrom(server_sock, &packet, sizeof(packet), 0, ap->ai_addr, &addrlen)) == -1) {
perror("recvfrom() error");
exit(2);
}
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;
printf("Time: %s", ctime(&time_struct));
}