xref: /freebsd-src/contrib/ntp/libntp/socket.c (revision f5f40dd63bc7acbb5312b26ac1ea1103c12352a6)
12b15cb3dSCy Schubert /*
22b15cb3dSCy Schubert  * socket.c - low-level socket operations
32b15cb3dSCy Schubert  */
42b15cb3dSCy Schubert 
52b15cb3dSCy Schubert #ifdef HAVE_CONFIG_H
62b15cb3dSCy Schubert # include <config.h>
72b15cb3dSCy Schubert #endif
82b15cb3dSCy Schubert 
92b15cb3dSCy Schubert #include <stdio.h>
102b15cb3dSCy Schubert 
112b15cb3dSCy Schubert #include "ntp.h"
122b15cb3dSCy Schubert #include "ntp_io.h"
132b15cb3dSCy Schubert #include "ntp_net.h"
142b15cb3dSCy Schubert #include "ntp_debug.h"
152b15cb3dSCy Schubert 
162b15cb3dSCy Schubert /*
172b15cb3dSCy Schubert  * Windows C runtime ioctl() can't deal properly with sockets,
182b15cb3dSCy Schubert  * map to ioctlsocket for this source file.
192b15cb3dSCy Schubert  */
202b15cb3dSCy Schubert #ifdef SYS_WINNT
212b15cb3dSCy Schubert #define ioctl(fd, opt, val)  ioctlsocket(fd, opt, (u_long *)(val))
222b15cb3dSCy Schubert #endif
232b15cb3dSCy Schubert 
242b15cb3dSCy Schubert /*
252b15cb3dSCy Schubert  * on Unix systems the stdio library typically
262b15cb3dSCy Schubert  * makes use of file descriptors in the lower
272b15cb3dSCy Schubert  * integer range.  stdio usually will make use
282b15cb3dSCy Schubert  * of the file descriptors in the range of
292b15cb3dSCy Schubert  * [0..FOPEN_MAX)
302b15cb3dSCy Schubert  * in order to keep this range clean, for socket
312b15cb3dSCy Schubert  * file descriptors we attempt to move them above
322b15cb3dSCy Schubert  * FOPEN_MAX. This is not as easy as it sounds as
332b15cb3dSCy Schubert  * FOPEN_MAX changes from implementation to implementation
342b15cb3dSCy Schubert  * and may exceed to current file decriptor limits.
352b15cb3dSCy Schubert  * We are using following strategy:
362b15cb3dSCy Schubert  * - keep a current socket fd boundary initialized with
372b15cb3dSCy Schubert  *   max(0, min(GETDTABLESIZE() - FD_CHUNK, FOPEN_MAX))
382b15cb3dSCy Schubert  * - attempt to move the descriptor to the boundary or
392b15cb3dSCy Schubert  *   above.
402b15cb3dSCy Schubert  *   - if that fails and boundary > 0 set boundary
412b15cb3dSCy Schubert  *     to min(0, socket_fd_boundary - FD_CHUNK)
422b15cb3dSCy Schubert  *     -> retry
432b15cb3dSCy Schubert  *     if failure and boundary == 0 return old fd
442b15cb3dSCy Schubert  *   - on success close old fd return new fd
452b15cb3dSCy Schubert  *
462b15cb3dSCy Schubert  * effects:
472b15cb3dSCy Schubert  *   - fds will be moved above the socket fd boundary
482b15cb3dSCy Schubert  *     if at all possible.
492b15cb3dSCy Schubert  *   - the socket boundary will be reduced until
502b15cb3dSCy Schubert  *     allocation is possible or 0 is reached - at this
512b15cb3dSCy Schubert  *     point the algrithm will be disabled
522b15cb3dSCy Schubert  */
532b15cb3dSCy Schubert SOCKET
move_fd(SOCKET fd)542b15cb3dSCy Schubert move_fd(
552b15cb3dSCy Schubert 	SOCKET fd
562b15cb3dSCy Schubert 	)
572b15cb3dSCy Schubert {
582b15cb3dSCy Schubert #if !defined(SYS_WINNT) && defined(F_DUPFD)
592b15cb3dSCy Schubert #ifndef FD_CHUNK
602b15cb3dSCy Schubert #define FD_CHUNK	10
612b15cb3dSCy Schubert #endif
622b15cb3dSCy Schubert #ifndef FOPEN_MAX
632b15cb3dSCy Schubert #define FOPEN_MAX	20
642b15cb3dSCy Schubert #endif
652b15cb3dSCy Schubert /*
662b15cb3dSCy Schubert  * number of fds we would like to have for
672b15cb3dSCy Schubert  * stdio FILE* available.
682b15cb3dSCy Schubert  * we can pick a "low" number as our use of
692b15cb3dSCy Schubert  * FILE* is limited to log files and temporarily
702b15cb3dSCy Schubert  * to data and config files. Except for log files
712b15cb3dSCy Schubert  * we don't keep the other FILE* open beyond the
722b15cb3dSCy Schubert  * scope of the function that opened it.
732b15cb3dSCy Schubert  */
742b15cb3dSCy Schubert #ifndef FD_PREFERRED_SOCKBOUNDARY
752b15cb3dSCy Schubert #define FD_PREFERRED_SOCKBOUNDARY 48
762b15cb3dSCy Schubert #endif
772b15cb3dSCy Schubert 
782b15cb3dSCy Schubert 	static SOCKET socket_boundary = -1;
792b15cb3dSCy Schubert 	SOCKET newfd;
802b15cb3dSCy Schubert 
819034852cSGleb Smirnoff 	REQUIRE((int)fd >= 0);
822b15cb3dSCy Schubert 
832b15cb3dSCy Schubert 	/*
842b15cb3dSCy Schubert 	 * check whether boundary has be set up
852b15cb3dSCy Schubert 	 * already
862b15cb3dSCy Schubert 	 */
872b15cb3dSCy Schubert 	if (socket_boundary == -1) {
882b15cb3dSCy Schubert 		socket_boundary = max(0, min(GETDTABLESIZE() - FD_CHUNK,
892b15cb3dSCy Schubert 					     min(FOPEN_MAX, FD_PREFERRED_SOCKBOUNDARY)));
902b15cb3dSCy Schubert 		TRACE(1, ("move_fd: estimated max descriptors: %d, "
912b15cb3dSCy Schubert 			  "initial socket boundary: %d\n",
922b15cb3dSCy Schubert 			  GETDTABLESIZE(), socket_boundary));
932b15cb3dSCy Schubert 	}
942b15cb3dSCy Schubert 
952b15cb3dSCy Schubert 	/*
962b15cb3dSCy Schubert 	 * Leave a space for stdio to work in. potentially moving the
972b15cb3dSCy Schubert 	 * socket_boundary lower until allocation succeeds.
982b15cb3dSCy Schubert 	 */
992b15cb3dSCy Schubert 	do {
1002b15cb3dSCy Schubert 		if (fd >= 0 && fd < socket_boundary) {
1012b15cb3dSCy Schubert 			/* inside reserved range: attempt to move fd */
1022b15cb3dSCy Schubert 			newfd = fcntl(fd, F_DUPFD, socket_boundary);
1032b15cb3dSCy Schubert 
1042b15cb3dSCy Schubert 			if (newfd != -1) {
1052b15cb3dSCy Schubert 				/* success: drop the old one - return the new one */
1062b15cb3dSCy Schubert 				close(fd);
1072b15cb3dSCy Schubert 				return newfd;
1082b15cb3dSCy Schubert 			}
1092b15cb3dSCy Schubert 		} else {
1102b15cb3dSCy Schubert 			/* outside reserved range: no work - return the original one */
1112b15cb3dSCy Schubert 			return fd;
1122b15cb3dSCy Schubert 		}
1132b15cb3dSCy Schubert 		socket_boundary = max(0, socket_boundary - FD_CHUNK);
1142b15cb3dSCy Schubert 		TRACE(1, ("move_fd: selecting new socket boundary: %d\n",
1152b15cb3dSCy Schubert 			  socket_boundary));
1162b15cb3dSCy Schubert 	} while (socket_boundary > 0);
1172b15cb3dSCy Schubert #else
1189034852cSGleb Smirnoff 	ENSURE((int)fd >= 0);
1192b15cb3dSCy Schubert #endif /* !defined(SYS_WINNT) && defined(F_DUPFD) */
1202b15cb3dSCy Schubert 	return fd;
1212b15cb3dSCy Schubert }
1222b15cb3dSCy Schubert 
1232b15cb3dSCy Schubert 
1242b15cb3dSCy Schubert /*
1252b15cb3dSCy Schubert  * make_socket_nonblocking() - set up descriptor to be non blocking
1262b15cb3dSCy Schubert  */
1272b15cb3dSCy Schubert void
make_socket_nonblocking(SOCKET fd)1282b15cb3dSCy Schubert make_socket_nonblocking(
1292b15cb3dSCy Schubert 	SOCKET fd
1302b15cb3dSCy Schubert 	)
1312b15cb3dSCy Schubert {
1322b15cb3dSCy Schubert 	/*
1332b15cb3dSCy Schubert 	 * set non-blocking,
1342b15cb3dSCy Schubert 	 */
1352b15cb3dSCy Schubert 
1362b15cb3dSCy Schubert #ifdef USE_FIONBIO
1372b15cb3dSCy Schubert 	/* in vxWorks we use FIONBIO, but the others are defined for old
1382b15cb3dSCy Schubert 	 * systems, so all hell breaks loose if we leave them defined
1392b15cb3dSCy Schubert 	 */
1402b15cb3dSCy Schubert #undef O_NONBLOCK
1412b15cb3dSCy Schubert #undef FNDELAY
1422b15cb3dSCy Schubert #undef O_NDELAY
1432b15cb3dSCy Schubert #endif
1442b15cb3dSCy Schubert 
1452b15cb3dSCy Schubert #if defined(O_NONBLOCK) /* POSIX */
1462b15cb3dSCy Schubert 	if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
1472b15cb3dSCy Schubert 		msyslog(LOG_ERR,
1482b15cb3dSCy Schubert 			"fcntl(O_NONBLOCK) fails on fd #%d: %m", fd);
1492b15cb3dSCy Schubert 		exit(1);
1502b15cb3dSCy Schubert 	}
1512b15cb3dSCy Schubert #elif defined(FNDELAY)
1522b15cb3dSCy Schubert 	if (fcntl(fd, F_SETFL, FNDELAY) < 0) {
1532b15cb3dSCy Schubert 		msyslog(LOG_ERR, "fcntl(FNDELAY) fails on fd #%d: %m",
1542b15cb3dSCy Schubert 			fd);
1552b15cb3dSCy Schubert 		exit(1);
1562b15cb3dSCy Schubert 	}
1572b15cb3dSCy Schubert #elif defined(O_NDELAY) /* generally the same as FNDELAY */
1582b15cb3dSCy Schubert 	if (fcntl(fd, F_SETFL, O_NDELAY) < 0) {
1592b15cb3dSCy Schubert 		msyslog(LOG_ERR, "fcntl(O_NDELAY) fails on fd #%d: %m",
1602b15cb3dSCy Schubert 			fd);
1612b15cb3dSCy Schubert 		exit(1);
1622b15cb3dSCy Schubert 	}
1632b15cb3dSCy Schubert #elif defined(FIONBIO)
1642b15cb3dSCy Schubert 	{
1652b15cb3dSCy Schubert 		int on = 1;
1662b15cb3dSCy Schubert 
1672b15cb3dSCy Schubert 		if (ioctl(fd, FIONBIO, &on) < 0) {
1682b15cb3dSCy Schubert 			msyslog(LOG_ERR,
1692b15cb3dSCy Schubert 				"ioctl(FIONBIO) fails on fd #%d: %m",
1702b15cb3dSCy Schubert 				fd);
1712b15cb3dSCy Schubert 			exit(1);
1722b15cb3dSCy Schubert 		}
1732b15cb3dSCy Schubert 	}
1742b15cb3dSCy Schubert #elif defined(FIOSNBIO)
1752b15cb3dSCy Schubert 	if (ioctl(fd, FIOSNBIO, &on) < 0) {
1762b15cb3dSCy Schubert 		msyslog(LOG_ERR,
1772b15cb3dSCy Schubert 			"ioctl(FIOSNBIO) fails on fd #%d: %m", fd);
1782b15cb3dSCy Schubert 		exit(1);
1792b15cb3dSCy Schubert 	}
1802b15cb3dSCy Schubert #else
1812b15cb3dSCy Schubert # include "Bletch: Need non-blocking I/O!"
1822b15cb3dSCy Schubert #endif
1832b15cb3dSCy Schubert }
1842b15cb3dSCy Schubert 
1852b15cb3dSCy Schubert #if 0
1862b15cb3dSCy Schubert 
1872b15cb3dSCy Schubert /* The following subroutines should probably be moved here */
1882b15cb3dSCy Schubert 
1892b15cb3dSCy Schubert static SOCKET
1902b15cb3dSCy Schubert open_socket(
1912b15cb3dSCy Schubert 	sockaddr_u *	addr,
1922b15cb3dSCy Schubert 	int		bcast,
1932b15cb3dSCy Schubert 	int		turn_off_reuse,
1942b15cb3dSCy Schubert 	endpt *		interf
1952b15cb3dSCy Schubert 	)
1962b15cb3dSCy Schubert void
1972b15cb3dSCy Schubert sendpkt(
1982b15cb3dSCy Schubert 	sockaddr_u *	dest,
199*f5f40dd6SCy Schubert 	endpt *		ep,
2002b15cb3dSCy Schubert 	int		ttl,
2012b15cb3dSCy Schubert 	struct pkt *	pkt,
2022b15cb3dSCy Schubert 	int		len
2032b15cb3dSCy Schubert 	)
2042b15cb3dSCy Schubert 
2052b15cb3dSCy Schubert static inline int
2062b15cb3dSCy Schubert read_refclock_packet(SOCKET fd, struct refclockio *rp, l_fp ts)
2072b15cb3dSCy Schubert 
2082b15cb3dSCy Schubert static inline int
2092b15cb3dSCy Schubert read_network_packet(
2102b15cb3dSCy Schubert 	SOCKET	fd,
211*f5f40dd6SCy Schubert 	endpt *	itf,
2122b15cb3dSCy Schubert 	l_fp	ts
2132b15cb3dSCy Schubert 	)
2142b15cb3dSCy Schubert 
2152b15cb3dSCy Schubert void
2162b15cb3dSCy Schubert kill_asyncio(int startfd)
2172b15cb3dSCy Schubert 
2182b15cb3dSCy Schubert #endif /* 0 */
219