diff options
Diffstat (limited to 'src/lib/connection_add.c')
-rw-r--r-- | src/lib/connection_add.c | 978 |
1 files changed, 978 insertions, 0 deletions
diff --git a/src/lib/connection_add.c b/src/lib/connection_add.c new file mode 100644 index 00000000..8d4f12ad --- /dev/null +++ b/src/lib/connection_add.c | |||
@@ -0,0 +1,978 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | */ | ||
19 | /** | ||
20 | * @file lib/connection_add.c | ||
21 | * @brief functions to add connection to our active set | ||
22 | * @author Christian Grothoff | ||
23 | */ | ||
24 | #include "internal.h" | ||
25 | #include "connection_add.h" | ||
26 | #include "daemon_ip_limit.h" | ||
27 | |||
28 | |||
29 | /** | ||
30 | * Main function of the thread that handles an individual | ||
31 | * connection when #MHD_USE_THREAD_PER_CONNECTION is set. | ||
32 | * | ||
33 | * @param data the `struct MHD_Connection` this thread will handle | ||
34 | * @return always 0 | ||
35 | */ | ||
36 | static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_ | ||
37 | thread_main_handle_connection (void *data) | ||
38 | { | ||
39 | struct MHD_Connection *con = data; | ||
40 | struct MHD_Daemon *daemon = con->daemon; | ||
41 | int num_ready; | ||
42 | fd_set rs; | ||
43 | fd_set ws; | ||
44 | fd_set es; | ||
45 | MHD_socket maxsock; | ||
46 | struct timeval tv; | ||
47 | struct timeval *tvp; | ||
48 | time_t now; | ||
49 | #if WINDOWS | ||
50 | #ifdef HAVE_POLL | ||
51 | int extra_slot; | ||
52 | #endif /* HAVE_POLL */ | ||
53 | #define EXTRA_SLOTS 1 | ||
54 | #else /* !WINDOWS */ | ||
55 | #define EXTRA_SLOTS 0 | ||
56 | #endif /* !WINDOWS */ | ||
57 | #ifdef HAVE_POLL | ||
58 | struct pollfd p[1 + EXTRA_SLOTS]; | ||
59 | #endif | ||
60 | #undef EXTRA_SLOTS | ||
61 | #ifdef HAVE_POLL | ||
62 | const bool use_poll = (MHD_ELS_POLL == daemon->event_loop_syscall); | ||
63 | #else /* ! HAVE_POLL */ | ||
64 | const bool use_poll = false; | ||
65 | #endif /* ! HAVE_POLL */ | ||
66 | bool was_suspended = false; | ||
67 | |||
68 | MHD_thread_init_(&con->pid); | ||
69 | |||
70 | while ( (! daemon->shutdown) && | ||
71 | (MHD_REQUEST_CLOSED != con->request.state) ) | ||
72 | { | ||
73 | const time_t timeout = daemon->connection_default_timeout; | ||
74 | #ifdef UPGRADE_SUPPORT | ||
75 | struct MHD_UpgradeResponseHandle * const urh = con->request.urh; | ||
76 | #else /* ! UPGRADE_SUPPORT */ | ||
77 | static const void * const urh = NULL; | ||
78 | #endif /* ! UPGRADE_SUPPORT */ | ||
79 | |||
80 | if ( (con->suspended) && | ||
81 | (NULL == urh) ) | ||
82 | { | ||
83 | /* Connection was suspended, wait for resume. */ | ||
84 | was_suspended = true; | ||
85 | if (! use_poll) | ||
86 | { | ||
87 | FD_ZERO (&rs); | ||
88 | if (! MHD_add_to_fd_set_ (MHD_itc_r_fd_ (daemon->itc), | ||
89 | &rs, | ||
90 | NULL, | ||
91 | FD_SETSIZE)) | ||
92 | { | ||
93 | #ifdef HAVE_MESSAGES | ||
94 | MHD_DLOG (con->daemon, | ||
95 | MHD_SC_SOCKET_OUTSIDE_OF_FDSET_RANGE, | ||
96 | _("Failed to add FD to fd_set\n")); | ||
97 | #endif | ||
98 | goto exit; | ||
99 | } | ||
100 | if (0 > MHD_SYS_select_ (MHD_itc_r_fd_ (daemon->itc) + 1, | ||
101 | &rs, | ||
102 | NULL, | ||
103 | NULL, | ||
104 | NULL)) | ||
105 | { | ||
106 | const int err = MHD_socket_get_error_(); | ||
107 | |||
108 | if (MHD_SCKT_ERR_IS_EINTR_(err)) | ||
109 | continue; | ||
110 | #ifdef HAVE_MESSAGES | ||
111 | MHD_DLOG (con->daemon, | ||
112 | MHD_SC_UNEXPECTED_SELECT_ERROR, | ||
113 | _("Error during select (%d): `%s'\n"), | ||
114 | err, | ||
115 | MHD_socket_strerr_ (err)); | ||
116 | #endif | ||
117 | break; | ||
118 | } | ||
119 | } | ||
120 | #ifdef HAVE_POLL | ||
121 | else /* use_poll */ | ||
122 | { | ||
123 | p[0].events = POLLIN; | ||
124 | p[0].fd = MHD_itc_r_fd_ (daemon->itc); | ||
125 | p[0].revents = 0; | ||
126 | if (0 > MHD_sys_poll_ (p, | ||
127 | 1, | ||
128 | -1)) | ||
129 | { | ||
130 | if (MHD_SCKT_LAST_ERR_IS_(MHD_SCKT_EINTR_)) | ||
131 | continue; | ||
132 | #ifdef HAVE_MESSAGES | ||
133 | MHD_DLOG (con->daemon, | ||
134 | MHD_SC_UNEXPECTED_POLL_ERROR, | ||
135 | _("Error during poll: `%s'\n"), | ||
136 | MHD_socket_last_strerr_ ()); | ||
137 | #endif | ||
138 | break; | ||
139 | } | ||
140 | } | ||
141 | #endif /* HAVE_POLL */ | ||
142 | MHD_itc_clear_ (daemon->itc); | ||
143 | continue; /* Check again for resume. */ | ||
144 | } /* End of "suspended" branch. */ | ||
145 | |||
146 | if (was_suspended) | ||
147 | { | ||
148 | MHD_update_last_activity_ (con); /* Reset timeout timer. */ | ||
149 | /* Process response queued during suspend and update states. */ | ||
150 | MHD_connection_handle_idle (con); | ||
151 | was_suspended = false; | ||
152 | } | ||
153 | |||
154 | tvp = NULL; | ||
155 | |||
156 | if ( (MHD_EVENT_LOOP_INFO_BLOCK == con->request.event_loop_info) | ||
157 | #ifdef HTTPS_SUPPORT | ||
158 | || ( (con->tls_read_ready) && | ||
159 | (MHD_EVENT_LOOP_INFO_READ == con->request.event_loop_info) ) | ||
160 | #endif /* HTTPS_SUPPORT */ | ||
161 | ) | ||
162 | { | ||
163 | /* do not block: more data may be inside of TLS buffers waiting or | ||
164 | * application must provide response data */ | ||
165 | tv.tv_sec = 0; | ||
166 | tv.tv_usec = 0; | ||
167 | tvp = &tv; | ||
168 | } | ||
169 | if ( (NULL == tvp) && | ||
170 | (timeout > 0) ) | ||
171 | { | ||
172 | now = MHD_monotonic_sec_counter(); | ||
173 | if (now - con->last_activity > timeout) | ||
174 | tv.tv_sec = 0; | ||
175 | else | ||
176 | { | ||
177 | const time_t seconds_left = timeout - (now - con->last_activity); | ||
178 | #if !defined(_WIN32) || defined(__CYGWIN__) | ||
179 | tv.tv_sec = seconds_left; | ||
180 | #else /* _WIN32 && !__CYGWIN__ */ | ||
181 | if (seconds_left > TIMEVAL_TV_SEC_MAX) | ||
182 | tv.tv_sec = TIMEVAL_TV_SEC_MAX; | ||
183 | else | ||
184 | tv.tv_sec = (_MHD_TIMEVAL_TV_SEC_TYPE) seconds_left; | ||
185 | #endif /* _WIN32 && ! __CYGWIN__ */ | ||
186 | } | ||
187 | tv.tv_usec = 0; | ||
188 | tvp = &tv; | ||
189 | } | ||
190 | if (! use_poll) | ||
191 | { | ||
192 | /* use select */ | ||
193 | bool err_state = false; | ||
194 | |||
195 | FD_ZERO (&rs); | ||
196 | FD_ZERO (&ws); | ||
197 | FD_ZERO (&es); | ||
198 | maxsock = MHD_INVALID_SOCKET; | ||
199 | switch (con->request.event_loop_info) | ||
200 | { | ||
201 | case MHD_EVENT_LOOP_INFO_READ: | ||
202 | if (! MHD_add_to_fd_set_ (con->socket_fd, | ||
203 | &rs, | ||
204 | &maxsock, | ||
205 | FD_SETSIZE)) | ||
206 | err_state = true; | ||
207 | break; | ||
208 | case MHD_EVENT_LOOP_INFO_WRITE: | ||
209 | if (! MHD_add_to_fd_set_ (con->socket_fd, | ||
210 | &ws, | ||
211 | &maxsock, | ||
212 | FD_SETSIZE)) | ||
213 | err_state = true; | ||
214 | break; | ||
215 | case MHD_EVENT_LOOP_INFO_BLOCK: | ||
216 | if (! MHD_add_to_fd_set_ (con->socket_fd, | ||
217 | &es, | ||
218 | &maxsock, | ||
219 | FD_SETSIZE)) | ||
220 | err_state = true; | ||
221 | break; | ||
222 | case MHD_EVENT_LOOP_INFO_CLEANUP: | ||
223 | /* how did we get here!? */ | ||
224 | goto exit; | ||
225 | } | ||
226 | #if WINDOWS | ||
227 | if (MHD_ITC_IS_VALID_(daemon->itc) ) | ||
228 | { | ||
229 | if (! MHD_add_to_fd_set_ (MHD_itc_r_fd_ (daemon->itc), | ||
230 | &rs, | ||
231 | &maxsock, | ||
232 | FD_SETSIZE)) | ||
233 | err_state = 1; | ||
234 | } | ||
235 | #endif | ||
236 | if (err_state) | ||
237 | { | ||
238 | #ifdef HAVE_MESSAGES | ||
239 | MHD_DLOG (con->daemon, | ||
240 | MHD_SC_SOCKET_OUTSIDE_OF_FDSET_RANGE, | ||
241 | _("Failed to add FD to fd_set\n")); | ||
242 | #endif | ||
243 | goto exit; | ||
244 | } | ||
245 | |||
246 | num_ready = MHD_SYS_select_ (maxsock + 1, | ||
247 | &rs, | ||
248 | &ws, | ||
249 | NULL, | ||
250 | tvp); | ||
251 | if (num_ready < 0) | ||
252 | { | ||
253 | const int err = MHD_socket_get_error_(); | ||
254 | |||
255 | if (MHD_SCKT_ERR_IS_EINTR_(err)) | ||
256 | continue; | ||
257 | #ifdef HAVE_MESSAGES | ||
258 | MHD_DLOG (con->daemon, | ||
259 | MHD_SC_UNEXPECTED_SELECT_ERROR, | ||
260 | _("Error during select (%d): `%s'\n"), | ||
261 | err, | ||
262 | MHD_socket_strerr_ (err)); | ||
263 | #endif | ||
264 | break; | ||
265 | } | ||
266 | #if WINDOWS | ||
267 | /* Clear ITC before other processing so additional | ||
268 | * signals will trigger select() again */ | ||
269 | if ( (MHD_ITC_IS_VALID_(daemon->itc)) && | ||
270 | (FD_ISSET (MHD_itc_r_fd_ (daemon->itc), | ||
271 | &rs)) ) | ||
272 | MHD_itc_clear_ (daemon->itc); | ||
273 | #endif | ||
274 | if (MHD_NO == | ||
275 | call_handlers (con, | ||
276 | FD_ISSET (con->socket_fd, | ||
277 | &rs), | ||
278 | FD_ISSET (con->socket_fd, | ||
279 | &ws), | ||
280 | FD_ISSET (con->socket_fd, | ||
281 | &es)) ) | ||
282 | goto exit; | ||
283 | } | ||
284 | #ifdef HAVE_POLL | ||
285 | else | ||
286 | { | ||
287 | /* use poll */ | ||
288 | memset (&p, | ||
289 | 0, | ||
290 | sizeof (p)); | ||
291 | p[0].fd = con->socket_fd; | ||
292 | switch (con->request.event_loop_info) | ||
293 | { | ||
294 | case MHD_EVENT_LOOP_INFO_READ: | ||
295 | p[0].events |= POLLIN | MHD_POLL_EVENTS_ERR_DISC; | ||
296 | break; | ||
297 | case MHD_EVENT_LOOP_INFO_WRITE: | ||
298 | p[0].events |= POLLOUT | MHD_POLL_EVENTS_ERR_DISC; | ||
299 | break; | ||
300 | case MHD_EVENT_LOOP_INFO_BLOCK: | ||
301 | p[0].events |= MHD_POLL_EVENTS_ERR_DISC; | ||
302 | break; | ||
303 | case MHD_EVENT_LOOP_INFO_CLEANUP: | ||
304 | /* how did we get here!? */ | ||
305 | goto exit; | ||
306 | } | ||
307 | #if WINDOWS | ||
308 | extra_slot = 0; | ||
309 | if (MHD_ITC_IS_VALID_(daemon->itc)) | ||
310 | { | ||
311 | p[1].events |= POLLIN; | ||
312 | p[1].fd = MHD_itc_r_fd_ (daemon->itc); | ||
313 | p[1].revents = 0; | ||
314 | extra_slot = 1; | ||
315 | } | ||
316 | #endif | ||
317 | if (MHD_sys_poll_ (p, | ||
318 | #if WINDOWS | ||
319 | 1 + extra_slot, | ||
320 | #else | ||
321 | 1, | ||
322 | #endif | ||
323 | (NULL == tvp) ? -1 : tv.tv_sec * 1000) < 0) | ||
324 | { | ||
325 | if (MHD_SCKT_LAST_ERR_IS_(MHD_SCKT_EINTR_)) | ||
326 | continue; | ||
327 | #ifdef HAVE_MESSAGES | ||
328 | MHD_DLOG (con->daemon, | ||
329 | MHD_SC_UNEXPECTED_POLL_ERROR, | ||
330 | _("Error during poll: `%s'\n"), | ||
331 | MHD_socket_last_strerr_ ()); | ||
332 | #endif | ||
333 | break; | ||
334 | } | ||
335 | #if WINDOWS | ||
336 | /* Clear ITC before other processing so additional | ||
337 | * signals will trigger poll() again */ | ||
338 | if ( (MHD_ITC_IS_VALID_(daemon->itc)) && | ||
339 | (0 != (p[1].revents & (POLLERR | POLLHUP | POLLIN))) ) | ||
340 | MHD_itc_clear_ (daemon->itc); | ||
341 | #endif | ||
342 | if (MHD_NO == | ||
343 | call_handlers (con, | ||
344 | 0 != (p[0].revents & POLLIN), | ||
345 | 0 != (p[0].revents & POLLOUT), | ||
346 | 0 != (p[0].revents & (POLLERR | MHD_POLL_REVENTS_ERR_DISC)))) | ||
347 | goto exit; | ||
348 | } | ||
349 | #endif | ||
350 | #ifdef UPGRADE_SUPPORT | ||
351 | if (MHD_REQUEST_UPGRADE == con->request.state) | ||
352 | { | ||
353 | /* Normal HTTP processing is finished, | ||
354 | * notify application. */ | ||
355 | if ( (NULL != con->request.response->termination_cb) && | ||
356 | (con->request.client_aware) ) | ||
357 | con->request.response->termination_cb | ||
358 | (con->request.response->termination_cb_cls, | ||
359 | MHD_REQUEST_TERMINATED_COMPLETED_OK, | ||
360 | con->request.client_context); | ||
361 | con->request.client_aware = false; | ||
362 | |||
363 | thread_main_connection_upgrade (con); | ||
364 | /* MHD_connection_finish_forward_() was called by thread_main_connection_upgrade(). */ | ||
365 | |||
366 | /* "Upgraded" data will not be used in this thread from this point. */ | ||
367 | con->request.urh->clean_ready = true; | ||
368 | /* If 'urh->was_closed' set to true, connection will be | ||
369 | * moved immediately to cleanup list. Otherwise connection | ||
370 | * will stay in suspended list until 'urh' will be marked | ||
371 | * with 'was_closed' by application. */ | ||
372 | MHD_resume_connection (con); | ||
373 | |||
374 | /* skip usual clean up */ | ||
375 | return (MHD_THRD_RTRN_TYPE_) 0; | ||
376 | } | ||
377 | #endif /* UPGRADE_SUPPORT */ | ||
378 | } | ||
379 | if (MHD_REQUEST_IN_CLEANUP != con->request.state) | ||
380 | { | ||
381 | #if DEBUG_CLOSE | ||
382 | #ifdef HAVE_MESSAGES | ||
383 | MHD_DLOG (con->daemon, | ||
384 | MHD_SC_THREAD_TERMINATING, | ||
385 | _("Processing thread terminating. Closing connection\n")); | ||
386 | #endif | ||
387 | #endif | ||
388 | if (MHD_REQUEST_CLOSED != con->request.state) | ||
389 | MHD_connection_close_ (con, | ||
390 | (daemon->shutdown) ? | ||
391 | MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN: | ||
392 | MHD_REQUEST_TERMINATED_WITH_ERROR); | ||
393 | MHD_connection_handle_idle (con); | ||
394 | } | ||
395 | exit: | ||
396 | if (NULL != con->request.response) | ||
397 | { | ||
398 | MHD_response_queue_for_destroy (con->request.response); | ||
399 | con->request.response = NULL; | ||
400 | } | ||
401 | |||
402 | if (MHD_INVALID_SOCKET != con->socket_fd) | ||
403 | { | ||
404 | shutdown (con->socket_fd, | ||
405 | SHUT_WR); | ||
406 | /* 'socket_fd' can be used in other thread to signal shutdown. | ||
407 | * To avoid data races, do not close socket here. Daemon will | ||
408 | * use more connections only after cleanup anyway. */ | ||
409 | } | ||
410 | return (MHD_THRD_RTRN_TYPE_) 0; | ||
411 | } | ||
412 | |||
413 | |||
414 | /** | ||
415 | * Add another client connection to the set of connections | ||
416 | * managed by MHD. This API is usually not needed (since | ||
417 | * MHD will accept inbound connections on the server socket). | ||
418 | * Use this API in special cases, for example if your HTTP | ||
419 | * server is behind NAT and needs to connect out to the | ||
420 | * HTTP client. | ||
421 | * | ||
422 | * The given client socket will be managed (and closed!) by MHD after | ||
423 | * this call and must no longer be used directly by the application | ||
424 | * afterwards. | ||
425 | * | ||
426 | * @param daemon daemon that manages the connection | ||
427 | * @param client_socket socket to manage (MHD will expect | ||
428 | * to receive an HTTP request from this socket next). | ||
429 | * @param addr IP address of the client | ||
430 | * @param addrlen number of bytes in @a addr | ||
431 | * @param external_add perform additional operations needed due | ||
432 | * to the application calling us directly | ||
433 | * @param non_blck indicate that socket in non-blocking mode | ||
434 | * @return #MHD_SC_OK on success | ||
435 | */ | ||
436 | static enum MHD_StatusCode | ||
437 | internal_add_connection (struct MHD_Daemon *daemon, | ||
438 | MHD_socket client_socket, | ||
439 | const struct sockaddr *addr, | ||
440 | socklen_t addrlen, | ||
441 | bool external_add, | ||
442 | bool non_blck) | ||
443 | { | ||
444 | enum MHD_StatusCode sc; | ||
445 | struct MHD_Connection *connection; | ||
446 | int eno = 0; | ||
447 | |||
448 | /* Direct add to master daemon could happen only with "external" add mode. */ | ||
449 | mhd_assert ( (NULL == daemon->worker_pool) || | ||
450 | (external_add) ); | ||
451 | if ( (external_add) && | ||
452 | (NULL != daemon->worker_pool) ) | ||
453 | { | ||
454 | unsigned int i; | ||
455 | |||
456 | /* have a pool, try to find a pool with capacity; we use the | ||
457 | socket as the initial offset into the pool for load | ||
458 | balancing */ | ||
459 | for (i = 0; i < daemon->worker_pool_size; ++i) | ||
460 | { | ||
461 | struct MHD_Daemon * const worker = | ||
462 | &daemon->worker_pool[(i + client_socket) % daemon->worker_pool_size]; | ||
463 | if (worker->connections < worker->global_connection_limit) | ||
464 | return internal_add_connection (worker, | ||
465 | client_socket, | ||
466 | addr, | ||
467 | addrlen, | ||
468 | true, | ||
469 | non_blck); | ||
470 | } | ||
471 | /* all pools are at their connection limit, must refuse */ | ||
472 | MHD_socket_close_chk_ (client_socket); | ||
473 | #if ENFILE | ||
474 | errno = ENFILE; | ||
475 | #endif | ||
476 | return MHD_SC_LIMIT_CONNECTIONS_REACHED; | ||
477 | } | ||
478 | |||
479 | if ( (! MHD_SCKT_FD_FITS_FDSET_(client_socket, | ||
480 | NULL)) && | ||
481 | (MHD_ELS_SELECT == daemon->event_loop_syscall) ) | ||
482 | { | ||
483 | #ifdef HAVE_MESSAGES | ||
484 | MHD_DLOG (daemon, | ||
485 | MHD_SC_SOCKET_OUTSIDE_OF_FDSET_RANGE, | ||
486 | _("Socket descriptor larger than FD_SETSIZE: %d > %d\n"), | ||
487 | (int) client_socket, | ||
488 | (int) FD_SETSIZE); | ||
489 | #endif | ||
490 | MHD_socket_close_chk_ (client_socket); | ||
491 | #if EINVAL | ||
492 | errno = EINVAL; | ||
493 | #endif | ||
494 | return MHD_SC_SOCKET_OUTSIDE_OF_FDSET_RANGE; | ||
495 | } | ||
496 | |||
497 | #ifdef MHD_socket_nosignal_ | ||
498 | if (! MHD_socket_nosignal_ (client_socket)) | ||
499 | { | ||
500 | #ifdef HAVE_MESSAGES | ||
501 | MHD_DLOG (daemon, | ||
502 | MHD_SC_ACCEPT_CONFIGURE_NOSIGPIPE_FAILED, | ||
503 | _("Failed to set SO_NOSIGPIPE on accepted socket: %s\n"), | ||
504 | MHD_socket_last_strerr_()); | ||
505 | #endif | ||
506 | #ifndef MSG_NOSIGNAL | ||
507 | /* Cannot use socket as it can produce SIGPIPE. */ | ||
508 | #ifdef ENOTSOCK | ||
509 | errno = ENOTSOCK; | ||
510 | #endif /* ENOTSOCK */ | ||
511 | return MHD_SC_ACCEPT_CONFIGURE_NOSIGPIPE_FAILED; | ||
512 | #endif /* ! MSG_NOSIGNAL */ | ||
513 | } | ||
514 | #endif /* MHD_socket_nosignal_ */ | ||
515 | |||
516 | |||
517 | #ifdef HAVE_MESSAGES | ||
518 | #if DEBUG_CONNECT | ||
519 | MHD_DLOG (daemon, | ||
520 | MHD_SC_CONNECTION_ACCEPTED, | ||
521 | _("Accepted connection on socket %d\n"), | ||
522 | client_socket); | ||
523 | #endif | ||
524 | #endif | ||
525 | if ( (daemon->connections == daemon->global_connection_limit) || | ||
526 | (MHD_NO == MHD_ip_limit_add (daemon, | ||
527 | addr, | ||
528 | addrlen)) ) | ||
529 | { | ||
530 | /* above connection limit - reject */ | ||
531 | #ifdef HAVE_MESSAGES | ||
532 | MHD_DLOG (daemon, | ||
533 | MHD_SC_LIMIT_CONNECTIONS_REACHED, | ||
534 | _("Server reached connection limit. Closing inbound connection.\n")); | ||
535 | #endif | ||
536 | MHD_socket_close_chk_ (client_socket); | ||
537 | #if ENFILE | ||
538 | errno = ENFILE; | ||
539 | #endif | ||
540 | return MHD_SC_LIMIT_CONNECTIONS_REACHED; | ||
541 | } | ||
542 | |||
543 | /* apply connection acceptance policy if present */ | ||
544 | if ( (NULL != daemon->accept_policy_cb) && | ||
545 | (MHD_NO == | ||
546 | daemon->accept_policy_cb (daemon->accept_policy_cb_cls, | ||
547 | addr, | ||
548 | addrlen)) ) | ||
549 | { | ||
550 | #if DEBUG_CLOSE | ||
551 | #ifdef HAVE_MESSAGES | ||
552 | MHD_DLOG (daemon, | ||
553 | MHD_SC_ACCEPT_POLICY_REJECTED, | ||
554 | _("Connection rejected by application. Closing connection.\n")); | ||
555 | #endif | ||
556 | #endif | ||
557 | MHD_socket_close_chk_ (client_socket); | ||
558 | MHD_ip_limit_del (daemon, | ||
559 | addr, | ||
560 | addrlen); | ||
561 | #if EACCESS | ||
562 | errno = EACCESS; | ||
563 | #endif | ||
564 | return MHD_SC_ACCEPT_POLICY_REJECTED; | ||
565 | } | ||
566 | |||
567 | if (NULL == | ||
568 | (connection = MHD_calloc_ (1, | ||
569 | sizeof (struct MHD_Connection)))) | ||
570 | { | ||
571 | eno = errno; | ||
572 | #ifdef HAVE_MESSAGES | ||
573 | MHD_DLOG (daemon, | ||
574 | MHD_SC_CONNECTION_MALLOC_FAILURE, | ||
575 | "Error allocating memory: %s\n", | ||
576 | MHD_strerror_ (errno)); | ||
577 | #endif | ||
578 | MHD_socket_close_chk_ (client_socket); | ||
579 | MHD_ip_limit_del (daemon, | ||
580 | addr, | ||
581 | addrlen); | ||
582 | errno = eno; | ||
583 | return MHD_SC_CONNECTION_MALLOC_FAILURE; | ||
584 | } | ||
585 | connection->request.pool | ||
586 | = MHD_pool_create (daemon->connection_memory_limit_b); | ||
587 | if (NULL == connection->request.pool) | ||
588 | { | ||
589 | #ifdef HAVE_MESSAGES | ||
590 | MHD_DLOG (daemon, | ||
591 | MHD_SC_POOL_MALLOC_FAILURE, | ||
592 | _("Error allocating memory: %s\n"), | ||
593 | MHD_strerror_ (errno)); | ||
594 | #endif | ||
595 | MHD_socket_close_chk_ (client_socket); | ||
596 | MHD_ip_limit_del (daemon, | ||
597 | addr, | ||
598 | addrlen); | ||
599 | free (connection); | ||
600 | #if ENOMEM | ||
601 | errno = ENOMEM; | ||
602 | #endif | ||
603 | return MHD_SC_POOL_MALLOC_FAILURE; | ||
604 | } | ||
605 | |||
606 | connection->connection_timeout = daemon->connection_default_timeout; | ||
607 | memcpy (&connection->addr, | ||
608 | addr, | ||
609 | addrlen); | ||
610 | connection->addr_len = addrlen; | ||
611 | connection->socket_fd = client_socket; | ||
612 | connection->sk_nonblck = non_blck; | ||
613 | connection->daemon = daemon; | ||
614 | connection->last_activity = MHD_monotonic_sec_counter(); | ||
615 | |||
616 | #ifdef HTTPS_SUPPORT | ||
617 | if (NULL != daemon->tls_api) | ||
618 | { | ||
619 | connection->tls_cs | ||
620 | = daemon->tls_api->setup_connection (daemon->tls_api->cls, | ||
621 | NULL /* FIXME */); | ||
622 | if (NULL == connection->tls_cs) | ||
623 | { | ||
624 | eno = EINVAL; | ||
625 | sc = -1; // FIXME! | ||
626 | goto cleanup; | ||
627 | } | ||
628 | } | ||
629 | else | ||
630 | #endif /* ! HTTPS_SUPPORT */ | ||
631 | /* set default connection handlers */ | ||
632 | MHD_set_http_callbacks_ (connection); | ||
633 | |||
634 | MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); | ||
635 | /* Firm check under lock. */ | ||
636 | if (daemon->connections >= daemon->global_connection_limit) | ||
637 | { | ||
638 | MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); | ||
639 | /* above connection limit - reject */ | ||
640 | #ifdef HAVE_MESSAGES | ||
641 | MHD_DLOG (daemon, | ||
642 | MHD_SC_LIMIT_CONNECTIONS_REACHED, | ||
643 | _("Server reached connection limit. Closing inbound connection.\n")); | ||
644 | #endif | ||
645 | #if ENFILE | ||
646 | eno = ENFILE; | ||
647 | #endif | ||
648 | sc = MHD_SC_LIMIT_CONNECTIONS_REACHED; | ||
649 | goto cleanup; | ||
650 | } | ||
651 | daemon->connections++; | ||
652 | if (MHD_TM_THREAD_PER_CONNECTION != daemon->threading_model) | ||
653 | { | ||
654 | XDLL_insert (daemon->normal_timeout_head, | ||
655 | daemon->normal_timeout_tail, | ||
656 | connection); | ||
657 | } | ||
658 | DLL_insert (daemon->connections_head, | ||
659 | daemon->connections_tail, | ||
660 | connection); | ||
661 | MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); | ||
662 | |||
663 | if (NULL != daemon->notify_connection_cb) | ||
664 | daemon->notify_connection_cb (daemon->notify_connection_cb_cls, | ||
665 | connection, | ||
666 | MHD_CONNECTION_NOTIFY_STARTED); | ||
667 | |||
668 | /* attempt to create handler thread */ | ||
669 | if (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_model) | ||
670 | { | ||
671 | if (! MHD_create_named_thread_ (&connection->pid, | ||
672 | "MHD-connection", | ||
673 | daemon->thread_stack_limit_b, | ||
674 | &thread_main_handle_connection, | ||
675 | connection)) | ||
676 | { | ||
677 | eno = errno; | ||
678 | #ifdef HAVE_MESSAGES | ||
679 | MHD_DLOG (daemon, | ||
680 | MHD_SC_THREAD_LAUNCH_FAILURE, | ||
681 | "Failed to create a thread: %s\n", | ||
682 | MHD_strerror_ (eno)); | ||
683 | #endif | ||
684 | sc = MHD_SC_THREAD_LAUNCH_FAILURE; | ||
685 | goto cleanup; | ||
686 | } | ||
687 | } | ||
688 | else | ||
689 | { | ||
690 | connection->pid = daemon->pid; | ||
691 | } | ||
692 | #ifdef EPOLL_SUPPORT | ||
693 | if (MHD_ELS_EPOLL == daemon->event_loop_syscall) | ||
694 | { | ||
695 | if ( (! daemon->enable_turbo) || | ||
696 | (external_add)) | ||
697 | { /* Do not manipulate EReady DL-list in 'external_add' mode. */ | ||
698 | struct epoll_event event; | ||
699 | |||
700 | event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET; | ||
701 | event.data.ptr = connection; | ||
702 | if (0 != epoll_ctl (daemon->epoll_fd, | ||
703 | EPOLL_CTL_ADD, | ||
704 | client_socket, | ||
705 | &event)) | ||
706 | { | ||
707 | eno = errno; | ||
708 | #ifdef HAVE_MESSAGES | ||
709 | MHD_DLOG (daemon, | ||
710 | MHD_SC_EPOLL_CTL_ADD_FAILED, | ||
711 | _("Call to epoll_ctl failed: %s\n"), | ||
712 | MHD_socket_last_strerr_ ()); | ||
713 | #endif | ||
714 | sc = MHD_SC_EPOLL_CTL_ADD_FAILED; | ||
715 | goto cleanup; | ||
716 | } | ||
717 | connection->epoll_state |= MHD_EPOLL_STATE_IN_EPOLL_SET; | ||
718 | } | ||
719 | else | ||
720 | { | ||
721 | connection->epoll_state |= MHD_EPOLL_STATE_READ_READY | MHD_EPOLL_STATE_WRITE_READY | ||
722 | | MHD_EPOLL_STATE_IN_EREADY_EDLL; | ||
723 | EDLL_insert (daemon->eready_head, | ||
724 | daemon->eready_tail, | ||
725 | connection); | ||
726 | } | ||
727 | } | ||
728 | else /* This 'else' is combined with next 'if'. */ | ||
729 | #endif | ||
730 | if ( (MHD_TM_THREAD_PER_CONNECTION != daemon->threading_model) && | ||
731 | (external_add) && | ||
732 | (MHD_ITC_IS_VALID_(daemon->itc)) && | ||
733 | (! MHD_itc_activate_ (daemon->itc, | ||
734 | "n")) ) | ||
735 | { | ||
736 | #ifdef HAVE_MESSAGES | ||
737 | MHD_DLOG (daemon, | ||
738 | MHD_SC_ITC_USE_FAILED, | ||
739 | _("Failed to signal new connection via inter-thread communication channel.")); | ||
740 | #endif | ||
741 | sc = MHD_SC_ITC_USE_FAILED; | ||
742 | } | ||
743 | return MHD_SC_OK; | ||
744 | |||
745 | cleanup: | ||
746 | if (NULL != daemon->notify_connection_cb) | ||
747 | daemon->notify_connection_cb (daemon->notify_connection_cb_cls, | ||
748 | connection, | ||
749 | MHD_CONNECTION_NOTIFY_CLOSED); | ||
750 | #ifdef HTTPS_SUPPORT | ||
751 | if (NULL != connection->tls_cs) | ||
752 | daemon->tls_api->teardown_connection (daemon->tls_api->cls, | ||
753 | connection->tls_cs); | ||
754 | #endif /* HTTPS_SUPPORT */ | ||
755 | MHD_socket_close_chk_ (client_socket); | ||
756 | MHD_ip_limit_del (daemon, | ||
757 | addr, | ||
758 | addrlen); | ||
759 | MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); | ||
760 | if (MHD_TM_THREAD_PER_CONNECTION != daemon->threading_model) | ||
761 | { | ||
762 | XDLL_remove (daemon->normal_timeout_head, | ||
763 | daemon->normal_timeout_tail, | ||
764 | connection); | ||
765 | } | ||
766 | DLL_remove (daemon->connections_head, | ||
767 | daemon->connections_tail, | ||
768 | connection); | ||
769 | MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); | ||
770 | MHD_pool_destroy (connection->request.pool); | ||
771 | free (connection); | ||
772 | if (0 != eno) | ||
773 | errno = eno; | ||
774 | else | ||
775 | errno = EINVAL; | ||
776 | return sc; | ||
777 | } | ||
778 | |||
779 | |||
780 | /** | ||
781 | * Add another client connection to the set of connections managed by | ||
782 | * MHD. This API is usually not needed (since MHD will accept inbound | ||
783 | * connections on the server socket). Use this API in special cases, | ||
784 | * for example if your HTTP server is behind NAT and needs to connect | ||
785 | * out to the HTTP client, or if you are building a proxy. | ||
786 | * | ||
787 | * If you use this API in conjunction with a internal select or a | ||
788 | * thread pool, you must set the option #MHD_USE_ITC to ensure that | ||
789 | * the freshly added connection is immediately processed by MHD. | ||
790 | * | ||
791 | * The given client socket will be managed (and closed!) by MHD after | ||
792 | * this call and must no longer be used directly by the application | ||
793 | * afterwards. | ||
794 | * | ||
795 | * @param daemon daemon that manages the connection | ||
796 | * @param client_socket socket to manage (MHD will expect | ||
797 | * to receive an HTTP request from this socket next). | ||
798 | * @param addr IP address of the client | ||
799 | * @param addrlen number of bytes in @a addr | ||
800 | * @return #MHD_YES on success, #MHD_NO if this daemon could | ||
801 | * not handle the connection (i.e. malloc() failed, etc). | ||
802 | * The socket will be closed in any case; `errno` is | ||
803 | * set to indicate further details about the error. | ||
804 | * @ingroup specialized | ||
805 | */ | ||
806 | enum MHD_StatusCode | ||
807 | MHD_daemon_add_connection (struct MHD_Daemon *daemon, | ||
808 | MHD_socket client_socket, | ||
809 | const struct sockaddr *addr, | ||
810 | socklen_t addrlen) | ||
811 | { | ||
812 | bool sk_nonbl; | ||
813 | |||
814 | if (! MHD_socket_nonblocking_ (client_socket)) | ||
815 | { | ||
816 | #ifdef HAVE_MESSAGES | ||
817 | MHD_DLOG (daemon, | ||
818 | MHD_SC_ACCEPT_CONFIGURE_NONBLOCKING_FAILED, | ||
819 | _("Failed to set nonblocking mode on new client socket: %s\n"), | ||
820 | MHD_socket_last_strerr_()); | ||
821 | #endif | ||
822 | sk_nonbl = false; | ||
823 | } | ||
824 | else | ||
825 | { | ||
826 | sk_nonbl = true; | ||
827 | } | ||
828 | |||
829 | if ( (daemon->enable_turbo) && | ||
830 | (! MHD_socket_noninheritable_ (client_socket)) ) | ||
831 | { | ||
832 | #ifdef HAVE_MESSAGES | ||
833 | MHD_DLOG (daemon, | ||
834 | MHD_SC_ACCEPT_CONFIGURE_NOINHERIT_FAILED, | ||
835 | _("Failed to set noninheritable mode on new client socket.\n")); | ||
836 | #endif | ||
837 | } | ||
838 | return internal_add_connection (daemon, | ||
839 | client_socket, | ||
840 | addr, | ||
841 | addrlen, | ||
842 | true, | ||
843 | sk_nonbl); | ||
844 | } | ||
845 | |||
846 | |||
847 | /** | ||
848 | * Accept an incoming connection and create the MHD_Connection object | ||
849 | * for it. This function also enforces policy by way of checking with | ||
850 | * the accept policy callback. @remark To be called only from thread | ||
851 | * that process daemon's select()/poll()/etc. | ||
852 | * | ||
853 | * @param daemon handle with the listen socket | ||
854 | * @return #MHD_SC_OK on success | ||
855 | */ | ||
856 | enum MHD_StatusCode | ||
857 | MHD_accept_connection_ (struct MHD_Daemon *daemon) | ||
858 | { | ||
859 | struct sockaddr_storage addrstorage; | ||
860 | struct sockaddr *addr = (struct sockaddr *) &addrstorage; | ||
861 | socklen_t addrlen; | ||
862 | MHD_socket s; | ||
863 | MHD_socket fd; | ||
864 | bool sk_nonbl; | ||
865 | |||
866 | addrlen = sizeof (addrstorage); | ||
867 | memset (addr, | ||
868 | 0, | ||
869 | sizeof (addrstorage)); | ||
870 | if ( (MHD_INVALID_SOCKET == (fd = daemon->listen_socket)) || | ||
871 | (daemon->was_quiesced) ) | ||
872 | return MHD_SC_DAEMON_ALREADY_QUIESCED; | ||
873 | #ifdef USE_ACCEPT4 | ||
874 | s = accept4 (fd, | ||
875 | addr, | ||
876 | &addrlen, | ||
877 | MAYBE_SOCK_CLOEXEC | MAYBE_SOCK_NONBLOCK); | ||
878 | sk_nonbl = (0 != MAYBE_SOCK_NONBLOCK); | ||
879 | #else /* ! USE_ACCEPT4 */ | ||
880 | s = accept (fd, | ||
881 | addr, | ||
882 | &addrlen); | ||
883 | sk_nonbl = false; | ||
884 | #endif /* ! USE_ACCEPT4 */ | ||
885 | if ( (MHD_INVALID_SOCKET == s) || | ||
886 | (addrlen <= 0) ) | ||
887 | { | ||
888 | const int err = MHD_socket_get_error_ (); | ||
889 | |||
890 | /* This could be a common occurance with multiple worker threads */ | ||
891 | if (MHD_SCKT_ERR_IS_ (err, | ||
892 | MHD_SCKT_EINVAL_)) | ||
893 | return MHD_SC_DAEMON_ALREADY_SHUTDOWN; /* can happen during shutdown, let's hope this is the cause... */ | ||
894 | if (MHD_SCKT_ERR_IS_DISCNN_BEFORE_ACCEPT_(err)) | ||
895 | return MHD_SC_ACCEPT_FAST_DISCONNECT; /* do not print error if client just disconnected early */ | ||
896 | if (MHD_SCKT_ERR_IS_EAGAIN_ (err) ) | ||
897 | return MHD_SC_ACCEPT_FAILED_EAGAIN; | ||
898 | if (MHD_INVALID_SOCKET != s) | ||
899 | { | ||
900 | MHD_socket_close_chk_ (s); | ||
901 | } | ||
902 | if ( MHD_SCKT_ERR_IS_LOW_RESOURCES_ (err) ) | ||
903 | { | ||
904 | /* system/process out of resources */ | ||
905 | if (0 == daemon->connections) | ||
906 | { | ||
907 | #ifdef HAVE_MESSAGES | ||
908 | /* Not setting 'at_limit' flag, as there is no way it | ||
909 | would ever be cleared. Instead trying to produce | ||
910 | bit fat ugly warning. */ | ||
911 | MHD_DLOG (daemon, | ||
912 | MHD_SC_ACCEPT_SYSTEM_LIMIT_REACHED_INSTANTLY, | ||
913 | _("Hit process or system resource limit at FIRST connection. This is really bad as there is no sane way to proceed. Will try busy waiting for system resources to become magically available.\n")); | ||
914 | #endif | ||
915 | return MHD_SC_ACCEPT_SYSTEM_LIMIT_REACHED_INSTANTLY; | ||
916 | } | ||
917 | else | ||
918 | { | ||
919 | MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); | ||
920 | daemon->at_limit = true; | ||
921 | MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); | ||
922 | #ifdef HAVE_MESSAGES | ||
923 | MHD_DLOG (daemon, | ||
924 | MHD_SC_ACCEPT_SYSTEM_LIMIT_REACHED, | ||
925 | _("Hit process or system resource limit at %u connections, temporarily suspending accept(). Consider setting a lower MHD_OPTION_CONNECTION_LIMIT.\n"), | ||
926 | (unsigned int) daemon->connections); | ||
927 | #endif | ||
928 | return MHD_SC_ACCEPT_SYSTEM_LIMIT_REACHED; | ||
929 | } | ||
930 | } | ||
931 | #ifdef HAVE_MESSAGES | ||
932 | MHD_DLOG (daemon, | ||
933 | MHD_SC_ACCEPT_FAILED_UNEXPECTEDLY, | ||
934 | _("Error accepting connection: %s\n"), | ||
935 | MHD_socket_strerr_(err)); | ||
936 | #endif | ||
937 | return MHD_SC_ACCEPT_FAILED_UNEXPECTEDLY; | ||
938 | } | ||
939 | #if !defined(USE_ACCEPT4) || !defined(HAVE_SOCK_NONBLOCK) | ||
940 | if (! MHD_socket_nonblocking_ (s)) | ||
941 | { | ||
942 | #ifdef HAVE_MESSAGES | ||
943 | MHD_DLOG (daemon, | ||
944 | MHD_SC_ACCEPT_CONFIGURE_NONBLOCKING_FAILED, | ||
945 | _("Failed to set nonblocking mode on incoming connection socket: %s\n"), | ||
946 | MHD_socket_last_strerr_()); | ||
947 | #endif | ||
948 | } | ||
949 | else | ||
950 | sk_nonbl = true; | ||
951 | #endif /* !USE_ACCEPT4 || !HAVE_SOCK_NONBLOCK */ | ||
952 | #if !defined(USE_ACCEPT4) || !defined(SOCK_CLOEXEC) | ||
953 | if (! MHD_socket_noninheritable_ (s)) | ||
954 | { | ||
955 | #ifdef HAVE_MESSAGES | ||
956 | MHD_DLOG (daemon, | ||
957 | MHD_SC_ACCEPT_CONFIGURE_NOINHERIT_FAILED, | ||
958 | _("Failed to set noninheritable mode on incoming connection socket.\n")); | ||
959 | #endif | ||
960 | } | ||
961 | #endif /* !USE_ACCEPT4 || !SOCK_CLOEXEC */ | ||
962 | #ifdef HAVE_MESSAGES | ||
963 | #if DEBUG_CONNECT | ||
964 | MHD_DLOG (daemon, | ||
965 | MHD_SC_CONNECTION_ACCEPTED, | ||
966 | _("Accepted connection on socket %d\n"), | ||
967 | s); | ||
968 | #endif | ||
969 | #endif | ||
970 | return internal_add_connection (daemon, | ||
971 | s, | ||
972 | addr, | ||
973 | addrlen, | ||
974 | false, | ||
975 | sk_nonbl); | ||
976 | } | ||
977 | |||
978 | /* end of connection_add.c */ | ||