Doxygen Book
ntputil.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: LGPL-2.1-only */
15 #include <errno.h>
16 #include <netdb.h>
17 #include <stdint.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <time.h>
21 #include <unistd.h>
22 
23 #include "ntputil.h"
24 
40 typedef struct _ntp_timestamp_t
41 {
42  uint32_t sec;
43  uint32_t frac;
45 
100 typedef struct _ntp_packet_t
101 {
102  uint8_t li_vn_mode;
103  uint8_t stratum;
104  uint8_t poll;
105  uint8_t precision;
106  uint32_t root_delay;
107  uint32_t root_dispersion;
108  uint32_t ref_id;
113 } ntp_packet_t;
114 
115 const uint64_t NTPUTIL_TIMESTAMP_DELTA = 2208988800ULL;
116 const double NTPUTIL_MAX_FRAC_DOUBLE = 4294967295.0L;
117 const int64_t NTPUTIL_SEC_TO_USEC_MULTIPLIER = 1000000;
118 const char NTPUTIL_DEFAULT_HNAME[] = "pool.ntp.org";
119 const uint16_t NTPUTIL_DEFAULT_PORT = 123;
120 
124 uint32_t
126 {
127  return ntohl (in);
128 }
129 
139 int64_t
140 ntputil_get_epoch (uint32_t hnums, char **hnames, uint16_t * ports)
141 {
142  struct sockaddr_in serv_addr;
143  struct hostent *srv = NULL;
144  struct hostent *default_srv = NULL;
145  uint16_t port = -1;
146  int32_t sockfd = -1;
147  uint32_t i;
148  int64_t ret;
149 
150  sockfd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
151  if (sockfd < 0) {
152  ret = -1;
153  goto ret_normal;
154  }
155 
156  for (i = 0; i < hnums; ++i) {
157  srv = gethostbyname (hnames[i]);
158  if (srv != NULL) {
159  port = ports[i];
160  break;
161  }
162  }
163 
164  if (srv == NULL) {
165  default_srv = gethostbyname (NTPUTIL_DEFAULT_HNAME);
166  if (default_srv == NULL) {
167  ret = -h_errno;
168  goto ret_close_sockfd;
169  }
170  srv = default_srv;
171  port = NTPUTIL_DEFAULT_PORT;
172  }
173 
174  memset (&serv_addr, 0, sizeof (serv_addr));
175  serv_addr.sin_family = AF_INET;
176  memcpy ((uint8_t *) & serv_addr.sin_addr.s_addr,
177  (uint8_t *) srv->h_addr_list[0], (size_t) srv->h_length);
178  serv_addr.sin_port = htons (port);
179 
180  ret = connect (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr));
181  if (ret < 0) {
182  ret = -errno;
183  goto ret_close_sockfd;
184  }
185 
186  {
187  ntp_packet_t packet;
188  uint32_t recv_sec;
189  uint32_t recv_frac;
190  double frac;
191  ssize_t n;
192 
193  memset (&packet, 0, sizeof (packet));
194 
195  /* li = 0, vn = 3, mode = 3 */
196  packet.li_vn_mode = 0x1B;
197 
198  /* Request */
199  n = write (sockfd, &packet, sizeof (packet));
200  if (n < 0) {
201  ret = -errno;
202  goto ret_close_sockfd;
203  }
204 
205  /* Receive */
206  n = read (sockfd, &packet, sizeof (packet));
207  if (n < 0) {
208  ret = -errno;
209  goto ret_close_sockfd;
210  }
211 
219  recv_sec = _convert_to_host_byte_order (packet.xmit_ts.sec);
220  recv_frac = _convert_to_host_byte_order (packet.xmit_ts.frac);
221 
227  if (recv_sec <= NTPUTIL_TIMESTAMP_DELTA) {
228  ret = -1;
229  goto ret_close_sockfd;
230  }
231 
232  ret = (int64_t) (recv_sec - NTPUTIL_TIMESTAMP_DELTA);
234  frac = ((double) recv_frac) / NTPUTIL_MAX_FRAC_DOUBLE;
236 
237  ret += (int64_t) frac;
238  }
239 
240 ret_close_sockfd:
241  close (sockfd);
242 
243 ret_normal:
244  return ret;
245 }
_ntp_packet_t::precision
uint8_t precision
Definition: ntputil.c:105
NTPUTIL_DEFAULT_HNAME
const char NTPUTIL_DEFAULT_HNAME[]
Definition: ntputil.c:118
ntp_packet_t
struct _ntp_packet_t ntp_packet_t
A custom data type to represent NTP packet header format.
_ntp_packet_t::recv_ts
ntp_timestamp_t recv_ts
Definition: ntputil.c:111
_ntp_packet_t::root_delay
uint32_t root_delay
Definition: ntputil.c:106
NTPUTIL_MAX_FRAC_DOUBLE
const double NTPUTIL_MAX_FRAC_DOUBLE
Definition: ntputil.c:116
NTPUTIL_DEFAULT_PORT
const uint16_t NTPUTIL_DEFAULT_PORT
Definition: ntputil.c:119
_ntp_packet_t::li_vn_mode
uint8_t li_vn_mode
Definition: ntputil.c:102
_ntp_timestamp_t
A custom data type to represent NTP timestamp format.
Definition: ntputil.c:40
NTPUTIL_TIMESTAMP_DELTA
const uint64_t NTPUTIL_TIMESTAMP_DELTA
Definition: ntputil.c:115
_ntp_packet_t::poll
uint8_t poll
Definition: ntputil.c:104
_ntp_packet_t::xmit_ts
ntp_timestamp_t xmit_ts
Definition: ntputil.c:112
ntputil_get_epoch
int64_t ntputil_get_epoch(uint32_t hnums, char **hnames, uint16_t *ports)
Get NTP timestamps from the given or public NTP servers.
Definition: ntputil.c:140
_ntp_packet_t::ref_id
uint32_t ref_id
Definition: ntputil.c:108
_ntp_timestamp_t::sec
uint32_t sec
Definition: ntputil.c:42
_ntp_packet_t::root_dispersion
uint32_t root_dispersion
Definition: ntputil.c:107
_ntp_packet_t::org_ts
ntp_timestamp_t org_ts
Definition: ntputil.c:110
ntputil.h
A header file of NTP utility functions.
_convert_to_host_byte_order
uint32_t _convert_to_host_byte_order(uint32_t in)
Wrapper function of ntohl.
Definition: ntputil.c:125
_ntp_packet_t::stratum
uint8_t stratum
Definition: ntputil.c:103
_ntp_packet_t::ref_ts
ntp_timestamp_t ref_ts
Definition: ntputil.c:109
_ntp_packet_t
A custom data type to represent NTP packet header format.
Definition: ntputil.c:100
ntp_timestamp_t
struct _ntp_timestamp_t ntp_timestamp_t
A custom data type to represent NTP timestamp format.
_ntp_timestamp_t::frac
uint32_t frac
Definition: ntputil.c:43
NTPUTIL_SEC_TO_USEC_MULTIPLIER
const int64_t NTPUTIL_SEC_TO_USEC_MULTIPLIER
Definition: ntputil.c:117