/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Portions of this source code were derived from Berkeley
* 4.3 BSD under license from the Regents of the University of
* California.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* get time from remote machine
*
* gets time, obtaining value from host
* on the (udp, tcp)/time tli connection. Since timeserver returns
* with time of day in seconds since Jan 1, 1900, must
* subtract seconds before Jan 1, 1970 to get
* what unix uses.
*/
#include "mt.h"
#include <rpc/rpc.h>
#include <errno.h>
#include <sys/poll.h>
#include <rpc/nettype.h>
#include <netdir.h>
#include <stdio.h>
extern int __rpc_timeval_to_msec();
#ifdef DEBUG
#define debug(msg) t_error(msg)
#else
#define debug(msg)
#endif
#define NYEARS (1970 - 1900)
#define TOFFSET ((uint_t)60*60*24*(365*NYEARS + (NYEARS/4)))
/*
* This is based upon the internet time server, but it contacts it by
* using TLI instead of socket.
*/
int
rtime_tli(char *host, struct timeval *timep, struct timeval *timeout)
{
uint32_t thetime;
int flag;
struct nd_addrlist *nlist = NULL;
struct nd_hostserv rpcbind_hs;
struct netconfig *nconf = NULL;
int foundit = 0;
int fd = -1;
nconf = __rpc_getconfip(timeout == NULL ? "tcp" : "udp");
if (nconf == NULL)
goto error;
if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) == -1) {
debug("open");
goto error;
}
if (t_bind(fd, NULL, NULL) < 0) {
debug("bind");
goto error;
}
/* Get the address of the rpcbind */
rpcbind_hs.h_host = host;
rpcbind_hs.h_serv = "time";
/* Basically get the address of the remote machine on IP */
if (netdir_getbyname(nconf, &rpcbind_hs, &nlist))
goto error;
if (nconf->nc_semantics == NC_TPI_CLTS) {
struct t_unitdata tu_data;
struct pollfd pfd;
int res;
int msec;
tu_data.addr = *nlist->n_addrs;
tu_data.udata.buf = (char *)&thetime;
tu_data.udata.len = (uint_t)sizeof (thetime);
tu_data.udata.maxlen = tu_data.udata.len;
tu_data.opt.len = 0;
tu_data.opt.maxlen = 0;
if (t_sndudata(fd, &tu_data) == -1) {
debug("udp");
goto error;
}
pfd.fd = fd;
pfd.events = POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND;
msec = __rpc_timeval_to_msec(timeout);
do {
res = poll(&pfd, 1, msec);
} while (res < 0);
if ((res <= 0) || (pfd.revents & POLLNVAL))
goto error;
if (t_rcvudata(fd, &tu_data, &flag) < 0) {
debug("udp");
goto error;
}
foundit = 1;
} else {
struct t_call sndcall;
sndcall.addr = *nlist->n_addrs;
sndcall.opt.len = sndcall.opt.maxlen = 0;
sndcall.udata.len = sndcall.udata.maxlen = 0;
if (t_connect(fd, &sndcall, NULL) == -1) {
debug("tcp");
goto error;
}
if (t_rcv(fd, (char *)&thetime, (uint_t)sizeof (thetime), &flag)
!= (uint_t)sizeof (thetime)) {
debug("tcp");
goto error;
}
foundit = 1;
}
thetime = ntohl(thetime);
timep->tv_sec = thetime - TOFFSET;
timep->tv_usec = 0;
error:
if (nconf) {
(void) freenetconfigent(nconf);
if (fd != -1) {
(void) t_close(fd);
if (nlist)
netdir_free((char *)nlist, ND_ADDRLIST);
}
}
return (foundit);
}