release.sh: allow REPO and GITBRANCH env override
[minix.git] / bin / date / netdate.c
blob5b5857c72cf7befcb6acb93e0b351bb0629ddc30
1 /* $NetBSD: netdate.c,v 1.30 2011/01/29 02:16:52 christos Exp $ */
3 /*-
4 * Copyright (c) 1990, 1993
5 * The Regents of the University of California. All rights reserved.
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 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)netdate.c 8.2 (Berkeley) 4/28/95";
36 #else
37 __RCSID("$NetBSD: netdate.c,v 1.30 2011/01/29 02:16:52 christos Exp $");
38 #endif
39 #endif /* not lint */
41 #include <sys/param.h>
42 #include <sys/time.h>
43 #include <sys/socket.h>
45 #include <netinet/in.h>
46 #include <netdb.h>
47 #define TSPTYPES
48 #include <protocols/timed.h>
50 #include <err.h>
51 #include <errno.h>
52 #include <poll.h>
53 #include <stdio.h>
54 #include <string.h>
55 #include <unistd.h>
57 #include "extern.h"
59 #define WAITACK 2000 /* milliseconds */
60 #define WAITDATEACK 5000 /* milliseconds */
62 static const char *
63 tsp_type_to_string(const struct tsp *msg)
65 unsigned i;
67 i = msg->tsp_type;
68 return i < TSPTYPENUMBER ? tsptype[i] : "unknown";
72 * Set the date in the machines controlled by timedaemons by communicating the
73 * new date to the local timedaemon. If the timedaemon is in the master state,
74 * it performs the correction on all slaves. If it is in the slave state, it
75 * notifies the master that a correction is needed.
76 * Returns 0 on success. Returns > 0 on failure.
78 int
79 netsettime(time_t tval)
81 struct sockaddr_in dest;
82 struct tsp msg;
83 char hostname[MAXHOSTNAMELEN];
84 struct servent *sp;
85 struct pollfd ready;
86 int found, s, timed_ack, waittime;
88 if ((sp = getservbyname("timed", "udp")) == NULL) {
89 warnx("udp/timed: unknown service");
90 return 2;
93 (void)memset(&dest, 0, sizeof(dest));
94 #ifdef BSD4_4
95 dest.sin_len = sizeof(dest);
96 #endif
97 dest.sin_family = AF_INET;
98 dest.sin_port = sp->s_port;
99 dest.sin_addr.s_addr = htonl(INADDR_ANY);
100 s = socket(AF_INET, SOCK_DGRAM, 0);
101 if (s == -1) {
102 if (errno != EAFNOSUPPORT)
103 warn("timed");
104 return 2;
107 #ifdef IP_PORTRANGE
109 static const int on = IP_PORTRANGE_LOW;
111 if (setsockopt(s, IPPROTO_IP, IP_PORTRANGE, &on,
112 sizeof(on)) == -1) {
113 warn("setsockopt");
114 goto bad;
117 #endif
119 msg.tsp_type = TSP_SETDATE;
120 msg.tsp_vers = TSPVERSION;
121 if (gethostname(hostname, sizeof(hostname)) == -1) {
122 warn("gethostname");
123 goto bad;
125 (void)strlcpy(msg.tsp_name, hostname, sizeof(msg.tsp_name));
126 msg.tsp_seq = htons((in_port_t)0);
127 msg.tsp_time.tv_sec = htonl((in_addr_t)tval); /* XXX: y2038 */
128 msg.tsp_time.tv_usec = htonl((in_addr_t)0);
129 if (connect(s, (const void *)&dest, sizeof(dest)) == -1) {
130 warn("connect");
131 goto bad;
133 if (send(s, &msg, sizeof(msg), 0) == -1) {
134 if (errno != ECONNREFUSED)
135 warn("send");
136 goto bad;
139 timed_ack = -1;
140 waittime = WAITACK;
141 ready.fd = s;
142 ready.events = POLLIN;
143 loop:
144 found = poll(&ready, 1, waittime);
147 socklen_t len;
148 int error;
150 len = sizeof(error);
151 if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) == -1) {
152 warn("getsockopt");
153 goto bad;
155 if (error) {
156 if (error != ECONNREFUSED) {
157 errno = error;
158 warn("send (delayed error)");
160 goto bad;
164 if (found > 0 && ready.revents & POLLIN) {
165 ssize_t ret;
167 if ((ret = recv(s, &msg, sizeof(msg), 0)) == -1) {
168 if (errno != ECONNREFUSED)
169 warn("recv");
170 goto bad;
171 } else if ((size_t)ret < sizeof(msg)) {
172 warnx("recv: incomplete packet");
173 goto bad;
176 msg.tsp_seq = ntohs(msg.tsp_seq);
177 msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec);
178 msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec);
179 switch (msg.tsp_type) {
180 case TSP_ACK:
181 timed_ack = TSP_ACK;
182 waittime = WAITDATEACK;
183 goto loop;
184 case TSP_DATEACK:
185 (void)close(s);
186 return 0;
187 default:
188 warnx("wrong ack received from timed: %s",
189 tsp_type_to_string(&msg));
190 timed_ack = -1;
191 break;
194 if (timed_ack == -1)
195 warnx("can't reach time daemon, time set locally");
197 bad:
198 (void)close(s);
199 return 2;