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