#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
#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
# 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_select.h"
#include "ntp_io.h"
#include "iosignal.h"
#include "ntp_refclock.h"
#include "ntp_if.h"
#include "ntp_stdlib.h"
#if defined(VMS)
#include <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
#if defined(VMS) || defined(SYS_WINNT)
struct ifconf {
int ifc_len;
union {
caddr_t ifcu_buf;
struct ifreq *ifcu_req;
} ifc_ifcu;
};
#define ifc_buf ifc_ifcu.ifcu_buf
#define ifc_req ifc_ifcu.ifcu_req
#endif
#if defined(USE_TTY_SIGPOLL) || defined(USE_UDP_SIGPOLL)
# if defined(SYS_AIX) && defined(_IO)
# undef _IO
# endif
# include <stropts.h>
#endif
volatile u_long packets_dropped;
volatile u_long packets_ignored;
volatile u_long packets_received;
u_long packets_sent;
u_long packets_notsent;
volatile u_long handler_calls;
volatile u_long handler_pkts;
u_long io_timereset;
struct interface *any_interface;
struct interface *loopback_interface;
static struct interface inter_list[MAXINTERFACES];
static int ninterfaces;
#ifdef REFCLOCK
static struct refclockio *refio;
#endif
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 *));
void
init_io(void)
{
#ifdef SYS_WINNT
WORD wVersionRequested;
WSADATA wsaData;
init_transmitbuff();
#endif
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
BLOCKIO();
(void) create_sockets(htons(NTP_PORT));
UNBLOCKIO();
#ifdef DEBUG
if (debug)
printf("init_io: maxactivefd %d\n", maxactivefd);
#endif
}
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
# ifdef STREAMS_TLI
struct strioctl ioc;
# endif
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
#ifdef DEBUG
if (debug)
printf("create_sockets(%d)\n", ntohs( (u_short) port));
#endif
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 (ifa->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;
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
# 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
if (
(vs = socket(AF_INET, SOCK_DGRAM, 0))
# ifndef SYS_WINNT
< 0
# else
== INVALID_SOCKET
# endif
) {
msyslog(LOG_ERR, "create_sockets: socket(AF_INET, SOCK_DGRAM) failed: %m");
exit(1);
}
# endif
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
ifc.ifc_len = ioc.ic_len;
ifc.ifc_buf = buf;
# endif
# else
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
{
msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFCONF) failed: %m - exiting");
exit(1);
}
# endif
for(n = ifc.ifc_len, ifr = ifc.ifc_req; n > 0;
ifr = (struct ifreq *)((char *)ifr + size))
{
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)
if (strchr(ifr->ifr_name, (int)':') != NULL) {
continue;
}
if
# ifdef VMS
(((struct sockaddr *)&(ifr->ifr_addr))->sa_family != AF_INET)
# else
(ifr->ifr_addr.sa_family != AF_INET)
# endif
continue;
# endif
ifreq = *ifr;
inter_list[i].flags = 0;
# 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
if (ioctl(vs, SIOCGIFFLAGS, (char *)&ifreq) < 0)
{
if (errno != ENXIO)
msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFFLAGS) failed: %m");
continue;
}
# endif
if ((ifreq.ifr_flags & IFF_UP) == 0)
continue;
inter_list[i].flags = 0;
if (ifreq.ifr_flags & IFF_BROADCAST)
inter_list[i].flags |= INT_BROADCAST;
# endif
# if !defined(SUN_3_3_STINKS)
if (
# if defined(IFF_LOCAL_LOOPBACK)
(ifreq.ifr_flags & IFF_LOCAL_LOOPBACK)
# elif defined(IFF_LOOPBACK)
(ifreq.ifr_flags & IFF_LOOPBACK)
# else
(inter_list[i].sin.sin_addr.s_addr == inet_addr("127.0.0.1"))
# endif
)
{
# ifndef SYS_WINNT
inter_list[i].flags |= INT_LOOPBACK;
# endif
if (loopback_interface == 0)
{
loopback_interface = &inter_list[i];
}
}
# endif
#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
if (ioctl(vs, SIOCGIFADDR, (char *)&ifreq) < 0)
{
if (errno != ENXIO)
msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFADDR) failed: %m");
continue;
}
# endif
# endif
#endif
# 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)
if (SRCADR(&inter_list[i].sin) == 0x7f000001)
{
inter_list[i].flags |= INT_LOOPBACK;
if (loopback_interface == 0)
loopback_interface = &inter_list[i];
}
# endif
# if !defined SYS_WINNT && !defined SYS_CYGWIN32
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
if (ioctl(vs, SIOCGIFBRDADDR, (char *)&ifreq) < 0)
{
msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFBRDADDR) failed: %m");
exit(1);
}
# endif
# 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
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
if (ioctl(vs, SIOCGIFNETMASK, (char *)&ifreq) < 0)
{
msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFNETMASK) failed: %m");
exit(1);
}
# endif
inter_list[i].mask = *(struct sockaddr_in *)&ifreq.ifr_addr;
# else
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
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
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);
}
for (i = 0; i < ninterfaces; i++)
{
int off = 0;
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)
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
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);
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;
}
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
inter_list[i].bfd = open_socket(&inter_list[i].bcast, INT_BROADCAST, 1);
inter_list[i].flags |= INT_BCASTOPEN;
#endif
}
}
void
io_multicast_add(
u_int32 addr
)
{
#ifdef MCAST
struct ip_mreq mreq;
int i = ninterfaces;
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++)
{
if (inter_list[i].sin.sin_addr.s_addr == addr) return;
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);
if (s < 0)
{
memset((char *)&inter_list[i], 0, sizeof inter_list[0]);
i = 0;
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);
}
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
struct in_addr iaddr;
iaddr.s_addr = addr;
msyslog(LOG_ERR, "cannot add multicast address %s as no MCAST support",
inet_ntoa(iaddr));
#endif
}
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;
}
}
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;
}
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)
{
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
{
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");
inter_list[i].flags &= ~INT_MULTICAST;
}
}
#else
msyslog(LOG_ERR, "this function requires multicast kernel");
#endif
}
static int
open_socket(
struct sockaddr_in *addr,
int flags,
int turn_off_reuse
)
{
int fd;
int on = 1, off = 0;
if ( (fd = socket(AF_INET, SOCK_DGRAM, 0))
#ifndef SYS_WINNT
< 0
#else
== INVALID_SOCKET
#endif
)
{
msyslog(LOG_ERR, "socket(AF_INET, SOCK_DGRAM, 0) failed: %m");
exit(1);
}
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on)))
{
msyslog(LOG_ERR, "setsockopt SO_REUSEADDR on fails: %m");
}
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);
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);
#ifdef USE_FIONBIO
#undef O_NONBLOCK
#undef FNDELAY
#undef O_NDELAY
#endif
#if defined(O_NONBLOCK)
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
{
msyslog(LOG_ERR, "fcntl(O_NONBLOCK) fails: %m");
exit(1);
}
#elif defined(FNDELAY)
if (fcntl(fd, F_SETFL, FNDELAY) < 0)
{
msyslog(LOG_ERR, "fcntl(FNDELAY) fails: %m");
exit(1);
}
#elif defined(O_NDELAY)
if (fcntl(fd, F_SETFL, O_NDELAY) < 0)
{
msyslog(LOG_ERR, "fcntl(O_NDELAY) fails: %m");
exit(1);
}
#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);
}
#elif defined(FIOSNBIO)
if (ioctl(fd,FIOSNBIO,&on) < 0)
{
msyslog(LOG_ERR, "ioctl(FIOSNBIO) fails: %m");
exit(1);
}
#else
# include "Bletch: Need non-blocking I/O!"
#endif
#ifdef HAVE_SIGNALED_IO
init_socket_sig(fd);
#endif
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 (flags & INT_BROADCAST)
{
if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST,
(char *)&on, sizeof(on)))
{
msyslog(LOG_ERR, "setsockopt(SO_BROADCAST): %m");
}
}
#endif
#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
return fd;
}
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;
}
}
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;
}
}
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
return any_interface;
}
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
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)
#endif
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
if (ttl >= 0 && ttl != inter->last_ttl)
{
char mttl = ttl;
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
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
{
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++;
if (slot >= 0)
{
msyslog(LOG_INFO, "Connection re-established to %s", ntoa(dest));
badaddrs[slot].port = 0;
}
}
}
#if !defined(HAVE_IO_COMPLETION_PORT)
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;
}
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;
l_fp ts_e;
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 (;;)
{
fds = activefds;
tvzero.tv_sec = tvzero.tv_usec = 0;
while (0 < (n = select(maxactivefd+1, &fds, (fd_set *)0, (fd_set *)0, &tvzero)))
{
++select_count;
++handler_pkts;
#ifdef REFCLOCK
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
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
ReadFile((HANDLE)fd, (char *)&rb->recv_space, (DWORD)i,
(LPDWORD)&(rb->recv_length), NULL)
#endif
;
if (rb->recv_length == -1)
{
msyslog(LOG_ERR, "clock read fd %d: %m", fd);
freerecvbuf(rb);
goto select_again;
}
rb->recv_srcclock = rp->srcclock;
rb->dstadr = 0;
rb->fd = fd;
rb->recv_time = ts;
rb->receiver = rp->clock_recv;
if (rp->io_input)
{
if (rp->io_input(rb) == 0)
{
freerecvbuf(rb);
#if 1
goto select_again;
#else
continue;
#endif
}
}
add_full_recv_buffer(rb);
rp->recvcount++;
packets_received++;
}
}
}
#endif
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--;
if (
#ifdef UDP_WILDCARD_DELIVERY
(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
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;
}
}
}
select_again:;
}
if (n == 0)
{
if (select_count == 0)
{
if (debug)
msyslog(LOG_DEBUG, "input_handler: select() returned 0");
--handler_count;
return;
}
get_systime(&ts_e);
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));
--handler_count;
return;
}
else if (n == -1)
{
#ifndef SYS_WINNT
int err = errno;
#else
DWORD err = WSAGetLastError();
#endif
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
)
{
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
)
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
struct interface *
findinterface(
struct sockaddr_in *addr
)
{
register int i;
register u_int32 saddr;
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;
}
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
int
io_addclock_simple(
struct refclockio *rio
)
{
BLOCKIO();
rio->next = refio;
refio = rio;
if (rio->fd > maxactivefd)
maxactivefd = rio->fd;
FD_SET(rio->fd, &activefds);
UNBLOCKIO();
return 1;
}
int
io_addclock(
struct refclockio *rio
)
{
BLOCKIO();
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;
}
void
io_closeclock(
struct refclockio *rio
)
{
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)
{
msyslog(LOG_ERR,
"internal error: refclockio structure not found");
return;
}
}
close_file(rio->fd);
}
#endif
void
kill_asyncio(void)
{
int i;
BLOCKIO();
for (i = 0; i <= maxactivefd; i++)
(void)close_socket(i);
}