Home | History | Annotate | Line # | Download | only in libntp
      1 /*	$NetBSD: socket.c,v 1.7 2024/08/18 20:47:13 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  */
     55 SOCKET
     56 move_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  */
    129 void
    130 make_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 
    191 static SOCKET
    192 open_socket(
    193 	sockaddr_u *	addr,
    194 	int		bcast,
    195 	int		turn_off_reuse,
    196 	endpt *		interf
    197 	)
    198 void
    199 sendpkt(
    200 	sockaddr_u *	dest,
    201 	endpt *		ep,
    202 	int		ttl,
    203 	struct pkt *	pkt,
    204 	int		len
    205 	)
    206 
    207 static inline int
    208 read_refclock_packet(SOCKET fd, struct refclockio *rp, l_fp ts)
    209 
    210 static inline int
    211 read_network_packet(
    212 	SOCKET	fd,
    213 	endpt *	itf,
    214 	l_fp	ts
    215 	)
    216 
    217 void
    218 kill_asyncio(int startfd)
    219 
    220 #endif /* 0 */
    221