netdate.c revision 161469
1228753Smm/*- 2228753Smm * Copyright (c) 1990, 1993 3228753Smm * The Regents of the University of California. All rights reserved. 4228753Smm * 5228753Smm * Redistribution and use in source and binary forms, with or without 6228753Smm * modification, are permitted provided that the following conditions 7228753Smm * are met: 8228753Smm * 1. Redistributions of source code must retain the above copyright 9228753Smm * notice, this list of conditions and the following disclaimer. 10228753Smm * 2. Redistributions in binary form must reproduce the above copyright 11228753Smm * notice, this list of conditions and the following disclaimer in the 12228753Smm * documentation and/or other materials provided with the distribution. 13228753Smm * 4. Neither the name of the University nor the names of its contributors 14228753Smm * may be used to endorse or promote products derived from this software 15228753Smm * without specific prior written permission. 16228753Smm * 17228753Smm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18228753Smm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19228753Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20228753Smm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21228753Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22228753Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23228753Smm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24228753Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25228753Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26228753Smm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27229592Smm * SUCH DAMAGE. 28228753Smm */ 29228753Smm 30228753Smm#if 0 31228753Smm#ifndef lint 32228753Smmstatic char sccsid[] = "@(#)netdate.c 8.1 (Berkeley) 5/31/93"; 33228753Smm#endif /* not lint */ 34228753Smm#endif 35228753Smm 36228753Smm#include <sys/cdefs.h> 37228753Smm__FBSDID("$FreeBSD: head/bin/date/netdate.c 161469 2006-08-20 06:31:24Z imp $"); 38228753Smm 39228753Smm#include <sys/param.h> 40228753Smm#include <sys/time.h> 41228753Smm#include <sys/socket.h> 42228753Smm 43228753Smm#include <netinet/in.h> 44228753Smm#include <netdb.h> 45228753Smm#define TSPTYPES 46228753Smm#include <protocols/timed.h> 47228753Smm 48228753Smm#include <err.h> 49228753Smm#include <errno.h> 50228753Smm#include <string.h> 51228753Smm#include <unistd.h> 52228753Smm 53228753Smm#include "extern.h" 54228753Smm 55228753Smm#define WAITACK 2 /* seconds */ 56228753Smm#define WAITDATEACK 5 /* seconds */ 57228753Smm 58228753Smmextern int retval; 59228753Smm 60228753Smm/* 61228753Smm * Set the date in the machines controlled by timedaemons by communicating the 62228753Smm * new date to the local timedaemon. If the timedaemon is in the master state, 63228753Smm * it performs the correction on all slaves. If it is in the slave state, it 64228753Smm * notifies the master that a correction is needed. 65228753Smm * Returns 0 on success. Returns > 0 on failure, setting retval to 2; 66228753Smm */ 67228753Smmint 68228753Smmnetsettime(time_t tval) 69228753Smm{ 70228753Smm struct timeval tout; 71228753Smm struct servent *sp; 72228753Smm struct tsp msg; 73228753Smm struct sockaddr_in lsin, dest, from; 74228753Smm fd_set ready; 75228753Smm long waittime; 76228753Smm int s, port, timed_ack, found, lerr; 77228753Smm socklen_t length; 78228753Smm char hostname[MAXHOSTNAMELEN]; 79228753Smm 80228753Smm if ((sp = getservbyname("timed", "udp")) == NULL) { 81228753Smm warnx("timed/udp: unknown service"); 82228753Smm return (retval = 2); 83228753Smm } 84228753Smm 85228753Smm dest.sin_port = sp->s_port; 86228753Smm dest.sin_family = AF_INET; 87228753Smm dest.sin_addr.s_addr = htonl((u_long)INADDR_ANY); 88228753Smm s = socket(AF_INET, SOCK_DGRAM, 0); 89228753Smm if (s < 0) { 90228753Smm if (errno != EPROTONOSUPPORT) 91228753Smm warn("timed"); 92228753Smm return (retval = 2); 93228753Smm } 94228753Smm 95228753Smm memset(&lsin, 0, sizeof(lsin)); 96228753Smm lsin.sin_family = AF_INET; 97228753Smm for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) { 98228753Smm lsin.sin_port = htons((u_short)port); 99228753Smm if (bind(s, (struct sockaddr *)&lsin, sizeof(lsin)) >= 0) 100228753Smm break; 101228753Smm if (errno == EADDRINUSE) 102228753Smm continue; 103228753Smm if (errno != EADDRNOTAVAIL) 104228753Smm warn("bind"); 105228753Smm goto bad; 106228753Smm } 107228753Smm if (port == IPPORT_RESERVED / 2) { 108228753Smm warnx("all ports in use"); 109228753Smm goto bad; 110228753Smm } 111228753Smm memset(&msg, 0, sizeof(msg)); 112228753Smm msg.tsp_type = TSP_SETDATE; 113228753Smm msg.tsp_vers = TSPVERSION; 114228753Smm if (gethostname(hostname, sizeof(hostname))) { 115228753Smm warn("gethostname"); 116228753Smm goto bad; 117228753Smm } 118228753Smm (void)strlcpy(msg.tsp_name, hostname, sizeof(msg.tsp_name)); 119228753Smm msg.tsp_seq = htons((u_short)0); 120228753Smm msg.tsp_time.tv_sec = htonl((u_long)tval); 121228753Smm msg.tsp_time.tv_usec = htonl((u_long)0); 122228753Smm length = sizeof(struct sockaddr_in); 123228753Smm if (connect(s, (struct sockaddr *)&dest, length) < 0) { 124228753Smm warn("connect"); 125228753Smm goto bad; 126228753Smm } 127228753Smm if (send(s, (char *)&msg, sizeof(struct tsp), 0) < 0) { 128228753Smm if (errno != ECONNREFUSED) 129228753Smm warn("send"); 130228753Smm goto bad; 131229592Smm } 132228753Smm 133228753Smm timed_ack = -1; 134228753Smm waittime = WAITACK; 135228753Smmloop: 136228753Smm tout.tv_sec = waittime; 137228753Smm tout.tv_usec = 0; 138228753Smm 139228753Smm FD_ZERO(&ready); 140228753Smm FD_SET(s, &ready); 141228753Smm found = select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout); 142228753Smm 143228753Smm length = sizeof(lerr); 144228753Smm if (!getsockopt(s, 145228753Smm SOL_SOCKET, SO_ERROR, (char *)&lerr, &length) && lerr) { 146228753Smm if (lerr != ECONNREFUSED) 147228753Smm warnc(lerr, "send (delayed error)"); 148228753Smm goto bad; 149228753Smm } 150228753Smm 151228753Smm if (found > 0 && FD_ISSET(s, &ready)) { 152228753Smm length = sizeof(struct sockaddr_in); 153228753Smm if (recvfrom(s, &msg, sizeof(struct tsp), 0, 154228753Smm (struct sockaddr *)&from, &length) < 0) { 155228753Smm if (errno != ECONNREFUSED) 156228753Smm warn("recvfrom"); 157228753Smm goto bad; 158228753Smm } 159228753Smm msg.tsp_seq = ntohs(msg.tsp_seq); 160228753Smm msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec); 161228753Smm msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec); 162228753Smm switch (msg.tsp_type) { 163228753Smm case TSP_ACK: 164228753Smm timed_ack = TSP_ACK; 165228753Smm waittime = WAITDATEACK; 166228753Smm goto loop; 167228753Smm case TSP_DATEACK: 168228753Smm (void)close(s); 169228753Smm return (0); 170228753Smm default: 171228753Smm warnx("wrong ack received from timed: %s", 172228753Smm tsptype[msg.tsp_type]); 173228753Smm timed_ack = -1; 174228753Smm break; 175228753Smm } 176228753Smm } 177228753Smm if (timed_ack == -1) 178228753Smm warnx("can't reach time daemon, time set locally"); 179228753Smm 180228753Smmbad: 181228753Smm (void)close(s); 182228753Smm return (retval = 2); 183228753Smm} 184228753Smm