ntp_io.c revision 54359
154359Sroberto/*
254359Sroberto * ntp_io.c - input/output routines for ntpd.	The socket-opening code
354359Sroberto *		   was shamelessly stolen from ntpd.
454359Sroberto */
554359Sroberto
654359Sroberto#ifdef HAVE_CONFIG_H
754359Sroberto# include <config.h>
854359Sroberto#endif
954359Sroberto
1054359Sroberto#include <stdio.h>
1154359Sroberto#include <signal.h>
1254359Sroberto#include <sys/types.h>
1354359Sroberto#ifdef HAVE_SYS_PARAM_H
1454359Sroberto# include <sys/param.h>
1554359Sroberto#endif /* HAVE_SYS_PARAM_H */
1654359Sroberto#ifdef HAVE_SYS_TIME_H
1754359Sroberto# include <sys/time.h>
1854359Sroberto#endif
1954359Sroberto#ifdef HAVE_NETINET_IN_H
2054359Sroberto# include <netinet/in.h>
2154359Sroberto#endif
2254359Sroberto#ifdef HAVE_SYS_IOCTL_H
2354359Sroberto# include <sys/ioctl.h>
2454359Sroberto#endif
2554359Sroberto#ifdef HAVE_SYS_SOCKIO_H	/* UXPV: SIOC* #defines (Frank Vance <fvance@waii.com>) */
2654359Sroberto# include <sys/sockio.h>
2754359Sroberto#endif
2854359Sroberto#include <arpa/inet.h>
2954359Sroberto
3054359Sroberto#if _BSDI_VERSION >= 199510
3154359Sroberto# include <ifaddrs.h>
3254359Sroberto#endif
3354359Sroberto
3454359Sroberto#include "ntp_machine.h"
3554359Sroberto#include "ntpd.h"
3654359Sroberto#include "ntp_io.h"
3754359Sroberto#include "iosignal.h"
3854359Sroberto#include "ntp_refclock.h"
3954359Sroberto#include "ntp_if.h"
4054359Sroberto#include "ntp_stdlib.h"
4154359Sroberto
4254359Sroberto#if defined(VMS)		/* most likely UCX-specific */
4354359Sroberto
4454359Sroberto#include <UCX$INETDEF.H>
4554359Sroberto
4654359Sroberto/* "un*x"-compatible names for some items in UCX$INETDEF.H */
4754359Sroberto#define ifreq		IFREQDEF
4854359Sroberto#define ifr_name	IFR$T_NAME
4954359Sroberto#define ifr_addr		IFR$R_DUMMY.IFR$T_ADDR
5054359Sroberto#define ifr_broadaddr	IFR$R_DUMMY.IFR$T_BROADADDR
5154359Sroberto#define ifr_flags		IFR$R_DUMMY.IFR$R_DUMMY_1_OVRL.IFR$W_FLAGS
5254359Sroberto#define IFF_UP		IFR$M_IFF_UP
5354359Sroberto#define IFF_BROADCAST	IFR$M_IFF_BROADCAST
5454359Sroberto#define IFF_LOOPBACK	IFR$M_IFF_LOOPBACK
5554359Sroberto
5654359Sroberto#endif /* VMS */
5754359Sroberto
5854359Sroberto
5954359Sroberto#if defined(VMS) || defined(SYS_WINNT)
6054359Sroberto/* structure used in SIOCGIFCONF request (after [KSR] OSF/1) */
6154359Srobertostruct ifconf {
6254359Sroberto	int ifc_len;			/* size of buffer */
6354359Sroberto	union {
6454359Sroberto		caddr_t ifcu_buf;
6554359Sroberto		struct ifreq *ifcu_req;
6654359Sroberto	} ifc_ifcu;
6754359Sroberto};
6854359Sroberto#define ifc_buf ifc_ifcu.ifcu_buf	/* buffer address */
6954359Sroberto#define ifc_req ifc_ifcu.ifcu_req	/* array of structures returned */
7054359Sroberto
7154359Sroberto#endif /* VMS */
7254359Sroberto
7354359Sroberto#if defined(USE_TTY_SIGPOLL) || defined(USE_UDP_SIGPOLL)
7454359Sroberto# if defined(SYS_AIX) && defined(_IO) /* XXX Identify AIX some other way */
7554359Sroberto#  undef _IO
7654359Sroberto# endif
7754359Sroberto# include <stropts.h>
7854359Sroberto#endif
7954359Sroberto
8054359Sroberto/*
8154359Sroberto * We do asynchronous input using the SIGIO facility.  A number of
8254359Sroberto * recvbuf buffers are preallocated for input.	In the signal
8354359Sroberto * handler we poll to see which sockets are ready and read the
8454359Sroberto * packets from them into the recvbuf's along with a time stamp and
8554359Sroberto * an indication of the source host and the interface it was received
8654359Sroberto * through.  This allows us to get as accurate receive time stamps
8754359Sroberto * as possible independent of other processing going on.
8854359Sroberto *
8954359Sroberto * We watch the number of recvbufs available to the signal handler
9054359Sroberto * and allocate more when this number drops below the low water
9154359Sroberto * mark.  If the signal handler should run out of buffers in the
9254359Sroberto * interim it will drop incoming frames, the idea being that it is
9354359Sroberto * better to drop a packet than to be inaccurate.
9454359Sroberto */
9554359Sroberto
9654359Sroberto
9754359Sroberto/*
9854359Sroberto * Other statistics of possible interest
9954359Sroberto */
10054359Srobertovolatile u_long packets_dropped;	/* total number of packets dropped on reception */
10154359Srobertovolatile u_long packets_ignored;	/* packets received on wild card interface */
10254359Srobertovolatile u_long packets_received;	/* total number of packets received */
10354359Srobertou_long packets_sent;	/* total number of packets sent */
10454359Srobertou_long packets_notsent; /* total number of packets which couldn't be sent */
10554359Sroberto
10654359Srobertovolatile u_long handler_calls;	/* number of calls to interrupt handler */
10754359Srobertovolatile u_long handler_pkts;	/* number of pkts received by handler */
10854359Srobertou_long io_timereset;		/* time counters were reset */
10954359Sroberto
11054359Sroberto/*
11154359Sroberto * Interface stuff
11254359Sroberto */
11354359Srobertostruct interface *any_interface;	/* pointer to default interface */
11454359Srobertostruct interface *loopback_interface;	/* point to loopback interface */
11554359Srobertostatic	struct interface inter_list[MAXINTERFACES];
11654359Srobertostatic	int ninterfaces;
11754359Sroberto
11854359Sroberto#ifdef REFCLOCK
11954359Sroberto/*
12054359Sroberto * Refclock stuff.	We keep a chain of structures with data concerning
12154359Sroberto * the guys we are doing I/O for.
12254359Sroberto */
12354359Srobertostatic	struct refclockio *refio;
12454359Sroberto#endif /* REFCLOCK */
12554359Sroberto
12654359Sroberto/*
12754359Sroberto * File descriptor masks etc. for call to select
12854359Sroberto */
12954359Srobertofd_set activefds;
13054359Srobertoint maxactivefd;
13154359Sroberto
13254359Srobertostatic	int create_sockets	P((u_int));
13354359Srobertostatic	int open_socket		P((struct sockaddr_in *, int, int));
13454359Srobertostatic	void	close_socket	P((int));
13554359Srobertostatic	void	close_file	P((int));
13654359Srobertostatic	char *	fdbits		P((int, fd_set *));
13754359Sroberto
13854359Sroberto/*
13954359Sroberto * init_io - initialize I/O data structures and call socket creation routine
14054359Sroberto */
14154359Srobertovoid
14254359Srobertoinit_io(void)
14354359Sroberto{
14454359Sroberto#ifdef SYS_WINNT
14554359Sroberto	WORD wVersionRequested;
14654359Sroberto	WSADATA wsaData;
14754359Sroberto	init_transmitbuff();
14854359Sroberto#endif /* SYS_WINNT */
14954359Sroberto
15054359Sroberto	/*
15154359Sroberto	 * Init buffer free list and stat counters
15254359Sroberto	 */
15354359Sroberto	init_recvbuff(RECV_INIT);
15454359Sroberto
15554359Sroberto	packets_dropped = packets_received = 0;
15654359Sroberto	packets_ignored = 0;
15754359Sroberto	packets_sent = packets_notsent = 0;
15854359Sroberto	handler_calls = handler_pkts = 0;
15954359Sroberto	io_timereset = 0;
16054359Sroberto	loopback_interface = 0;
16154359Sroberto
16254359Sroberto#ifdef REFCLOCK
16354359Sroberto	refio = 0;
16454359Sroberto#endif
16554359Sroberto
16654359Sroberto#if defined(HAVE_SIGNALED_IO)
16754359Sroberto	(void) set_signal();
16854359Sroberto#endif
16954359Sroberto
17054359Sroberto#ifdef SYS_WINNT
17154359Sroberto	wVersionRequested = MAKEWORD(1,1);
17254359Sroberto	if (WSAStartup(wVersionRequested, &wsaData))
17354359Sroberto	{
17454359Sroberto		msyslog(LOG_ERR, "No useable winsock.dll: %m");
17554359Sroberto		exit(1);
17654359Sroberto	}
17754359Sroberto#endif /* SYS_WINNT */
17854359Sroberto
17954359Sroberto	/*
18054359Sroberto	 * Create the sockets
18154359Sroberto	 */
18254359Sroberto	BLOCKIO();
18354359Sroberto	(void) create_sockets(htons(NTP_PORT));
18454359Sroberto	UNBLOCKIO();
18554359Sroberto
18654359Sroberto#ifdef DEBUG
18754359Sroberto	if (debug)
18854359Sroberto	    printf("init_io: maxactivefd %d\n", maxactivefd);
18954359Sroberto#endif
19054359Sroberto}
19154359Sroberto
19254359Sroberto/*
19354359Sroberto * create_sockets - create a socket for each interface plus a default
19454359Sroberto *			socket for when we don't know where to send
19554359Sroberto */
19654359Srobertostatic int
19754359Srobertocreate_sockets(
19854359Sroberto	u_int port
19954359Sroberto	)
20054359Sroberto{
20154359Sroberto#if _BSDI_VERSION >= 199510
20254359Sroberto	int i, j;
20354359Sroberto	struct ifaddrs *ifaddrs, *ifap;
20454359Sroberto	struct sockaddr_in resmask;
20554359Sroberto#if 	_BSDI_VERSION < 199701
20654359Sroberto	struct ifaddrs *lp;
20754359Sroberto	int num_if;
20854359Sroberto#endif
20954359Sroberto#else	/* _BSDI_VERSION >= 199510 */
21054359Sroberto# ifdef STREAMS_TLI
21154359Sroberto	struct strioctl ioc;
21254359Sroberto# endif /* STREAMS_TLI */
21354359Sroberto	char	buf[MAXINTERFACES*sizeof(struct ifreq)];
21454359Sroberto	struct	ifconf	ifc;
21554359Sroberto	struct	ifreq	ifreq, *ifr;
21654359Sroberto	int n, i, j, vs, size = 0;
21754359Sroberto	struct sockaddr_in resmask;
21854359Sroberto#endif	/* _BSDI_VERSION >= 199510 */
21954359Sroberto
22054359Sroberto#ifdef DEBUG
22154359Sroberto	if (debug)
22254359Sroberto	    printf("create_sockets(%d)\n", ntohs( (u_short) port));
22354359Sroberto#endif
22454359Sroberto
22554359Sroberto	/*
22654359Sroberto	 * create pseudo-interface with wildcard address
22754359Sroberto	 */
22854359Sroberto	inter_list[0].sin.sin_family = AF_INET;
22954359Sroberto	inter_list[0].sin.sin_port = port;
23054359Sroberto	inter_list[0].sin.sin_addr.s_addr = htonl(INADDR_ANY);
23154359Sroberto	(void) strncpy(inter_list[0].name, "wildcard",
23254359Sroberto		       sizeof(inter_list[0].name));
23354359Sroberto	inter_list[0].mask.sin_addr.s_addr = htonl(~ (u_int32)0);
23454359Sroberto	inter_list[0].received = 0;
23554359Sroberto	inter_list[0].sent = 0;
23654359Sroberto	inter_list[0].notsent = 0;
23754359Sroberto	inter_list[0].flags = INT_BROADCAST;
23854359Sroberto
23954359Sroberto#if _BSDI_VERSION >= 199510
24054359Sroberto#if 	_BSDI_VERSION >= 199701
24154359Sroberto	if (getifaddrs(&ifaddrs) < 0)
24254359Sroberto	{
24354359Sroberto		msyslog(LOG_ERR, "getifaddrs: %m");
24454359Sroberto		exit(1);
24554359Sroberto	}
24654359Sroberto	i = 1;
24754359Sroberto	for (ifap = ifaddrs; ifap != NULL; ifap = ifap->ifa_next)
24854359Sroberto#else
24954359Sroberto	    if (getifaddrs(&ifaddrs, &num_if) < 0)
25054359Sroberto	    {
25154359Sroberto		    msyslog(LOG_ERR, "create_sockets: getifaddrs() failed: %m");
25254359Sroberto		    exit(1);
25354359Sroberto	    }
25454359Sroberto
25554359Sroberto	i = 1;
25654359Sroberto
25754359Sroberto	for (ifap = ifaddrs, lp = ifap + num_if; ifap < lp; ifap++)
25854359Sroberto#endif
25954359Sroberto	{
26054359Sroberto		struct sockaddr_in *sin;
26154359Sroberto
26254359Sroberto		if (!ifap->ifa_addr)
26354359Sroberto		    continue;
26454359Sroberto
26554359Sroberto		if (ifap->ifa_addr->sa_family != AF_INET)
26654359Sroberto		    continue;
26754359Sroberto
26854359Sroberto		if ((ifap->ifa_flags & IFF_UP) == 0)
26954359Sroberto		    continue;
27054359Sroberto
27154359Sroberto		if (ifap->ifa_flags & IFF_LOOPBACK)
27254359Sroberto		{
27354359Sroberto			sin = (struct sockaddr_in *)ifap->ifa_addr;
27454359Sroberto			if (ntohl(sin->sin_addr.s_addr) != 0x7f000001)
27554359Sroberto			{
27654359Sroberto				continue;
27754359Sroberto			}
27854359Sroberto		}
27954359Sroberto
28054359Sroberto		inter_list[i].flags = 0;
28154359Sroberto		if (ifap->ifa_flags & IFF_BROADCAST)
28254359Sroberto		    inter_list[i].flags |= INT_BROADCAST;
28354359Sroberto
28454359Sroberto		(void)strcpy(inter_list[i].name, ifap->ifa_name);
28554359Sroberto
28654359Sroberto		sin = (struct sockaddr_in *)ifap->ifa_addr;
28754359Sroberto		inter_list[i].sin = *sin;
28854359Sroberto		inter_list[i].sin.sin_port = port;
28954359Sroberto
29054359Sroberto		if (ifap->ifa_flags & IFF_LOOPBACK)
29154359Sroberto		{
29254359Sroberto			inter_list[i].flags = INT_LOOPBACK;
29354359Sroberto			if (loopback_interface == NULL
29454359Sroberto			    || ntohl(sin->sin_addr.s_addr) != 0x7f000001)
29554359Sroberto			    loopback_interface = &inter_list[i];
29654359Sroberto		}
29754359Sroberto
29854359Sroberto		if (inter_list[i].flags & INT_BROADCAST)
29954359Sroberto		{
30054359Sroberto			sin = (struct sockaddr_in *)ifap->ifa_broadaddr;
30154359Sroberto			inter_list[i].bcast = *sin;
30254359Sroberto			inter_list[i].bcast.sin_port = port;
30354359Sroberto		}
30454359Sroberto
30554359Sroberto		if (ifap->ifa_flags & (IFF_LOOPBACK|IFF_POINTOPOINT))
30654359Sroberto		{
30754359Sroberto			inter_list[i].mask.sin_addr.s_addr = 0xffffffff;
30854359Sroberto		}
30954359Sroberto		else
31054359Sroberto		{
31154359Sroberto			sin = (struct sockaddr_in *)ifap->ifa_netmask;
31254359Sroberto			inter_list[i].mask = *sin;
31354359Sroberto		}
31454359Sroberto		inter_list[i].mask.sin_family = AF_INET;
31554359Sroberto		inter_list[i].mask.sin_len = sizeof *sin;
31654359Sroberto
31754359Sroberto		/*
31854359Sroberto		 * look for an already existing source interface address.  If
31954359Sroberto		 * the machine has multiple point to point interfaces, then
32054359Sroberto		 * the local address may appear more than once.
32154359Sroberto		 *
32254359Sroberto		 * A second problem exists if we have two addresses on
32354359Sroberto		 * the same network (via "ifconfig alias ...").  Don't
32454359Sroberto		 * make two xntp interfaces for the two aliases on the
32554359Sroberto		 * one physical interface. -wsr
32654359Sroberto		 */
32754359Sroberto		for (j=0; j < i; j++)
32854359Sroberto		    if (inter_list[j].sin.sin_addr.s_addr &
32954359Sroberto			inter_list[j].mask.sin_addr.s_addr ==
33054359Sroberto			inter_list[i].sin.sin_addr.s_addr &
33154359Sroberto			inter_list[i].mask.sin_addr.s_addr)
33254359Sroberto		    {
33354359Sroberto			    if (inter_list[j].flags & INT_LOOPBACK)
33454359Sroberto				inter_list[j] = inter_list[i];
33554359Sroberto			    break;
33654359Sroberto		    }
33754359Sroberto		if (j == i)
33854359Sroberto		    i++;
33954359Sroberto		if (i > MAXINTERFACES)
34054359Sroberto		    break;
34154359Sroberto	}
34254359Sroberto	free(ifaddrs);
34354359Sroberto#else	/* _BSDI_VERSION >= 199510 */
34454359Sroberto# ifdef USE_STREAMS_DEVICE_FOR_IF_CONFIG
34554359Sroberto	if ((vs = open("/dev/ip", O_RDONLY)) < 0)
34654359Sroberto	{
34754359Sroberto		msyslog(LOG_ERR, "create_sockets: open(/dev/ip) failed: %m");
34854359Sroberto		exit(1);
34954359Sroberto	}
35054359Sroberto# else /* not USE_STREAMS_DEVICE_FOR_IF_CONFIG */
35154359Sroberto	if (
35254359Sroberto		(vs = socket(AF_INET, SOCK_DGRAM, 0))
35354359Sroberto#  ifndef SYS_WINNT
35454359Sroberto		< 0
35554359Sroberto#  else /* SYS_WINNT */
35654359Sroberto		== INVALID_SOCKET
35754359Sroberto#  endif /* SYS_WINNT */
35854359Sroberto		) {
35954359Sroberto		msyslog(LOG_ERR, "create_sockets: socket(AF_INET, SOCK_DGRAM) failed: %m");
36054359Sroberto		exit(1);
36154359Sroberto	}
36254359Sroberto# endif /* not USE_STREAMS_DEVICE_FOR_IF_CONFIG */
36354359Sroberto
36454359Sroberto	i = 1;
36554359Sroberto# if !defined(SYS_WINNT)
36654359Sroberto	ifc.ifc_len = sizeof(buf);
36754359Sroberto# endif
36854359Sroberto# ifdef STREAMS_TLI
36954359Sroberto	ioc.ic_cmd = SIOCGIFCONF;
37054359Sroberto	ioc.ic_timout = 0;
37154359Sroberto	ioc.ic_dp = (caddr_t)buf;
37254359Sroberto	ioc.ic_len = sizeof(buf);
37354359Sroberto	if(ioctl(vs, I_STR, &ioc) < 0 ||
37454359Sroberto	   ioc.ic_len < sizeof(struct ifreq))
37554359Sroberto	{
37654359Sroberto		msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFCONF) failed: %m - exiting");
37754359Sroberto		exit(1);
37854359Sroberto	}
37954359Sroberto#  ifdef SIZE_RETURNED_IN_BUFFER
38054359Sroberto	ifc.ifc_len = ioc.ic_len - sizeof(int);
38154359Sroberto	ifc.ifc_buf = buf + sizeof(int);
38254359Sroberto#  else /* not SIZE_RETURNED_IN_BUFFER */
38354359Sroberto	ifc.ifc_len = ioc.ic_len;
38454359Sroberto	ifc.ifc_buf = buf;
38554359Sroberto#  endif /* not SIZE_RETURNED_IN_BUFFER */
38654359Sroberto
38754359Sroberto# else /* not STREAMS_TLI */
38854359Sroberto	ifc.ifc_len = sizeof(buf);
38954359Sroberto	ifc.ifc_buf = buf;
39054359Sroberto#  ifndef SYS_WINNT
39154359Sroberto	if (ioctl(vs, SIOCGIFCONF, (char *)&ifc) < 0)
39254359Sroberto#  else
39354359Sroberto 	if (WSAIoctl(vs, SIO_GET_INTERFACE_LIST, 0, 0, ifc.ifc_buf, ifc.ifc_len, &ifc.ifc_len, 0, 0) == SOCKET_ERROR)
39454359Sroberto#  endif /* SYS_WINNT */
39554359Sroberto{
39654359Sroberto		msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFCONF) failed: %m - exiting");
39754359Sroberto		exit(1);
39854359Sroberto}
39954359Sroberto
40054359Sroberto# endif /* not STREAMS_TLI */
40154359Sroberto
40254359Sroberto	for(n = ifc.ifc_len, ifr = ifc.ifc_req; n > 0;
40354359Sroberto	    ifr = (struct ifreq *)((char *)ifr + size))
40454359Sroberto	{
40554359Sroberto		extern int listen_to_virtual_ips;
40654359Sroberto
40754359Sroberto		size = sizeof(*ifr);
40854359Sroberto
40954359Sroberto# ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
41054359Sroberto		if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr))
41154359Sroberto		    size += ifr->ifr_addr.sa_len - sizeof(struct sockaddr);
41254359Sroberto# endif
41354359Sroberto		n -= size;
41454359Sroberto
41554359Sroberto# if !defined(SYS_WINNT)
41654359Sroberto		/* Exclude logical interfaces (indicated by ':' in the interface name)	*/
41754359Sroberto		if (debug)
41854359Sroberto			printf("interface <%s> ", ifr->ifr_name);
41954359Sroberto		if ((listen_to_virtual_ips == 0)
42054359Sroberto		    && (strchr(ifr->ifr_name, (int)':') != NULL)) {
42154359Sroberto			if (debug)
42254359Sroberto			    printf("ignored\n");
42354359Sroberto			continue;
42454359Sroberto		}
42554359Sroberto		if (debug)
42654359Sroberto		    printf("OK\n");
42754359Sroberto
42854359Sroberto		if (
42954359Sroberto#  ifdef VMS /* VMS+UCX */
43054359Sroberto			(((struct sockaddr *)&(ifr->ifr_addr))->sa_family != AF_INET)
43154359Sroberto#  else
43254359Sroberto			(ifr->ifr_addr.sa_family != AF_INET)
43354359Sroberto#  endif /* VMS+UCX */
43454359Sroberto			) {
43554359Sroberto			if (debug)
43654359Sroberto			    printf("ignoring %s - not AF_INET\n",
43754359Sroberto				   ifr->ifr_name);
43854359Sroberto			continue;
43954359Sroberto		}
44054359Sroberto# endif /* SYS_WINNT */
44154359Sroberto		ifreq = *ifr;
44254359Sroberto		inter_list[i].flags = 0;
44354359Sroberto		/* is it broadcast capable? */
44454359Sroberto# ifndef SYS_WINNT
44554359Sroberto#  ifdef STREAMS_TLI
44654359Sroberto		ioc.ic_cmd = SIOCGIFFLAGS;
44754359Sroberto		ioc.ic_timout = 0;
44854359Sroberto		ioc.ic_dp = (caddr_t)&ifreq;
44954359Sroberto		ioc.ic_len = sizeof(struct ifreq);
45054359Sroberto		if(ioctl(vs, I_STR, &ioc)) {
45154359Sroberto			msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFFLAGS) failed: %m");
45254359Sroberto			continue;
45354359Sroberto		}
45454359Sroberto#  else /* not STREAMS_TLI */
45554359Sroberto		if (ioctl(vs, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
45654359Sroberto			if (errno != ENXIO)
45754359Sroberto			    msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFFLAGS) failed: %m");
45854359Sroberto			continue;
45954359Sroberto		}
46054359Sroberto#  endif /* not STREAMS_TLI */
46154359Sroberto		if ((ifreq.ifr_flags & IFF_UP) == 0) {
46254359Sroberto			if (debug)
46354359Sroberto			    printf("ignoring %s - interface not UP\n",
46454359Sroberto				   ifr->ifr_name);
46554359Sroberto			continue;
46654359Sroberto		}
46754359Sroberto		inter_list[i].flags = 0;
46854359Sroberto		if (ifreq.ifr_flags & IFF_BROADCAST)
46954359Sroberto		    inter_list[i].flags |= INT_BROADCAST;
47054359Sroberto# endif /* not SYS_WINNT */
47154359Sroberto# if !defined(SUN_3_3_STINKS)
47254359Sroberto		if (
47354359Sroberto#  if defined(IFF_LOCAL_LOOPBACK) /* defined(SYS_HPUX) && (SYS_HPUX < 8) */
47454359Sroberto			(ifreq.ifr_flags & IFF_LOCAL_LOOPBACK)
47554359Sroberto#  elif defined(IFF_LOOPBACK)
47654359Sroberto			(ifreq.ifr_flags & IFF_LOOPBACK)
47754359Sroberto#  else /* not IFF_LOCAL_LOOPBACK and not IFF_LOOPBACK */
47854359Sroberto			/* test against 127.0.0.1 (yuck!!) */
47954359Sroberto			(inter_list[i].sin.sin_addr.s_addr == inet_addr("127.0.0.1"))
48054359Sroberto#  endif /* not IFF_LOCAL_LOOPBACK and not IFF_LOOPBACK */
48154359Sroberto			)
48254359Sroberto		{
48354359Sroberto#  ifndef SYS_WINNT
48454359Sroberto			inter_list[i].flags |= INT_LOOPBACK;
48554359Sroberto#  endif /* not SYS_WINNT */
48654359Sroberto			if (loopback_interface == 0)
48754359Sroberto			{
48854359Sroberto				loopback_interface = &inter_list[i];
48954359Sroberto			}
49054359Sroberto		}
49154359Sroberto# endif /* not SUN_3_3_STINKS */
49254359Sroberto
49354359Sroberto#if 0
49454359Sroberto# ifndef SYS_WINNT
49554359Sroberto#  ifdef STREAMS_TLI
49654359Sroberto		ioc.ic_cmd = SIOCGIFADDR;
49754359Sroberto		ioc.ic_timout = 0;
49854359Sroberto		ioc.ic_dp = (caddr_t)&ifreq;
49954359Sroberto		ioc.ic_len = sizeof(struct ifreq);
50054359Sroberto		if (ioctl(vs, I_STR, &ioc))
50154359Sroberto		{
50254359Sroberto			msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFADDR) failed: %m");
50354359Sroberto			continue;
50454359Sroberto		}
50554359Sroberto#  else /* not STREAMS_TLI */
50654359Sroberto		if (ioctl(vs, SIOCGIFADDR, (char *)&ifreq) < 0)
50754359Sroberto		{
50854359Sroberto			if (errno != ENXIO)
50954359Sroberto			    msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFADDR) failed: %m");
51054359Sroberto			continue;
51154359Sroberto		}
51254359Sroberto#  endif /* not STREAMS_TLI */
51354359Sroberto# endif /* not SYS_WINNT */
51454359Sroberto#endif /* 0 */
51554359Sroberto# if defined(SYS_WINNT)
51654359Sroberto		{int TODO_FillInTheNameWithSomeThingReasonble;}
51754359Sroberto# else
51854359Sroberto  		(void)strncpy(inter_list[i].name, ifreq.ifr_name,
51954359Sroberto  			      sizeof(inter_list[i].name));
52054359Sroberto# endif
52154359Sroberto		inter_list[i].sin = *(struct sockaddr_in *)&ifr->ifr_addr;
52254359Sroberto		inter_list[i].sin.sin_family = AF_INET;
52354359Sroberto		inter_list[i].sin.sin_port = port;
52454359Sroberto
52554359Sroberto# if defined(SUN_3_3_STINKS)
52654359Sroberto		/*
52754359Sroberto		 * Oh, barf!  I'm too disgusted to even explain this
52854359Sroberto		 */
52954359Sroberto		if (SRCADR(&inter_list[i].sin) == 0x7f000001)
53054359Sroberto		{
53154359Sroberto			inter_list[i].flags |= INT_LOOPBACK;
53254359Sroberto			if (loopback_interface == 0)
53354359Sroberto			    loopback_interface = &inter_list[i];
53454359Sroberto		}
53554359Sroberto# endif /* SUN_3_3_STINKS */
53654359Sroberto# if !defined SYS_WINNT && !defined SYS_CYGWIN32 /* no interface flags on NT */
53754359Sroberto		if (inter_list[i].flags & INT_BROADCAST) {
53854359Sroberto#  ifdef STREAMS_TLI
53954359Sroberto			ioc.ic_cmd = SIOCGIFBRDADDR;
54054359Sroberto			ioc.ic_timout = 0;
54154359Sroberto			ioc.ic_dp = (caddr_t)&ifreq;
54254359Sroberto			ioc.ic_len = sizeof(struct ifreq);
54354359Sroberto			if(ioctl(vs, I_STR, &ioc)) {
54454359Sroberto				msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFBRDADDR) failed: %m");
54554359Sroberto				exit(1);
54654359Sroberto			}
54754359Sroberto#  else /* not STREAMS_TLI */
54854359Sroberto			if (ioctl(vs, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
54954359Sroberto				msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFBRDADDR) failed: %m");
55054359Sroberto				exit(1);
55154359Sroberto			}
55254359Sroberto#  endif /* not STREAMS_TLI */
55354359Sroberto
55454359Sroberto#  ifndef ifr_broadaddr
55554359Sroberto			inter_list[i].bcast =
55654359Sroberto			    *(struct sockaddr_in *)&ifreq.ifr_addr;
55754359Sroberto#  else
55854359Sroberto			inter_list[i].bcast =
55954359Sroberto			    *(struct sockaddr_in *)&ifreq.ifr_broadaddr;
56054359Sroberto#  endif /* ifr_broadaddr */
56154359Sroberto			inter_list[i].bcast.sin_family = AF_INET;
56254359Sroberto			inter_list[i].bcast.sin_port = port;
56354359Sroberto		}
56454359Sroberto
56554359Sroberto#  ifdef STREAMS_TLI
56654359Sroberto		ioc.ic_cmd = SIOCGIFNETMASK;
56754359Sroberto		ioc.ic_timout = 0;
56854359Sroberto		ioc.ic_dp = (caddr_t)&ifreq;
56954359Sroberto		ioc.ic_len = sizeof(struct ifreq);
57054359Sroberto		if(ioctl(vs, I_STR, &ioc)) {
57154359Sroberto			msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFNETMASK) failed: %m");
57254359Sroberto			exit(1);
57354359Sroberto		}
57454359Sroberto#  else /* not STREAMS_TLI */
57554359Sroberto		if (ioctl(vs, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
57654359Sroberto			msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFNETMASK) failed: %m");
57754359Sroberto			exit(1);
57854359Sroberto		}
57954359Sroberto#  endif /* not STREAMS_TLI */
58054359Sroberto		inter_list[i].mask                 = *(struct sockaddr_in *)&ifreq.ifr_addr;
58154359Sroberto# else
58254359Sroberto		/* winnt here */
58354359Sroberto		inter_list[i].bcast                = ifreq.ifr_broadaddr;
58454359Sroberto		inter_list[i].bcast.sin_family	   = AF_INET;
58554359Sroberto		inter_list[i].bcast.sin_port	   = port;
58654359Sroberto		inter_list[i].mask                 = ifreq.ifr_mask;
58754359Sroberto# endif /* not SYS_WINNT */
58854359Sroberto
58954359Sroberto		/*
59054359Sroberto		 * look for an already existing source interface address.  If
59154359Sroberto		 * the machine has multiple point to point interfaces, then
59254359Sroberto		 * the local address may appear more than once.
59354359Sroberto		 */
59454359Sroberto		for (j=0; j < i; j++)
59554359Sroberto		    if (inter_list[j].sin.sin_addr.s_addr ==
59654359Sroberto			inter_list[i].sin.sin_addr.s_addr) {
59754359Sroberto			    break;
59854359Sroberto		    }
59954359Sroberto		if (j == i)
60054359Sroberto		    i++;
60154359Sroberto		if (i > MAXINTERFACES)
60254359Sroberto		    break;
60354359Sroberto	}
60454359Sroberto	closesocket(vs);
60554359Sroberto#endif	/* _BSDI_VERSION >= 199510 */
60654359Sroberto
60754359Sroberto	ninterfaces = i;
60854359Sroberto	maxactivefd = 0;
60954359Sroberto	FD_ZERO(&activefds);
61054359Sroberto	for (i = 0; i < ninterfaces; i++) {
61154359Sroberto		inter_list[i].fd =
61254359Sroberto		    open_socket(&inter_list[i].sin,
61354359Sroberto				inter_list[i].flags & INT_BROADCAST, 0);
61454359Sroberto	}
61554359Sroberto
61654359Sroberto	/*
61754359Sroberto	 * Now that we have opened all the sockets, turn off the reuse flag for
61854359Sroberto	 * security.
61954359Sroberto	 */
62054359Sroberto	for (i = 0; i < ninterfaces; i++) {
62154359Sroberto		int off = 0;
62254359Sroberto
62354359Sroberto		/*
62454359Sroberto		 * if inter_list[ n ].fd  is -1, we might have a adapter
62554359Sroberto		 * configured but not present
62654359Sroberto		 */
62754359Sroberto		if ( inter_list[ i ].fd != -1 ) {
62854359Sroberto			if (setsockopt(inter_list[i].fd, SOL_SOCKET,
62954359Sroberto				       SO_REUSEADDR, (char *)&off,
63054359Sroberto				       sizeof(off))) {
63154359Sroberto				msyslog(LOG_ERR, "create_sockets: setsockopt(SO_REUSEADDR,off) failed: %m");
63254359Sroberto			}
63354359Sroberto		}
63454359Sroberto	}
63554359Sroberto
63654359Sroberto#if defined(MCAST)
63754359Sroberto	/*
63854359Sroberto	 * enable possible multicast reception on the broadcast socket
63954359Sroberto	 */
64054359Sroberto	inter_list[0].bcast.sin_addr.s_addr = htonl(INADDR_ANY);
64154359Sroberto	inter_list[0].bcast.sin_family = AF_INET;
64254359Sroberto	inter_list[0].bcast.sin_port = port;
64354359Sroberto#endif /* MCAST */
64454359Sroberto
64554359Sroberto	/*
64654359Sroberto	 * Blacklist all bound interface addresses
64754359Sroberto	 */
64854359Sroberto	resmask.sin_addr.s_addr = ~ (u_int32)0;
64954359Sroberto	for (i = 1; i < ninterfaces; i++)
65054359Sroberto	    hack_restrict(RESTRICT_FLAGS, &inter_list[i].sin, &resmask,
65154359Sroberto			  RESM_NTPONLY|RESM_INTERFACE, RES_IGNORE);
65254359Sroberto
65354359Sroberto	any_interface = &inter_list[0];
65454359Sroberto#ifdef DEBUG
65554359Sroberto	if (debug > 2) {
65654359Sroberto		printf("create_sockets: ninterfaces=%d\n", ninterfaces);
65754359Sroberto		for (i = 0; i < ninterfaces; i++) {
65854359Sroberto			printf("interface %d:  fd=%d,  bfd=%d,  name=%.8s,  flags=0x%x\n",
65954359Sroberto			       i,
66054359Sroberto			       inter_list[i].fd,
66154359Sroberto			       inter_list[i].bfd,
66254359Sroberto			       inter_list[i].name,
66354359Sroberto			       inter_list[i].flags);
66454359Sroberto			/* Leave these as three printf calls. */
66554359Sroberto			printf("              sin=%s",
66654359Sroberto			       inet_ntoa((inter_list[i].sin.sin_addr)));
66754359Sroberto			if (inter_list[i].flags & INT_BROADCAST)
66854359Sroberto			    printf("  bcast=%s,",
66954359Sroberto				   inet_ntoa((inter_list[i].bcast.sin_addr)));
67054359Sroberto			printf("  mask=%s\n",
67154359Sroberto			       inet_ntoa((inter_list[i].mask.sin_addr)));
67254359Sroberto		}
67354359Sroberto	}
67454359Sroberto#endif
67554359Sroberto#if defined (HAVE_IO_COMPLETION_PORT)
67654359Sroberto	for (i = 0; i < ninterfaces; i++) {
67754359Sroberto		io_completion_port_add_socket(&inter_list[i]);
67854359Sroberto	}
67954359Sroberto#endif
68054359Sroberto	return ninterfaces;
68154359Sroberto}
68254359Sroberto
68354359Sroberto/*
68454359Sroberto * io_setbclient - open the broadcast client sockets
68554359Sroberto */
68654359Srobertovoid
68754359Srobertoio_setbclient(void)
68854359Sroberto{
68954359Sroberto	int i;
69054359Sroberto
69154359Sroberto	for (i = 1; i < ninterfaces; i++)
69254359Sroberto	{
69354359Sroberto		if (!(inter_list[i].flags & INT_BROADCAST))
69454359Sroberto		    continue;
69554359Sroberto		if (inter_list[i].flags & INT_BCASTOPEN)
69654359Sroberto		    continue;
69754359Sroberto#ifdef	SYS_SOLARIS
69854359Sroberto		inter_list[i].bcast.sin_addr.s_addr = htonl(INADDR_ANY);
69954359Sroberto#endif
70054359Sroberto#ifdef OPEN_BCAST_SOCKET /* Was: !SYS_DOMAINOS && !SYS_LINUX */
70154359Sroberto		inter_list[i].bfd = open_socket(&inter_list[i].bcast, INT_BROADCAST, 1);
70254359Sroberto		inter_list[i].flags |= INT_BCASTOPEN;
70354359Sroberto#endif
70454359Sroberto	}
70554359Sroberto}
70654359Sroberto
70754359Sroberto
70854359Sroberto/*
70954359Sroberto * io_multicast_add() - add multicast group address
71054359Sroberto */
71154359Srobertovoid
71254359Srobertoio_multicast_add(
71354359Sroberto	u_int32 addr
71454359Sroberto	)
71554359Sroberto{
71654359Sroberto#ifdef MCAST
71754359Sroberto	struct ip_mreq mreq;
71854359Sroberto	int i = ninterfaces;	/* Use the next interface */
71954359Sroberto	u_int32 haddr = ntohl(addr);
72054359Sroberto	struct in_addr iaddr;
72154359Sroberto	int s;
72254359Sroberto	struct sockaddr_in *sinp;
72354359Sroberto
72454359Sroberto	iaddr.s_addr = addr;
72554359Sroberto
72654359Sroberto	if (!IN_CLASSD(haddr))
72754359Sroberto	{
72854359Sroberto		msyslog(LOG_ERR,
72954359Sroberto			"cannot add multicast address %s as it is not class D",
73054359Sroberto			inet_ntoa(iaddr));
73154359Sroberto		return;
73254359Sroberto	}
73354359Sroberto
73454359Sroberto	for (i = 0; i < ninterfaces; i++)
73554359Sroberto	{
73654359Sroberto		/* Already have this address */
73754359Sroberto		if (inter_list[i].sin.sin_addr.s_addr == addr) return;
73854359Sroberto		/* found a free slot */
73954359Sroberto		if (inter_list[i].sin.sin_addr.s_addr == 0 &&
74054359Sroberto		    inter_list[i].fd <= 0 && inter_list[i].bfd <= 0 &&
74154359Sroberto		    inter_list[i].flags == 0) break;
74254359Sroberto	}
74354359Sroberto	sinp = &(inter_list[i].sin);
74454359Sroberto
74554359Sroberto	memset((char *)&mreq, 0, sizeof(mreq));
74654359Sroberto	memset((char *)&inter_list[i], 0, sizeof inter_list[0]);
74754359Sroberto	sinp->sin_family = AF_INET;
74854359Sroberto	sinp->sin_addr = iaddr;
74954359Sroberto	sinp->sin_port = htons(123);
75054359Sroberto
75154359Sroberto	s = open_socket(sinp, 0, 1);
75254359Sroberto	/* Try opening a socket for the specified class D address */
75354359Sroberto	/* This works under SunOS 4.x, but not OSF1 .. :-( */
75454359Sroberto	if (s < 0)
75554359Sroberto	{
75654359Sroberto		memset((char *)&inter_list[i], 0, sizeof inter_list[0]);
75754359Sroberto		i = 0;
75854359Sroberto		/* HACK ! -- stuff in an address */
75954359Sroberto		inter_list[i].bcast.sin_addr.s_addr = addr;
76054359Sroberto		msyslog(LOG_ERR, "...multicast address %s using wildcard socket",
76154359Sroberto			inet_ntoa(iaddr));
76254359Sroberto	}
76354359Sroberto	else
76454359Sroberto	{
76554359Sroberto		inter_list[i].fd = s;
76654359Sroberto		inter_list[i].bfd = -1;
76754359Sroberto		(void) strncpy(inter_list[i].name, "multicast",
76854359Sroberto			       sizeof(inter_list[i].name));
76954359Sroberto		inter_list[i].mask.sin_addr.s_addr = htonl(~(u_int32)0);
77054359Sroberto	}
77154359Sroberto
77254359Sroberto	/*
77354359Sroberto	 * enable reception of multicast packets
77454359Sroberto	 */
77554359Sroberto	mreq.imr_multiaddr = iaddr;
77654359Sroberto	mreq.imr_interface.s_addr = htonl(INADDR_ANY);
77754359Sroberto	if (setsockopt(inter_list[i].fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
77854359Sroberto		       (char *)&mreq, sizeof(mreq)) == -1)
77954359Sroberto	    msyslog(LOG_ERR,
78054359Sroberto		    "setsockopt IP_ADD_MEMBERSHIP fails: %m for %x / %x (%s)",
78154359Sroberto		    mreq.imr_multiaddr.s_addr, mreq.imr_interface.s_addr,
78254359Sroberto		    inet_ntoa(iaddr));
78354359Sroberto	inter_list[i].flags |= INT_MULTICAST;
78454359Sroberto	if (i >= ninterfaces) ninterfaces = i+1;
78554359Sroberto#else /* MCAST */
78654359Sroberto	struct in_addr iaddr;
78754359Sroberto
78854359Sroberto	iaddr.s_addr = addr;
78954359Sroberto	msyslog(LOG_ERR, "cannot add multicast address %s as no MCAST support",
79054359Sroberto		inet_ntoa(iaddr));
79154359Sroberto#endif /* MCAST */
79254359Sroberto}
79354359Sroberto
79454359Sroberto/*
79554359Sroberto * io_unsetbclient - close the broadcast client sockets
79654359Sroberto */
79754359Srobertovoid
79854359Srobertoio_unsetbclient(void)
79954359Sroberto{
80054359Sroberto	int i;
80154359Sroberto
80254359Sroberto	for (i = 1; i < ninterfaces; i++)
80354359Sroberto	{
80454359Sroberto		if (!(inter_list[i].flags & INT_BCASTOPEN))
80554359Sroberto		    continue;
80654359Sroberto		close_socket(inter_list[i].bfd);
80754359Sroberto		inter_list[i].bfd = -1;
80854359Sroberto		inter_list[i].flags &= ~INT_BCASTOPEN;
80954359Sroberto	}
81054359Sroberto}
81154359Sroberto
81254359Sroberto
81354359Sroberto/*
81454359Sroberto * io_multicast_del() - delete multicast group address
81554359Sroberto */
81654359Srobertovoid
81754359Srobertoio_multicast_del(
81854359Sroberto	u_int32 addr
81954359Sroberto	)
82054359Sroberto{
82154359Sroberto#ifdef MCAST
82254359Sroberto	int i;
82354359Sroberto	struct ip_mreq mreq;
82454359Sroberto	u_int32 haddr = ntohl(addr);
82554359Sroberto	struct sockaddr_in sinaddr;
82654359Sroberto
82754359Sroberto	if (!IN_CLASSD(haddr))
82854359Sroberto	{
82954359Sroberto		sinaddr.sin_addr.s_addr = addr;
83054359Sroberto		msyslog(LOG_ERR,
83154359Sroberto			"invalid multicast address %s", ntoa(&sinaddr));
83254359Sroberto		return;
83354359Sroberto	}
83454359Sroberto
83554359Sroberto	/*
83654359Sroberto	 * Disable reception of multicast packets
83754359Sroberto	 */
83854359Sroberto	mreq.imr_multiaddr.s_addr = addr;
83954359Sroberto	mreq.imr_interface.s_addr = htonl(INADDR_ANY);
84054359Sroberto	for (i = 0; i < ninterfaces; i++)
84154359Sroberto	{
84254359Sroberto		if (!(inter_list[i].flags & INT_MULTICAST))
84354359Sroberto		    continue;
84454359Sroberto		if (!(inter_list[i].fd < 0))
84554359Sroberto		    continue;
84654359Sroberto		if (addr != inter_list[i].sin.sin_addr.s_addr)
84754359Sroberto		    continue;
84854359Sroberto		if (i != 0)
84954359Sroberto		{
85054359Sroberto			/* we have an explicit fd, so we can close it */
85154359Sroberto			close_socket(inter_list[i].fd);
85254359Sroberto			memset((char *)&inter_list[i], 0, sizeof inter_list[0]);
85354359Sroberto			inter_list[i].fd = -1;
85454359Sroberto			inter_list[i].bfd = -1;
85554359Sroberto		}
85654359Sroberto		else
85754359Sroberto		{
85854359Sroberto			/* We are sharing "any address" port :-(  Don't close it! */
85954359Sroberto			if (setsockopt(inter_list[i].fd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
86054359Sroberto				       (char *)&mreq, sizeof(mreq)) == -1)
86154359Sroberto			    msyslog(LOG_ERR, "setsockopt IP_DROP_MEMBERSHIP fails: %m");
86254359Sroberto			/* This is **WRONG** -- there may be others ! */
86354359Sroberto			/* There should be a count of users ... */
86454359Sroberto			inter_list[i].flags &= ~INT_MULTICAST;
86554359Sroberto		}
86654359Sroberto	}
86754359Sroberto#else /* not MCAST */
86854359Sroberto	msyslog(LOG_ERR, "this function requires multicast kernel");
86954359Sroberto#endif /* not MCAST */
87054359Sroberto}
87154359Sroberto
87254359Sroberto
87354359Sroberto/*
87454359Sroberto * open_socket - open a socket, returning the file descriptor
87554359Sroberto */
87654359Srobertostatic int
87754359Srobertoopen_socket(
87854359Sroberto	struct sockaddr_in *addr,
87954359Sroberto	int flags,
88054359Sroberto	int turn_off_reuse
88154359Sroberto	)
88254359Sroberto{
88354359Sroberto	int fd;
88454359Sroberto	int on = 1, off = 0;
88554359Sroberto
88654359Sroberto	/* create a datagram (UDP) socket */
88754359Sroberto	if (  (fd = socket(AF_INET, SOCK_DGRAM, 0))
88854359Sroberto#ifndef SYS_WINNT
88954359Sroberto	      < 0
89054359Sroberto#else
89154359Sroberto	      == INVALID_SOCKET
89254359Sroberto#endif /* SYS_WINNT */
89354359Sroberto	      )
89454359Sroberto	{
89554359Sroberto		msyslog(LOG_ERR, "socket(AF_INET, SOCK_DGRAM, 0) failed: %m");
89654359Sroberto		exit(1);
89754359Sroberto		/*NOTREACHED*/
89854359Sroberto	}
89954359Sroberto
90054359Sroberto	/* set SO_REUSEADDR since we will be binding the same port
90154359Sroberto	   number on each interface */
90254359Sroberto	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
90354359Sroberto		       (char *)&on, sizeof(on)))
90454359Sroberto	{
90554359Sroberto		msyslog(LOG_ERR, "setsockopt SO_REUSEADDR on fails: %m");
90654359Sroberto	}
90754359Sroberto
90854359Sroberto	/*
90954359Sroberto	 * bind the local address.
91054359Sroberto	 */
91154359Sroberto	if (bind(fd, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
91254359Sroberto		char buff[160];
91354359Sroberto		sprintf(buff,
91454359Sroberto			"bind() fd %d, family %d, port %d, addr %s, in_classd=%d flags=%d fails: %%m",
91554359Sroberto			fd, addr->sin_family, (int)ntohs(addr->sin_port),
91654359Sroberto			ntoa(addr),
91754359Sroberto			IN_CLASSD(ntohl(addr->sin_addr.s_addr)), flags);
91854359Sroberto		msyslog(LOG_ERR, buff);
91954359Sroberto		closesocket(fd);
92054359Sroberto
92154359Sroberto		/*
92254359Sroberto		 * soft fail if opening a class D address
92354359Sroberto		 */
92454359Sroberto		if (IN_CLASSD(ntohl(addr->sin_addr.s_addr)))
92554359Sroberto		    return -1;
92654359Sroberto#if 0
92754359Sroberto		exit(1);
92854359Sroberto#else
92954359Sroberto		return -1;
93054359Sroberto#endif
93154359Sroberto	}
93254359Sroberto#ifdef DEBUG
93354359Sroberto	if (debug)
93454359Sroberto	    printf("bind() fd %d, family %d, port %d, addr %s, flags=%d\n",
93554359Sroberto		   fd,
93654359Sroberto		   addr->sin_family,
93754359Sroberto		   (int)ntohs(addr->sin_port),
93854359Sroberto		   ntoa(addr),
93954359Sroberto		   flags);
94054359Sroberto#endif
94154359Sroberto	if (fd > maxactivefd)
94254359Sroberto	    maxactivefd = fd;
94354359Sroberto	FD_SET(fd, &activefds);
94454359Sroberto
94554359Sroberto	/*
94654359Sroberto	 * set non-blocking,
94754359Sroberto	 */
94854359Sroberto
94954359Sroberto#ifdef USE_FIONBIO
95054359Sroberto	/* in vxWorks we use FIONBIO, but the others are defined for old systems, so
95154359Sroberto	 * all hell breaks loose if we leave them defined
95254359Sroberto	 */
95354359Sroberto#undef O_NONBLOCK
95454359Sroberto#undef FNDELAY
95554359Sroberto#undef O_NDELAY
95654359Sroberto#endif
95754359Sroberto
95854359Sroberto#if defined(O_NONBLOCK) /* POSIX */
95954359Sroberto	if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
96054359Sroberto	{
96154359Sroberto		msyslog(LOG_ERR, "fcntl(O_NONBLOCK) fails: %m");
96254359Sroberto		exit(1);
96354359Sroberto		/*NOTREACHED*/
96454359Sroberto	}
96554359Sroberto#elif defined(FNDELAY)
96654359Sroberto	if (fcntl(fd, F_SETFL, FNDELAY) < 0)
96754359Sroberto	{
96854359Sroberto		msyslog(LOG_ERR, "fcntl(FNDELAY) fails: %m");
96954359Sroberto		exit(1);
97054359Sroberto		/*NOTREACHED*/
97154359Sroberto	}
97254359Sroberto#elif defined(O_NDELAY) /* generally the same as FNDELAY */
97354359Sroberto	if (fcntl(fd, F_SETFL, O_NDELAY) < 0)
97454359Sroberto	{
97554359Sroberto		msyslog(LOG_ERR, "fcntl(O_NDELAY) fails: %m");
97654359Sroberto		exit(1);
97754359Sroberto		/*NOTREACHED*/
97854359Sroberto	}
97954359Sroberto#elif defined(FIONBIO)
98054359Sroberto	if (
98154359Sroberto# if defined(VMS)
98254359Sroberto		(ioctl(fd,FIONBIO,&1) < 0)
98354359Sroberto# elif defined(SYS_WINNT)
98454359Sroberto		(ioctlsocket(fd,FIONBIO,(u_long *) &on) == SOCKET_ERROR)
98554359Sroberto# else
98654359Sroberto		(ioctl(fd,FIONBIO,&on) < 0)
98754359Sroberto# endif
98854359Sroberto	   )
98954359Sroberto	{
99054359Sroberto		msyslog(LOG_ERR, "ioctl(FIONBIO) fails: %m");
99154359Sroberto		exit(1);
99254359Sroberto		/*NOTREACHED*/
99354359Sroberto	}
99454359Sroberto#elif defined(FIOSNBIO)
99554359Sroberto	if (ioctl(fd,FIOSNBIO,&on) < 0)
99654359Sroberto	{
99754359Sroberto		msyslog(LOG_ERR, "ioctl(FIOSNBIO) fails: %m");
99854359Sroberto		exit(1);
99954359Sroberto		/*NOTREACHED*/
100054359Sroberto	}
100154359Sroberto#else
100254359Sroberto# include "Bletch: Need non-blocking I/O!"
100354359Sroberto#endif
100454359Sroberto
100554359Sroberto#ifdef HAVE_SIGNALED_IO
100654359Sroberto	init_socket_sig(fd);
100754359Sroberto#endif /* not HAVE_SIGNALED_IO */
100854359Sroberto
100954359Sroberto	/*
101054359Sroberto	 *	Turn off the SO_REUSEADDR socket option.  It apparently
101154359Sroberto	 *	causes heartburn on systems with multicast IP installed.
101254359Sroberto	 *	On normal systems it only gets looked at when the address
101354359Sroberto	 *	is being bound anyway..
101454359Sroberto	 */
101554359Sroberto	if (turn_off_reuse)
101654359Sroberto	    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
101754359Sroberto			   (char *)&off, sizeof(off)))
101854359Sroberto	    {
101954359Sroberto		    msyslog(LOG_ERR, "setsockopt SO_REUSEADDR off fails: %m");
102054359Sroberto	    }
102154359Sroberto
102254359Sroberto#ifdef SO_BROADCAST
102354359Sroberto	/* if this interface can support broadcast, set SO_BROADCAST */
102454359Sroberto	if (flags & INT_BROADCAST)
102554359Sroberto	{
102654359Sroberto		if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST,
102754359Sroberto			       (char *)&on, sizeof(on)))
102854359Sroberto		{
102954359Sroberto			msyslog(LOG_ERR, "setsockopt(SO_BROADCAST): %m");
103054359Sroberto		}
103154359Sroberto	}
103254359Sroberto#endif /* SO_BROADCAST */
103354359Sroberto
103454359Sroberto#if !defined(SYS_WINNT) && !defined(VMS)
103554359Sroberto# ifdef DEBUG
103654359Sroberto	if (debug > 1)
103754359Sroberto	    printf("flags for fd %d: 0%o\n", fd,
103854359Sroberto		   fcntl(fd, F_GETFL, 0));
103954359Sroberto# endif
104054359Sroberto#endif /* SYS_WINNT || VMS */
104154359Sroberto
104254359Sroberto	return fd;
104354359Sroberto}
104454359Sroberto
104554359Sroberto
104654359Sroberto/*
104754359Sroberto * close_socket - close a socket and remove from the activefd list
104854359Sroberto */
104954359Srobertostatic void
105054359Srobertoclose_socket(
105154359Sroberto	int fd
105254359Sroberto	)
105354359Sroberto{
105454359Sroberto	int i, newmax;
105554359Sroberto
105654359Sroberto	(void) closesocket(fd);
105754359Sroberto	FD_CLR( (u_int) fd, &activefds);
105854359Sroberto
105954359Sroberto	if (fd >= maxactivefd)
106054359Sroberto	{
106154359Sroberto		newmax = 0;
106254359Sroberto		for (i = 0; i < maxactivefd; i++)
106354359Sroberto		    if (FD_ISSET(i, &activefds))
106454359Sroberto			newmax = i;
106554359Sroberto		maxactivefd = newmax;
106654359Sroberto	}
106754359Sroberto}
106854359Sroberto
106954359Sroberto
107054359Sroberto/*
107154359Sroberto * close_file - close a file and remove from the activefd list
107254359Sroberto * added 1/31/1997 Greg Schueman for Windows NT portability
107354359Sroberto */
107454359Srobertostatic void
107554359Srobertoclose_file(
107654359Sroberto	int fd
107754359Sroberto	)
107854359Sroberto{
107954359Sroberto	int i, newmax;
108054359Sroberto
108154359Sroberto	(void) close(fd);
108254359Sroberto	FD_CLR( (u_int) fd, &activefds);
108354359Sroberto
108454359Sroberto	if (fd >= maxactivefd)
108554359Sroberto	{
108654359Sroberto		newmax = 0;
108754359Sroberto		for (i = 0; i < maxactivefd; i++)
108854359Sroberto		    if (FD_ISSET(i, &activefds))
108954359Sroberto			newmax = i;
109054359Sroberto		maxactivefd = newmax;
109154359Sroberto	}
109254359Sroberto}
109354359Sroberto
109454359Sroberto
109554359Sroberto/*
109654359Sroberto * findbcastinter - find broadcast interface corresponding to address
109754359Sroberto */
109854359Srobertostruct interface *
109954359Srobertofindbcastinter(
110054359Sroberto	struct sockaddr_in *addr
110154359Sroberto	)
110254359Sroberto{
110354359Sroberto#if defined(SIOCGIFCONF) || defined(SYS_WINNT)
110454359Sroberto	register int i;
110554359Sroberto	register u_int32 netnum;
110654359Sroberto
110754359Sroberto	netnum = NSRCADR(addr);
110854359Sroberto	for (i = 1; i < ninterfaces; i++)
110954359Sroberto	{
111054359Sroberto		if (!(inter_list[i].flags & INT_BROADCAST))
111154359Sroberto		    continue;
111254359Sroberto		if (NSRCADR(&inter_list[i].bcast) == netnum)
111354359Sroberto		    return &inter_list[i];
111454359Sroberto		if ((NSRCADR(&inter_list[i].sin) & NSRCADR(&inter_list[i].mask))
111554359Sroberto		    == (netnum & NSRCADR(&inter_list[i].mask)))
111654359Sroberto		    return &inter_list[i];
111754359Sroberto	}
111854359Sroberto#endif /* SIOCGIFCONF */
111954359Sroberto	return any_interface;
112054359Sroberto}
112154359Sroberto
112254359Sroberto
112354359Sroberto/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
112454359Sroberto/*
112554359Sroberto * sendpkt - send a packet to the specified destination. Maintain a
112654359Sroberto * send error cache so that only the first consecutive error for a
112754359Sroberto * destination is logged.
112854359Sroberto */
112954359Srobertovoid
113054359Srobertosendpkt(
113154359Sroberto	struct sockaddr_in *dest,
113254359Sroberto	struct interface *inter,
113354359Sroberto	int ttl,
113454359Sroberto	struct pkt *pkt,
113554359Sroberto	int len
113654359Sroberto	)
113754359Sroberto{
113854359Sroberto	int cc, slot;
113954359Sroberto#ifdef SYS_WINNT
114054359Sroberto	DWORD err;
114154359Sroberto#endif /* SYS_WINNT */
114254359Sroberto
114354359Sroberto	/*
114454359Sroberto	 * Send error cache. Empty slots have port == 0
114554359Sroberto	 * Set ERRORCACHESIZE to 0 to disable
114654359Sroberto	 */
114754359Sroberto	struct cache {
114854359Sroberto		u_short port;
114954359Sroberto		struct	in_addr addr;
115054359Sroberto	};
115154359Sroberto
115254359Sroberto#ifndef ERRORCACHESIZE
115354359Sroberto#define ERRORCACHESIZE 8
115454359Sroberto#endif
115554359Sroberto#if ERRORCACHESIZE > 0
115654359Sroberto	static struct cache badaddrs[ERRORCACHESIZE];
115754359Sroberto#else
115854359Sroberto#define badaddrs ((struct cache *)0)		/* Only used in empty loops! */
115954359Sroberto#endif
116054359Sroberto
116154359Sroberto	/*
116254359Sroberto	 * check if the source address is a multicast address - replace
116354359Sroberto	 * interface with any-interface if so.
116454359Sroberto	 */
116554359Sroberto	if (IN_MULTICAST(ntohl(inter->sin.sin_addr.s_addr)))
116654359Sroberto	    inter = any_interface;
116754359Sroberto#ifdef DEBUG
116854359Sroberto	if (debug > 1)
116954359Sroberto	    printf("%ssendpkt(fd=%d dst=%s, src=%s, ttl=%d, len=%d)\n",
117054359Sroberto		   (ttl >= 0) ? "\tMCAST\t*****" : "",
117154359Sroberto		   inter->fd, ntoa(dest),
117254359Sroberto		   ntoa(&inter->sin), ttl, len);
117354359Sroberto#endif
117454359Sroberto
117554359Sroberto#ifdef MCAST
117654359Sroberto	/* for the moment we use the bcast option to set multicast ttl */
117754359Sroberto	if (ttl >= 0 && ttl != inter->last_ttl)
117854359Sroberto	{
117954359Sroberto		char mttl = ttl;
118054359Sroberto
118154359Sroberto		/* set the multicast ttl for outgoing packets */
118254359Sroberto		if (setsockopt(inter->fd, IPPROTO_IP, IP_MULTICAST_TTL,
118354359Sroberto			       &mttl, sizeof(mttl)) == -1)
118454359Sroberto		{
118554359Sroberto			msyslog(LOG_ERR, "setsockopt IP_MULTICAST_TTL fails: %m");
118654359Sroberto		}
118754359Sroberto		else inter->last_ttl = ttl;
118854359Sroberto	}
118954359Sroberto#endif /* MCAST */
119054359Sroberto
119154359Sroberto	for (slot = ERRORCACHESIZE; --slot >= 0; )
119254359Sroberto	    if (badaddrs[slot].port == dest->sin_port &&
119354359Sroberto		badaddrs[slot].addr.s_addr == dest->sin_addr.s_addr)
119454359Sroberto		break;
119554359Sroberto
119654359Sroberto#if defined(HAVE_IO_COMPLETION_PORT)
119754359Sroberto        err = io_completion_port_sendto(inter, pkt, len, dest);
119854359Sroberto	if (err != ERROR_SUCCESS)
119954359Sroberto#else
120054359Sroberto	cc = sendto(inter->fd, (char *)pkt, len, 0, (struct sockaddr *)dest,
120154359Sroberto		    sizeof(struct sockaddr_in));
120254359Sroberto	if (cc == -1)
120354359Sroberto#endif
120454359Sroberto	{
120554359Sroberto		inter->notsent++;
120654359Sroberto		packets_notsent++;
120754359Sroberto#if defined(HAVE_IO_COMPLETION_PORT)
120854359Sroberto		if (err != WSAEWOULDBLOCK && err != WSAENOBUFS && slot < 0)
120954359Sroberto#else
121054359Sroberto		if (errno != EWOULDBLOCK && errno != ENOBUFS && slot < 0)
121154359Sroberto#endif
121254359Sroberto		{
121354359Sroberto			/*
121454359Sroberto			 * Remember this, if there's an empty slot
121554359Sroberto			 */
121654359Sroberto			for (slot = ERRORCACHESIZE; --slot >= 0; )
121754359Sroberto			    if (badaddrs[slot].port == 0)
121854359Sroberto			    {
121954359Sroberto				    badaddrs[slot].port = dest->sin_port;
122054359Sroberto				    badaddrs[slot].addr = dest->sin_addr;
122154359Sroberto				    break;
122254359Sroberto			    }
122354359Sroberto			msyslog(LOG_ERR, "sendto(%s): %m", ntoa(dest));
122454359Sroberto		}
122554359Sroberto	}
122654359Sroberto	else
122754359Sroberto	{
122854359Sroberto		inter->sent++;
122954359Sroberto		packets_sent++;
123054359Sroberto		/*
123154359Sroberto		 * He's not bad any more
123254359Sroberto		 */
123354359Sroberto		if (slot >= 0)
123454359Sroberto		{
123554359Sroberto			msyslog(LOG_INFO, "Connection re-established to %s", ntoa(dest));
123654359Sroberto			badaddrs[slot].port = 0;
123754359Sroberto		}
123854359Sroberto	}
123954359Sroberto}
124054359Sroberto
124154359Sroberto#if !defined(HAVE_IO_COMPLETION_PORT)
124254359Sroberto/*
124354359Sroberto * fdbits - generate ascii representation of fd_set (FAU debug support)
124454359Sroberto * HFDF format - highest fd first.
124554359Sroberto */
124654359Srobertostatic char *
124754359Srobertofdbits(
124854359Sroberto	int count,
124954359Sroberto	fd_set *set
125054359Sroberto	)
125154359Sroberto{
125254359Sroberto	static char buffer[256];
125354359Sroberto	char * buf = buffer;
125454359Sroberto
125554359Sroberto	count = (count < 256) ? count : 255;
125654359Sroberto
125754359Sroberto	while (count >= 0)
125854359Sroberto	{
125954359Sroberto		*buf++ = FD_ISSET(count, set) ? '#' : '-';
126054359Sroberto		count--;
126154359Sroberto	}
126254359Sroberto	*buf = '\0';
126354359Sroberto
126454359Sroberto	return buffer;
126554359Sroberto}
126654359Sroberto
126754359Sroberto/*
126854359Sroberto * input_handler - receive packets asynchronously
126954359Sroberto */
127054359Srobertoextern void
127154359Srobertoinput_handler(
127254359Sroberto	l_fp *cts
127354359Sroberto	)
127454359Sroberto{
127554359Sroberto	register int i, n;
127654359Sroberto	register struct recvbuf *rb;
127754359Sroberto	register int doing;
127854359Sroberto	register int fd;
127954359Sroberto	struct timeval tvzero;
128054359Sroberto	int fromlen;
128154359Sroberto	l_fp ts;			/* Timestamp at BOselect() gob */
128254359Sroberto	l_fp ts_e;			/* Timestamp at EOselect() gob */
128354359Sroberto	fd_set fds;
128454359Sroberto	int select_count = 0;
128554359Sroberto	static int handler_count = 0;
128654359Sroberto
128754359Sroberto	++handler_count;
128854359Sroberto	if (handler_count != 1)
128954359Sroberto	    msyslog(LOG_ERR, "input_handler: handler_count is %d!", handler_count);
129054359Sroberto	handler_calls++;
129154359Sroberto	ts = *cts;
129254359Sroberto
129354359Sroberto	for (;;)
129454359Sroberto	{
129554359Sroberto		/*
129654359Sroberto		 * Do a poll to see who has data
129754359Sroberto		 */
129854359Sroberto
129954359Sroberto		fds = activefds;
130054359Sroberto		tvzero.tv_sec = tvzero.tv_usec = 0;
130154359Sroberto
130254359Sroberto		/*
130354359Sroberto		 * If we have something to do, freeze a timestamp.
130454359Sroberto		 * See below for the other cases (nothing (left) to do or error)
130554359Sroberto		 */
130654359Sroberto		while (0 < (n = select(maxactivefd+1, &fds, (fd_set *)0, (fd_set *)0, &tvzero)))
130754359Sroberto		{
130854359Sroberto			++select_count;
130954359Sroberto			++handler_pkts;
131054359Sroberto
131154359Sroberto#ifdef REFCLOCK
131254359Sroberto			/*
131354359Sroberto			 * Check out the reference clocks first, if any
131454359Sroberto			 */
131554359Sroberto			if (refio != 0)
131654359Sroberto			{
131754359Sroberto				register struct refclockio *rp;
131854359Sroberto
131954359Sroberto				for (rp = refio; rp != 0 && n > 0; rp = rp->next)
132054359Sroberto				{
132154359Sroberto					fd = rp->fd;
132254359Sroberto					if (FD_ISSET(fd, &fds))
132354359Sroberto					{
132454359Sroberto						n--;
132554359Sroberto						if (free_recvbuffs() == 0)
132654359Sroberto						{
132754359Sroberto							char buf[RX_BUFF_SIZE];
132854359Sroberto
132954359Sroberto#ifndef SYS_WINNT
133054359Sroberto							(void) read(fd, buf, sizeof buf);
133154359Sroberto#else
133254359Sroberto							(void) ReadFile((HANDLE)fd, buf, (DWORD)sizeof buf, NULL, NULL);
133354359Sroberto#endif /* SYS_WINNT */
133454359Sroberto							packets_dropped++;
133554359Sroberto							goto select_again;
133654359Sroberto						}
133754359Sroberto
133854359Sroberto						rb = get_free_recv_buffer();
133954359Sroberto
134054359Sroberto						i = (rp->datalen == 0
134154359Sroberto						     || rp->datalen > sizeof(rb->recv_space))
134254359Sroberto						    ? sizeof(rb->recv_space) : rp->datalen;
134354359Sroberto#ifndef SYS_WINNT
134454359Sroberto						rb->recv_length =
134554359Sroberto						    read(fd, (char *)&rb->recv_space, (unsigned)i)
134654359Sroberto#else  /* SYS_WINNT */
134754359Sroberto						    ReadFile((HANDLE)fd, (char *)&rb->recv_space, (DWORD)i,
134854359Sroberto							     (LPDWORD)&(rb->recv_length), NULL)
134954359Sroberto#endif /* SYS_WINNT */
135054359Sroberto						    ;
135154359Sroberto
135254359Sroberto						if (rb->recv_length == -1)
135354359Sroberto						{
135454359Sroberto							msyslog(LOG_ERR, "clock read fd %d: %m", fd);
135554359Sroberto							freerecvbuf(rb);
135654359Sroberto							goto select_again;
135754359Sroberto						}
135854359Sroberto
135954359Sroberto						/*
136054359Sroberto						 * Got one.  Mark how and when it got here,
136154359Sroberto						 * put it on the full list and do bookkeeping.
136254359Sroberto						 */
136354359Sroberto						rb->recv_srcclock = rp->srcclock;
136454359Sroberto						rb->dstadr = 0;
136554359Sroberto						rb->fd = fd;
136654359Sroberto						rb->recv_time = ts;
136754359Sroberto						rb->receiver = rp->clock_recv;
136854359Sroberto
136954359Sroberto						if (rp->io_input)
137054359Sroberto						{
137154359Sroberto							/*
137254359Sroberto							 * have direct input routine for refclocks
137354359Sroberto							 */
137454359Sroberto							if (rp->io_input(rb) == 0)
137554359Sroberto							{
137654359Sroberto								/*
137754359Sroberto								 * data was consumed - nothing to pass up
137854359Sroberto								 * into block input machine
137954359Sroberto								 */
138054359Sroberto								freerecvbuf(rb);
138154359Sroberto#if 1
138254359Sroberto								goto select_again;
138354359Sroberto#else
138454359Sroberto								continue;
138554359Sroberto#endif
138654359Sroberto							}
138754359Sroberto						}
138854359Sroberto
138954359Sroberto						add_full_recv_buffer(rb);
139054359Sroberto
139154359Sroberto						rp->recvcount++;
139254359Sroberto						packets_received++;
139354359Sroberto					}
139454359Sroberto				}
139554359Sroberto			}
139654359Sroberto#endif /* REFCLOCK */
139754359Sroberto
139854359Sroberto			/*
139954359Sroberto			 * Loop through the interfaces looking for data to read.
140054359Sroberto			 */
140154359Sroberto			for (i = ninterfaces - 1; (i >= 0) && (n > 0); i--)
140254359Sroberto			{
140354359Sroberto				for (doing = 0; (doing < 2) && (n > 0); doing++)
140454359Sroberto				{
140554359Sroberto					if (doing == 0)
140654359Sroberto					{
140754359Sroberto						fd = inter_list[i].fd;
140854359Sroberto					}
140954359Sroberto					else
141054359Sroberto					{
141154359Sroberto						if (!(inter_list[i].flags & INT_BCASTOPEN))
141254359Sroberto						    break;
141354359Sroberto						fd = inter_list[i].bfd;
141454359Sroberto					}
141554359Sroberto					if (fd < 0) continue;
141654359Sroberto					if (FD_ISSET(fd, &fds))
141754359Sroberto					{
141854359Sroberto						n--;
141954359Sroberto
142054359Sroberto						/*
142154359Sroberto						 * Get a buffer and read the frame.  If we
142254359Sroberto						 * haven't got a buffer, or this is received
142354359Sroberto						 * on the wild card socket, just dump the
142454359Sroberto						 * packet.
142554359Sroberto						 */
142654359Sroberto						if (
142754359Sroberto#ifdef UDP_WILDCARD_DELIVERY
142854359Sroberto				/*
142954359Sroberto				 * these guys manage to put properly addressed
143054359Sroberto				 * packets into the wildcard queue
143154359Sroberto				 */
143254359Sroberto							(free_recvbuffs() == 0)
143354359Sroberto#else
143454359Sroberto							((i == 0) || (free_recvbuffs() == 0))
143554359Sroberto#endif
143654359Sroberto							)
143754359Sroberto	{
143854359Sroberto		char buf[RX_BUFF_SIZE];
143954359Sroberto		struct sockaddr from;
144054359Sroberto
144154359Sroberto		fromlen = sizeof from;
144254359Sroberto		(void) recvfrom(fd, buf, sizeof(buf), 0, &from, &fromlen);
144354359Sroberto#ifdef DEBUG
144454359Sroberto		if (debug)
144554359Sroberto		    printf("%s on %d(%lu) fd=%d from %s\n",
144654359Sroberto			   (i) ? "drop" : "ignore",
144754359Sroberto			   i, free_recvbuffs(), fd,
144854359Sroberto			   inet_ntoa(((struct sockaddr_in *) &from)->sin_addr));
144954359Sroberto#endif
145054359Sroberto		if (i == 0)
145154359Sroberto		    packets_ignored++;
145254359Sroberto		else
145354359Sroberto		    packets_dropped++;
145454359Sroberto		goto select_again;
145554359Sroberto	}
145654359Sroberto
145754359Sroberto	rb = get_free_recv_buffer();
145854359Sroberto
145954359Sroberto	fromlen = sizeof(struct sockaddr_in);
146054359Sroberto	rb->recv_length = recvfrom(fd,
146154359Sroberto				   (char *)&rb->recv_space,
146254359Sroberto				   sizeof(rb->recv_space), 0,
146354359Sroberto				   (struct sockaddr *)&rb->recv_srcadr,
146454359Sroberto				   &fromlen);
146554359Sroberto	if (rb->recv_length == 0
146654359Sroberto#ifdef EWOULDBLOCK
146754359Sroberto		 || errno==EWOULDBLOCK
146854359Sroberto#endif
146954359Sroberto#ifdef EAGAIN
147054359Sroberto		 || errno==EAGAIN
147154359Sroberto#endif
147254359Sroberto		 ) {
147354359Sroberto		freerecvbuf(rb);
147454359Sroberto	    continue;
147554359Sroberto	}
147654359Sroberto	else if (rb->recv_length < 0)
147754359Sroberto	{
147854359Sroberto		msyslog(LOG_ERR, "recvfrom() fd=%d: %m", fd);
147954359Sroberto#ifdef DEBUG
148054359Sroberto		if (debug)
148154359Sroberto		    printf("input_handler: fd=%d dropped (bad recvfrom)\n", fd);
148254359Sroberto#endif
148354359Sroberto		freerecvbuf(rb);
148454359Sroberto		continue;
148554359Sroberto	}
148654359Sroberto#ifdef DEBUG
148754359Sroberto	if (debug > 2)
148854359Sroberto	    printf("input_handler: fd=%d length %d from %08lx %s\n",
148954359Sroberto		   fd, rb->recv_length,
149054359Sroberto		   (u_long)ntohl(rb->recv_srcadr.sin_addr.s_addr) &
149154359Sroberto		   0x00000000ffffffff,
149254359Sroberto		   inet_ntoa(rb->recv_srcadr.sin_addr));
149354359Sroberto#endif
149454359Sroberto
149554359Sroberto	/*
149654359Sroberto	 * Got one.  Mark how and when it got here,
149754359Sroberto	 * put it on the full list and do bookkeeping.
149854359Sroberto	 */
149954359Sroberto	rb->dstadr = &inter_list[i];
150054359Sroberto	rb->fd = fd;
150154359Sroberto	rb->recv_time = ts;
150254359Sroberto	rb->receiver = receive;
150354359Sroberto
150454359Sroberto	add_full_recv_buffer(rb);
150554359Sroberto
150654359Sroberto	inter_list[i].received++;
150754359Sroberto	packets_received++;
150854359Sroberto	goto select_again;
150954359Sroberto					}
151054359Sroberto					/* Check more interfaces */
151154359Sroberto				}
151254359Sroberto			}
151354359Sroberto		select_again:;
151454359Sroberto			/*
151554359Sroberto			 * Done everything from that select.  Poll again.
151654359Sroberto			 */
151754359Sroberto		}
151854359Sroberto
151954359Sroberto		/*
152054359Sroberto		 * If nothing more to do, try again.
152154359Sroberto		 * If nothing to do, just return.
152254359Sroberto		 * If an error occurred, complain and return.
152354359Sroberto		 */
152454359Sroberto		if (n == 0)
152554359Sroberto		{
152654359Sroberto			if (select_count == 0) /* We really had nothing to do */
152754359Sroberto			{
152854359Sroberto				if (debug)
152954359Sroberto				    msyslog(LOG_DEBUG, "input_handler: select() returned 0");
153054359Sroberto				--handler_count;
153154359Sroberto				return;
153254359Sroberto			}
153354359Sroberto			/* We've done our work */
153454359Sroberto			get_systime(&ts_e);
153554359Sroberto			/*
153654359Sroberto			 * (ts_e - ts) is the amount of time we spent processing
153754359Sroberto			 * this gob of file descriptors.  Log it.
153854359Sroberto			 */
153954359Sroberto			L_SUB(&ts_e, &ts);
154054359Sroberto			if (debug > 3)
154154359Sroberto			    msyslog(LOG_INFO, "input_handler: Processed a gob of fd's in %s msec", lfptoms(&ts_e, 6));
154254359Sroberto
154354359Sroberto			/* just bail. */
154454359Sroberto			--handler_count;
154554359Sroberto			return;
154654359Sroberto		}
154754359Sroberto		else if (n == -1)
154854359Sroberto		{
154954359Sroberto#ifndef SYS_WINNT
155054359Sroberto			int err = errno;
155154359Sroberto#else
155254359Sroberto			DWORD err = WSAGetLastError();
155354359Sroberto#endif /* SYS_WINNT */
155454359Sroberto
155554359Sroberto			/*
155654359Sroberto			 * extended FAU debugging output
155754359Sroberto			 */
155854359Sroberto			msyslog(LOG_ERR, "select(%d, %s, 0L, 0L, &0.000000) error: %m",
155954359Sroberto				maxactivefd+1, fdbits(maxactivefd, &activefds));
156054359Sroberto			if (
156154359Sroberto#ifndef SYS_WINNT
156254359Sroberto				(err == EBADF)
156354359Sroberto#else
156454359Sroberto				(err == WSAEBADF)
156554359Sroberto#endif /* SYS_WINNT */
156654359Sroberto				)
156754359Sroberto			{
156854359Sroberto				int j, b;
156954359Sroberto
157054359Sroberto				fds = activefds;
157154359Sroberto				for (j = 0; j <= maxactivefd; j++)
157254359Sroberto				    if (
157354359Sroberto#ifndef SYS_WINNT
157454359Sroberto					    (FD_ISSET(j, &fds) && (read(j, &b, 0) == -1))
157554359Sroberto#else
157654359Sroberto					    (FD_ISSET(j, &fds) && (!ReadFile((HANDLE)j, &b, 0, NULL, NULL)))
157754359Sroberto#endif /* SYS_WINNT */
157854359Sroberto					    )
157954359Sroberto					msyslog(LOG_ERR, "Bad file descriptor %d", j);
158054359Sroberto			}
158154359Sroberto			--handler_count;
158254359Sroberto			return;
158354359Sroberto		}
158454359Sroberto	}
158554359Sroberto	msyslog(LOG_ERR, "input_handler: fell out of infinite for(;;) loop!");
158654359Sroberto	--handler_count;
158754359Sroberto	return;
158854359Sroberto}
158954359Sroberto
159054359Sroberto#endif
159154359Sroberto
159254359Sroberto/*
159354359Sroberto * findinterface - utility used by other modules to find an interface
159454359Sroberto *		   given an address.
159554359Sroberto */
159654359Srobertostruct interface *
159754359Srobertofindinterface(
159854359Sroberto	struct sockaddr_in *addr
159954359Sroberto	)
160054359Sroberto{
160154359Sroberto	register int i;
160254359Sroberto	register u_int32 saddr;
160354359Sroberto
160454359Sroberto	/*
160554359Sroberto	 * Just match the address portion.
160654359Sroberto	 */
160754359Sroberto	saddr = addr->sin_addr.s_addr;
160854359Sroberto	for (i = 0; i < ninterfaces; i++)
160954359Sroberto	{
161054359Sroberto		if (inter_list[i].sin.sin_addr.s_addr == saddr)
161154359Sroberto		    return &inter_list[i];
161254359Sroberto	}
161354359Sroberto	return (struct interface *)0;
161454359Sroberto}
161554359Sroberto
161654359Sroberto
161754359Sroberto/*
161854359Sroberto * io_clr_stats - clear I/O module statistics
161954359Sroberto */
162054359Srobertovoid
162154359Srobertoio_clr_stats(void)
162254359Sroberto{
162354359Sroberto	packets_dropped = 0;
162454359Sroberto	packets_ignored = 0;
162554359Sroberto	packets_received = 0;
162654359Sroberto	packets_sent = 0;
162754359Sroberto	packets_notsent = 0;
162854359Sroberto
162954359Sroberto	handler_calls = 0;
163054359Sroberto	handler_pkts = 0;
163154359Sroberto	io_timereset = current_time;
163254359Sroberto}
163354359Sroberto
163454359Sroberto
163554359Sroberto#ifdef REFCLOCK
163654359Sroberto/*
163754359Sroberto * This is a hack so that I don't have to fool with these ioctls in the
163854359Sroberto * pps driver ... we are already non-blocking and turn on SIGIO thru
163954359Sroberto * another mechanisim
164054359Sroberto */
164154359Srobertoint
164254359Srobertoio_addclock_simple(
164354359Sroberto	struct refclockio *rio
164454359Sroberto	)
164554359Sroberto{
164654359Sroberto	BLOCKIO();
164754359Sroberto	/*
164854359Sroberto	 * Stuff the I/O structure in the list and mark the descriptor
164954359Sroberto	 * in use.	There is a harmless (I hope) race condition here.
165054359Sroberto	 */
165154359Sroberto	rio->next = refio;
165254359Sroberto	refio = rio;
165354359Sroberto
165454359Sroberto	if (rio->fd > maxactivefd)
165554359Sroberto	    maxactivefd = rio->fd;
165654359Sroberto	FD_SET(rio->fd, &activefds);
165754359Sroberto	UNBLOCKIO();
165854359Sroberto	return 1;
165954359Sroberto}
166054359Sroberto
166154359Sroberto/*
166254359Sroberto * io_addclock - add a reference clock to the list and arrange that we
166354359Sroberto *				 get SIGIO interrupts from it.
166454359Sroberto */
166554359Srobertoint
166654359Srobertoio_addclock(
166754359Sroberto	struct refclockio *rio
166854359Sroberto	)
166954359Sroberto{
167054359Sroberto	BLOCKIO();
167154359Sroberto	/*
167254359Sroberto	 * Stuff the I/O structure in the list and mark the descriptor
167354359Sroberto	 * in use.	There is a harmless (I hope) race condition here.
167454359Sroberto	 */
167554359Sroberto	rio->next = refio;
167654359Sroberto	refio = rio;
167754359Sroberto
167854359Sroberto# ifdef HAVE_SIGNALED_IO
167954359Sroberto	if (init_clock_sig(rio))
168054359Sroberto	{
168154359Sroberto		refio = rio->next;
168254359Sroberto		UNBLOCKIO();
168354359Sroberto		return 0;
168454359Sroberto	}
168554359Sroberto# elif defined(HAVE_IO_COMPLETION_PORT)
168654359Sroberto	if (io_completion_port_add_clock_io(rio))
168754359Sroberto	{
168854359Sroberto		refio = rio->next;
168954359Sroberto		UNBLOCKIO();
169054359Sroberto		return 0;
169154359Sroberto	}
169254359Sroberto# endif
169354359Sroberto
169454359Sroberto	if (rio->fd > maxactivefd)
169554359Sroberto	    maxactivefd = rio->fd;
169654359Sroberto	FD_SET(rio->fd, &activefds);
169754359Sroberto
169854359Sroberto	UNBLOCKIO();
169954359Sroberto	return 1;
170054359Sroberto}
170154359Sroberto
170254359Sroberto/*
170354359Sroberto * io_closeclock - close the clock in the I/O structure given
170454359Sroberto */
170554359Srobertovoid
170654359Srobertoio_closeclock(
170754359Sroberto	struct refclockio *rio
170854359Sroberto	)
170954359Sroberto{
171054359Sroberto	/*
171154359Sroberto	 * Remove structure from the list
171254359Sroberto	 */
171354359Sroberto	if (refio == rio)
171454359Sroberto	{
171554359Sroberto		refio = rio->next;
171654359Sroberto	}
171754359Sroberto	else
171854359Sroberto	{
171954359Sroberto		register struct refclockio *rp;
172054359Sroberto
172154359Sroberto		for (rp = refio; rp != 0; rp = rp->next)
172254359Sroberto		    if (rp->next == rio)
172354359Sroberto		    {
172454359Sroberto			    rp->next = rio->next;
172554359Sroberto			    break;
172654359Sroberto		    }
172754359Sroberto
172854359Sroberto		if (rp == 0)
172954359Sroberto		{
173054359Sroberto			/*
173154359Sroberto			 * Internal error.	Report it.
173254359Sroberto			 */
173354359Sroberto			msyslog(LOG_ERR,
173454359Sroberto				"internal error: refclockio structure not found");
173554359Sroberto			return;
173654359Sroberto		}
173754359Sroberto	}
173854359Sroberto
173954359Sroberto	/*
174054359Sroberto	 * Close the descriptor.
174154359Sroberto	 */
174254359Sroberto	close_file(rio->fd);
174354359Sroberto}
174454359Sroberto#endif	/* REFCLOCK */
174554359Sroberto
174654359Srobertovoid
174754359Srobertokill_asyncio(void)
174854359Sroberto{
174954359Sroberto	int i;
175054359Sroberto
175154359Sroberto	BLOCKIO();
175254359Sroberto	for (i = 0; i <= maxactivefd; i++)
175354359Sroberto	    (void)close_socket(i);
175454359Sroberto}
1755