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
move_fd(SOCKET fd)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
make_socket_nonblocking(SOCKET fd)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