1275970Scy/* 2275970Scy * socket.c - low-level socket operations 3275970Scy */ 4275970Scy 5275970Scy#ifdef HAVE_CONFIG_H 6275970Scy# include <config.h> 7275970Scy#endif 8275970Scy 9275970Scy#include <stdio.h> 10275970Scy 11275970Scy#include "ntp.h" 12275970Scy#include "ntp_io.h" 13275970Scy#include "ntp_net.h" 14275970Scy#include "ntp_debug.h" 15275970Scy 16275970Scy/* 17275970Scy * Windows C runtime ioctl() can't deal properly with sockets, 18275970Scy * map to ioctlsocket for this source file. 19275970Scy */ 20275970Scy#ifdef SYS_WINNT 21275970Scy#define ioctl(fd, opt, val) ioctlsocket(fd, opt, (u_long *)(val)) 22275970Scy#endif 23275970Scy 24275970Scy/* 25275970Scy * on Unix systems the stdio library typically 26275970Scy * makes use of file descriptors in the lower 27275970Scy * integer range. stdio usually will make use 28275970Scy * of the file descriptors in the range of 29275970Scy * [0..FOPEN_MAX) 30275970Scy * in order to keep this range clean, for socket 31275970Scy * file descriptors we attempt to move them above 32275970Scy * FOPEN_MAX. This is not as easy as it sounds as 33275970Scy * FOPEN_MAX changes from implementation to implementation 34275970Scy * and may exceed to current file decriptor limits. 35275970Scy * We are using following strategy: 36275970Scy * - keep a current socket fd boundary initialized with 37275970Scy * max(0, min(GETDTABLESIZE() - FD_CHUNK, FOPEN_MAX)) 38275970Scy * - attempt to move the descriptor to the boundary or 39275970Scy * above. 40275970Scy * - if that fails and boundary > 0 set boundary 41275970Scy * to min(0, socket_fd_boundary - FD_CHUNK) 42275970Scy * -> retry 43275970Scy * if failure and boundary == 0 return old fd 44275970Scy * - on success close old fd return new fd 45275970Scy * 46275970Scy * effects: 47275970Scy * - fds will be moved above the socket fd boundary 48275970Scy * if at all possible. 49275970Scy * - the socket boundary will be reduced until 50275970Scy * allocation is possible or 0 is reached - at this 51275970Scy * point the algrithm will be disabled 52275970Scy */ 53275970ScySOCKET 54275970Scymove_fd( 55275970Scy SOCKET fd 56275970Scy ) 57275970Scy{ 58275970Scy#if !defined(SYS_WINNT) && defined(F_DUPFD) 59275970Scy#ifndef FD_CHUNK 60275970Scy#define FD_CHUNK 10 61275970Scy#endif 62275970Scy#ifndef FOPEN_MAX 63275970Scy#define FOPEN_MAX 20 64275970Scy#endif 65275970Scy/* 66275970Scy * number of fds we would like to have for 67275970Scy * stdio FILE* available. 68275970Scy * we can pick a "low" number as our use of 69275970Scy * FILE* is limited to log files and temporarily 70275970Scy * to data and config files. Except for log files 71275970Scy * we don't keep the other FILE* open beyond the 72275970Scy * scope of the function that opened it. 73275970Scy */ 74275970Scy#ifndef FD_PREFERRED_SOCKBOUNDARY 75275970Scy#define FD_PREFERRED_SOCKBOUNDARY 48 76275970Scy#endif 77275970Scy 78275970Scy static SOCKET socket_boundary = -1; 79275970Scy SOCKET newfd; 80275970Scy 81289997Sglebius REQUIRE((int)fd >= 0); 82275970Scy 83275970Scy /* 84275970Scy * check whether boundary has be set up 85275970Scy * already 86275970Scy */ 87275970Scy if (socket_boundary == -1) { 88275970Scy socket_boundary = max(0, min(GETDTABLESIZE() - FD_CHUNK, 89275970Scy min(FOPEN_MAX, FD_PREFERRED_SOCKBOUNDARY))); 90275970Scy TRACE(1, ("move_fd: estimated max descriptors: %d, " 91275970Scy "initial socket boundary: %d\n", 92275970Scy GETDTABLESIZE(), socket_boundary)); 93275970Scy } 94275970Scy 95275970Scy /* 96275970Scy * Leave a space for stdio to work in. potentially moving the 97275970Scy * socket_boundary lower until allocation succeeds. 98275970Scy */ 99275970Scy do { 100275970Scy if (fd >= 0 && fd < socket_boundary) { 101275970Scy /* inside reserved range: attempt to move fd */ 102275970Scy newfd = fcntl(fd, F_DUPFD, socket_boundary); 103275970Scy 104275970Scy if (newfd != -1) { 105275970Scy /* success: drop the old one - return the new one */ 106275970Scy close(fd); 107275970Scy return newfd; 108275970Scy } 109275970Scy } else { 110275970Scy /* outside reserved range: no work - return the original one */ 111275970Scy return fd; 112275970Scy } 113275970Scy socket_boundary = max(0, socket_boundary - FD_CHUNK); 114275970Scy TRACE(1, ("move_fd: selecting new socket boundary: %d\n", 115275970Scy socket_boundary)); 116275970Scy } while (socket_boundary > 0); 117275970Scy#else 118289997Sglebius ENSURE((int)fd >= 0); 119275970Scy#endif /* !defined(SYS_WINNT) && defined(F_DUPFD) */ 120275970Scy return fd; 121275970Scy} 122275970Scy 123275970Scy 124275970Scy/* 125275970Scy * make_socket_nonblocking() - set up descriptor to be non blocking 126275970Scy */ 127275970Scyvoid 128275970Scymake_socket_nonblocking( 129275970Scy SOCKET fd 130275970Scy ) 131275970Scy{ 132275970Scy /* 133275970Scy * set non-blocking, 134275970Scy */ 135275970Scy 136275970Scy#ifdef USE_FIONBIO 137275970Scy /* in vxWorks we use FIONBIO, but the others are defined for old 138275970Scy * systems, so all hell breaks loose if we leave them defined 139275970Scy */ 140275970Scy#undef O_NONBLOCK 141275970Scy#undef FNDELAY 142275970Scy#undef O_NDELAY 143275970Scy#endif 144275970Scy 145275970Scy#if defined(O_NONBLOCK) /* POSIX */ 146275970Scy if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { 147275970Scy msyslog(LOG_ERR, 148275970Scy "fcntl(O_NONBLOCK) fails on fd #%d: %m", fd); 149275970Scy exit(1); 150275970Scy } 151275970Scy#elif defined(FNDELAY) 152275970Scy if (fcntl(fd, F_SETFL, FNDELAY) < 0) { 153275970Scy msyslog(LOG_ERR, "fcntl(FNDELAY) fails on fd #%d: %m", 154275970Scy fd); 155275970Scy exit(1); 156275970Scy } 157275970Scy#elif defined(O_NDELAY) /* generally the same as FNDELAY */ 158275970Scy if (fcntl(fd, F_SETFL, O_NDELAY) < 0) { 159275970Scy msyslog(LOG_ERR, "fcntl(O_NDELAY) fails on fd #%d: %m", 160275970Scy fd); 161275970Scy exit(1); 162275970Scy } 163275970Scy#elif defined(FIONBIO) 164275970Scy { 165275970Scy int on = 1; 166275970Scy 167275970Scy if (ioctl(fd, FIONBIO, &on) < 0) { 168275970Scy msyslog(LOG_ERR, 169275970Scy "ioctl(FIONBIO) fails on fd #%d: %m", 170275970Scy fd); 171275970Scy exit(1); 172275970Scy } 173275970Scy } 174275970Scy#elif defined(FIOSNBIO) 175275970Scy if (ioctl(fd, FIOSNBIO, &on) < 0) { 176275970Scy msyslog(LOG_ERR, 177275970Scy "ioctl(FIOSNBIO) fails on fd #%d: %m", fd); 178275970Scy exit(1); 179275970Scy } 180275970Scy#else 181275970Scy# include "Bletch: Need non-blocking I/O!" 182275970Scy#endif 183275970Scy} 184275970Scy 185275970Scy#if 0 186275970Scy 187275970Scy/* The following subroutines should probably be moved here */ 188275970Scy 189275970Scystatic SOCKET 190275970Scyopen_socket( 191275970Scy sockaddr_u * addr, 192275970Scy int bcast, 193275970Scy int turn_off_reuse, 194275970Scy endpt * interf 195275970Scy ) 196275970Scyvoid 197275970Scysendpkt( 198275970Scy sockaddr_u * dest, 199275970Scy struct interface * ep, 200275970Scy int ttl, 201275970Scy struct pkt * pkt, 202275970Scy int len 203275970Scy ) 204275970Scy 205275970Scystatic inline int 206275970Scyread_refclock_packet(SOCKET fd, struct refclockio *rp, l_fp ts) 207275970Scy 208275970Scystatic inline int 209275970Scyread_network_packet( 210275970Scy SOCKET fd, 211275970Scy struct interface * itf, 212275970Scy l_fp ts 213275970Scy ) 214275970Scy 215275970Scyvoid 216275970Scykill_asyncio(int startfd) 217275970Scy 218275970Scy#endif /* 0 */ 219