2 * socket.c - low-level socket operations
14 #include "ntp_debug.h"
17 * Windows C runtime ioctl() can't deal properly with sockets,
18 * map to ioctlsocket for this source file.
21 #define ioctl(fd, opt, val) ioctlsocket(fd, opt, (u_long *)(val))
25 * on Unix systems the stdio library typically
26 * makes use of file descriptors in the lower
27 * integer range. stdio usually will make use
28 * of the file descriptors in the range of
30 * in order to keep this range clean, for socket
31 * file descriptors we attempt to move them above
32 * FOPEN_MAX. This is not as easy as it sounds as
33 * FOPEN_MAX changes from implementation to implementation
34 * and may exceed to current file decriptor limits.
35 * We are using following strategy:
36 * - keep a current socket fd boundary initialized with
37 * max(0, min(GETDTABLESIZE() - FD_CHUNK, FOPEN_MAX))
38 * - attempt to move the descriptor to the boundary or
40 * - if that fails and boundary > 0 set boundary
41 * to min(0, socket_fd_boundary - FD_CHUNK)
43 * if failure and boundary == 0 return old fd
44 * - on success close old fd return new fd
47 * - fds will be moved above the socket fd boundary
49 * - the socket boundary will be reduced until
50 * allocation is possible or 0 is reached - at this
51 * point the algrithm will be disabled
58 #if !defined(SYS_WINNT) && defined(F_DUPFD)
66 * number of fds we would like to have for
67 * stdio FILE* available.
68 * we can pick a "low" number as our use of
69 * FILE* is limited to log files and temporarily
70 * to data and config files. Except for log files
71 * we don't keep the other FILE* open beyond the
72 * scope of the function that opened it.
74 #ifndef FD_PREFERRED_SOCKBOUNDARY
75 #define FD_PREFERRED_SOCKBOUNDARY 48
78 static SOCKET socket_boundary = -1;
81 REQUIRE((int)fd >= 0);
84 * check whether boundary has be set up
87 if (socket_boundary == -1) {
88 socket_boundary = max(0, min(GETDTABLESIZE() - FD_CHUNK,
89 min(FOPEN_MAX, FD_PREFERRED_SOCKBOUNDARY)));
90 TRACE(1, ("move_fd: estimated max descriptors: %d, "
91 "initial socket boundary: %d\n",
92 GETDTABLESIZE(), socket_boundary));
96 * Leave a space for stdio to work in. potentially moving the
97 * socket_boundary lower until allocation succeeds.
100 if (fd >= 0 && fd < socket_boundary) {
101 /* inside reserved range: attempt to move fd */
102 newfd = fcntl(fd, F_DUPFD, socket_boundary);
105 /* success: drop the old one - return the new one */
110 /* outside reserved range: no work - return the original one */
113 socket_boundary = max(0, socket_boundary - FD_CHUNK);
114 TRACE(1, ("move_fd: selecting new socket boundary: %d\n",
116 } while (socket_boundary > 0);
118 ENSURE((int)fd >= 0);
119 #endif /* !defined(SYS_WINNT) && defined(F_DUPFD) */
125 * make_socket_nonblocking() - set up descriptor to be non blocking
128 make_socket_nonblocking(
137 /* in vxWorks we use FIONBIO, but the others are defined for old
138 * systems, so all hell breaks loose if we leave them defined
145 #if defined(O_NONBLOCK) /* POSIX */
146 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
148 "fcntl(O_NONBLOCK) fails on fd #%d: %m", fd);
151 #elif defined(FNDELAY)
152 if (fcntl(fd, F_SETFL, FNDELAY) < 0) {
153 msyslog(LOG_ERR, "fcntl(FNDELAY) fails on fd #%d: %m",
157 #elif defined(O_NDELAY) /* generally the same as FNDELAY */
158 if (fcntl(fd, F_SETFL, O_NDELAY) < 0) {
159 msyslog(LOG_ERR, "fcntl(O_NDELAY) fails on fd #%d: %m",
163 #elif defined(FIONBIO)
167 if (ioctl(fd, FIONBIO, &on) < 0) {
169 "ioctl(FIONBIO) fails on fd #%d: %m",
174 #elif defined(FIOSNBIO)
175 if (ioctl(fd, FIOSNBIO, &on) < 0) {
177 "ioctl(FIOSNBIO) fails on fd #%d: %m", fd);
181 # include "Bletch: Need non-blocking I/O!"
187 /* The following subroutines should probably be moved here */
199 struct interface * ep,
206 read_refclock_packet(SOCKET fd, struct refclockio *rp, l_fp ts)
211 struct interface * itf,
216 kill_asyncio(int startfd)