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