socket.c revision 290001
1/* 2 * socket.c - low-level socket operations 3 */ 4 5#ifdef HAVE_CONFIG_H 6# include <config.h> 7#endif 8 9#include <stdio.h> 10 11#include "ntp.h" 12#include "ntp_io.h" 13#include "ntp_net.h" 14#include "ntp_debug.h" 15 16/* 17 * Windows C runtime ioctl() can't deal properly with sockets, 18 * map to ioctlsocket for this source file. 19 */ 20#ifdef SYS_WINNT 21#define ioctl(fd, opt, val) ioctlsocket(fd, opt, (u_long *)(val)) 22#endif 23 24/* 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 29 * [0..FOPEN_MAX) 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 39 * above. 40 * - if that fails and boundary > 0 set boundary 41 * to min(0, socket_fd_boundary - FD_CHUNK) 42 * -> retry 43 * if failure and boundary == 0 return old fd 44 * - on success close old fd return new fd 45 * 46 * effects: 47 * - fds will be moved above the socket fd boundary 48 * if at all possible. 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 52 */ 53SOCKET 54move_fd( 55 SOCKET fd 56 ) 57{ 58#if !defined(SYS_WINNT) && defined(F_DUPFD) 59#ifndef FD_CHUNK 60#define FD_CHUNK 10 61#endif 62#ifndef FOPEN_MAX 63#define FOPEN_MAX 20 64#endif 65/* 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. 73 */ 74#ifndef FD_PREFERRED_SOCKBOUNDARY 75#define FD_PREFERRED_SOCKBOUNDARY 48 76#endif 77 78 static SOCKET socket_boundary = -1; 79 SOCKET newfd; 80 81 REQUIRE((int)fd >= 0); 82 83 /* 84 * check whether boundary has be set up 85 * already 86 */ 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)); 93 } 94 95 /* 96 * Leave a space for stdio to work in. potentially moving the 97 * socket_boundary lower until allocation succeeds. 98 */ 99 do { 100 if (fd >= 0 && fd < socket_boundary) { 101 /* inside reserved range: attempt to move fd */ 102 newfd = fcntl(fd, F_DUPFD, socket_boundary); 103 104 if (newfd != -1) { 105 /* success: drop the old one - return the new one */ 106 close(fd); 107 return newfd; 108 } 109 } else { 110 /* outside reserved range: no work - return the original one */ 111 return fd; 112 } 113 socket_boundary = max(0, socket_boundary - FD_CHUNK); 114 TRACE(1, ("move_fd: selecting new socket boundary: %d\n", 115 socket_boundary)); 116 } while (socket_boundary > 0); 117#else 118 ENSURE((int)fd >= 0); 119#endif /* !defined(SYS_WINNT) && defined(F_DUPFD) */ 120 return fd; 121} 122 123 124/* 125 * make_socket_nonblocking() - set up descriptor to be non blocking 126 */ 127void 128make_socket_nonblocking( 129 SOCKET fd 130 ) 131{ 132 /* 133 * set non-blocking, 134 */ 135 136#ifdef USE_FIONBIO 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 139 */ 140#undef O_NONBLOCK 141#undef FNDELAY 142#undef O_NDELAY 143#endif 144 145#if defined(O_NONBLOCK) /* POSIX */ 146 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { 147 msyslog(LOG_ERR, 148 "fcntl(O_NONBLOCK) fails on fd #%d: %m", fd); 149 exit(1); 150 } 151#elif defined(FNDELAY) 152 if (fcntl(fd, F_SETFL, FNDELAY) < 0) { 153 msyslog(LOG_ERR, "fcntl(FNDELAY) fails on fd #%d: %m", 154 fd); 155 exit(1); 156 } 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", 160 fd); 161 exit(1); 162 } 163#elif defined(FIONBIO) 164 { 165 int on = 1; 166 167 if (ioctl(fd, FIONBIO, &on) < 0) { 168 msyslog(LOG_ERR, 169 "ioctl(FIONBIO) fails on fd #%d: %m", 170 fd); 171 exit(1); 172 } 173 } 174#elif defined(FIOSNBIO) 175 if (ioctl(fd, FIOSNBIO, &on) < 0) { 176 msyslog(LOG_ERR, 177 "ioctl(FIOSNBIO) fails on fd #%d: %m", fd); 178 exit(1); 179 } 180#else 181# include "Bletch: Need non-blocking I/O!" 182#endif 183} 184 185#if 0 186 187/* The following subroutines should probably be moved here */ 188 189static SOCKET 190open_socket( 191 sockaddr_u * addr, 192 int bcast, 193 int turn_off_reuse, 194 endpt * interf 195 ) 196void 197sendpkt( 198 sockaddr_u * dest, 199 struct interface * ep, 200 int ttl, 201 struct pkt * pkt, 202 int len 203 ) 204 205static inline int 206read_refclock_packet(SOCKET fd, struct refclockio *rp, l_fp ts) 207 208static inline int 209read_network_packet( 210 SOCKET fd, 211 struct interface * itf, 212 l_fp ts 213 ) 214 215void 216kill_asyncio(int startfd) 217 218#endif /* 0 */ 219