}
#if 0
-/*
- * open_socket - open a socket, returning the file descriptor
- */
+
+/* The following subroutines should probably be moved here */
static SOCKET
open_socket(
int turn_off_reuse,
endpt * interf
)
-{
- SOCKET fd;
- int errval;
- char scopetext[16];
- /*
- * int is OK for REUSEADR per
- * http://www.kohala.com/start/mcast.api.txt
- */
- int on = 1;
- int off = 0;
-
- if (IS_IPV6(addr) && !ipv6_works)
- return INVALID_SOCKET;
-
- /* create a datagram (UDP) socket */
- fd = socket(AF(addr), SOCK_DGRAM, 0);
- if (INVALID_SOCKET == fd) {
- errval = socket_errno();
- msyslog(LOG_ERR,
- "socket(AF_INET%s, SOCK_DGRAM, 0) failed on address %s: %m",
- IS_IPV6(addr) ? "6" : "", stoa(addr));
-
- if (errval == EPROTONOSUPPORT ||
- errval == EAFNOSUPPORT ||
- errval == EPFNOSUPPORT)
- return (INVALID_SOCKET);
-
- errno = errval;
- msyslog(LOG_ERR,
- "unexpected socket() error %m code %d (not EPROTONOSUPPORT nor EAFNOSUPPORT nor EPFNOSUPPORT) - exiting",
- errno);
- exit(1);
- }
-
-#ifdef SYS_WINNT
- connection_reset_fix(fd, addr);
-#endif
- /*
- * Fixup the file descriptor for some systems
- * See bug #530 for details of the issue.
- */
- fd = move_fd(fd);
-
- /*
- * set SO_REUSEADDR since we will be binding the same port
- * number on each interface according to turn_off_reuse.
- * This is undesirable on Windows versions starting with
- * Windows XP (numeric version 5.1).
- */
-#ifdef SYS_WINNT
- if (isc_win32os_versioncheck(5, 1, 0, 0) < 0) /* before 5.1 */
-#endif
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
- (char *)((turn_off_reuse)
- ? &off
- : &on),
- sizeof(on))) {
-
- msyslog(LOG_ERR,
- "setsockopt SO_REUSEADDR %s fails for address %s: %m",
- (turn_off_reuse)
- ? "off"
- : "on",
- stoa(addr));
- closesocket(fd);
- return INVALID_SOCKET;
- }
-#ifdef SO_EXCLUSIVEADDRUSE
- /*
- * setting SO_EXCLUSIVEADDRUSE on the wildcard we open
- * first will cause more specific binds to fail.
- */
- if (!(interf->flags & INT_WILDCARD))
- set_excladdruse(fd);
-#endif
-
- /*
- * IPv4 specific options go here
- */
- if (IS_IPV4(addr)) {
-#if defined(HAVE_IPTOS_SUPPORT)
- if (setsockopt(fd, IPPROTO_IP, IP_TOS, (char *)&qos,
- sizeof(qos)))
- msyslog(LOG_ERR,
- "setsockopt IP_TOS (%02x) fails on address %s: %m",
- qos, stoa(addr));
-#endif /* HAVE_IPTOS_SUPPORT */
- if (bcast)
- socket_broadcast_enable(interf, fd, addr);
- }
-
- /*
- * IPv6 specific options go here
- */
- if (IS_IPV6(addr)) {
-#ifdef IPV6_V6ONLY
- if (isc_net_probe_ipv6only() == ISC_R_SUCCESS
- && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
- (char*)&on, sizeof(on)))
- msyslog(LOG_ERR,
- "setsockopt IPV6_V6ONLY on fails on address %s: %m",
- stoa(addr));
-#endif
-#ifdef IPV6_BINDV6ONLY
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_BINDV6ONLY,
- (char*)&on, sizeof(on)))
- msyslog(LOG_ERR,
- "setsockopt IPV6_BINDV6ONLY on fails on address %s: %m",
- stoa(addr));
-#endif
- }
-
-#ifdef OS_NEEDS_REUSEADDR_FOR_IFADDRBIND
- /*
- * some OSes don't allow binding to more specific
- * addresses if a wildcard address already bound
- * to the port and SO_REUSEADDR is not set
- */
- if (!is_wildcard_addr(addr))
- set_wildcard_reuse(AF(addr), 1);
-#endif
-
- /*
- * bind the local address.
- */
- errval = bind(fd, &addr->sa, SOCKLEN(addr));
-
-#ifdef OS_NEEDS_REUSEADDR_FOR_IFADDRBIND
- if (!is_wildcard_addr(addr))
- set_wildcard_reuse(AF(addr), 0);
-#endif
-
- if (errval < 0) {
- /*
- * Don't log this under all conditions
- */
- if (turn_off_reuse == 0
-#ifdef DEBUG
- || debug > 1
-#endif
- ) {
- if (SCOPE(addr))
- snprintf(scopetext, sizeof(scopetext),
- "%%%d", SCOPE(addr));
- else
- scopetext[0] = 0;
-
- msyslog(LOG_ERR,
- "bind(%d) AF_INET%s %s%s#%d%s flags 0x%x failed: %m",
- fd, IS_IPV6(addr) ? "6" : "",
- stoa(addr), scopetext, SRCPORT(addr),
- IS_MCAST(addr) ? " (multicast)" : "",
- interf->flags);
- }
-
- closesocket(fd);
-
- return INVALID_SOCKET;
- }
-
-#ifdef HAVE_TIMESTAMP
- {
- if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMP,
- (char*)&on, sizeof(on)))
- msyslog(LOG_DEBUG,
- "setsockopt SO_TIMESTAMP on fails on address %s: %m",
- stoa(addr));
- else
- TRACE(4, ("setsockopt SO_TIMESTAMP enabled on fd %d address %s\n",
- fd, stoa(addr)));
- }
-#endif
- TRACE(4, ("bind(%d) AF_INET%s, addr %s%%%d#%d, flags 0x%x\n",
- fd, IS_IPV6(addr) ? "6" : "", stoa(addr),
- SCOPE(addr), SRCPORT(addr), interf->flags));
-
- init_nonblocking_io(fd);
-
-#ifdef HAVE_SIGNALED_IO
- init_socket_sig(fd);
-#endif /* not HAVE_SIGNALED_IO */
-
- add_fd_to_list(fd, FD_TYPE_SOCKET);
-
-#if !defined(SYS_WINNT) && !defined(VMS)
- TRACE(4, ("flags for fd %d: 0x%x\n", fd,
- fcntl(fd, F_GETFL, 0)));
-#endif /* SYS_WINNT || VMS */
-
-#if defined (HAVE_IO_COMPLETION_PORT)
-/*
- * Add the socket to the completion port
- */
- if (io_completion_port_add_socket(fd, interf)) {
- msyslog(LOG_ERR, "unable to set up io completion port - EXITING");
- exit(1);
- }
-#endif
- return fd;
-}
-
-
-#ifdef SYS_WINNT
-#define sendto(fd, buf, len, flags, dest, destsz) \
- io_completion_port_sendto(fd, buf, len, (sockaddr_u *)(dest))
-#endif
-
-/* 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(
sockaddr_u * dest,
struct pkt * pkt,
int len
)
-{
- endpt * src;
- int ismcast;
- int cc;
- int rc;
- u_char cttl;
-
- ismcast = IS_MCAST(dest);
- if (!ismcast)
- src = ep;
- else
- src = (IS_IPV4(dest))
- ? mc4_list
- : mc6_list;
-
- if (NULL == src) {
- /*
- * unbound peer - drop request and wait for better
- * network conditions
- */
- TRACE(2, ("%ssendpkt(dst=%s, ttl=%d, len=%d): no interface - IGNORED\n",
- ismcast ? "\tMCAST\t***** " : "",
- stoa(dest), ttl, len));
- return;
- }
-
- do {
- TRACE(2, ("%ssendpkt(%d, dst=%s, src=%s, ttl=%d, len=%d)\n",
- ismcast ? "\tMCAST\t***** " : "", src->fd,
- stoa(dest), stoa(&src->sin), ttl, len));
-#ifdef MCAST
- /*
- * for the moment we use the bcast option to set multicast ttl
- */
- if (ismcast && ttl > 0 && ttl != src->last_ttl) {
- /*
- * set the multicast ttl for outgoing packets
- */
- switch (AF(&src->sin)) {
-
- case AF_INET :
- cttl = (u_char)ttl;
- rc = setsockopt(src->fd, IPPROTO_IP,
- IP_MULTICAST_TTL,
- (void *)&cttl,
- sizeof(cttl));
- break;
-
-# ifdef INCLUDE_IPV6_SUPPORT
- case AF_INET6 :
- rc = setsockopt(src->fd, IPPROTO_IPV6,
- IPV6_MULTICAST_HOPS,
- (void *)&ttl,
- sizeof(ttl));
- break;
-# endif /* INCLUDE_IPV6_SUPPORT */
-
- default:
- rc = 0;
- }
-
- if (!rc)
- src->last_ttl = ttl;
- else
- msyslog(LOG_ERR,
- "setsockopt IP_MULTICAST_TTL/IPV6_MULTICAST_HOPS fails on address %s: %m",
- stoa(&src->sin));
- }
-#endif /* MCAST */
-
-#ifdef SIM
- cc = simulate_server(dest, src, pkt);
-#else
- cc = sendto(src->fd, (char *)pkt, (u_int)len, 0,
- &dest->sa, SOCKLEN(dest));
-#endif
- if (cc == -1) {
- src->notsent++;
- packets_notsent++;
- } else {
- src->sent++;
- packets_sent++;
- }
- if (ismcast)
- src = src->mclink;
- } while (ismcast && src != NULL);
-}
-/*
- * Routine to read the refclock packets for a specific interface
- * Return the number of bytes read. That way we know if we should
- * read it again or go on to the next one if no bytes returned
- */
static inline int
read_refclock_packet(SOCKET fd, struct refclockio *rp, l_fp ts)
-{
- int i;
- int buflen;
- register struct recvbuf *rb;
-
- rb = get_free_recv_buffer();
-
- if (NULL == rb) {
- /*
- * No buffer space available - just drop the packet
- */
- char buf[RX_BUFF_SIZE];
-
- buflen = read(fd, buf, sizeof buf);
- packets_dropped++;
- return (buflen);
- }
-
- i = (rp->datalen == 0
- || rp->datalen > sizeof(rb->recv_space))
- ? sizeof(rb->recv_space)
- : rp->datalen;
- buflen = read(fd, (char *)&rb->recv_space, (unsigned)i);
-
- if (buflen < 0) {
- if (errno != EINTR && errno != EAGAIN)
- msyslog(LOG_ERR, "clock read fd %d: %m", fd);
- freerecvbuf(rb);
- return (buflen);
- }
-
- /*
- * Got one. Mark how and when it got here,
- * put it on the full list and do bookkeeping.
- */
- rb->recv_length = buflen;
- 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);
- return (buflen);
- }
- }
-
- add_full_recv_buffer(rb);
-
- rp->recvcount++;
- packets_received++;
- return (buflen);
-}
-
-/*
- * Routine to read the network NTP packets for a specific interface
- * Return the number of bytes read. That way we know if we should
- * read it again or go on to the next one if no bytes returned
- */
static inline int
read_network_packet(
SOCKET fd,
struct interface * itf,
l_fp ts
)
-{
- GETSOCKNAME_SOCKLEN_TYPE fromlen;
- int buflen;
- register struct recvbuf *rb;
-#ifdef HAVE_TIMESTAMP
- struct msghdr msghdr;
- struct iovec iovec;
- char control[TIMESTAMP_CTLMSGBUF_SIZE];
-#endif
-
- /*
- * Get a buffer and read the frame. If we
- * haven't got a buffer, or this is received
- * on a disallowed socket, just dump the
- * packet.
- */
-
- rb = get_free_recv_buffer();
- if (NULL == rb || itf->ignore_packets) {
- char buf[RX_BUFF_SIZE];
- sockaddr_u from;
-
- if (rb != NULL)
- freerecvbuf(rb);
-
- fromlen = sizeof(from);
- buflen = recvfrom(fd, buf, sizeof(buf), 0,
- &from.sa, &fromlen);
- TRACE(4, ("%s on (%lu) fd=%d from %s\n",
- (itf->ignore_packets)
- ? "ignore"
- : "drop",
- free_recvbuffs(), fd, stoa(&from)));
- if (itf->ignore_packets)
- packets_ignored++;
- else
- packets_dropped++;
- return (buflen);
- }
-
- fromlen = sizeof(rb->recv_srcadr);
-
-#ifndef HAVE_TIMESTAMP
- rb->recv_length = recvfrom(fd, (char *)&rb->recv_space,
- sizeof(rb->recv_space), 0,
- &rb->recv_srcadr.sa, &fromlen);
-#else
- iovec.iov_base = &rb->recv_space;
- iovec.iov_len = sizeof(rb->recv_space);
- msghdr.msg_name = &rb->recv_srcadr;
- msghdr.msg_namelen = fromlen;
- msghdr.msg_iov = &iovec;
- msghdr.msg_iovlen = 1;
- msghdr.msg_control = (void *)&control;
- msghdr.msg_controllen = sizeof(control);
- msghdr.msg_flags = 0;
- rb->recv_length = recvmsg(fd, &msghdr, 0);
-#endif
-
- buflen = rb->recv_length;
-
- if (buflen == 0 || (buflen == -1 &&
- (EWOULDBLOCK == errno
-#ifdef EAGAIN
- || EAGAIN == errno
-#endif
- ))) {
- freerecvbuf(rb);
- return (buflen);
- } else if (buflen < 0) {
- msyslog(LOG_ERR, "recvfrom(%s) fd=%d: %m",
- stoa(&rb->recv_srcadr), fd);
- TRACE(5, ("read_network_packet: fd=%d dropped (bad recvfrom)\n",
- fd));
- freerecvbuf(rb);
- return (buflen);
- }
- TRACE(3, ("read_network_packet: fd=%d length %d from %s\n",
- fd, buflen, stoa(&rb->recv_srcadr)));
-
- /*
- * Got one. Mark how and when it got here,
- * put it on the full list and do bookkeeping.
- */
- rb->dstadr = itf;
- rb->fd = fd;
-#ifdef HAVE_TIMESTAMP
- /* pick up a network time stamp if possible */
- ts = fetch_timestamp(rb, &msghdr, ts);
-#endif
- rb->recv_time = ts;
- rb->receiver = receive;
-
- add_full_recv_buffer(rb);
-
- itf->received++;
- packets_received++;
- return (buflen);
-}
-
-
-/*
- * On NT a SOCKET is an unsigned int so we cannot possibly keep it in
- * an array. So we use one of the ISC_LIST functions to hold the
- * socket value and use that when we want to enumerate it.
- *
- * This routine is called by the forked intres child process to close
- * all open sockets. On Windows there's no need as intres runs in
- * the same process as a thread.
- */
-#ifndef SYS_WINNT
void
kill_asyncio(int startfd)
-{
- BLOCKIO();
-
- /*
- * In the child process we do not maintain activefds and
- * maxactivefd. Zeroing maxactivefd disables code which
- * maintains it in close_and_delete_fd_from_list().
- */
- maxactivefd = 0;
-
- while (fd_list != NULL)
- close_and_delete_fd_from_list(fd_list->fd);
-
- UNBLOCKIO();
-}
-#endif /* !SYS_WINNT */
#endif /* 0 */