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 9 static char sccsid[] = "@(#)netdate.c 5.1 (Berkeley) 12/04/90"; 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 25 extern 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 */ 34 netsettime(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; 100 loop: 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 147 bad: 148 (void)close(s); 149 return(retval = 2); 150 } 151