split out from date.c; some reworking for cleanliness.
[unix-history] / usr / src / bin / date / netdate.c
CommitLineData
927c4ffc
KB
1/*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8#ifndef lint
9static char sccsid[] = "@(#)netdate.c 5.1 (Berkeley) %G%";
10#endif /* not lint */
11
12#include <sys/param.h>
13#include <sys/time.h>
14#include <sys/socket.h>
15#include <sys/errno.h>
16#include <netinet/in.h>
17#include <netdb.h>
18#define TSPTYPES
19#include <protocols/timed.h>
20#include <stdio.h>
21
22#define WAITACK 2 /* seconds */
23#define WAITDATEACK 5 /* seconds */
24
25extern int retval;
26
27/*
28 * Set the date in the machines controlled by timedaemons by communicating the
29 * new date to the local timedaemon. If the timedaemon is in the master state,
30 * it performs the correction on all slaves. If it is in the slave state, it
31 * notifies the master that a correction is needed.
32 * Returns 0 on success. Returns > 0 on failure, setting retval to 2;
33 */
34netsettime(tval)
35 time_t tval;
36{
37 struct timeval tout;
38 struct servent *sp;
39 struct tsp msg;
40 struct sockaddr_in sin, dest, from;
41 fd_set ready;
42 long waittime;
43 int s, length, port, timed_ack, found, err;
44 char hostname[MAXHOSTNAMELEN];
45
46 if ((sp = getservbyname("timed", "udp")) == NULL) {
47 (void)fprintf(stderr, "date: udp/timed: unknown service.n");
48 return (retval = 2);
49 }
50
51 dest.sin_port = sp->s_port;
52 dest.sin_family = AF_INET;
53 dest.sin_addr.s_addr = htonl((u_long)INADDR_ANY);
54 s = socket(AF_INET, SOCK_DGRAM, 0);
55 if (s < 0) {
56 if (errno != EPROTONOSUPPORT)
57 perror("date: timed");
58 return(retval = 2);
59 }
60
61 bzero((char *)&sin, sizeof(sin));
62 sin.sin_family = AF_INET;
63 for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
64 sin.sin_port = htons((u_short)port);
65 if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
66 break;
67 if (errno == EADDRINUSE)
68 continue;
69 if (errno != EADDRNOTAVAIL)
70 perror("date: bind");
71 goto bad;
72 }
73 if (port == IPPORT_RESERVED / 2) {
74 (void)fprintf(stderr, "date: all ports in use.\n");
75 goto bad;
76 }
77 msg.tsp_type = TSP_SETDATE;
78 msg.tsp_vers = TSPVERSION;
79 if (gethostname(hostname, sizeof(hostname))) {
80 perror("date: gethostname");
81 goto bad;
82 }
83 (void)strncpy(msg.tsp_name, hostname, sizeof(hostname));
84 msg.tsp_seq = htons((u_short)0);
85 msg.tsp_time.tv_sec = htonl((u_long)tval);
86 msg.tsp_time.tv_usec = htonl((u_long)0);
87 length = sizeof(struct sockaddr_in);
88 if (connect(s, &dest, length) < 0) {
89 perror("date: connect");
90 goto bad;
91 }
92 if (send(s, (char *)&msg, sizeof(struct tsp), 0) < 0) {
93 if (errno != ECONNREFUSED)
94 perror("date: send");
95 goto bad;
96 }
97
98 timed_ack = -1;
99 waittime = WAITACK;
100loop:
101 tout.tv_sec = waittime;
102 tout.tv_usec = 0;
103
104 FD_ZERO(&ready);
105 FD_SET(s, &ready);
106 found = select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout);
107
108 length = sizeof(err);
109 if (!getsockopt(s, SOL_SOCKET, SO_ERROR, (char *)&err, &length)
110 && err) {
111 if (err != ECONNREFUSED)
112 perror("date: send (delayed error)");
113 goto bad;
114 }
115
116 if (found > 0 && FD_ISSET(s, &ready)) {
117 length = sizeof(struct sockaddr_in);
118 if (recvfrom(s, (char *)&msg, sizeof(struct tsp), 0, &from,
119 &length) < 0) {
120 if (errno != ECONNREFUSED)
121 perror("date: recvfrom");
122 goto bad;
123 }
124 msg.tsp_seq = ntohs(msg.tsp_seq);
125 msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec);
126 msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec);
127 switch (msg.tsp_type) {
128 case TSP_ACK:
129 timed_ack = TSP_ACK;
130 waittime = WAITDATEACK;
131 goto loop;
132 case TSP_DATEACK:
133 (void)close(s);
134 return (0);
135 default:
136 (void)fprintf(stderr,
137 "date: wrong ack received from timed: %s.\n",
138 tsptype[msg.tsp_type]);
139 timed_ack = -1;
140 break;
141 }
142 }
143 if (timed_ack == -1)
144 (void)fprintf(stderr,
145 "date: can't reach time daemon, time set locally.\n");
146
147bad:
148 (void)close(s);
149 return(retval = 2);
150}