Change client_check() to calculate the best offset and the best frequency
[dragonfly.git] / usr.sbin / dntpd / ntpreq.c
1 /*
2  * Copyright (c) 2005 The DragonFly Project.  All rights reserved.
3  * 
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  * 
34  * $DragonFly: src/usr.sbin/dntpd/ntpreq.c,v 1.3 2005/04/24 09:39:27 dillon Exp $
35  */
36
37 #include "defs.h"
38
39 static __inline void
40 s_fixedpt_ntoh(struct s_fixedpt *fixed)
41 {
42     fixed->int_parts = ntohs(fixed->int_parts);
43     fixed->fractions = ntohs(fixed->fractions);
44 }
45
46 static __inline void
47 s_fixedpt_hton(struct s_fixedpt *fixed)
48 {
49     fixed->int_parts = htons(fixed->int_parts);
50     fixed->fractions = htons(fixed->fractions);
51 }
52
53
54 static __inline void
55 l_fixedpt_ntoh(struct l_fixedpt *fixed)
56 {
57     fixed->int_partl = ntohl(fixed->int_partl);
58     fixed->fractionl = ntohl(fixed->fractionl);
59 }
60
61 static __inline void
62 l_fixedpt_hton(struct l_fixedpt *fixed)
63 {
64     fixed->int_partl = htonl(fixed->int_partl);
65     fixed->fractionl = htonl(fixed->fractionl);
66 }
67
68 static void
69 ntp_ntoh(struct ntp_msg *msg)
70 {
71     msg->refid = ntohl(msg->refid);
72     s_fixedpt_ntoh(&msg->rootdelay);
73     s_fixedpt_ntoh(&msg->dispersion);
74     l_fixedpt_ntoh(&msg->reftime);
75     l_fixedpt_ntoh(&msg->orgtime);
76     l_fixedpt_ntoh(&msg->rectime);
77     l_fixedpt_ntoh(&msg->xmttime);
78     msg->keyid = ntohl(msg->keyid);
79 }
80
81 static void
82 ntp_hton(struct ntp_msg *msg)
83 {
84     msg->refid = htonl(msg->refid);
85     s_fixedpt_hton(&msg->rootdelay);
86     s_fixedpt_hton(&msg->dispersion);
87     l_fixedpt_hton(&msg->reftime);
88     l_fixedpt_hton(&msg->orgtime);
89     l_fixedpt_hton(&msg->rectime);
90     l_fixedpt_hton(&msg->xmttime);
91     msg->keyid = htonl(msg->keyid);
92 }
93
94 int
95 udp_ntptimereq(int fd, struct timeval *rtvp, struct timeval *ltvp, 
96                struct timeval *lbtvp)
97 {
98     struct ntp_msg wmsg;
99     struct ntp_msg rmsg;
100     struct timeval tv1;
101     struct timeval seltv;
102     fd_set rfds;
103     int error;
104     int n;
105
106     /*
107      * Setup the message
108      */
109     bzero(&wmsg, sizeof(wmsg));
110     wmsg.status = LI_ALARM | MODE_CLIENT | (NTP_VERSION << 3);
111     wmsg.ppoll = 4;
112     wmsg.precision = -6;
113     wmsg.rootdelay.int_parts = 1;
114     wmsg.dispersion.int_parts = 1;
115     wmsg.refid = 0;
116     wmsg.xmttime.int_partl = time(NULL) + JAN_1970;
117     wmsg.xmttime.fractionl = random();
118
119     /*
120      * Timed transmit
121      */
122     gettimeofday(&tv1, NULL);
123     ntp_hton(&wmsg);
124     n = write(fd, &wmsg, NTP_MSGSIZE_NOAUTH);
125     if (n != NTP_MSGSIZE_NOAUTH)
126         return(-1);
127     ntp_ntoh(&wmsg);
128
129     /*
130      * Wait for reply
131      */
132     seltv.tv_sec = 2;
133     seltv.tv_usec = 0;
134     FD_ZERO(&rfds);
135     FD_SET(fd, &rfds);
136     select(fd + 1, &rfds, NULL, NULL, &seltv);
137
138     /*
139      * Drain socket, process the first matching reply or error out.
140      * Errors are not necessarily fatal.  e.g. a signal could cause select()
141      * to return early.
142      */
143     error = -1;
144     while ((n = read(fd, &rmsg, sizeof(rmsg))) >= 0) {
145         if (n < NTP_MSGSIZE_NOAUTH)
146             continue;
147         ntp_ntoh(&rmsg);
148         if (bcmp(&rmsg.orgtime, &wmsg.xmttime, sizeof(rmsg.orgtime)) != 0)
149             continue;
150
151         /*
152          * Ok, we have a good reply, how long did it take?
153          *
154          * reftime
155          * orgtime
156          * rectime
157          * xmttime
158          */
159         gettimeofday(ltvp, NULL);
160         sysntp_getbasetime(lbtvp);
161
162         l_fixedpt_to_tv(&rmsg.xmttime, rtvp);
163         tv_add_micro(rtvp, (long)(tv_delta_double(&tv1, ltvp) * 1000000.0) / 2);
164
165         error = 0;
166         break;
167     }
168     return(error);
169 }
170