netdate.c revision 90108
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1990, 1993 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * Redistribution and use in source and binary forms, with or without 61556Srgrimes * modification, are permitted provided that the following conditions 71556Srgrimes * are met: 81556Srgrimes * 1. Redistributions of source code must retain the above copyright 91556Srgrimes * notice, this list of conditions and the following disclaimer. 101556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111556Srgrimes * notice, this list of conditions and the following disclaimer in the 121556Srgrimes * documentation and/or other materials provided with the distribution. 131556Srgrimes * 3. All advertising materials mentioning features or use of this software 141556Srgrimes * must display the following acknowledgement: 151556Srgrimes * This product includes software developed by the University of 161556Srgrimes * California, Berkeley and its contributors. 171556Srgrimes * 4. Neither the name of the University nor the names of its contributors 181556Srgrimes * may be used to endorse or promote products derived from this software 191556Srgrimes * without specific prior written permission. 201556Srgrimes * 211556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311556Srgrimes * SUCH DAMAGE. 321556Srgrimes */ 331556Srgrimes 341556Srgrimes#ifndef lint 3535773Scharnier#if 0 3636006Scharnierstatic char sccsid[] = "@(#)netdate.c 8.1 (Berkeley) 5/31/93"; 3735773Scharnier#endif 3835773Scharnierstatic const char rcsid[] = 3950471Speter "$FreeBSD: head/bin/date/netdate.c 90108 2002-02-02 06:24:13Z imp $"; 401556Srgrimes#endif /* not lint */ 411556Srgrimes 421556Srgrimes#include <sys/param.h> 431556Srgrimes#include <sys/time.h> 441556Srgrimes#include <sys/socket.h> 451556Srgrimes 461556Srgrimes#include <netinet/in.h> 471556Srgrimes#include <netdb.h> 481556Srgrimes#define TSPTYPES 491556Srgrimes#include <protocols/timed.h> 501556Srgrimes 511556Srgrimes#include <err.h> 521556Srgrimes#include <errno.h> 531556Srgrimes#include <string.h> 541556Srgrimes#include <unistd.h> 551556Srgrimes 561556Srgrimes#include "extern.h" 571556Srgrimes 581556Srgrimes#define WAITACK 2 /* seconds */ 591556Srgrimes#define WAITDATEACK 5 /* seconds */ 601556Srgrimes 611556Srgrimesextern int retval; 621556Srgrimes 631556Srgrimes/* 641556Srgrimes * Set the date in the machines controlled by timedaemons by communicating the 651556Srgrimes * new date to the local timedaemon. If the timedaemon is in the master state, 661556Srgrimes * it performs the correction on all slaves. If it is in the slave state, it 671556Srgrimes * notifies the master that a correction is needed. 681556Srgrimes * Returns 0 on success. Returns > 0 on failure, setting retval to 2; 691556Srgrimes */ 701556Srgrimesint 7190108Simpnetsettime(time_t tval) 721556Srgrimes{ 731556Srgrimes struct timeval tout; 741556Srgrimes struct servent *sp; 751556Srgrimes struct tsp msg; 761556Srgrimes struct sockaddr_in sin, dest, from; 771556Srgrimes fd_set ready; 781556Srgrimes long waittime; 791556Srgrimes int s, length, port, timed_ack, found, err; 801556Srgrimes char hostname[MAXHOSTNAMELEN]; 811556Srgrimes 821556Srgrimes if ((sp = getservbyname("timed", "udp")) == NULL) { 831556Srgrimes warnx("udp/timed: unknown service"); 841556Srgrimes return (retval = 2); 851556Srgrimes } 861556Srgrimes 871556Srgrimes dest.sin_port = sp->s_port; 881556Srgrimes dest.sin_family = AF_INET; 891556Srgrimes dest.sin_addr.s_addr = htonl((u_long)INADDR_ANY); 901556Srgrimes s = socket(AF_INET, SOCK_DGRAM, 0); 911556Srgrimes if (s < 0) { 921556Srgrimes if (errno != EPROTONOSUPPORT) 931556Srgrimes warn("timed"); 941556Srgrimes return (retval = 2); 951556Srgrimes } 961556Srgrimes 971556Srgrimes memset(&sin, 0, sizeof(sin)); 981556Srgrimes sin.sin_family = AF_INET; 991556Srgrimes for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) { 1001556Srgrimes sin.sin_port = htons((u_short)port); 1011556Srgrimes if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) 1021556Srgrimes break; 1031556Srgrimes if (errno == EADDRINUSE) 1041556Srgrimes continue; 1051556Srgrimes if (errno != EADDRNOTAVAIL) 1061556Srgrimes warn("bind"); 1071556Srgrimes goto bad; 1081556Srgrimes } 1091556Srgrimes if (port == IPPORT_RESERVED / 2) { 1101556Srgrimes warnx("all ports in use"); 1111556Srgrimes goto bad; 1121556Srgrimes } 1131556Srgrimes msg.tsp_type = TSP_SETDATE; 1141556Srgrimes msg.tsp_vers = TSPVERSION; 1151556Srgrimes if (gethostname(hostname, sizeof(hostname))) { 1161556Srgrimes warn("gethostname"); 1171556Srgrimes goto bad; 1181556Srgrimes } 11926362Scharnier (void)strncpy(msg.tsp_name, hostname, sizeof(msg.tsp_name) - 1); 12023622Sguido msg.tsp_name[sizeof(msg.tsp_name) - 1] = '\0'; 1211556Srgrimes msg.tsp_seq = htons((u_short)0); 1221556Srgrimes msg.tsp_time.tv_sec = htonl((u_long)tval); 1231556Srgrimes msg.tsp_time.tv_usec = htonl((u_long)0); 1241556Srgrimes length = sizeof(struct sockaddr_in); 1251556Srgrimes if (connect(s, (struct sockaddr *)&dest, length) < 0) { 1261556Srgrimes warn("connect"); 1271556Srgrimes goto bad; 1281556Srgrimes } 1291556Srgrimes if (send(s, (char *)&msg, sizeof(struct tsp), 0) < 0) { 1301556Srgrimes if (errno != ECONNREFUSED) 1311556Srgrimes warn("send"); 1321556Srgrimes goto bad; 1331556Srgrimes } 1341556Srgrimes 1351556Srgrimes timed_ack = -1; 1361556Srgrimes waittime = WAITACK; 1371556Srgrimesloop: 1381556Srgrimes tout.tv_sec = waittime; 1391556Srgrimes tout.tv_usec = 0; 1401556Srgrimes 1411556Srgrimes FD_ZERO(&ready); 1421556Srgrimes FD_SET(s, &ready); 1431556Srgrimes found = select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout); 1441556Srgrimes 1451556Srgrimes length = sizeof(err); 1461556Srgrimes if (!getsockopt(s, 1471556Srgrimes SOL_SOCKET, SO_ERROR, (char *)&err, &length) && err) { 1481556Srgrimes if (err != ECONNREFUSED) 14974819Sfenner warnc(err, "send (delayed error)"); 1501556Srgrimes goto bad; 1511556Srgrimes } 1521556Srgrimes 1531556Srgrimes if (found > 0 && FD_ISSET(s, &ready)) { 1541556Srgrimes length = sizeof(struct sockaddr_in); 1551556Srgrimes if (recvfrom(s, &msg, sizeof(struct tsp), 0, 1561556Srgrimes (struct sockaddr *)&from, &length) < 0) { 1571556Srgrimes if (errno != ECONNREFUSED) 1581556Srgrimes warn("recvfrom"); 1591556Srgrimes goto bad; 1601556Srgrimes } 1611556Srgrimes msg.tsp_seq = ntohs(msg.tsp_seq); 1621556Srgrimes msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec); 1631556Srgrimes msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec); 1641556Srgrimes switch (msg.tsp_type) { 1651556Srgrimes case TSP_ACK: 1661556Srgrimes timed_ack = TSP_ACK; 1671556Srgrimes waittime = WAITDATEACK; 1681556Srgrimes goto loop; 1691556Srgrimes case TSP_DATEACK: 1701556Srgrimes (void)close(s); 1711556Srgrimes return (0); 1721556Srgrimes default: 1738855Srgrimes warnx("wrong ack received from timed: %s", 1741556Srgrimes tsptype[msg.tsp_type]); 1751556Srgrimes timed_ack = -1; 1761556Srgrimes break; 1771556Srgrimes } 1781556Srgrimes } 1791556Srgrimes if (timed_ack == -1) 1801556Srgrimes warnx("can't reach time daemon, time set locally"); 1811556Srgrimes 1821556Srgrimesbad: 1831556Srgrimes (void)close(s); 1841556Srgrimes return (retval = 2); 1851556Srgrimes} 186