diff options
author | roberto <roberto@FreeBSD.org> | 1999-12-09 13:01:21 +0000 |
---|---|---|
committer | roberto <roberto@FreeBSD.org> | 1999-12-09 13:01:21 +0000 |
commit | ef64b99e8412f2273dd2e8b3291c2f78ffc4667f (patch) | |
tree | fc0cfa1aab0ff6b228f511b410733ef4f35d1ead /contrib/ntp/ntpd/ntp_io.c | |
download | FreeBSD-src-ef64b99e8412f2273dd2e8b3291c2f78ffc4667f.zip FreeBSD-src-ef64b99e8412f2273dd2e8b3291c2f78ffc4667f.tar.gz |
Virgin import of ntpd 4.0.98f
Diffstat (limited to 'contrib/ntp/ntpd/ntp_io.c')
-rw-r--r-- | contrib/ntp/ntpd/ntp_io.c | 1754 |
1 files changed, 1754 insertions, 0 deletions
diff --git a/contrib/ntp/ntpd/ntp_io.c b/contrib/ntp/ntpd/ntp_io.c new file mode 100644 index 0000000..e920249 --- /dev/null +++ b/contrib/ntp/ntpd/ntp_io.c @@ -0,0 +1,1754 @@ +/* + * ntp_io.c - input/output routines for ntpd. The socket-opening code + * was shamelessly stolen from ntpd. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <signal.h> +#include <sys/types.h> +#ifdef HAVE_SYS_PARAM_H +# include <sys/param.h> +#endif /* HAVE_SYS_PARAM_H */ +#ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +#endif +#ifdef HAVE_NETINET_IN_H +# include <netinet/in.h> +#endif +#ifdef HAVE_SYS_IOCTL_H +# include <sys/ioctl.h> +#endif +#ifdef HAVE_SYS_SOCKIO_H /* UXPV: SIOC* #defines (Frank Vance <fvance@waii.com>) */ +# include <sys/sockio.h> +#endif +#include <arpa/inet.h> + +#if _BSDI_VERSION >= 199510 +# include <ifaddrs.h> +#endif + +#include "ntp_machine.h" +#include "ntpd.h" +#include "ntp_io.h" +#include "iosignal.h" +#include "ntp_refclock.h" +#include "ntp_if.h" +#include "ntp_stdlib.h" + +#if defined(VMS) /* most likely UCX-specific */ + +#include <UCX$INETDEF.H> + +/* "un*x"-compatible names for some items in UCX$INETDEF.H */ +#define ifreq IFREQDEF +#define ifr_name IFR$T_NAME +#define ifr_addr IFR$R_DUMMY.IFR$T_ADDR +#define ifr_broadaddr IFR$R_DUMMY.IFR$T_BROADADDR +#define ifr_flags IFR$R_DUMMY.IFR$R_DUMMY_1_OVRL.IFR$W_FLAGS +#define IFF_UP IFR$M_IFF_UP +#define IFF_BROADCAST IFR$M_IFF_BROADCAST +#define IFF_LOOPBACK IFR$M_IFF_LOOPBACK + +#endif /* VMS */ + + +#if defined(VMS) || defined(SYS_WINNT) +/* structure used in SIOCGIFCONF request (after [KSR] OSF/1) */ +struct ifconf { + int ifc_len; /* size of buffer */ + union { + caddr_t ifcu_buf; + struct ifreq *ifcu_req; + } ifc_ifcu; +}; +#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ +#define ifc_req ifc_ifcu.ifcu_req /* array of structures returned */ + +#endif /* VMS */ + +#if defined(USE_TTY_SIGPOLL) || defined(USE_UDP_SIGPOLL) +# if defined(SYS_AIX) && defined(_IO) /* XXX Identify AIX some other way */ +# undef _IO +# endif +# include <stropts.h> +#endif + +/* + * We do asynchronous input using the SIGIO facility. A number of + * recvbuf buffers are preallocated for input. In the signal + * handler we poll to see which sockets are ready and read the + * packets from them into the recvbuf's along with a time stamp and + * an indication of the source host and the interface it was received + * through. This allows us to get as accurate receive time stamps + * as possible independent of other processing going on. + * + * We watch the number of recvbufs available to the signal handler + * and allocate more when this number drops below the low water + * mark. If the signal handler should run out of buffers in the + * interim it will drop incoming frames, the idea being that it is + * better to drop a packet than to be inaccurate. + */ + + +/* + * Other statistics of possible interest + */ +volatile u_long packets_dropped; /* total number of packets dropped on reception */ +volatile u_long packets_ignored; /* packets received on wild card interface */ +volatile u_long packets_received; /* total number of packets received */ +u_long packets_sent; /* total number of packets sent */ +u_long packets_notsent; /* total number of packets which couldn't be sent */ + +volatile u_long handler_calls; /* number of calls to interrupt handler */ +volatile u_long handler_pkts; /* number of pkts received by handler */ +u_long io_timereset; /* time counters were reset */ + +/* + * Interface stuff + */ +struct interface *any_interface; /* pointer to default interface */ +struct interface *loopback_interface; /* point to loopback interface */ +static struct interface inter_list[MAXINTERFACES]; +static int ninterfaces; + +#ifdef REFCLOCK +/* + * Refclock stuff. We keep a chain of structures with data concerning + * the guys we are doing I/O for. + */ +static struct refclockio *refio; +#endif /* REFCLOCK */ + +/* + * File descriptor masks etc. for call to select + */ +fd_set activefds; +int maxactivefd; + +static int create_sockets P((u_int)); +static int open_socket P((struct sockaddr_in *, int, int)); +static void close_socket P((int)); +static void close_file P((int)); +static char * fdbits P((int, fd_set *)); + +/* + * init_io - initialize I/O data structures and call socket creation routine + */ +void +init_io(void) +{ +#ifdef SYS_WINNT + WORD wVersionRequested; + WSADATA wsaData; + init_transmitbuff(); +#endif /* SYS_WINNT */ + + /* + * Init buffer free list and stat counters + */ + init_recvbuff(RECV_INIT); + + packets_dropped = packets_received = 0; + packets_ignored = 0; + packets_sent = packets_notsent = 0; + handler_calls = handler_pkts = 0; + io_timereset = 0; + loopback_interface = 0; + +#ifdef REFCLOCK + refio = 0; +#endif + +#if defined(HAVE_SIGNALED_IO) + (void) set_signal(); +#endif + +#ifdef SYS_WINNT + wVersionRequested = MAKEWORD(1,1); + if (WSAStartup(wVersionRequested, &wsaData)) + { + msyslog(LOG_ERR, "No useable winsock.dll: %m"); + exit(1); + } +#endif /* SYS_WINNT */ + + /* + * Create the sockets + */ + BLOCKIO(); + (void) create_sockets(htons(NTP_PORT)); + UNBLOCKIO(); + +#ifdef DEBUG + if (debug) + printf("init_io: maxactivefd %d\n", maxactivefd); +#endif +} + +/* + * create_sockets - create a socket for each interface plus a default + * socket for when we don't know where to send + */ +static int +create_sockets( + u_int port + ) +{ +#if _BSDI_VERSION >= 199510 + int i, j; + struct ifaddrs *ifaddrs, *ifap; + struct sockaddr_in resmask; +#if _BSDI_VERSION < 199701 + struct ifaddrs *lp; + int num_if; +#endif +#else /* _BSDI_VERSION >= 199510 */ +# ifdef STREAMS_TLI + struct strioctl ioc; +# endif /* STREAMS_TLI */ + char buf[MAXINTERFACES*sizeof(struct ifreq)]; + struct ifconf ifc; + struct ifreq ifreq, *ifr; + int n, i, j, vs, size = 0; + struct sockaddr_in resmask; +#endif /* _BSDI_VERSION >= 199510 */ + +#ifdef DEBUG + if (debug) + printf("create_sockets(%d)\n", ntohs( (u_short) port)); +#endif + + /* + * create pseudo-interface with wildcard address + */ + inter_list[0].sin.sin_family = AF_INET; + inter_list[0].sin.sin_port = port; + inter_list[0].sin.sin_addr.s_addr = htonl(INADDR_ANY); + (void) strncpy(inter_list[0].name, "wildcard", + sizeof(inter_list[0].name)); + inter_list[0].mask.sin_addr.s_addr = htonl(~ (u_int32)0); + inter_list[0].received = 0; + inter_list[0].sent = 0; + inter_list[0].notsent = 0; + inter_list[0].flags = INT_BROADCAST; + +#if _BSDI_VERSION >= 199510 +#if _BSDI_VERSION >= 199701 + if (getifaddrs(&ifaddrs) < 0) + { + msyslog(LOG_ERR, "getifaddrs: %m"); + exit(1); + } + i = 1; + for (ifap = ifaddrs; ifap != NULL; ifap = ifap->ifa_next) +#else + if (getifaddrs(&ifaddrs, &num_if) < 0) + { + msyslog(LOG_ERR, "create_sockets: getifaddrs() failed: %m"); + exit(1); + } + + i = 1; + + for (ifap = ifaddrs, lp = ifap + num_if; ifap < lp; ifap++) +#endif + { + struct sockaddr_in *sin; + + if (!ifap->ifa_addr) + continue; + + if (ifap->ifa_addr->sa_family != AF_INET) + continue; + + if ((ifap->ifa_flags & IFF_UP) == 0) + continue; + + if (ifap->ifa_flags & IFF_LOOPBACK) + { + sin = (struct sockaddr_in *)ifap->ifa_addr; + if (ntohl(sin->sin_addr.s_addr) != 0x7f000001) + { + continue; + } + } + + inter_list[i].flags = 0; + if (ifap->ifa_flags & IFF_BROADCAST) + inter_list[i].flags |= INT_BROADCAST; + + (void)strcpy(inter_list[i].name, ifap->ifa_name); + + sin = (struct sockaddr_in *)ifap->ifa_addr; + inter_list[i].sin = *sin; + inter_list[i].sin.sin_port = port; + + if (ifap->ifa_flags & IFF_LOOPBACK) + { + inter_list[i].flags = INT_LOOPBACK; + if (loopback_interface == NULL + || ntohl(sin->sin_addr.s_addr) != 0x7f000001) + loopback_interface = &inter_list[i]; + } + + if (inter_list[i].flags & INT_BROADCAST) + { + sin = (struct sockaddr_in *)ifap->ifa_broadaddr; + inter_list[i].bcast = *sin; + inter_list[i].bcast.sin_port = port; + } + + if (ifap->ifa_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) + { + inter_list[i].mask.sin_addr.s_addr = 0xffffffff; + } + else + { + sin = (struct sockaddr_in *)ifap->ifa_netmask; + inter_list[i].mask = *sin; + } + inter_list[i].mask.sin_family = AF_INET; + inter_list[i].mask.sin_len = sizeof *sin; + + /* + * look for an already existing source interface address. If + * the machine has multiple point to point interfaces, then + * the local address may appear more than once. + * + * A second problem exists if we have two addresses on + * the same network (via "ifconfig alias ..."). Don't + * make two xntp interfaces for the two aliases on the + * one physical interface. -wsr + */ + for (j=0; j < i; j++) + if (inter_list[j].sin.sin_addr.s_addr & + inter_list[j].mask.sin_addr.s_addr == + inter_list[i].sin.sin_addr.s_addr & + inter_list[i].mask.sin_addr.s_addr) + { + if (inter_list[j].flags & INT_LOOPBACK) + inter_list[j] = inter_list[i]; + break; + } + if (j == i) + i++; + if (i > MAXINTERFACES) + break; + } + free(ifaddrs); +#else /* _BSDI_VERSION >= 199510 */ +# ifdef USE_STREAMS_DEVICE_FOR_IF_CONFIG + if ((vs = open("/dev/ip", O_RDONLY)) < 0) + { + msyslog(LOG_ERR, "create_sockets: open(/dev/ip) failed: %m"); + exit(1); + } +# else /* not USE_STREAMS_DEVICE_FOR_IF_CONFIG */ + if ( + (vs = socket(AF_INET, SOCK_DGRAM, 0)) +# ifndef SYS_WINNT + < 0 +# else /* SYS_WINNT */ + == INVALID_SOCKET +# endif /* SYS_WINNT */ + ) { + msyslog(LOG_ERR, "create_sockets: socket(AF_INET, SOCK_DGRAM) failed: %m"); + exit(1); + } +# endif /* not USE_STREAMS_DEVICE_FOR_IF_CONFIG */ + + i = 1; +# if !defined(SYS_WINNT) + ifc.ifc_len = sizeof(buf); +# endif +# ifdef STREAMS_TLI + ioc.ic_cmd = SIOCGIFCONF; + ioc.ic_timout = 0; + ioc.ic_dp = (caddr_t)buf; + ioc.ic_len = sizeof(buf); + if(ioctl(vs, I_STR, &ioc) < 0 || + ioc.ic_len < sizeof(struct ifreq)) + { + msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFCONF) failed: %m - exiting"); + exit(1); + } +# ifdef SIZE_RETURNED_IN_BUFFER + ifc.ifc_len = ioc.ic_len - sizeof(int); + ifc.ifc_buf = buf + sizeof(int); +# else /* not SIZE_RETURNED_IN_BUFFER */ + ifc.ifc_len = ioc.ic_len; + ifc.ifc_buf = buf; +# endif /* not SIZE_RETURNED_IN_BUFFER */ + +# else /* not STREAMS_TLI */ + ifc.ifc_len = sizeof(buf); + ifc.ifc_buf = buf; +# ifndef SYS_WINNT + if (ioctl(vs, SIOCGIFCONF, (char *)&ifc) < 0) +# else + if (WSAIoctl(vs, SIO_GET_INTERFACE_LIST, 0, 0, ifc.ifc_buf, ifc.ifc_len, &ifc.ifc_len, 0, 0) == SOCKET_ERROR) +# endif /* SYS_WINNT */ +{ + msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFCONF) failed: %m - exiting"); + exit(1); +} + +# endif /* not STREAMS_TLI */ + + for(n = ifc.ifc_len, ifr = ifc.ifc_req; n > 0; + ifr = (struct ifreq *)((char *)ifr + size)) + { + extern int listen_to_virtual_ips; + + size = sizeof(*ifr); + +# ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR + if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr)) + size += ifr->ifr_addr.sa_len - sizeof(struct sockaddr); +# endif + n -= size; + +# if !defined(SYS_WINNT) + /* Exclude logical interfaces (indicated by ':' in the interface name) */ + if (debug) + printf("interface <%s> ", ifr->ifr_name); + if ((listen_to_virtual_ips == 0) + && (strchr(ifr->ifr_name, (int)':') != NULL)) { + if (debug) + printf("ignored\n"); + continue; + } + if (debug) + printf("OK\n"); + + if ( +# ifdef VMS /* VMS+UCX */ + (((struct sockaddr *)&(ifr->ifr_addr))->sa_family != AF_INET) +# else + (ifr->ifr_addr.sa_family != AF_INET) +# endif /* VMS+UCX */ + ) { + if (debug) + printf("ignoring %s - not AF_INET\n", + ifr->ifr_name); + continue; + } +# endif /* SYS_WINNT */ + ifreq = *ifr; + inter_list[i].flags = 0; + /* is it broadcast capable? */ +# ifndef SYS_WINNT +# ifdef STREAMS_TLI + ioc.ic_cmd = SIOCGIFFLAGS; + ioc.ic_timout = 0; + ioc.ic_dp = (caddr_t)&ifreq; + ioc.ic_len = sizeof(struct ifreq); + if(ioctl(vs, I_STR, &ioc)) { + msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFFLAGS) failed: %m"); + continue; + } +# else /* not STREAMS_TLI */ + if (ioctl(vs, SIOCGIFFLAGS, (char *)&ifreq) < 0) { + if (errno != ENXIO) + msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFFLAGS) failed: %m"); + continue; + } +# endif /* not STREAMS_TLI */ + if ((ifreq.ifr_flags & IFF_UP) == 0) { + if (debug) + printf("ignoring %s - interface not UP\n", + ifr->ifr_name); + continue; + } + inter_list[i].flags = 0; + if (ifreq.ifr_flags & IFF_BROADCAST) + inter_list[i].flags |= INT_BROADCAST; +# endif /* not SYS_WINNT */ +# if !defined(SUN_3_3_STINKS) + if ( +# if defined(IFF_LOCAL_LOOPBACK) /* defined(SYS_HPUX) && (SYS_HPUX < 8) */ + (ifreq.ifr_flags & IFF_LOCAL_LOOPBACK) +# elif defined(IFF_LOOPBACK) + (ifreq.ifr_flags & IFF_LOOPBACK) +# else /* not IFF_LOCAL_LOOPBACK and not IFF_LOOPBACK */ + /* test against 127.0.0.1 (yuck!!) */ + (inter_list[i].sin.sin_addr.s_addr == inet_addr("127.0.0.1")) +# endif /* not IFF_LOCAL_LOOPBACK and not IFF_LOOPBACK */ + ) + { +# ifndef SYS_WINNT + inter_list[i].flags |= INT_LOOPBACK; +# endif /* not SYS_WINNT */ + if (loopback_interface == 0) + { + loopback_interface = &inter_list[i]; + } + } +# endif /* not SUN_3_3_STINKS */ + +#if 0 +# ifndef SYS_WINNT +# ifdef STREAMS_TLI + ioc.ic_cmd = SIOCGIFADDR; + ioc.ic_timout = 0; + ioc.ic_dp = (caddr_t)&ifreq; + ioc.ic_len = sizeof(struct ifreq); + if (ioctl(vs, I_STR, &ioc)) + { + msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFADDR) failed: %m"); + continue; + } +# else /* not STREAMS_TLI */ + if (ioctl(vs, SIOCGIFADDR, (char *)&ifreq) < 0) + { + if (errno != ENXIO) + msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFADDR) failed: %m"); + continue; + } +# endif /* not STREAMS_TLI */ +# endif /* not SYS_WINNT */ +#endif /* 0 */ +# if defined(SYS_WINNT) + {int TODO_FillInTheNameWithSomeThingReasonble;} +# else + (void)strncpy(inter_list[i].name, ifreq.ifr_name, + sizeof(inter_list[i].name)); +# endif + inter_list[i].sin = *(struct sockaddr_in *)&ifr->ifr_addr; + inter_list[i].sin.sin_family = AF_INET; + inter_list[i].sin.sin_port = port; + +# if defined(SUN_3_3_STINKS) + /* + * Oh, barf! I'm too disgusted to even explain this + */ + if (SRCADR(&inter_list[i].sin) == 0x7f000001) + { + inter_list[i].flags |= INT_LOOPBACK; + if (loopback_interface == 0) + loopback_interface = &inter_list[i]; + } +# endif /* SUN_3_3_STINKS */ +# if !defined SYS_WINNT && !defined SYS_CYGWIN32 /* no interface flags on NT */ + if (inter_list[i].flags & INT_BROADCAST) { +# ifdef STREAMS_TLI + ioc.ic_cmd = SIOCGIFBRDADDR; + ioc.ic_timout = 0; + ioc.ic_dp = (caddr_t)&ifreq; + ioc.ic_len = sizeof(struct ifreq); + if(ioctl(vs, I_STR, &ioc)) { + msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFBRDADDR) failed: %m"); + exit(1); + } +# else /* not STREAMS_TLI */ + if (ioctl(vs, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { + msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFBRDADDR) failed: %m"); + exit(1); + } +# endif /* not STREAMS_TLI */ + +# ifndef ifr_broadaddr + inter_list[i].bcast = + *(struct sockaddr_in *)&ifreq.ifr_addr; +# else + inter_list[i].bcast = + *(struct sockaddr_in *)&ifreq.ifr_broadaddr; +# endif /* ifr_broadaddr */ + inter_list[i].bcast.sin_family = AF_INET; + inter_list[i].bcast.sin_port = port; + } + +# ifdef STREAMS_TLI + ioc.ic_cmd = SIOCGIFNETMASK; + ioc.ic_timout = 0; + ioc.ic_dp = (caddr_t)&ifreq; + ioc.ic_len = sizeof(struct ifreq); + if(ioctl(vs, I_STR, &ioc)) { + msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFNETMASK) failed: %m"); + exit(1); + } +# else /* not STREAMS_TLI */ + if (ioctl(vs, SIOCGIFNETMASK, (char *)&ifreq) < 0) { + msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFNETMASK) failed: %m"); + exit(1); + } +# endif /* not STREAMS_TLI */ + inter_list[i].mask = *(struct sockaddr_in *)&ifreq.ifr_addr; +# else + /* winnt here */ + inter_list[i].bcast = ifreq.ifr_broadaddr; + inter_list[i].bcast.sin_family = AF_INET; + inter_list[i].bcast.sin_port = port; + inter_list[i].mask = ifreq.ifr_mask; +# endif /* not SYS_WINNT */ + + /* + * look for an already existing source interface address. If + * the machine has multiple point to point interfaces, then + * the local address may appear more than once. + */ + for (j=0; j < i; j++) + if (inter_list[j].sin.sin_addr.s_addr == + inter_list[i].sin.sin_addr.s_addr) { + break; + } + if (j == i) + i++; + if (i > MAXINTERFACES) + break; + } + closesocket(vs); +#endif /* _BSDI_VERSION >= 199510 */ + + ninterfaces = i; + maxactivefd = 0; + FD_ZERO(&activefds); + for (i = 0; i < ninterfaces; i++) { + inter_list[i].fd = + open_socket(&inter_list[i].sin, + inter_list[i].flags & INT_BROADCAST, 0); + } + + /* + * Now that we have opened all the sockets, turn off the reuse flag for + * security. + */ + for (i = 0; i < ninterfaces; i++) { + int off = 0; + + /* + * if inter_list[ n ].fd is -1, we might have a adapter + * configured but not present + */ + if ( inter_list[ i ].fd != -1 ) { + if (setsockopt(inter_list[i].fd, SOL_SOCKET, + SO_REUSEADDR, (char *)&off, + sizeof(off))) { + msyslog(LOG_ERR, "create_sockets: setsockopt(SO_REUSEADDR,off) failed: %m"); + } + } + } + +#if defined(MCAST) + /* + * enable possible multicast reception on the broadcast socket + */ + inter_list[0].bcast.sin_addr.s_addr = htonl(INADDR_ANY); + inter_list[0].bcast.sin_family = AF_INET; + inter_list[0].bcast.sin_port = port; +#endif /* MCAST */ + + /* + * Blacklist all bound interface addresses + */ + resmask.sin_addr.s_addr = ~ (u_int32)0; + for (i = 1; i < ninterfaces; i++) + hack_restrict(RESTRICT_FLAGS, &inter_list[i].sin, &resmask, + RESM_NTPONLY|RESM_INTERFACE, RES_IGNORE); + + any_interface = &inter_list[0]; +#ifdef DEBUG + if (debug > 2) { + printf("create_sockets: ninterfaces=%d\n", ninterfaces); + for (i = 0; i < ninterfaces; i++) { + printf("interface %d: fd=%d, bfd=%d, name=%.8s, flags=0x%x\n", + i, + inter_list[i].fd, + inter_list[i].bfd, + inter_list[i].name, + inter_list[i].flags); + /* Leave these as three printf calls. */ + printf(" sin=%s", + inet_ntoa((inter_list[i].sin.sin_addr))); + if (inter_list[i].flags & INT_BROADCAST) + printf(" bcast=%s,", + inet_ntoa((inter_list[i].bcast.sin_addr))); + printf(" mask=%s\n", + inet_ntoa((inter_list[i].mask.sin_addr))); + } + } +#endif +#if defined (HAVE_IO_COMPLETION_PORT) + for (i = 0; i < ninterfaces; i++) { + io_completion_port_add_socket(&inter_list[i]); + } +#endif + return ninterfaces; +} + +/* + * io_setbclient - open the broadcast client sockets + */ +void +io_setbclient(void) +{ + int i; + + for (i = 1; i < ninterfaces; i++) + { + if (!(inter_list[i].flags & INT_BROADCAST)) + continue; + if (inter_list[i].flags & INT_BCASTOPEN) + continue; +#ifdef SYS_SOLARIS + inter_list[i].bcast.sin_addr.s_addr = htonl(INADDR_ANY); +#endif +#ifdef OPEN_BCAST_SOCKET /* Was: !SYS_DOMAINOS && !SYS_LINUX */ + inter_list[i].bfd = open_socket(&inter_list[i].bcast, INT_BROADCAST, 1); + inter_list[i].flags |= INT_BCASTOPEN; +#endif + } +} + + +/* + * io_multicast_add() - add multicast group address + */ +void +io_multicast_add( + u_int32 addr + ) +{ +#ifdef MCAST + struct ip_mreq mreq; + int i = ninterfaces; /* Use the next interface */ + u_int32 haddr = ntohl(addr); + struct in_addr iaddr; + int s; + struct sockaddr_in *sinp; + + iaddr.s_addr = addr; + + if (!IN_CLASSD(haddr)) + { + msyslog(LOG_ERR, + "cannot add multicast address %s as it is not class D", + inet_ntoa(iaddr)); + return; + } + + for (i = 0; i < ninterfaces; i++) + { + /* Already have this address */ + if (inter_list[i].sin.sin_addr.s_addr == addr) return; + /* found a free slot */ + if (inter_list[i].sin.sin_addr.s_addr == 0 && + inter_list[i].fd <= 0 && inter_list[i].bfd <= 0 && + inter_list[i].flags == 0) break; + } + sinp = &(inter_list[i].sin); + + memset((char *)&mreq, 0, sizeof(mreq)); + memset((char *)&inter_list[i], 0, sizeof inter_list[0]); + sinp->sin_family = AF_INET; + sinp->sin_addr = iaddr; + sinp->sin_port = htons(123); + + s = open_socket(sinp, 0, 1); + /* Try opening a socket for the specified class D address */ + /* This works under SunOS 4.x, but not OSF1 .. :-( */ + if (s < 0) + { + memset((char *)&inter_list[i], 0, sizeof inter_list[0]); + i = 0; + /* HACK ! -- stuff in an address */ + inter_list[i].bcast.sin_addr.s_addr = addr; + msyslog(LOG_ERR, "...multicast address %s using wildcard socket", + inet_ntoa(iaddr)); + } + else + { + inter_list[i].fd = s; + inter_list[i].bfd = -1; + (void) strncpy(inter_list[i].name, "multicast", + sizeof(inter_list[i].name)); + inter_list[i].mask.sin_addr.s_addr = htonl(~(u_int32)0); + } + + /* + * enable reception of multicast packets + */ + mreq.imr_multiaddr = iaddr; + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + if (setsockopt(inter_list[i].fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (char *)&mreq, sizeof(mreq)) == -1) + msyslog(LOG_ERR, + "setsockopt IP_ADD_MEMBERSHIP fails: %m for %x / %x (%s)", + mreq.imr_multiaddr.s_addr, mreq.imr_interface.s_addr, + inet_ntoa(iaddr)); + inter_list[i].flags |= INT_MULTICAST; + if (i >= ninterfaces) ninterfaces = i+1; +#else /* MCAST */ + struct in_addr iaddr; + + iaddr.s_addr = addr; + msyslog(LOG_ERR, "cannot add multicast address %s as no MCAST support", + inet_ntoa(iaddr)); +#endif /* MCAST */ +} + +/* + * io_unsetbclient - close the broadcast client sockets + */ +void +io_unsetbclient(void) +{ + int i; + + for (i = 1; i < ninterfaces; i++) + { + if (!(inter_list[i].flags & INT_BCASTOPEN)) + continue; + close_socket(inter_list[i].bfd); + inter_list[i].bfd = -1; + inter_list[i].flags &= ~INT_BCASTOPEN; + } +} + + +/* + * io_multicast_del() - delete multicast group address + */ +void +io_multicast_del( + u_int32 addr + ) +{ +#ifdef MCAST + int i; + struct ip_mreq mreq; + u_int32 haddr = ntohl(addr); + struct sockaddr_in sinaddr; + + if (!IN_CLASSD(haddr)) + { + sinaddr.sin_addr.s_addr = addr; + msyslog(LOG_ERR, + "invalid multicast address %s", ntoa(&sinaddr)); + return; + } + + /* + * Disable reception of multicast packets + */ + mreq.imr_multiaddr.s_addr = addr; + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + for (i = 0; i < ninterfaces; i++) + { + if (!(inter_list[i].flags & INT_MULTICAST)) + continue; + if (!(inter_list[i].fd < 0)) + continue; + if (addr != inter_list[i].sin.sin_addr.s_addr) + continue; + if (i != 0) + { + /* we have an explicit fd, so we can close it */ + close_socket(inter_list[i].fd); + memset((char *)&inter_list[i], 0, sizeof inter_list[0]); + inter_list[i].fd = -1; + inter_list[i].bfd = -1; + } + else + { + /* We are sharing "any address" port :-( Don't close it! */ + if (setsockopt(inter_list[i].fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, + (char *)&mreq, sizeof(mreq)) == -1) + msyslog(LOG_ERR, "setsockopt IP_DROP_MEMBERSHIP fails: %m"); + /* This is **WRONG** -- there may be others ! */ + /* There should be a count of users ... */ + inter_list[i].flags &= ~INT_MULTICAST; + } + } +#else /* not MCAST */ + msyslog(LOG_ERR, "this function requires multicast kernel"); +#endif /* not MCAST */ +} + + +/* + * open_socket - open a socket, returning the file descriptor + */ +static int +open_socket( + struct sockaddr_in *addr, + int flags, + int turn_off_reuse + ) +{ + int fd; + int on = 1, off = 0; + + /* create a datagram (UDP) socket */ + if ( (fd = socket(AF_INET, SOCK_DGRAM, 0)) +#ifndef SYS_WINNT + < 0 +#else + == INVALID_SOCKET +#endif /* SYS_WINNT */ + ) + { + msyslog(LOG_ERR, "socket(AF_INET, SOCK_DGRAM, 0) failed: %m"); + exit(1); + /*NOTREACHED*/ + } + + /* set SO_REUSEADDR since we will be binding the same port + number on each interface */ + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + (char *)&on, sizeof(on))) + { + msyslog(LOG_ERR, "setsockopt SO_REUSEADDR on fails: %m"); + } + + /* + * bind the local address. + */ + if (bind(fd, (struct sockaddr *)addr, sizeof(*addr)) < 0) { + char buff[160]; + sprintf(buff, + "bind() fd %d, family %d, port %d, addr %s, in_classd=%d flags=%d fails: %%m", + fd, addr->sin_family, (int)ntohs(addr->sin_port), + ntoa(addr), + IN_CLASSD(ntohl(addr->sin_addr.s_addr)), flags); + msyslog(LOG_ERR, buff); + closesocket(fd); + + /* + * soft fail if opening a class D address + */ + if (IN_CLASSD(ntohl(addr->sin_addr.s_addr))) + return -1; +#if 0 + exit(1); +#else + return -1; +#endif + } +#ifdef DEBUG + if (debug) + printf("bind() fd %d, family %d, port %d, addr %s, flags=%d\n", + fd, + addr->sin_family, + (int)ntohs(addr->sin_port), + ntoa(addr), + flags); +#endif + if (fd > maxactivefd) + maxactivefd = fd; + FD_SET(fd, &activefds); + + /* + * set non-blocking, + */ + +#ifdef USE_FIONBIO + /* in vxWorks we use FIONBIO, but the others are defined for old systems, so + * all hell breaks loose if we leave them defined + */ +#undef O_NONBLOCK +#undef FNDELAY +#undef O_NDELAY +#endif + +#if defined(O_NONBLOCK) /* POSIX */ + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) + { + msyslog(LOG_ERR, "fcntl(O_NONBLOCK) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#elif defined(FNDELAY) + if (fcntl(fd, F_SETFL, FNDELAY) < 0) + { + msyslog(LOG_ERR, "fcntl(FNDELAY) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#elif defined(O_NDELAY) /* generally the same as FNDELAY */ + if (fcntl(fd, F_SETFL, O_NDELAY) < 0) + { + msyslog(LOG_ERR, "fcntl(O_NDELAY) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#elif defined(FIONBIO) + if ( +# if defined(VMS) + (ioctl(fd,FIONBIO,&1) < 0) +# elif defined(SYS_WINNT) + (ioctlsocket(fd,FIONBIO,(u_long *) &on) == SOCKET_ERROR) +# else + (ioctl(fd,FIONBIO,&on) < 0) +# endif + ) + { + msyslog(LOG_ERR, "ioctl(FIONBIO) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#elif defined(FIOSNBIO) + if (ioctl(fd,FIOSNBIO,&on) < 0) + { + msyslog(LOG_ERR, "ioctl(FIOSNBIO) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#else +# include "Bletch: Need non-blocking I/O!" +#endif + +#ifdef HAVE_SIGNALED_IO + init_socket_sig(fd); +#endif /* not HAVE_SIGNALED_IO */ + + /* + * Turn off the SO_REUSEADDR socket option. It apparently + * causes heartburn on systems with multicast IP installed. + * On normal systems it only gets looked at when the address + * is being bound anyway.. + */ + if (turn_off_reuse) + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + (char *)&off, sizeof(off))) + { + msyslog(LOG_ERR, "setsockopt SO_REUSEADDR off fails: %m"); + } + +#ifdef SO_BROADCAST + /* if this interface can support broadcast, set SO_BROADCAST */ + if (flags & INT_BROADCAST) + { + if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, + (char *)&on, sizeof(on))) + { + msyslog(LOG_ERR, "setsockopt(SO_BROADCAST): %m"); + } + } +#endif /* SO_BROADCAST */ + +#if !defined(SYS_WINNT) && !defined(VMS) +# ifdef DEBUG + if (debug > 1) + printf("flags for fd %d: 0%o\n", fd, + fcntl(fd, F_GETFL, 0)); +# endif +#endif /* SYS_WINNT || VMS */ + + return fd; +} + + +/* + * close_socket - close a socket and remove from the activefd list + */ +static void +close_socket( + int fd + ) +{ + int i, newmax; + + (void) closesocket(fd); + FD_CLR( (u_int) fd, &activefds); + + if (fd >= maxactivefd) + { + newmax = 0; + for (i = 0; i < maxactivefd; i++) + if (FD_ISSET(i, &activefds)) + newmax = i; + maxactivefd = newmax; + } +} + + +/* + * close_file - close a file and remove from the activefd list + * added 1/31/1997 Greg Schueman for Windows NT portability + */ +static void +close_file( + int fd + ) +{ + int i, newmax; + + (void) close(fd); + FD_CLR( (u_int) fd, &activefds); + + if (fd >= maxactivefd) + { + newmax = 0; + for (i = 0; i < maxactivefd; i++) + if (FD_ISSET(i, &activefds)) + newmax = i; + maxactivefd = newmax; + } +} + + +/* + * findbcastinter - find broadcast interface corresponding to address + */ +struct interface * +findbcastinter( + struct sockaddr_in *addr + ) +{ +#if defined(SIOCGIFCONF) || defined(SYS_WINNT) + register int i; + register u_int32 netnum; + + netnum = NSRCADR(addr); + for (i = 1; i < ninterfaces; i++) + { + if (!(inter_list[i].flags & INT_BROADCAST)) + continue; + if (NSRCADR(&inter_list[i].bcast) == netnum) + return &inter_list[i]; + if ((NSRCADR(&inter_list[i].sin) & NSRCADR(&inter_list[i].mask)) + == (netnum & NSRCADR(&inter_list[i].mask))) + return &inter_list[i]; + } +#endif /* SIOCGIFCONF */ + return any_interface; +} + + +/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ +/* + * sendpkt - send a packet to the specified destination. Maintain a + * send error cache so that only the first consecutive error for a + * destination is logged. + */ +void +sendpkt( + struct sockaddr_in *dest, + struct interface *inter, + int ttl, + struct pkt *pkt, + int len + ) +{ + int cc, slot; +#ifdef SYS_WINNT + DWORD err; +#endif /* SYS_WINNT */ + + /* + * Send error cache. Empty slots have port == 0 + * Set ERRORCACHESIZE to 0 to disable + */ + struct cache { + u_short port; + struct in_addr addr; + }; + +#ifndef ERRORCACHESIZE +#define ERRORCACHESIZE 8 +#endif +#if ERRORCACHESIZE > 0 + static struct cache badaddrs[ERRORCACHESIZE]; +#else +#define badaddrs ((struct cache *)0) /* Only used in empty loops! */ +#endif + + /* + * check if the source address is a multicast address - replace + * interface with any-interface if so. + */ + if (IN_MULTICAST(ntohl(inter->sin.sin_addr.s_addr))) + inter = any_interface; +#ifdef DEBUG + if (debug > 1) + printf("%ssendpkt(fd=%d dst=%s, src=%s, ttl=%d, len=%d)\n", + (ttl >= 0) ? "\tMCAST\t*****" : "", + inter->fd, ntoa(dest), + ntoa(&inter->sin), ttl, len); +#endif + +#ifdef MCAST + /* for the moment we use the bcast option to set multicast ttl */ + if (ttl >= 0 && ttl != inter->last_ttl) + { + char mttl = ttl; + + /* set the multicast ttl for outgoing packets */ + if (setsockopt(inter->fd, IPPROTO_IP, IP_MULTICAST_TTL, + &mttl, sizeof(mttl)) == -1) + { + msyslog(LOG_ERR, "setsockopt IP_MULTICAST_TTL fails: %m"); + } + else inter->last_ttl = ttl; + } +#endif /* MCAST */ + + for (slot = ERRORCACHESIZE; --slot >= 0; ) + if (badaddrs[slot].port == dest->sin_port && + badaddrs[slot].addr.s_addr == dest->sin_addr.s_addr) + break; + +#if defined(HAVE_IO_COMPLETION_PORT) + err = io_completion_port_sendto(inter, pkt, len, dest); + if (err != ERROR_SUCCESS) +#else + cc = sendto(inter->fd, (char *)pkt, len, 0, (struct sockaddr *)dest, + sizeof(struct sockaddr_in)); + if (cc == -1) +#endif + { + inter->notsent++; + packets_notsent++; +#if defined(HAVE_IO_COMPLETION_PORT) + if (err != WSAEWOULDBLOCK && err != WSAENOBUFS && slot < 0) +#else + if (errno != EWOULDBLOCK && errno != ENOBUFS && slot < 0) +#endif + { + /* + * Remember this, if there's an empty slot + */ + for (slot = ERRORCACHESIZE; --slot >= 0; ) + if (badaddrs[slot].port == 0) + { + badaddrs[slot].port = dest->sin_port; + badaddrs[slot].addr = dest->sin_addr; + break; + } + msyslog(LOG_ERR, "sendto(%s): %m", ntoa(dest)); + } + } + else + { + inter->sent++; + packets_sent++; + /* + * He's not bad any more + */ + if (slot >= 0) + { + msyslog(LOG_INFO, "Connection re-established to %s", ntoa(dest)); + badaddrs[slot].port = 0; + } + } +} + +#if !defined(HAVE_IO_COMPLETION_PORT) +/* + * fdbits - generate ascii representation of fd_set (FAU debug support) + * HFDF format - highest fd first. + */ +static char * +fdbits( + int count, + fd_set *set + ) +{ + static char buffer[256]; + char * buf = buffer; + + count = (count < 256) ? count : 255; + + while (count >= 0) + { + *buf++ = FD_ISSET(count, set) ? '#' : '-'; + count--; + } + *buf = '\0'; + + return buffer; +} + +/* + * input_handler - receive packets asynchronously + */ +extern void +input_handler( + l_fp *cts + ) +{ + register int i, n; + register struct recvbuf *rb; + register int doing; + register int fd; + struct timeval tvzero; + int fromlen; + l_fp ts; /* Timestamp at BOselect() gob */ + l_fp ts_e; /* Timestamp at EOselect() gob */ + fd_set fds; + int select_count = 0; + static int handler_count = 0; + + ++handler_count; + if (handler_count != 1) + msyslog(LOG_ERR, "input_handler: handler_count is %d!", handler_count); + handler_calls++; + ts = *cts; + + for (;;) + { + /* + * Do a poll to see who has data + */ + + fds = activefds; + tvzero.tv_sec = tvzero.tv_usec = 0; + + /* + * If we have something to do, freeze a timestamp. + * See below for the other cases (nothing (left) to do or error) + */ + while (0 < (n = select(maxactivefd+1, &fds, (fd_set *)0, (fd_set *)0, &tvzero))) + { + ++select_count; + ++handler_pkts; + +#ifdef REFCLOCK + /* + * Check out the reference clocks first, if any + */ + if (refio != 0) + { + register struct refclockio *rp; + + for (rp = refio; rp != 0 && n > 0; rp = rp->next) + { + fd = rp->fd; + if (FD_ISSET(fd, &fds)) + { + n--; + if (free_recvbuffs() == 0) + { + char buf[RX_BUFF_SIZE]; + +#ifndef SYS_WINNT + (void) read(fd, buf, sizeof buf); +#else + (void) ReadFile((HANDLE)fd, buf, (DWORD)sizeof buf, NULL, NULL); +#endif /* SYS_WINNT */ + packets_dropped++; + goto select_again; + } + + rb = get_free_recv_buffer(); + + i = (rp->datalen == 0 + || rp->datalen > sizeof(rb->recv_space)) + ? sizeof(rb->recv_space) : rp->datalen; +#ifndef SYS_WINNT + rb->recv_length = + read(fd, (char *)&rb->recv_space, (unsigned)i) +#else /* SYS_WINNT */ + ReadFile((HANDLE)fd, (char *)&rb->recv_space, (DWORD)i, + (LPDWORD)&(rb->recv_length), NULL) +#endif /* SYS_WINNT */ + ; + + if (rb->recv_length == -1) + { + msyslog(LOG_ERR, "clock read fd %d: %m", fd); + freerecvbuf(rb); + goto select_again; + } + + /* + * Got one. Mark how and when it got here, + * put it on the full list and do bookkeeping. + */ + rb->recv_srcclock = rp->srcclock; + rb->dstadr = 0; + rb->fd = fd; + rb->recv_time = ts; + rb->receiver = rp->clock_recv; + + if (rp->io_input) + { + /* + * have direct input routine for refclocks + */ + if (rp->io_input(rb) == 0) + { + /* + * data was consumed - nothing to pass up + * into block input machine + */ + freerecvbuf(rb); +#if 1 + goto select_again; +#else + continue; +#endif + } + } + + add_full_recv_buffer(rb); + + rp->recvcount++; + packets_received++; + } + } + } +#endif /* REFCLOCK */ + + /* + * Loop through the interfaces looking for data to read. + */ + for (i = ninterfaces - 1; (i >= 0) && (n > 0); i--) + { + for (doing = 0; (doing < 2) && (n > 0); doing++) + { + if (doing == 0) + { + fd = inter_list[i].fd; + } + else + { + if (!(inter_list[i].flags & INT_BCASTOPEN)) + break; + fd = inter_list[i].bfd; + } + if (fd < 0) continue; + if (FD_ISSET(fd, &fds)) + { + n--; + + /* + * Get a buffer and read the frame. If we + * haven't got a buffer, or this is received + * on the wild card socket, just dump the + * packet. + */ + if ( +#ifdef UDP_WILDCARD_DELIVERY + /* + * these guys manage to put properly addressed + * packets into the wildcard queue + */ + (free_recvbuffs() == 0) +#else + ((i == 0) || (free_recvbuffs() == 0)) +#endif + ) + { + char buf[RX_BUFF_SIZE]; + struct sockaddr from; + + fromlen = sizeof from; + (void) recvfrom(fd, buf, sizeof(buf), 0, &from, &fromlen); +#ifdef DEBUG + if (debug) + printf("%s on %d(%lu) fd=%d from %s\n", + (i) ? "drop" : "ignore", + i, free_recvbuffs(), fd, + inet_ntoa(((struct sockaddr_in *) &from)->sin_addr)); +#endif + if (i == 0) + packets_ignored++; + else + packets_dropped++; + goto select_again; + } + + rb = get_free_recv_buffer(); + + fromlen = sizeof(struct sockaddr_in); + rb->recv_length = recvfrom(fd, + (char *)&rb->recv_space, + sizeof(rb->recv_space), 0, + (struct sockaddr *)&rb->recv_srcadr, + &fromlen); + if (rb->recv_length == 0 +#ifdef EWOULDBLOCK + || errno==EWOULDBLOCK +#endif +#ifdef EAGAIN + || errno==EAGAIN +#endif + ) { + freerecvbuf(rb); + continue; + } + else if (rb->recv_length < 0) + { + msyslog(LOG_ERR, "recvfrom() fd=%d: %m", fd); +#ifdef DEBUG + if (debug) + printf("input_handler: fd=%d dropped (bad recvfrom)\n", fd); +#endif + freerecvbuf(rb); + continue; + } +#ifdef DEBUG + if (debug > 2) + printf("input_handler: fd=%d length %d from %08lx %s\n", + fd, rb->recv_length, + (u_long)ntohl(rb->recv_srcadr.sin_addr.s_addr) & + 0x00000000ffffffff, + inet_ntoa(rb->recv_srcadr.sin_addr)); +#endif + + /* + * Got one. Mark how and when it got here, + * put it on the full list and do bookkeeping. + */ + rb->dstadr = &inter_list[i]; + rb->fd = fd; + rb->recv_time = ts; + rb->receiver = receive; + + add_full_recv_buffer(rb); + + inter_list[i].received++; + packets_received++; + goto select_again; + } + /* Check more interfaces */ + } + } + select_again:; + /* + * Done everything from that select. Poll again. + */ + } + + /* + * If nothing more to do, try again. + * If nothing to do, just return. + * If an error occurred, complain and return. + */ + if (n == 0) + { + if (select_count == 0) /* We really had nothing to do */ + { + if (debug) + msyslog(LOG_DEBUG, "input_handler: select() returned 0"); + --handler_count; + return; + } + /* We've done our work */ + get_systime(&ts_e); + /* + * (ts_e - ts) is the amount of time we spent processing + * this gob of file descriptors. Log it. + */ + L_SUB(&ts_e, &ts); + if (debug > 3) + msyslog(LOG_INFO, "input_handler: Processed a gob of fd's in %s msec", lfptoms(&ts_e, 6)); + + /* just bail. */ + --handler_count; + return; + } + else if (n == -1) + { +#ifndef SYS_WINNT + int err = errno; +#else + DWORD err = WSAGetLastError(); +#endif /* SYS_WINNT */ + + /* + * extended FAU debugging output + */ + msyslog(LOG_ERR, "select(%d, %s, 0L, 0L, &0.000000) error: %m", + maxactivefd+1, fdbits(maxactivefd, &activefds)); + if ( +#ifndef SYS_WINNT + (err == EBADF) +#else + (err == WSAEBADF) +#endif /* SYS_WINNT */ + ) + { + int j, b; + + fds = activefds; + for (j = 0; j <= maxactivefd; j++) + if ( +#ifndef SYS_WINNT + (FD_ISSET(j, &fds) && (read(j, &b, 0) == -1)) +#else + (FD_ISSET(j, &fds) && (!ReadFile((HANDLE)j, &b, 0, NULL, NULL))) +#endif /* SYS_WINNT */ + ) + msyslog(LOG_ERR, "Bad file descriptor %d", j); + } + --handler_count; + return; + } + } + msyslog(LOG_ERR, "input_handler: fell out of infinite for(;;) loop!"); + --handler_count; + return; +} + +#endif + +/* + * findinterface - utility used by other modules to find an interface + * given an address. + */ +struct interface * +findinterface( + struct sockaddr_in *addr + ) +{ + register int i; + register u_int32 saddr; + + /* + * Just match the address portion. + */ + saddr = addr->sin_addr.s_addr; + for (i = 0; i < ninterfaces; i++) + { + if (inter_list[i].sin.sin_addr.s_addr == saddr) + return &inter_list[i]; + } + return (struct interface *)0; +} + + +/* + * io_clr_stats - clear I/O module statistics + */ +void +io_clr_stats(void) +{ + packets_dropped = 0; + packets_ignored = 0; + packets_received = 0; + packets_sent = 0; + packets_notsent = 0; + + handler_calls = 0; + handler_pkts = 0; + io_timereset = current_time; +} + + +#ifdef REFCLOCK +/* + * This is a hack so that I don't have to fool with these ioctls in the + * pps driver ... we are already non-blocking and turn on SIGIO thru + * another mechanisim + */ +int +io_addclock_simple( + struct refclockio *rio + ) +{ + BLOCKIO(); + /* + * Stuff the I/O structure in the list and mark the descriptor + * in use. There is a harmless (I hope) race condition here. + */ + rio->next = refio; + refio = rio; + + if (rio->fd > maxactivefd) + maxactivefd = rio->fd; + FD_SET(rio->fd, &activefds); + UNBLOCKIO(); + return 1; +} + +/* + * io_addclock - add a reference clock to the list and arrange that we + * get SIGIO interrupts from it. + */ +int +io_addclock( + struct refclockio *rio + ) +{ + BLOCKIO(); + /* + * Stuff the I/O structure in the list and mark the descriptor + * in use. There is a harmless (I hope) race condition here. + */ + rio->next = refio; + refio = rio; + +# ifdef HAVE_SIGNALED_IO + if (init_clock_sig(rio)) + { + refio = rio->next; + UNBLOCKIO(); + return 0; + } +# elif defined(HAVE_IO_COMPLETION_PORT) + if (io_completion_port_add_clock_io(rio)) + { + refio = rio->next; + UNBLOCKIO(); + return 0; + } +# endif + + if (rio->fd > maxactivefd) + maxactivefd = rio->fd; + FD_SET(rio->fd, &activefds); + + UNBLOCKIO(); + return 1; +} + +/* + * io_closeclock - close the clock in the I/O structure given + */ +void +io_closeclock( + struct refclockio *rio + ) +{ + /* + * Remove structure from the list + */ + if (refio == rio) + { + refio = rio->next; + } + else + { + register struct refclockio *rp; + + for (rp = refio; rp != 0; rp = rp->next) + if (rp->next == rio) + { + rp->next = rio->next; + break; + } + + if (rp == 0) + { + /* + * Internal error. Report it. + */ + msyslog(LOG_ERR, + "internal error: refclockio structure not found"); + return; + } + } + + /* + * Close the descriptor. + */ + close_file(rio->fd); +} +#endif /* REFCLOCK */ + +void +kill_asyncio(void) +{ + int i; + + BLOCKIO(); + for (i = 0; i <= maxactivefd; i++) + (void)close_socket(i); +} |