12b15cb3dSCy Schubert /*
22b15cb3dSCy Schubert * socket.c - low-level socket operations
32b15cb3dSCy Schubert */
42b15cb3dSCy Schubert
52b15cb3dSCy Schubert #ifdef HAVE_CONFIG_H
62b15cb3dSCy Schubert # include <config.h>
72b15cb3dSCy Schubert #endif
82b15cb3dSCy Schubert
92b15cb3dSCy Schubert #include <stdio.h>
102b15cb3dSCy Schubert
112b15cb3dSCy Schubert #include "ntp.h"
122b15cb3dSCy Schubert #include "ntp_io.h"
132b15cb3dSCy Schubert #include "ntp_net.h"
142b15cb3dSCy Schubert #include "ntp_debug.h"
152b15cb3dSCy Schubert
162b15cb3dSCy Schubert /*
172b15cb3dSCy Schubert * Windows C runtime ioctl() can't deal properly with sockets,
182b15cb3dSCy Schubert * map to ioctlsocket for this source file.
192b15cb3dSCy Schubert */
202b15cb3dSCy Schubert #ifdef SYS_WINNT
212b15cb3dSCy Schubert #define ioctl(fd, opt, val) ioctlsocket(fd, opt, (u_long *)(val))
222b15cb3dSCy Schubert #endif
232b15cb3dSCy Schubert
242b15cb3dSCy Schubert /*
252b15cb3dSCy Schubert * on Unix systems the stdio library typically
262b15cb3dSCy Schubert * makes use of file descriptors in the lower
272b15cb3dSCy Schubert * integer range. stdio usually will make use
282b15cb3dSCy Schubert * of the file descriptors in the range of
292b15cb3dSCy Schubert * [0..FOPEN_MAX)
302b15cb3dSCy Schubert * in order to keep this range clean, for socket
312b15cb3dSCy Schubert * file descriptors we attempt to move them above
322b15cb3dSCy Schubert * FOPEN_MAX. This is not as easy as it sounds as
332b15cb3dSCy Schubert * FOPEN_MAX changes from implementation to implementation
342b15cb3dSCy Schubert * and may exceed to current file decriptor limits.
352b15cb3dSCy Schubert * We are using following strategy:
362b15cb3dSCy Schubert * - keep a current socket fd boundary initialized with
372b15cb3dSCy Schubert * max(0, min(GETDTABLESIZE() - FD_CHUNK, FOPEN_MAX))
382b15cb3dSCy Schubert * - attempt to move the descriptor to the boundary or
392b15cb3dSCy Schubert * above.
402b15cb3dSCy Schubert * - if that fails and boundary > 0 set boundary
412b15cb3dSCy Schubert * to min(0, socket_fd_boundary - FD_CHUNK)
422b15cb3dSCy Schubert * -> retry
432b15cb3dSCy Schubert * if failure and boundary == 0 return old fd
442b15cb3dSCy Schubert * - on success close old fd return new fd
452b15cb3dSCy Schubert *
462b15cb3dSCy Schubert * effects:
472b15cb3dSCy Schubert * - fds will be moved above the socket fd boundary
482b15cb3dSCy Schubert * if at all possible.
492b15cb3dSCy Schubert * - the socket boundary will be reduced until
502b15cb3dSCy Schubert * allocation is possible or 0 is reached - at this
512b15cb3dSCy Schubert * point the algrithm will be disabled
522b15cb3dSCy Schubert */
532b15cb3dSCy Schubert SOCKET
move_fd(SOCKET fd)542b15cb3dSCy Schubert move_fd(
552b15cb3dSCy Schubert SOCKET fd
562b15cb3dSCy Schubert )
572b15cb3dSCy Schubert {
582b15cb3dSCy Schubert #if !defined(SYS_WINNT) && defined(F_DUPFD)
592b15cb3dSCy Schubert #ifndef FD_CHUNK
602b15cb3dSCy Schubert #define FD_CHUNK 10
612b15cb3dSCy Schubert #endif
622b15cb3dSCy Schubert #ifndef FOPEN_MAX
632b15cb3dSCy Schubert #define FOPEN_MAX 20
642b15cb3dSCy Schubert #endif
652b15cb3dSCy Schubert /*
662b15cb3dSCy Schubert * number of fds we would like to have for
672b15cb3dSCy Schubert * stdio FILE* available.
682b15cb3dSCy Schubert * we can pick a "low" number as our use of
692b15cb3dSCy Schubert * FILE* is limited to log files and temporarily
702b15cb3dSCy Schubert * to data and config files. Except for log files
712b15cb3dSCy Schubert * we don't keep the other FILE* open beyond the
722b15cb3dSCy Schubert * scope of the function that opened it.
732b15cb3dSCy Schubert */
742b15cb3dSCy Schubert #ifndef FD_PREFERRED_SOCKBOUNDARY
752b15cb3dSCy Schubert #define FD_PREFERRED_SOCKBOUNDARY 48
762b15cb3dSCy Schubert #endif
772b15cb3dSCy Schubert
782b15cb3dSCy Schubert static SOCKET socket_boundary = -1;
792b15cb3dSCy Schubert SOCKET newfd;
802b15cb3dSCy Schubert
819034852cSGleb Smirnoff REQUIRE((int)fd >= 0);
822b15cb3dSCy Schubert
832b15cb3dSCy Schubert /*
842b15cb3dSCy Schubert * check whether boundary has be set up
852b15cb3dSCy Schubert * already
862b15cb3dSCy Schubert */
872b15cb3dSCy Schubert if (socket_boundary == -1) {
882b15cb3dSCy Schubert socket_boundary = max(0, min(GETDTABLESIZE() - FD_CHUNK,
892b15cb3dSCy Schubert min(FOPEN_MAX, FD_PREFERRED_SOCKBOUNDARY)));
902b15cb3dSCy Schubert TRACE(1, ("move_fd: estimated max descriptors: %d, "
912b15cb3dSCy Schubert "initial socket boundary: %d\n",
922b15cb3dSCy Schubert GETDTABLESIZE(), socket_boundary));
932b15cb3dSCy Schubert }
942b15cb3dSCy Schubert
952b15cb3dSCy Schubert /*
962b15cb3dSCy Schubert * Leave a space for stdio to work in. potentially moving the
972b15cb3dSCy Schubert * socket_boundary lower until allocation succeeds.
982b15cb3dSCy Schubert */
992b15cb3dSCy Schubert do {
1002b15cb3dSCy Schubert if (fd >= 0 && fd < socket_boundary) {
1012b15cb3dSCy Schubert /* inside reserved range: attempt to move fd */
1022b15cb3dSCy Schubert newfd = fcntl(fd, F_DUPFD, socket_boundary);
1032b15cb3dSCy Schubert
1042b15cb3dSCy Schubert if (newfd != -1) {
1052b15cb3dSCy Schubert /* success: drop the old one - return the new one */
1062b15cb3dSCy Schubert close(fd);
1072b15cb3dSCy Schubert return newfd;
1082b15cb3dSCy Schubert }
1092b15cb3dSCy Schubert } else {
1102b15cb3dSCy Schubert /* outside reserved range: no work - return the original one */
1112b15cb3dSCy Schubert return fd;
1122b15cb3dSCy Schubert }
1132b15cb3dSCy Schubert socket_boundary = max(0, socket_boundary - FD_CHUNK);
1142b15cb3dSCy Schubert TRACE(1, ("move_fd: selecting new socket boundary: %d\n",
1152b15cb3dSCy Schubert socket_boundary));
1162b15cb3dSCy Schubert } while (socket_boundary > 0);
1172b15cb3dSCy Schubert #else
1189034852cSGleb Smirnoff ENSURE((int)fd >= 0);
1192b15cb3dSCy Schubert #endif /* !defined(SYS_WINNT) && defined(F_DUPFD) */
1202b15cb3dSCy Schubert return fd;
1212b15cb3dSCy Schubert }
1222b15cb3dSCy Schubert
1232b15cb3dSCy Schubert
1242b15cb3dSCy Schubert /*
1252b15cb3dSCy Schubert * make_socket_nonblocking() - set up descriptor to be non blocking
1262b15cb3dSCy Schubert */
1272b15cb3dSCy Schubert void
make_socket_nonblocking(SOCKET fd)1282b15cb3dSCy Schubert make_socket_nonblocking(
1292b15cb3dSCy Schubert SOCKET fd
1302b15cb3dSCy Schubert )
1312b15cb3dSCy Schubert {
1322b15cb3dSCy Schubert /*
1332b15cb3dSCy Schubert * set non-blocking,
1342b15cb3dSCy Schubert */
1352b15cb3dSCy Schubert
1362b15cb3dSCy Schubert #ifdef USE_FIONBIO
1372b15cb3dSCy Schubert /* in vxWorks we use FIONBIO, but the others are defined for old
1382b15cb3dSCy Schubert * systems, so all hell breaks loose if we leave them defined
1392b15cb3dSCy Schubert */
1402b15cb3dSCy Schubert #undef O_NONBLOCK
1412b15cb3dSCy Schubert #undef FNDELAY
1422b15cb3dSCy Schubert #undef O_NDELAY
1432b15cb3dSCy Schubert #endif
1442b15cb3dSCy Schubert
1452b15cb3dSCy Schubert #if defined(O_NONBLOCK) /* POSIX */
1462b15cb3dSCy Schubert if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
1472b15cb3dSCy Schubert msyslog(LOG_ERR,
1482b15cb3dSCy Schubert "fcntl(O_NONBLOCK) fails on fd #%d: %m", fd);
1492b15cb3dSCy Schubert exit(1);
1502b15cb3dSCy Schubert }
1512b15cb3dSCy Schubert #elif defined(FNDELAY)
1522b15cb3dSCy Schubert if (fcntl(fd, F_SETFL, FNDELAY) < 0) {
1532b15cb3dSCy Schubert msyslog(LOG_ERR, "fcntl(FNDELAY) fails on fd #%d: %m",
1542b15cb3dSCy Schubert fd);
1552b15cb3dSCy Schubert exit(1);
1562b15cb3dSCy Schubert }
1572b15cb3dSCy Schubert #elif defined(O_NDELAY) /* generally the same as FNDELAY */
1582b15cb3dSCy Schubert if (fcntl(fd, F_SETFL, O_NDELAY) < 0) {
1592b15cb3dSCy Schubert msyslog(LOG_ERR, "fcntl(O_NDELAY) fails on fd #%d: %m",
1602b15cb3dSCy Schubert fd);
1612b15cb3dSCy Schubert exit(1);
1622b15cb3dSCy Schubert }
1632b15cb3dSCy Schubert #elif defined(FIONBIO)
1642b15cb3dSCy Schubert {
1652b15cb3dSCy Schubert int on = 1;
1662b15cb3dSCy Schubert
1672b15cb3dSCy Schubert if (ioctl(fd, FIONBIO, &on) < 0) {
1682b15cb3dSCy Schubert msyslog(LOG_ERR,
1692b15cb3dSCy Schubert "ioctl(FIONBIO) fails on fd #%d: %m",
1702b15cb3dSCy Schubert fd);
1712b15cb3dSCy Schubert exit(1);
1722b15cb3dSCy Schubert }
1732b15cb3dSCy Schubert }
1742b15cb3dSCy Schubert #elif defined(FIOSNBIO)
1752b15cb3dSCy Schubert if (ioctl(fd, FIOSNBIO, &on) < 0) {
1762b15cb3dSCy Schubert msyslog(LOG_ERR,
1772b15cb3dSCy Schubert "ioctl(FIOSNBIO) fails on fd #%d: %m", fd);
1782b15cb3dSCy Schubert exit(1);
1792b15cb3dSCy Schubert }
1802b15cb3dSCy Schubert #else
1812b15cb3dSCy Schubert # include "Bletch: Need non-blocking I/O!"
1822b15cb3dSCy Schubert #endif
1832b15cb3dSCy Schubert }
1842b15cb3dSCy Schubert
1852b15cb3dSCy Schubert #if 0
1862b15cb3dSCy Schubert
1872b15cb3dSCy Schubert /* The following subroutines should probably be moved here */
1882b15cb3dSCy Schubert
1892b15cb3dSCy Schubert static SOCKET
1902b15cb3dSCy Schubert open_socket(
1912b15cb3dSCy Schubert sockaddr_u * addr,
1922b15cb3dSCy Schubert int bcast,
1932b15cb3dSCy Schubert int turn_off_reuse,
1942b15cb3dSCy Schubert endpt * interf
1952b15cb3dSCy Schubert )
1962b15cb3dSCy Schubert void
1972b15cb3dSCy Schubert sendpkt(
1982b15cb3dSCy Schubert sockaddr_u * dest,
199*f5f40dd6SCy Schubert endpt * ep,
2002b15cb3dSCy Schubert int ttl,
2012b15cb3dSCy Schubert struct pkt * pkt,
2022b15cb3dSCy Schubert int len
2032b15cb3dSCy Schubert )
2042b15cb3dSCy Schubert
2052b15cb3dSCy Schubert static inline int
2062b15cb3dSCy Schubert read_refclock_packet(SOCKET fd, struct refclockio *rp, l_fp ts)
2072b15cb3dSCy Schubert
2082b15cb3dSCy Schubert static inline int
2092b15cb3dSCy Schubert read_network_packet(
2102b15cb3dSCy Schubert SOCKET fd,
211*f5f40dd6SCy Schubert endpt * itf,
2122b15cb3dSCy Schubert l_fp ts
2132b15cb3dSCy Schubert )
2142b15cb3dSCy Schubert
2152b15cb3dSCy Schubert void
2162b15cb3dSCy Schubert kill_asyncio(int startfd)
2172b15cb3dSCy Schubert
2182b15cb3dSCy Schubert #endif /* 0 */
219