option-tester: Add many changes
[ntpsec.git] / ntpd / ntp_packetstamp.c
blobdc0d8ea12dd07963332244b1ec93f07940027c1b
1 /*
2 * ntp_packetstamp.c - grubby platform-dependent details of packet timestamps
4 * One of our serious platform dependencies (things POSIX doesn't
5 * specify a facility for) is isolated here.
6 */
7 #include "config.h"
9 #ifdef HAVE_SYS_IOCTL_H
10 # include <sys/ioctl.h>
11 #endif
13 #include "ntpd.h"
14 #include "ntp_stdlib.h"
15 #include "timespecops.h"
17 /* We handle 3 flavors of timestamp:
18 * SO_TIMESTAMPNS/SCM_TIMESTAMPNS Linux (maybe others)
19 * SO_TS_CLOCK/SCM_REALTIME FreeBSD
20 * SO_TIMESTAMP/SCM_TIMESTAMP Everybody else
22 * Linux supports both SO_TIMESTAMP and SO_TIMESTAMPNS so it's
23 * important to check for SO_TIMESTAMPNS first to get the better accuracy.
25 * FreeBSD needs 2 setsockopt, SO_TIMESTAMP and SO_TS_CLOCK
27 * Note that the if/elif tests are done in several places.
28 * It's important that they all check in the same order to
29 * be consistent in case some systems support more than one.
31 * If SO_xxx exists, we assume that SCM_xxx does too.
32 * All flavors assume the CMSG_xxx macros exist.
37 void
38 enable_packetstamps(
39 int fd,
40 sockaddr_u * addr
43 const int on = 1;
44 static bool once = false;
45 #if defined(SO_TS_CLOCK)
46 const int ts_type = SO_TS_REALTIME;
47 #endif
49 #if defined (SO_TIMESTAMPNS)
50 if (!once) {
51 once = true;
52 msyslog(LOG_INFO, "INIT: Using SO_TIMESTAMPNS(ns)");
54 if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPNS,
55 (const void *)&on, sizeof(on)))
56 msyslog(LOG_DEBUG,
57 "ERR: setsockopt SO_TIMESTAMPNS on fails on address %s: %s",
58 socktoa(addr), strerror(errno));
59 else
60 DPRINT(4, ("ERR: setsockopt SO_TIMESTAMPNS enabled on fd %d address %s\n",
61 fd, socktoa(addr)));
62 #elif defined(SO_TIMESTAMP)
63 #if !defined(SO_TS_CLOCK)
64 if (!once) {
65 once = true;
66 msyslog(LOG_INFO, "INIT: Using SO_TIMESTAMP(us)");
68 #endif
69 if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMP,
70 (const void*)&on, sizeof(on)))
71 msyslog(LOG_DEBUG,
72 "ERR: setsockopt SO_TIMESTAMP on fails on address %s: %s",
73 socktoa(addr), strerror(errno));
74 else
75 DPRINT(4, ("setsockopt SO_TIMESTAMP enabled on fd %d address %s\n",
76 fd, socktoa(addr)));
77 #if defined(SO_TS_CLOCK)
78 /* FreeBSD */
79 if (!once) {
80 once = true;
81 msyslog(LOG_INFO, "INIT: Using SO_TS_CLOCK(ns)");
83 if (setsockopt(fd, SOL_SOCKET, SO_TS_CLOCK,
84 (const void*)&ts_type, sizeof(ts_type)))
85 msyslog(LOG_DEBUG,
86 "ERR: setsockop SO_TS_CLOCK on fails on address %s: %s",
87 socktoa(addr), strerror(errno));
88 else
89 DPRINT(4, ("setsockopt SO_TS_CLOCK enabled on fd %d address %s\n",
90 fd, socktoa(addr)));
91 #endif
92 #else
93 # error "Can't get packet timestamp"
94 #endif
99 * extract timestamps from control message buffer
101 l_fp
102 fetch_packetstamp(
103 struct msghdr * msghdr
106 struct cmsghdr * cmsghdr;
107 #if defined(SO_TIMESTAMPNS) || defined(SO_TS_CLOCK)
108 struct timespec * tsp;
109 #elif defined(SO_TIMESTAMP)
110 struct timeval * tvp;
111 #endif
112 l_fp nts = 0; /* network time stamp */
114 /* There should be only one cmsg. */
115 cmsghdr = CMSG_FIRSTHDR(msghdr);
116 if (NULL == cmsghdr) {
117 DPRINT(4, ("fetch_timestamp: can't find timestamp\n"));
118 msyslog(LOG_ERR, "ERR: fetch_timestamp: no msghdrs");
119 exit(2);
120 /* return ts; ** Kludge to use time from select. */
122 #if defined(SO_TIMESTAMPNS)
123 /* Linux and ?? */
124 if (SCM_TIMESTAMPNS != cmsghdr->cmsg_type) {
125 #elif defined(SO_TS_CLOCK)
126 /* FreeBSD */
127 if (SCM_REALTIME != cmsghdr->cmsg_type) {
128 #elif defined(SO_TIMESTAMP)
129 if (SCM_TIMESTAMP != cmsghdr->cmsg_type) {
130 #else
131 # error "Can't get packet timestamp"
132 #endif
133 DPRINT(4,
134 ("fetch_timestamp: strange control message 0x%x\n",
135 (unsigned)cmsghdr->cmsg_type));
136 msyslog(LOG_ERR,
137 "ERR: fetch_timestamp: strange control message 0x%x",
138 (unsigned)cmsghdr->cmsg_type);
139 exit(2);
140 /* Could loop and skip strange types. */
141 /* cmsghdr = CMSG_NXTHDR(msghdr, cmsghdr); */
144 /* cmsghdr now points to a timestamp slot */
146 #if defined(SO_TIMESTAMPNS) || defined(SO_TS_CLOCK)
147 tsp = (struct timespec *)CMSG_DATA(cmsghdr);
148 DPRINT(4, ("fetch_timestamp: system nsec network time stamp: %ld.%09ld\n",
149 (long)tsp->tv_sec, tsp->tv_nsec));
150 nts = tspec_stamp_to_lfp(*tsp);
151 #elif defined(SO_TIMESTAMP)
152 tvp = (struct timeval *)CMSG_DATA(cmsghdr);
153 DPRINT(4, ("fetch_timestamp: system usec network time stamp: %jd.%06ld\n",
154 (intmax_t)tvp->tv_sec, (long)tvp->tv_usec));
155 nts = tspec_stamp_to_lfp(tval_to_tspec(*tvp));
156 #else
157 # error "Can't get packet timestamp"
158 #endif
159 return nts;
162 // end