Removed
Link Here
|
1 |
From dd19ce4f24eec64177cdcfcf294b8efbb631a24b Mon Sep 17 00:00:00 2001 |
2 |
From: Jeremy Harris <jgh146exb@wizmail.org> |
3 |
Date: Wed, 17 Nov 2021 17:19:54 +0000 |
4 |
Subject: [PATCH] select() -> poll(). Bug 2831 |
5 |
|
6 |
--- |
7 |
doc/ChangeLog | 8 +++ |
8 |
src/daemon.c | 126 +++++++++++++++++++------------------- |
9 |
src/deliver.c | 54 ++++++++-------- |
10 |
src/exim.c | 9 +-- |
11 |
src/expand.c | 6 +- |
12 |
src/functions.h | 7 +++ |
13 |
src/ip.c | 12 +--- |
14 |
src/malware.c | 6 +- |
15 |
src/receive.c | 15 +---- |
16 |
src/smtp_in.c | 18 +----- |
17 |
src/spam.c | 42 ++++--------- |
18 |
src/transport.c | 4 +- |
19 |
src/transports/smtp.c | 37 ++++------- |
20 |
13 files changed, 142 insertions(+), 202 deletions(-) |
21 |
|
22 |
diff --git a/doc/ChangeLog b/doc/ChangeLog |
23 |
index 7f6814d5e..58996c3f8 100644 |
24 |
--- a/doc/ChangeLog |
25 |
+++ b/doc/ChangeLog |
26 |
@@ -40,6 +40,14 @@ JH/09 Fix macro-definition during "-be" expansion testing. The move to |
27 |
write-protected store for macros had not accounted for these runtime |
28 |
additions; fix by removing this protection for "-be" mode. |
29 |
|
30 |
+JH/10 Convert all uses of select() to poll(). FreeBSD 12.2 was found to be |
31 |
+ handing out large-numbered file descriptors, violating the usual Unix |
32 |
+ assumption (and required by Posix) that the lowest possible number will be |
33 |
+ allocated by the kernel when a new one is needed. In the daemon, and any |
34 |
+ child procesees, values higher than 1024 (being bigger than FD_SETSIZE) |
35 |
+ are not useable for FD_SET() [and hence select()] and overwrite the stack. |
36 |
+ Assorted crashes happen. |
37 |
+ |
38 |
|
39 |
Exim version 4.95 |
40 |
----------------- |
41 |
diff --git a/src/daemon.c b/src/daemon.c |
42 |
index 0b8d5d595..a248a4f40 100644 |
43 |
--- a/src/daemon.c |
44 |
+++ b/src/daemon.c |
45 |
@@ -87,7 +87,7 @@ sigchld_seen = TRUE; |
46 |
} |
47 |
|
48 |
|
49 |
-/* SIGTERM handler. Try to get the damon pif file removed |
50 |
+/* SIGTERM handler. Try to get the damon pid file removed |
51 |
before exiting. */ |
52 |
|
53 |
static void |
54 |
@@ -141,7 +141,7 @@ Uunlink(s); |
55 |
|
56 |
static void |
57 |
close_daemon_sockets(int daemon_notifier_fd, |
58 |
- int * listen_sockets, int listen_socket_count) |
59 |
+ struct pollfd * fd_polls, int listen_socket_count) |
60 |
{ |
61 |
if (daemon_notifier_fd >= 0) |
62 |
{ |
63 |
@@ -152,7 +152,7 @@ if (daemon_notifier_fd >= 0) |
64 |
#endif |
65 |
} |
66 |
|
67 |
-for (int i = 0; i < listen_socket_count; i++) (void) close(listen_sockets[i]); |
68 |
+for (int i = 0; i < listen_socket_count; i++) (void) close(fd_polls[i].fd); |
69 |
} |
70 |
|
71 |
|
72 |
@@ -167,7 +167,7 @@ is required so that they can be closed in the sub-process. Take care not to |
73 |
leak store in this process - reset the stacking pool at the end. |
74 |
|
75 |
Arguments: |
76 |
- listen_sockets sockets which are listening for incoming calls |
77 |
+ fd_polls sockets which are listening for incoming calls |
78 |
listen_socket_count count of listening sockets |
79 |
accept_socket socket of the current accepted call |
80 |
accepted socket information about the current call |
81 |
@@ -176,7 +176,7 @@ Returns: nothing |
82 |
*/ |
83 |
|
84 |
static void |
85 |
-handle_smtp_call(int *listen_sockets, int listen_socket_count, |
86 |
+handle_smtp_call(struct pollfd *fd_polls, int listen_socket_count, |
87 |
int accept_socket, struct sockaddr *accepted) |
88 |
{ |
89 |
pid_t pid; |
90 |
@@ -459,7 +459,7 @@ if (pid == 0) |
91 |
extensive comment before the reception loop in exim.c for a fuller |
92 |
explanation of this logic. */ |
93 |
|
94 |
- close_daemon_sockets(daemon_notifier_fd, listen_sockets, listen_socket_count); |
95 |
+ close_daemon_sockets(daemon_notifier_fd, fd_polls, listen_socket_count); |
96 |
|
97 |
/* Set FD_CLOEXEC on the SMTP socket. We don't want any rogue child processes |
98 |
to be able to communicate with them, under any circumstances. */ |
99 |
@@ -1305,13 +1305,6 @@ return FALSE; |
100 |
|
101 |
|
102 |
|
103 |
-static void |
104 |
-add_listener_socket(int fd, fd_set * fds, int * fd_max) |
105 |
-{ |
106 |
-FD_SET(fd, fds); |
107 |
-if (fd > *fd_max) *fd_max = fd; |
108 |
-} |
109 |
- |
110 |
/************************************************* |
111 |
* Exim Daemon Mainline * |
112 |
*************************************************/ |
113 |
@@ -1339,9 +1332,8 @@ void |
114 |
daemon_go(void) |
115 |
{ |
116 |
struct passwd * pw; |
117 |
-int * listen_sockets = NULL; |
118 |
-int listen_socket_count = 0, listen_fd_max = 0; |
119 |
-fd_set select_listen; |
120 |
+struct pollfd * fd_polls, * tls_watch_poll = NULL, * dnotify_poll = NULL; |
121 |
+int listen_socket_count = 0, poll_fd_count; |
122 |
ip_address_item * addresses = NULL; |
123 |
time_t last_connection_time = (time_t)0; |
124 |
int local_queue_run_max = atoi(CS expand_string(queue_run_max)); |
125 |
@@ -1353,17 +1345,21 @@ debugging lines get the pid added. */ |
126 |
|
127 |
DEBUG(D_any|D_v) debug_selector |= D_pid; |
128 |
|
129 |
-FD_ZERO(&select_listen); |
130 |
+/* Allocate enough pollstructs for inetd mode plus the ancillary sockets; |
131 |
+also used when there are no listen sockets. */ |
132 |
+ |
133 |
+fd_polls = store_get(sizeof(struct pollfd) * 3, FALSE); |
134 |
+ |
135 |
if (f.inetd_wait_mode) |
136 |
{ |
137 |
listen_socket_count = 1; |
138 |
- listen_sockets = store_get(sizeof(int), FALSE); |
139 |
(void) close(3); |
140 |
if (dup2(0, 3) == -1) |
141 |
log_write(0, LOG_MAIN|LOG_PANIC_DIE, |
142 |
"failed to dup inetd socket safely away: %s", strerror(errno)); |
143 |
|
144 |
- listen_sockets[0] = 3; |
145 |
+ fd_polls[0].fd = 3; |
146 |
+ fd_polls[0].events = POLLIN; |
147 |
(void) close(0); |
148 |
(void) close(1); |
149 |
(void) close(2); |
150 |
@@ -1390,9 +1386,6 @@ if (f.inetd_wait_mode) |
151 |
if (setsockopt(3, IPPROTO_TCP, TCP_NODELAY, US &on, sizeof(on))) |
152 |
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to set socket NODELAY: %s", |
153 |
strerror(errno)); |
154 |
- |
155 |
- FD_SET(3, &select_listen); |
156 |
- listen_fd_max = 3; |
157 |
} |
158 |
|
159 |
|
160 |
@@ -1686,11 +1679,16 @@ if (f.daemon_listen && !f.inetd_wait_mode) |
161 |
} |
162 |
} |
163 |
|
164 |
- /* Get a vector to remember all the sockets in */ |
165 |
+ /* Get a vector to remember all the sockets in. |
166 |
+ Two extra elements for the ancillary sockets */ |
167 |
|
168 |
for (ipa = addresses; ipa; ipa = ipa->next) |
169 |
listen_socket_count++; |
170 |
- listen_sockets = store_get(sizeof(int) * listen_socket_count, FALSE); |
171 |
+ fd_polls = store_get(sizeof(struct pollfd) * (listen_socket_count + 2), |
172 |
+ FALSE); |
173 |
+ for (struct pollfd * p = fd_polls; p < fd_polls + listen_socket_count + 2; |
174 |
+ p++) |
175 |
+ { p->fd = -1; p->events = POLLIN; } |
176 |
|
177 |
} /* daemon_listen but not inetd_wait_mode */ |
178 |
|
179 |
@@ -1795,7 +1793,7 @@ if (f.daemon_listen && !f.inetd_wait_mode) |
180 |
wildcard = ipa->address[0] == 0; |
181 |
} |
182 |
|
183 |
- if ((listen_sockets[sk] = fd = ip_socket(SOCK_STREAM, af)) < 0) |
184 |
+ if ((fd_polls[sk].fd = fd = ip_socket(SOCK_STREAM, af)) < 0) |
185 |
{ |
186 |
if (check_special_case(0, addresses, ipa, FALSE)) |
187 |
{ |
188 |
@@ -1804,7 +1802,7 @@ if (f.daemon_listen && !f.inetd_wait_mode) |
189 |
goto SKIP_SOCKET; |
190 |
} |
191 |
log_write(0, LOG_PANIC_DIE, "IPv%c socket creation failed: %s", |
192 |
- (af == AF_INET6)? '6' : '4', strerror(errno)); |
193 |
+ af == AF_INET6 ? '6' : '4', strerror(errno)); |
194 |
} |
195 |
|
196 |
/* If this is an IPv6 wildcard socket, set IPV6_V6ONLY if that option is |
197 |
@@ -1903,8 +1901,7 @@ if (f.daemon_listen && !f.inetd_wait_mode) |
198 |
f.tcp_fastopen_ok = FALSE; |
199 |
} |
200 |
#endif |
201 |
- |
202 |
- add_listener_socket(fd, &select_listen, &listen_fd_max); |
203 |
+ fd_polls[sk].fd = fd; |
204 |
continue; |
205 |
} |
206 |
|
207 |
@@ -2187,14 +2184,21 @@ tls_daemon_init(); |
208 |
|
209 |
/* Add ancillary sockets to the set for select */ |
210 |
|
211 |
+poll_fd_count = listen_socket_count; |
212 |
#ifndef DISABLE_TLS |
213 |
if (tls_watch_fd >= 0) |
214 |
- add_listener_socket(tls_watch_fd, &select_listen, &listen_fd_max); |
215 |
+ { |
216 |
+ tls_watch_poll = &fd_polls[poll_fd_count++]; |
217 |
+ tls_watch_poll->fd = tls_watch_fd; |
218 |
+ tls_watch_poll->events = POLLIN; |
219 |
+ } |
220 |
#endif |
221 |
if (daemon_notifier_fd >= 0) |
222 |
- add_listener_socket(daemon_notifier_fd, &select_listen, &listen_fd_max); |
223 |
- |
224 |
-listen_fd_max++; |
225 |
+ { |
226 |
+ dnotify_poll = &fd_polls[poll_fd_count++]; |
227 |
+ dnotify_poll->fd = daemon_notifier_fd; |
228 |
+ dnotify_poll->events = POLLIN; |
229 |
+ } |
230 |
|
231 |
/* Close the log so it can be renamed and moved. In the few cases below where |
232 |
this long-running process writes to the log (always exceptional conditions), it |
233 |
@@ -2293,7 +2297,7 @@ for (;;) |
234 |
/* Close any open listening sockets in the child */ |
235 |
|
236 |
close_daemon_sockets(daemon_notifier_fd, |
237 |
- listen_sockets, listen_socket_count); |
238 |
+ fd_polls, listen_socket_count); |
239 |
|
240 |
/* Reset SIGHUP and SIGCHLD in the child in both cases. */ |
241 |
|
242 |
@@ -2421,9 +2425,8 @@ for (;;) |
243 |
|
244 |
if (f.daemon_listen) |
245 |
{ |
246 |
- int check_lsk = 0, lcount; |
247 |
+ int lcount; |
248 |
BOOL select_failed = FALSE; |
249 |
- fd_set fds = select_listen; |
250 |
|
251 |
DEBUG(D_any) debug_printf("Listening...\n"); |
252 |
|
253 |
@@ -2440,8 +2443,7 @@ for (;;) |
254 |
errno = EINTR; |
255 |
} |
256 |
else |
257 |
- lcount = select(listen_fd_max, (SELECT_ARG2_TYPE *)&fds, |
258 |
- NULL, NULL, NULL); |
259 |
+ lcount = poll(fd_polls, poll_fd_count, -1); |
260 |
|
261 |
if (lcount < 0) |
262 |
{ |
263 |
@@ -2461,15 +2463,15 @@ for (;;) |
264 |
handle_ending_processes(); |
265 |
|
266 |
#ifndef DISABLE_TLS |
267 |
+ { |
268 |
+ int old_tfd; |
269 |
/* Create or rotate any required keys; handle (delayed) filewatch event */ |
270 |
- for (int old_tfd = tls_daemon_tick(); old_tfd >= 0; ) |
271 |
- { |
272 |
- FD_CLR(old_tfd, &select_listen); |
273 |
- if (old_tfd == listen_fd_max - 1) listen_fd_max = old_tfd; |
274 |
- if (tls_watch_fd >= 0) |
275 |
- add_listener_socket(tls_watch_fd, &select_listen, &listen_fd_max); |
276 |
- break; |
277 |
- } |
278 |
+ |
279 |
+ if ((old_tfd = tls_daemon_tick()) >= 0) |
280 |
+ for (struct pollfd * p = &fd_polls[listen_socket_count]; |
281 |
+ p < fd_polls + poll_fd_count; p++) |
282 |
+ if (p->fd == old_tfd) { p->fd = tls_watch_fd ; break; } |
283 |
+ } |
284 |
#endif |
285 |
errno = select_errno; |
286 |
} |
287 |
@@ -2490,22 +2492,23 @@ for (;;) |
288 |
if (!select_failed) |
289 |
{ |
290 |
#if !defined(DISABLE_TLS) && (defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT)) |
291 |
- if (tls_watch_fd >= 0 && FD_ISSET(tls_watch_fd, &fds)) |
292 |
+ if (tls_watch_poll && tls_watch_poll->revents & POLLIN) |
293 |
{ |
294 |
+ tls_watch_poll->revents = 0; |
295 |
tls_watch_trigger_time = time(NULL); /* Set up delayed event */ |
296 |
tls_watch_discard_event(tls_watch_fd); |
297 |
break; /* to top of daemon loop */ |
298 |
} |
299 |
#endif |
300 |
- if (daemon_notifier_fd >= 0 && FD_ISSET(daemon_notifier_fd, &fds)) |
301 |
+ if (dnotify_poll && dnotify_poll->revents & POLLIN) |
302 |
{ |
303 |
+ dnotify_poll->revents = 0; |
304 |
sigalrm_seen = daemon_notification(); |
305 |
break; /* to top of daemon loop */ |
306 |
} |
307 |
- while (check_lsk < listen_socket_count) |
308 |
- { |
309 |
- int lfd = listen_sockets[check_lsk++]; |
310 |
- if (FD_ISSET(lfd, &fds)) |
311 |
+ for (struct pollfd * p = fd_polls; p < fd_polls + listen_socket_count; |
312 |
+ p++) |
313 |
+ if (p->revents & POLLIN) |
314 |
{ |
315 |
EXIM_SOCKLEN_T alen = sizeof(accepted); |
316 |
#ifdef TCP_INFO |
317 |
@@ -2516,23 +2519,23 @@ for (;;) |
318 |
|
319 |
smtp_listen_backlog = 0; |
320 |
if ( smtp_backlog_monitor > 0 |
321 |
- && getsockopt(lfd, IPPROTO_TCP, TCP_INFO, &ti, &tlen) == 0) |
322 |
+ && getsockopt(p->fd, IPPROTO_TCP, TCP_INFO, &ti, &tlen) == 0) |
323 |
{ |
324 |
# ifdef EXIM_HAVE_TCPI_UNACKED |
325 |
DEBUG(D_interface) debug_printf("listen fd %d queue max %u curr %u\n", |
326 |
- lfd, ti.tcpi_sacked, ti.tcpi_unacked); |
327 |
+ p->fd, ti.tcpi_sacked, ti.tcpi_unacked); |
328 |
smtp_listen_backlog = ti.tcpi_unacked; |
329 |
# elif defined(__FreeBSD__) /* This does not work. Investigate kernel sourcecode. */ |
330 |
DEBUG(D_interface) debug_printf("listen fd %d queue max %u curr %u\n", |
331 |
- lfd, ti.__tcpi_sacked, ti.__tcpi_unacked); |
332 |
+ p->fd, ti.__tcpi_sacked, ti.__tcpi_unacked); |
333 |
smtp_listen_backlog = ti.__tcpi_unacked; |
334 |
# endif |
335 |
} |
336 |
#endif |
337 |
- accept_socket = accept(lfd, (struct sockaddr *)&accepted, &alen); |
338 |
+ p->revents = 0; |
339 |
+ accept_socket = accept(p->fd, (struct sockaddr *)&accepted, &alen); |
340 |
break; |
341 |
} |
342 |
- } |
343 |
} |
344 |
|
345 |
/* If select or accept has failed and this was not caused by an |
346 |
@@ -2591,7 +2594,7 @@ for (;;) |
347 |
#endif |
348 |
if (inetd_wait_timeout) |
349 |
last_connection_time = time(NULL); |
350 |
- handle_smtp_call(listen_sockets, listen_socket_count, accept_socket, |
351 |
+ handle_smtp_call(fd_polls, listen_socket_count, accept_socket, |
352 |
(struct sockaddr *)&accepted); |
353 |
} |
354 |
} |
355 |
@@ -2606,10 +2609,8 @@ for (;;) |
356 |
|
357 |
else |
358 |
{ |
359 |
- struct timeval tv; |
360 |
- tv.tv_sec = queue_interval; |
361 |
- tv.tv_usec = 0; |
362 |
- select(0, NULL, NULL, NULL, &tv); |
363 |
+ struct pollfd p; |
364 |
+ poll(&p, 0, queue_interval * 1000); |
365 |
handle_ending_processes(); |
366 |
} |
367 |
|
368 |
@@ -2634,8 +2635,7 @@ for (;;) |
369 |
{ |
370 |
log_write(0, LOG_MAIN, "pid %d: SIGHUP received: re-exec daemon", |
371 |
getpid()); |
372 |
- close_daemon_sockets(daemon_notifier_fd, |
373 |
- listen_sockets, listen_socket_count); |
374 |
+ close_daemon_sockets(daemon_notifier_fd, fd_polls, listen_socket_count); |
375 |
ALARM_CLR(0); |
376 |
signal(SIGHUP, SIG_IGN); |
377 |
sighup_argv[0] = exim_path; |
378 |
diff --git a/src/deliver.c b/src/deliver.c |
379 |
index 4594c4a1d..8aad811c6 100644 |
380 |
--- a/src/deliver.c |
381 |
+++ b/src/deliver.c |
382 |
@@ -74,6 +74,7 @@ static BOOL update_spool; |
383 |
static BOOL remove_journal; |
384 |
static int parcount = 0; |
385 |
static pardata *parlist = NULL; |
386 |
+static struct pollfd *parpoll; |
387 |
static int return_count; |
388 |
static uschar *frozen_info = US""; |
389 |
static uschar *used_return_path = NULL; |
390 |
@@ -3306,7 +3307,7 @@ BOOL done = p->done; |
391 |
|
392 |
/* Loop through all items, reading from the pipe when necessary. The pipe |
393 |
used to be non-blocking. But I do not see a reason for using non-blocking I/O |
394 |
-here, as the preceding select() tells us, if data is available for reading. |
395 |
+here, as the preceding poll() tells us, if data is available for reading. |
396 |
|
397 |
A read() on a "selected" handle should never block, but(!) it may return |
398 |
less data then we expected. (The buffer size we pass to read() shouldn't be |
399 |
@@ -3840,7 +3841,7 @@ static address_item * |
400 |
par_wait(void) |
401 |
{ |
402 |
int poffset, status; |
403 |
-address_item *addr, *addrlist; |
404 |
+address_item * addr, * addrlist; |
405 |
pid_t pid; |
406 |
|
407 |
set_process_info("delivering %s: waiting for a remote delivery subprocess " |
408 |
@@ -3850,18 +3851,18 @@ set_process_info("delivering %s: waiting for a remote delivery subprocess " |
409 |
existence - in which case give an error return. We cannot proceed just by |
410 |
waiting for a completion, because a subprocess may have filled up its pipe, and |
411 |
be waiting for it to be emptied. Therefore, if no processes have finished, we |
412 |
-wait for one of the pipes to acquire some data by calling select(), with a |
413 |
+wait for one of the pipes to acquire some data by calling poll(), with a |
414 |
timeout just in case. |
415 |
|
416 |
The simple approach is just to iterate after reading data from a ready pipe. |
417 |
This leads to non-ideal behaviour when the subprocess has written its final Z |
418 |
item, closed the pipe, and is in the process of exiting (the common case). A |
419 |
-call to waitpid() yields nothing completed, but select() shows the pipe ready - |
420 |
+call to waitpid() yields nothing completed, but poll() shows the pipe ready - |
421 |
reading it yields EOF, so you end up with busy-waiting until the subprocess has |
422 |
actually finished. |
423 |
|
424 |
To avoid this, if all the data that is needed has been read from a subprocess |
425 |
-after select(), an explicit wait() for it is done. We know that all it is doing |
426 |
+after poll(), an explicit wait() for it is done. We know that all it is doing |
427 |
is writing to the pipe and then exiting, so the wait should not be long. |
428 |
|
429 |
The non-blocking waitpid() is to some extent just insurance; if we could |
430 |
@@ -3881,9 +3882,7 @@ for (;;) /* Normally we do not repeat this loop */ |
431 |
{ |
432 |
while ((pid = waitpid(-1, &status, WNOHANG)) <= 0) |
433 |
{ |
434 |
- struct timeval tv; |
435 |
- fd_set select_pipes; |
436 |
- int maxpipe, readycount; |
437 |
+ int readycount; |
438 |
|
439 |
/* A return value of -1 can mean several things. If errno != ECHILD, it |
440 |
either means invalid options (which we discount), or that this process was |
441 |
@@ -3907,7 +3906,7 @@ for (;;) /* Normally we do not repeat this loop */ |
442 |
subprocesses are still in existence. If kill() gives an OK return, we know |
443 |
it must be for one of our processes - it can't be for a re-use of the pid, |
444 |
because if our process had finished, waitpid() would have found it. If any |
445 |
- of our subprocesses are in existence, we proceed to use select() as if |
446 |
+ of our subprocesses are in existence, we proceed to use poll() as if |
447 |
waitpid() had returned zero. I think this is safe. */ |
448 |
|
449 |
if (pid < 0) |
450 |
@@ -3931,7 +3930,7 @@ for (;;) /* Normally we do not repeat this loop */ |
451 |
if (poffset >= remote_max_parallel) |
452 |
{ |
453 |
DEBUG(D_deliver) debug_printf("*** no delivery children found\n"); |
454 |
- return NULL; /* This is the error return */ |
455 |
+ return NULL; /* This is the error return */ |
456 |
} |
457 |
} |
458 |
|
459 |
@@ -3940,28 +3939,23 @@ for (;;) /* Normally we do not repeat this loop */ |
460 |
subprocess, but there are no completed subprocesses. See if any pipes are |
461 |
ready with any data for reading. */ |
462 |
|
463 |
- DEBUG(D_deliver) debug_printf("selecting on subprocess pipes\n"); |
464 |
+ DEBUG(D_deliver) debug_printf("polling subprocess pipes\n"); |
465 |
|
466 |
- maxpipe = 0; |
467 |
- FD_ZERO(&select_pipes); |
468 |
for (poffset = 0; poffset < remote_max_parallel; poffset++) |
469 |
if (parlist[poffset].pid != 0) |
470 |
- { |
471 |
- int fd = parlist[poffset].fd; |
472 |
- FD_SET(fd, &select_pipes); |
473 |
- if (fd > maxpipe) maxpipe = fd; |
474 |
- } |
475 |
+ { |
476 |
+ parpoll[poffset].fd = parlist[poffset].fd; |
477 |
+ parpoll[poffset].events = POLLIN; |
478 |
+ } |
479 |
+ else |
480 |
+ parpoll[poffset].fd = -1; |
481 |
|
482 |
/* Stick in a 60-second timeout, just in case. */ |
483 |
|
484 |
- tv.tv_sec = 60; |
485 |
- tv.tv_usec = 0; |
486 |
- |
487 |
- readycount = select(maxpipe + 1, (SELECT_ARG2_TYPE *)&select_pipes, |
488 |
- NULL, NULL, &tv); |
489 |
+ readycount = poll(parpoll, remote_max_parallel, 60 * 1000); |
490 |
|
491 |
/* Scan through the pipes and read any that are ready; use the count |
492 |
- returned by select() to stop when there are no more. Select() can return |
493 |
+ returned by poll() to stop when there are no more. Select() can return |
494 |
with no processes (e.g. if interrupted). This shouldn't matter. |
495 |
|
496 |
If par_read_pipe() returns TRUE, it means that either the terminating Z was |
497 |
@@ -3978,7 +3972,7 @@ for (;;) /* Normally we do not repeat this loop */ |
498 |
poffset++) |
499 |
{ |
500 |
if ( (pid = parlist[poffset].pid) != 0 |
501 |
- && FD_ISSET(parlist[poffset].fd, &select_pipes) |
502 |
+ && parpoll[poffset].revents |
503 |
) |
504 |
{ |
505 |
readycount--; |
506 |
@@ -4016,7 +4010,7 @@ for (;;) /* Normally we do not repeat this loop */ |
507 |
"transport process list", pid); |
508 |
} /* End of the "for" loop */ |
509 |
|
510 |
-/* Come here when all the data was completely read after a select(), and |
511 |
+/* Come here when all the data was completely read after a poll(), and |
512 |
the process in pid has been wait()ed for. */ |
513 |
|
514 |
PROCESS_DONE: |
515 |
@@ -4051,7 +4045,7 @@ if ((status & 0xffff) != 0) |
516 |
"%s %d", |
517 |
addrlist->transport->driver_name, |
518 |
status, |
519 |
- (msb == 0)? "terminated by signal" : "exit code", |
520 |
+ msb == 0 ? "terminated by signal" : "exit code", |
521 |
code); |
522 |
|
523 |
if (msb != 0 || (code != SIGTERM && code != SIGKILL && code != SIGQUIT)) |
524 |
@@ -4069,7 +4063,8 @@ if ((status & 0xffff) != 0) |
525 |
/* Else complete reading the pipe to get the result of the delivery, if all |
526 |
the data has not yet been obtained. */ |
527 |
|
528 |
-else if (!parlist[poffset].done) (void)par_read_pipe(poffset, TRUE); |
529 |
+else if (!parlist[poffset].done) |
530 |
+ (void) par_read_pipe(poffset, TRUE); |
531 |
|
532 |
/* Put the data count and return path into globals, mark the data slot unused, |
533 |
decrement the count of subprocesses, and return the address chain. */ |
534 |
@@ -4218,6 +4213,7 @@ if (!parlist) |
535 |
parlist = store_get(remote_max_parallel * sizeof(pardata), FALSE); |
536 |
for (poffset = 0; poffset < remote_max_parallel; poffset++) |
537 |
parlist[poffset].pid = 0; |
538 |
+ parpoll = store_get(remote_max_parallel * sizeof(struct pollfd), FALSE); |
539 |
} |
540 |
|
541 |
/* Now loop for each remote delivery */ |
542 |
@@ -4613,7 +4609,7 @@ nonmatch domains |
543 |
that it can use either of them, though it prefers O_NONBLOCK, which |
544 |
distinguishes between EOF and no-more-data. */ |
545 |
|
546 |
-/* The data appears in a timely manner and we already did a select on |
547 |
+/* The data appears in a timely manner and we already did a poll on |
548 |
all pipes, so I do not see a reason to use non-blocking IO here |
549 |
|
550 |
#ifdef O_NONBLOCK |
551 |
diff --git a/src/exim.c b/src/exim.c |
552 |
index 133761de9..42db457c0 100644 |
553 |
--- a/src/exim.c |
554 |
+++ b/src/exim.c |
555 |
@@ -5735,13 +5735,8 @@ for (BOOL more = TRUE; more; ) |
556 |
the file copy. */ |
557 |
|
558 |
if (!receive_timeout) |
559 |
- { |
560 |
- struct timeval t = { .tv_sec = 30*60, .tv_usec = 0 }; /* 30 minutes */ |
561 |
- fd_set r; |
562 |
- |
563 |
- FD_ZERO(&r); FD_SET(0, &r); |
564 |
- if (select(1, &r, NULL, NULL, &t) == 0) mainlog_close(); |
565 |
- } |
566 |
+ if (poll_one_fd(0, POLLIN, 30*60*1000) == 0) /* 30 minutes */ |
567 |
+ mainlog_close(); |
568 |
|
569 |
/* Read the data for the message. If filter_test is not FTEST_NONE, this |
570 |
will just read the headers for the message, and not write anything onto the |
571 |
diff --git a/src/expand.c b/src/expand.c |
572 |
index 59554840e..bfae2a3c0 100644 |
573 |
--- a/src/expand.c |
574 |
+++ b/src/expand.c |
575 |
@@ -1760,8 +1760,6 @@ const uschar * where; |
576 |
#ifndef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS |
577 |
uschar * sname; |
578 |
#endif |
579 |
-fd_set fds; |
580 |
-struct timeval tv; |
581 |
|
582 |
if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) |
583 |
{ |
584 |
@@ -1805,9 +1803,7 @@ if (connect(fd, (const struct sockaddr *)&sa_un, len) < 0) |
585 |
buf[0] = NOTIFY_QUEUE_SIZE_REQ; |
586 |
if (send(fd, buf, 1, 0) < 0) { where = US"send"; goto bad; } |
587 |
|
588 |
-FD_ZERO(&fds); FD_SET(fd, &fds); |
589 |
-tv.tv_sec = 2; tv.tv_usec = 0; |
590 |
-if (select(fd + 1, (SELECT_ARG2_TYPE *)&fds, NULL, NULL, &tv) != 1) |
591 |
+if (poll_one_fd(fd, POLLIN, 2 * 1000) != 1) |
592 |
{ |
593 |
DEBUG(D_expand) debug_printf("no daemon response; using local evaluation\n"); |
594 |
len = snprintf(CS buf, sizeof(buf), "%u", queue_count_cached()); |
595 |
diff --git a/src/functions.h b/src/functions.h |
596 |
index 3dd890a00..0cf80dfbb 100644 |
597 |
--- a/src/functions.h |
598 |
+++ b/src/functions.h |
599 |
@@ -1255,6 +1255,13 @@ child_open(uschar **argv, uschar **envp, int newumask, int *infdptr, |
600 |
outfdptr, make_leader, purpose); |
601 |
} |
602 |
|
603 |
+static inline int |
604 |
+poll_one_fd(int fd, short pollbits, int tmo_millisec) |
605 |
+{ |
606 |
+struct pollfd p = {.fd = fd, .events = pollbits}; |
607 |
+return poll(&p, 1, tmo_millisec); |
608 |
+} |
609 |
+ |
610 |
# endif /* !COMPILE_UTILITY */ |
611 |
|
612 |
/******************************************************************************/ |
613 |
diff --git a/src/ip.c b/src/ip.c |
614 |
index d83d6f910..aa42343fb 100644 |
615 |
--- a/src/ip.c |
616 |
+++ b/src/ip.c |
617 |
@@ -589,9 +589,7 @@ Returns: TRUE => ready for i/o |
618 |
BOOL |
619 |
fd_ready(int fd, time_t timelimit) |
620 |
{ |
621 |
-fd_set select_inset; |
622 |
-int time_left = timelimit - time(NULL); |
623 |
-int rc; |
624 |
+int rc, time_left = timelimit - time(NULL); |
625 |
|
626 |
if (time_left <= 0) |
627 |
{ |
628 |
@@ -602,12 +600,8 @@ if (time_left <= 0) |
629 |
|
630 |
do |
631 |
{ |
632 |
- struct timeval tv = { .tv_sec = time_left, .tv_usec = 0 }; |
633 |
- FD_ZERO (&select_inset); |
634 |
- FD_SET (fd, &select_inset); |
635 |
- |
636 |
/*DEBUG(D_transport) debug_printf("waiting for data on fd\n");*/ |
637 |
- rc = select(fd + 1, (SELECT_ARG2_TYPE *)&select_inset, NULL, NULL, &tv); |
638 |
+ rc = poll_one_fd(fd, POLLIN, time_left * 1000); |
639 |
|
640 |
/* If some interrupt arrived, just retry. We presume this to be rare, |
641 |
but it can happen (e.g. the SIGUSR1 signal sent by exiwhat causes |
642 |
@@ -636,7 +630,7 @@ do |
643 |
/* Checking the FD_ISSET is not enough, if we're interrupted, the |
644 |
select_inset may still contain the 'input'. */ |
645 |
} |
646 |
-while (rc < 0 || !FD_ISSET(fd, &select_inset)); |
647 |
+while (rc < 0); |
648 |
return TRUE; |
649 |
} |
650 |
|
651 |
diff --git a/src/malware.c b/src/malware.c |
652 |
index 10a390dfa..d9ab3b9dd 100644 |
653 |
--- a/src/malware.c |
654 |
+++ b/src/malware.c |
655 |
@@ -277,11 +277,7 @@ int fd = ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5, |
656 |
/* Under some fault conditions, FreeBSD 12.2 seen to send a (non-TFO) SYN |
657 |
and, getting no response, wait for a long time. Impose a 5s max. */ |
658 |
if (fd >= 0) |
659 |
- { |
660 |
- struct timeval tv = {.tv_sec = 5}; |
661 |
- fd_set fds; |
662 |
- FD_ZERO(&fds); FD_SET(fd, &fds); (void) select(fd+1, NULL, &fds, NULL, &tv); |
663 |
- } |
664 |
+ (void) poll_one_fd(fd, POLLOUT, 5 * 1000); |
665 |
#endif |
666 |
return fd; |
667 |
} |
668 |
diff --git a/src/receive.c b/src/receive.c |
669 |
index fab0f00c4..3adcbbd88 100644 |
670 |
--- a/src/receive.c |
671 |
+++ b/src/receive.c |
672 |
@@ -624,12 +624,8 @@ if (!receive_timeout && !receive_hasc()) |
673 |
if (t.tv_sec > 30*60) |
674 |
mainlog_close(); |
675 |
else |
676 |
- { |
677 |
- fd_set r; |
678 |
- FD_ZERO(&r); FD_SET(0, &r); |
679 |
- t.tv_sec = 30*60 - t.tv_sec; t.tv_usec = 0; |
680 |
- if (select(1, &r, NULL, NULL, &t) == 0) mainlog_close(); |
681 |
- } |
682 |
+ if (poll_one_fd(0, POLLIN, (30*60 - t.tv_sec) * 1000) == 0) |
683 |
+ mainlog_close(); |
684 |
} |
685 |
} |
686 |
|
687 |
@@ -4234,12 +4230,7 @@ response, but the chance of this happening should be small. */ |
688 |
if (smtp_input && sender_host_address && !f.sender_host_notsocket && |
689 |
!receive_smtp_buffered()) |
690 |
{ |
691 |
- struct timeval tv = {.tv_sec = 0, .tv_usec = 0}; |
692 |
- fd_set select_check; |
693 |
- FD_ZERO(&select_check); |
694 |
- FD_SET(fileno(smtp_in), &select_check); |
695 |
- |
696 |
- if (select(fileno(smtp_in) + 1, &select_check, NULL, NULL, &tv) != 0) |
697 |
+ if (poll_one_fd(fileno(smtp_in), POLLIN, 0) != 0) |
698 |
{ |
699 |
int c = (receive_getc)(GETC_BUFFER_UNLIMITED); |
700 |
if (c != EOF) (receive_ungetc)(c); else |
701 |
diff --git a/src/smtp_in.c b/src/smtp_in.c |
702 |
index 824178e4d..7cb966f24 100644 |
703 |
--- a/src/smtp_in.c |
704 |
+++ b/src/smtp_in.c |
705 |
@@ -346,8 +346,6 @@ static BOOL |
706 |
wouldblock_reading(void) |
707 |
{ |
708 |
int fd, rc; |
709 |
-fd_set fds; |
710 |
-struct timeval tzero = {.tv_sec = 0, .tv_usec = 0}; |
711 |
|
712 |
#ifndef DISABLE_TLS |
713 |
if (tls_in.active.sock >= 0) |
714 |
@@ -358,9 +356,7 @@ if (smtp_inptr < smtp_inend) |
715 |
return FALSE; |
716 |
|
717 |
fd = fileno(smtp_in); |
718 |
-FD_ZERO(&fds); |
719 |
-FD_SET(fd, &fds); |
720 |
-rc = select(fd + 1, (SELECT_ARG2_TYPE *)&fds, NULL, NULL, &tzero); |
721 |
+rc = poll_one_fd(fd, POLLIN, 0); |
722 |
|
723 |
if (rc <= 0) return TRUE; /* Not ready to read */ |
724 |
rc = smtp_getc(GETC_BUFFER_UNLIMITED); |
725 |
@@ -3942,16 +3938,8 @@ log_write(L_smtp_connection, LOG_MAIN, "%s closed by QUIT", |
726 |
/* Pause, hoping client will FIN first so that they get the TIME_WAIT. |
727 |
The socket should become readble (though with no data) */ |
728 |
|
729 |
- { |
730 |
- int fd = fileno(smtp_in); |
731 |
- fd_set fds; |
732 |
- struct timeval t_limit = {.tv_sec = 0, .tv_usec = 200*1000}; |
733 |
- |
734 |
- FD_ZERO(&fds); |
735 |
- FD_SET(fd, &fds); |
736 |
- (void) select(fd + 1, (SELECT_ARG2_TYPE *)&fds, NULL, NULL, &t_limit); |
737 |
- } |
738 |
-#endif /*!DAEMON_CLOSE_NOWAIT*/ |
739 |
+(void) poll_one_fd(fileno(smtp_in), POLLIN, 200); |
740 |
+#endif /*!SERVERSIDE_CLOSE_NOWAIT*/ |
741 |
} |
742 |
|
743 |
|
744 |
diff --git a/src/spam.c b/src/spam.c |
745 |
index 470e5fae7..e3316ed96 100644 |
746 |
--- a/src/spam.c |
747 |
+++ b/src/spam.c |
748 |
@@ -194,12 +194,6 @@ uschar *p,*q; |
749 |
int override = 0; |
750 |
time_t start; |
751 |
size_t read, wrote; |
752 |
-#ifndef NO_POLL_H |
753 |
-struct pollfd pollfd; |
754 |
-#else /* Patch posted by Erik ? for OS X */ |
755 |
-struct timeval select_tv; /* and applied by PH */ |
756 |
-fd_set select_fd; |
757 |
-#endif |
758 |
uschar *spamd_address_work; |
759 |
spamd_address_container * sd; |
760 |
|
761 |
@@ -395,19 +389,19 @@ if (wrote == -1) |
762 |
} |
763 |
|
764 |
/* now send the file */ |
765 |
-/* spamd sometimes accepts connections but doesn't read data off |
766 |
- * the connection. We make the file descriptor non-blocking so |
767 |
- * that the write will only write sufficient data without blocking |
768 |
- * and we poll the descriptor to make sure that we can write without |
769 |
- * blocking. Short writes are gracefully handled and if the whole |
770 |
- * transaction takes too long it is aborted. |
771 |
- * Note: poll() is not supported in OSX 10.2 and is reported to be |
772 |
- * broken in more recent versions (up to 10.4). |
773 |
+/* spamd sometimes accepts connections but doesn't read data off the connection. |
774 |
+We make the file descriptor non-blocking so that the write will only write |
775 |
+sufficient data without blocking and we poll the descriptor to make sure that we |
776 |
+can write without blocking. Short writes are gracefully handled and if the |
777 |
+whole transaction takes too long it is aborted. |
778 |
+ |
779 |
+Note: poll() is not supported in OSX 10.2 and is reported to be broken in more |
780 |
+ recent versions (up to 10.4). Workaround using select() removed 2021/11 (jgh). |
781 |
*/ |
782 |
-#ifndef NO_POLL_H |
783 |
-pollfd.fd = spamd_cctx.sock; |
784 |
-pollfd.events = POLLOUT; |
785 |
+#ifdef NO_POLL_H |
786 |
+# error Need poll(2) support |
787 |
#endif |
788 |
+ |
789 |
(void)fcntl(spamd_cctx.sock, F_SETFL, O_NONBLOCK); |
790 |
do |
791 |
{ |
792 |
@@ -416,19 +410,7 @@ do |
793 |
{ |
794 |
offset = 0; |
795 |
again: |
796 |
-#ifndef NO_POLL_H |
797 |
- result = poll(&pollfd, 1, 1000); |
798 |
- |
799 |
-/* Patch posted by Erik ? for OS X and applied by PH */ |
800 |
-#else |
801 |
- select_tv.tv_sec = 1; |
802 |
- select_tv.tv_usec = 0; |
803 |
- FD_ZERO(&select_fd); |
804 |
- FD_SET(spamd_cctx.sock, &select_fd); |
805 |
- result = select(spamd_cctx.sock+1, NULL, &select_fd, NULL, &select_tv); |
806 |
-#endif |
807 |
-/* End Erik's patch */ |
808 |
- |
809 |
+ result = poll_one_fd(spamd_cctx.sock, POLLOUT, 1000); |
810 |
if (result == -1 && errno == EINTR) |
811 |
goto again; |
812 |
else if (result < 1) |
813 |
diff --git a/src/transport.c b/src/transport.c |
814 |
index 8c74030f0..ef523657e 100644 |
815 |
--- a/src/transport.c |
816 |
+++ b/src/transport.c |
817 |
@@ -253,7 +253,6 @@ for (int i = 0; i < 100; i++) |
818 |
|
819 |
for(;;) |
820 |
{ |
821 |
- fd_set fds; |
822 |
/* This code makes use of alarm() in order to implement the timeout. This |
823 |
isn't a very tidy way of doing things. Using non-blocking I/O with select() |
824 |
provides a neater approach. However, I don't know how to do this when TLS is |
825 |
@@ -281,8 +280,7 @@ for (int i = 0; i < 100; i++) |
826 |
if (rc >= 0 || errno != ENOTCONN || connretry <= 0) |
827 |
break; |
828 |
|
829 |
- FD_ZERO(&fds); FD_SET(fd, &fds); |
830 |
- select(fd+1, NULL, &fds, NULL, NULL); /* could set timout? */ |
831 |
+ poll_one_fd(fd, POLLOUT, -1); /* could set timeout? retval check? */ |
832 |
connretry--; |
833 |
} |
834 |
|
835 |
diff --git a/src/transports/smtp.c b/src/transports/smtp.c |
836 |
index d321bd69e..c64bb7010 100644 |
837 |
--- a/src/transports/smtp.c |
838 |
+++ b/src/transports/smtp.c |
839 |
@@ -3550,8 +3550,8 @@ void |
840 |
smtp_proxy_tls(void * ct_ctx, uschar * buf, size_t bsize, int * pfd, |
841 |
int timeout) |
842 |
{ |
843 |
-fd_set rfds, efds; |
844 |
-int max_fd = MAX(pfd[0], tls_out.active.sock) + 1; |
845 |
+struct pollfd p[2] = {{.fd = tls_out.active.sock, .events = POLLIN}, |
846 |
+ {.fd = pfd[0], .events = POLLIN}}; |
847 |
int rc, i; |
848 |
BOOL send_tls_shutdown = TRUE; |
849 |
|
850 |
@@ -3560,23 +3560,16 @@ if ((rc = exim_fork(US"tls-proxy"))) |
851 |
_exit(rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS); |
852 |
|
853 |
set_process_info("proxying TLS connection for continued transport"); |
854 |
-FD_ZERO(&rfds); |
855 |
-FD_SET(tls_out.active.sock, &rfds); |
856 |
-FD_SET(pfd[0], &rfds); |
857 |
|
858 |
-for (int fd_bits = 3; fd_bits; ) |
859 |
+do |
860 |
{ |
861 |
time_t time_left = timeout; |
862 |
time_t time_start = time(NULL); |
863 |
|
864 |
/* wait for data */ |
865 |
- efds = rfds; |
866 |
do |
867 |
{ |
868 |
- struct timeval tv = { time_left, 0 }; |
869 |
- |
870 |
- rc = select(max_fd, |
871 |
- (SELECT_ARG2_TYPE *)&rfds, NULL, (SELECT_ARG2_TYPE *)&efds, &tv); |
872 |
+ rc = poll(p, 2, time_left * 1000); |
873 |
|
874 |
if (rc < 0 && errno == EINTR) |
875 |
if ((time_left -= time(NULL) - time_start) > 0) continue; |
876 |
@@ -3589,23 +3582,22 @@ for (int fd_bits = 3; fd_bits; ) |
877 |
|
878 |
/* For errors where not readable, bomb out */ |
879 |
|
880 |
- if (FD_ISSET(tls_out.active.sock, &efds) || FD_ISSET(pfd[0], &efds)) |
881 |
+ if (p[0].revents & POLLERR || p[1].revents & POLLERR) |
882 |
{ |
883 |
DEBUG(D_transport) debug_printf("select: exceptional cond on %s fd\n", |
884 |
- FD_ISSET(pfd[0], &efds) ? "proxy" : "tls"); |
885 |
- if (!(FD_ISSET(tls_out.active.sock, &rfds) || FD_ISSET(pfd[0], &rfds))) |
886 |
+ p[0].revents & POLLERR ? "tls" : "proxy"); |
887 |
+ if (!(p[0].revents & POLLIN || p[1].events & POLLIN)) |
888 |
goto done; |
889 |
DEBUG(D_transport) debug_printf("- but also readable; no exit yet\n"); |
890 |
} |
891 |
} |
892 |
- while (rc < 0 || !(FD_ISSET(tls_out.active.sock, &rfds) || FD_ISSET(pfd[0], &rfds))); |
893 |
+ while (rc < 0 || !(p[0].revents & POLLIN || p[1].revents & POLLIN)); |
894 |
|
895 |
/* handle inbound data */ |
896 |
- if (FD_ISSET(tls_out.active.sock, &rfds)) |
897 |
+ if (p[0].revents & POLLIN) |
898 |
if ((rc = tls_read(ct_ctx, buf, bsize)) <= 0) /* Expect -1 for EOF; */ |
899 |
{ /* that reaps the TLS Close Notify record */ |
900 |
- fd_bits &= ~1; |
901 |
- FD_CLR(tls_out.active.sock, &rfds); |
902 |
+ p[0].fd = -1; |
903 |
shutdown(pfd[0], SHUT_WR); |
904 |
timeout = 5; |
905 |
} |
906 |
@@ -3616,11 +3608,10 @@ for (int fd_bits = 3; fd_bits; ) |
907 |
/* Handle outbound data. We cannot combine payload and the TLS-close |
908 |
due to the limitations of the (pipe) channel feeding us. Maybe use a unix-domain |
909 |
socket? */ |
910 |
- if (FD_ISSET(pfd[0], &rfds)) |
911 |
+ if (p[1].revents & POLLIN) |
912 |
if ((rc = read(pfd[0], buf, bsize)) <= 0) |
913 |
{ |
914 |
- fd_bits &= ~2; |
915 |
- FD_CLR(pfd[0], &rfds); |
916 |
+ p[1].fd = -1; |
917 |
|
918 |
# ifdef EXIM_TCP_CORK /* Use _CORK to get TLS Close Notify in FIN segment */ |
919 |
(void) setsockopt(tls_out.active.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on)); |
920 |
@@ -3633,10 +3624,8 @@ for (int fd_bits = 3; fd_bits; ) |
921 |
for (int nbytes = 0; rc - nbytes > 0; nbytes += i) |
922 |
if ((i = tls_write(ct_ctx, buf + nbytes, rc - nbytes, FALSE)) < 0) |
923 |
goto done; |
924 |
- |
925 |
- if (fd_bits & 1) FD_SET(tls_out.active.sock, &rfds); |
926 |
- if (fd_bits & 2) FD_SET(pfd[0], &rfds); |
927 |
} |
928 |
+while (p[0].fd >= 0 || p[1].fd >= 0); |
929 |
|
930 |
done: |
931 |
if (send_tls_shutdown) tls_close(ct_ctx, TLS_SHUTDOWN_NOWAIT); |