1/* $NetBSD: socket.c,v 1.6 2020/05/25 20:47:24 christos Exp $ */ 2 3/* 4 * socket.c - low-level socket operations 5 */ 6 7#ifdef HAVE_CONFIG_H 8# include <config.h> 9#endif 10 11#include <stdio.h> 12 13#include "ntp.h" 14#include "ntp_io.h" 15#include "ntp_net.h" 16#include "ntp_debug.h" 17 18/* 19 * Windows C runtime ioctl() can't deal properly with sockets, 20 * map to ioctlsocket for this source file. 21 */ 22#ifdef SYS_WINNT 23#define ioctl(fd, opt, val) ioctlsocket(fd, opt, (u_long *)(val)) 24#endif 25 26/* 27 * on Unix systems the stdio library typically 28 * makes use of file descriptors in the lower 29 * integer range. stdio usually will make use 30 * of the file descriptors in the range of 31 * [0..FOPEN_MAX) 32 * in order to keep this range clean, for socket 33 * file descriptors we attempt to move them above 34 * FOPEN_MAX. This is not as easy as it sounds as 35 * FOPEN_MAX changes from implementation to implementation 36 * and may exceed to current file decriptor limits. 37 * We are using following strategy: 38 * - keep a current socket fd boundary initialized with 39 * max(0, min(GETDTABLESIZE() - FD_CHUNK, FOPEN_MAX)) 40 * - attempt to move the descriptor to the boundary or 41 * above. 42 * - if that fails and boundary > 0 set boundary 43 * to min(0, socket_fd_boundary - FD_CHUNK) 44 * -> retry 45 * if failure and boundary == 0 return old fd 46 * - on success close old fd return new fd 47 * 48 * effects: 49 * - fds will be moved above the socket fd boundary 50 * if at all possible. 51 * - the socket boundary will be reduced until 52 * allocation is possible or 0 is reached - at this 53 * point the algrithm will be disabled 54 */ 55SOCKET 56move_fd( 57 SOCKET fd 58 ) 59{ 60#if !defined(SYS_WINNT) && defined(F_DUPFD) 61#ifndef FD_CHUNK 62#define FD_CHUNK 10 63#endif 64#ifndef FOPEN_MAX 65#define FOPEN_MAX 20 66#endif 67/* 68 * number of fds we would like to have for 69 * stdio FILE* available. 70 * we can pick a "low" number as our use of 71 * FILE* is limited to log files and temporarily 72 * to data and config files. Except for log files 73 * we don't keep the other FILE* open beyond the 74 * scope of the function that opened it. 75 */ 76#ifndef FD_PREFERRED_SOCKBOUNDARY 77#define FD_PREFERRED_SOCKBOUNDARY 48 78#endif 79 80 static SOCKET socket_boundary = -1; 81 SOCKET newfd; 82 83 REQUIRE((int)fd >= 0); 84 85 /* 86 * check whether boundary has be set up 87 * already 88 */ 89 if (socket_boundary == -1) { 90 socket_boundary = max(0, min(GETDTABLESIZE() - FD_CHUNK, 91 min(FOPEN_MAX, FD_PREFERRED_SOCKBOUNDARY))); 92 TRACE(1, ("move_fd: estimated max descriptors: %d, " 93 "initial socket boundary: %d\n", 94 GETDTABLESIZE(), socket_boundary)); 95 } 96 97 /* 98 * Leave a space for stdio to work in. potentially moving the 99 * socket_boundary lower until allocation succeeds. 100 */ 101 do { 102 if (fd >= 0 && fd < socket_boundary) { 103 /* inside reserved range: attempt to move fd */ 104 newfd = fcntl(fd, F_DUPFD, socket_boundary); 105 106 if (newfd != -1) { 107 /* success: drop the old one - return the new one */ 108 close(fd); 109 return newfd; 110 } 111 } else { 112 /* outside reserved range: no work - return the original one */ 113 return fd; 114 } 115 socket_boundary = max(0, socket_boundary - FD_CHUNK); 116 TRACE(1, ("move_fd: selecting new socket boundary: %d\n", 117 socket_boundary)); 118 } while (socket_boundary > 0); 119#else 120 ENSURE((int)fd >= 0); 121#endif /* !defined(SYS_WINNT) && defined(F_DUPFD) */ 122 return fd; 123} 124 125 126/* 127 * make_socket_nonblocking() - set up descriptor to be non blocking 128 */ 129void 130make_socket_nonblocking( 131 SOCKET fd 132 ) 133{ 134 /* 135 * set non-blocking, 136 */ 137 138#ifdef USE_FIONBIO 139 /* in vxWorks we use FIONBIO, but the others are defined for old 140 * systems, so all hell breaks loose if we leave them defined 141 */ 142#undef O_NONBLOCK 143#undef FNDELAY 144#undef O_NDELAY 145#endif 146 147#if defined(O_NONBLOCK) /* POSIX */ 148 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { 149 msyslog(LOG_ERR, 150 "fcntl(O_NONBLOCK) fails on fd #%d: %m", fd); 151 exit(1); 152 } 153#elif defined(FNDELAY) 154 if (fcntl(fd, F_SETFL, FNDELAY) < 0) { 155 msyslog(LOG_ERR, "fcntl(FNDELAY) fails on fd #%d: %m", 156 fd); 157 exit(1); 158 } 159#elif defined(O_NDELAY) /* generally the same as FNDELAY */ 160 if (fcntl(fd, F_SETFL, O_NDELAY) < 0) { 161 msyslog(LOG_ERR, "fcntl(O_NDELAY) fails on fd #%d: %m", 162 fd); 163 exit(1); 164 } 165#elif defined(FIONBIO) 166 { 167 int on = 1; 168 169 if (ioctl(fd, FIONBIO, &on) < 0) { 170 msyslog(LOG_ERR, 171 "ioctl(FIONBIO) fails on fd #%d: %m", 172 fd); 173 exit(1); 174 } 175 } 176#elif defined(FIOSNBIO) 177 if (ioctl(fd, FIOSNBIO, &on) < 0) { 178 msyslog(LOG_ERR, 179 "ioctl(FIOSNBIO) fails on fd #%d: %m", fd); 180 exit(1); 181 } 182#else 183# include "Bletch: Need non-blocking I/O!" 184#endif 185} 186 187#if 0 188 189/* The following subroutines should probably be moved here */ 190 191static SOCKET 192open_socket( 193 sockaddr_u * addr, 194 int bcast, 195 int turn_off_reuse, 196 endpt * interf 197 ) 198void 199sendpkt( 200 sockaddr_u * dest, 201 struct interface * ep, 202 int ttl, 203 struct pkt * pkt, 204 int len 205 ) 206 207static inline int 208read_refclock_packet(SOCKET fd, struct refclockio *rp, l_fp ts) 209 210static inline int 211read_network_packet( 212 SOCKET fd, 213 struct interface * itf, 214 l_fp ts 215 ) 216 217void 218kill_asyncio(int startfd) 219 220#endif /* 0 */ 221