diff options
Diffstat (limited to 'src/daemon')
-rw-r--r-- | src/daemon/connection.c | 225 | ||||
-rw-r--r-- | src/daemon/connection_https.c | 55 | ||||
-rw-r--r-- | src/daemon/daemon.c | 289 | ||||
-rw-r--r-- | src/daemon/internal.h | 85 |
4 files changed, 380 insertions, 274 deletions
diff --git a/src/daemon/connection.c b/src/daemon/connection.c index 33571ea9..54cbb17d 100644 --- a/src/daemon/connection.c +++ b/src/daemon/connection.c | |||
@@ -275,6 +275,7 @@ need_100_continue (struct MHD_Connection *connection) | |||
275 | strlen (HTTP_100_CONTINUE))); | 275 | strlen (HTTP_100_CONTINUE))); |
276 | } | 276 | } |
277 | 277 | ||
278 | |||
278 | /** | 279 | /** |
279 | * Close the given connection and give the | 280 | * Close the given connection and give the |
280 | * specified termination code to the user. | 281 | * specified termination code to the user. |
@@ -283,31 +284,52 @@ void | |||
283 | MHD_connection_close (struct MHD_Connection *connection, | 284 | MHD_connection_close (struct MHD_Connection *connection, |
284 | enum MHD_RequestTerminationCode termination_code) | 285 | enum MHD_RequestTerminationCode termination_code) |
285 | { | 286 | { |
287 | struct MHD_Daemon *daemon; | ||
288 | |||
289 | daemon = connection->daemon; | ||
286 | SHUTDOWN (connection->socket_fd, SHUT_RDWR); | 290 | SHUTDOWN (connection->socket_fd, SHUT_RDWR); |
287 | CLOSE (connection->socket_fd); | ||
288 | connection->socket_fd = -1; | ||
289 | connection->state = MHD_CONNECTION_CLOSED; | 291 | connection->state = MHD_CONNECTION_CLOSED; |
290 | if ( (NULL != connection->daemon->notify_completed) && | 292 | if ( (NULL != daemon->notify_completed) && |
291 | (MHD_YES == connection->client_aware) ) | 293 | (MHD_YES == connection->client_aware) ) |
292 | connection->daemon->notify_completed (connection->daemon-> | 294 | daemon->notify_completed (daemon->notify_completed_cls, |
293 | notify_completed_cls, connection, | 295 | connection, |
294 | &connection->client_context, | 296 | &connection->client_context, |
295 | termination_code); | 297 | termination_code); |
296 | connection->client_aware = MHD_NO; | 298 | connection->client_aware = MHD_NO; |
297 | } | 299 | } |
298 | 300 | ||
301 | |||
299 | /** | 302 | /** |
300 | * A serious error occured, close the | 303 | * A serious error occured, close the |
301 | * connection (and notify the application). | 304 | * connection (and notify the application). |
305 | * | ||
306 | * @param connection connection to close with error | ||
307 | * @param emsg error message (can be NULL) | ||
302 | */ | 308 | */ |
303 | static void | 309 | static void |
304 | connection_close_error (struct MHD_Connection *connection) | 310 | connection_close_error (struct MHD_Connection *connection, |
311 | const char *emsg) | ||
305 | { | 312 | { |
313 | #if HAVE_MESSAGES | ||
314 | if (NULL != emsg) | ||
315 | MHD_DLOG (connection->daemon, emsg); | ||
316 | #endif | ||
306 | MHD_connection_close (connection, MHD_REQUEST_TERMINATED_WITH_ERROR); | 317 | MHD_connection_close (connection, MHD_REQUEST_TERMINATED_WITH_ERROR); |
307 | } | 318 | } |
308 | 319 | ||
309 | 320 | ||
310 | /** | 321 | /** |
322 | * Macro to only include error message in call to | ||
323 | * "connection_close_error" if we have HAVE_MESSAGES. | ||
324 | */ | ||
325 | #if HAVE_MESSAGES | ||
326 | #define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, emsg) | ||
327 | #else | ||
328 | #define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, NULL) | ||
329 | #endif | ||
330 | |||
331 | |||
332 | /** | ||
311 | * Prepare the response buffer of this connection for | 333 | * Prepare the response buffer of this connection for |
312 | * sending. Assumes that the response mutex is | 334 | * sending. Assumes that the response mutex is |
313 | * already held. If the transmission is complete, | 335 | * already held. If the transmission is complete, |
@@ -357,16 +379,12 @@ try_ready_normal_body (struct MHD_Connection *connection) | |||
357 | if ( (ret == MHD_CONTENT_READER_END_OF_STREAM) || | 379 | if ( (ret == MHD_CONTENT_READER_END_OF_STREAM) || |
358 | (ret == MHD_CONTENT_READER_END_WITH_ERROR) ) | 380 | (ret == MHD_CONTENT_READER_END_WITH_ERROR) ) |
359 | { | 381 | { |
360 | /* either error or http 1.0 transfer, close | 382 | /* either error or http 1.0 transfer, close socket! */ |
361 | socket! */ | ||
362 | #if DEBUG_CLOSE | ||
363 | #if HAVE_MESSAGES | ||
364 | MHD_DLOG (connection->daemon, | ||
365 | "Closing connection (end of response or error)\n"); | ||
366 | #endif | ||
367 | #endif | ||
368 | response->total_size = connection->response_write_position; | 383 | response->total_size = connection->response_write_position; |
369 | connection_close_error (connection); | 384 | CONNECTION_CLOSE_ERROR (connection, |
385 | (ret == MHD_CONTENT_READER_END_OF_STREAM) | ||
386 | ? "Closing connection (end of response)\n" | ||
387 | : "Closing connection (stream error)\n"); | ||
370 | return MHD_NO; | 388 | return MHD_NO; |
371 | } | 389 | } |
372 | response->data_start = connection->response_write_position; | 390 | response->data_start = connection->response_write_position; |
@@ -405,13 +423,8 @@ try_ready_chunked_body (struct MHD_Connection *connection) | |||
405 | if (size < 128) | 423 | if (size < 128) |
406 | { | 424 | { |
407 | /* not enough memory */ | 425 | /* not enough memory */ |
408 | #if DEBUG_CLOSE | 426 | CONNECTION_CLOSE_ERROR (connection, |
409 | #if HAVE_MESSAGES | 427 | "Closing connection (out of memory)\n"); |
410 | MHD_DLOG (connection->daemon, | ||
411 | "Closing connection (out of memory)\n"); | ||
412 | #endif | ||
413 | #endif | ||
414 | connection_close_error (connection); | ||
415 | return MHD_NO; | 428 | return MHD_NO; |
416 | } | 429 | } |
417 | buf = MHD_pool_allocate (connection->pool, size, MHD_NO); | 430 | buf = MHD_pool_allocate (connection->pool, size, MHD_NO); |
@@ -445,14 +458,9 @@ try_ready_chunked_body (struct MHD_Connection *connection) | |||
445 | if (ret == MHD_CONTENT_READER_END_WITH_ERROR) | 458 | if (ret == MHD_CONTENT_READER_END_WITH_ERROR) |
446 | { | 459 | { |
447 | /* error, close socket! */ | 460 | /* error, close socket! */ |
448 | #if DEBUG_CLOSE | ||
449 | #if HAVE_MESSAGES | ||
450 | MHD_DLOG (connection->daemon, | ||
451 | "Closing connection (error generating response)\n"); | ||
452 | #endif | ||
453 | #endif | ||
454 | response->total_size = connection->response_write_position; | 461 | response->total_size = connection->response_write_position; |
455 | connection_close_error (connection); | 462 | CONNECTION_CLOSE_ERROR (connection, |
463 | "Closing connection (error generating response)\n"); | ||
456 | return MHD_NO; | 464 | return MHD_NO; |
457 | } | 465 | } |
458 | if (ret == MHD_CONTENT_READER_END_OF_STREAM) | 466 | if (ret == MHD_CONTENT_READER_END_OF_STREAM) |
@@ -722,11 +730,8 @@ transmit_error_response (struct MHD_Connection *connection, | |||
722 | if (MHD_NO == build_header_response (connection)) | 730 | if (MHD_NO == build_header_response (connection)) |
723 | { | 731 | { |
724 | /* oops - close! */ | 732 | /* oops - close! */ |
725 | #if HAVE_MESSAGES | 733 | CONNECTION_CLOSE_ERROR (connection, |
726 | MHD_DLOG (connection->daemon, | 734 | "Closing connection (failed to create response header)\n"); |
727 | "Closing connection (failed to create response header)\n"); | ||
728 | #endif | ||
729 | connection->state = MHD_CONNECTION_CLOSED; | ||
730 | } | 735 | } |
731 | else | 736 | else |
732 | { | 737 | { |
@@ -788,11 +793,9 @@ MHD_connection_get_pollfd (struct MHD_Connection *connection, struct MHD_Pollfd | |||
788 | connection->pool = MHD_pool_create (connection->daemon->pool_size); | 793 | connection->pool = MHD_pool_create (connection->daemon->pool_size); |
789 | if (connection->pool == NULL) | 794 | if (connection->pool == NULL) |
790 | { | 795 | { |
791 | #if HAVE_MESSAGES | 796 | CONNECTION_CLOSE_ERROR (connection, |
792 | MHD_DLOG (connection->daemon, "Failed to create memory pool!\n"); | 797 | "Failed to create memory pool!\n"); |
793 | #endif | 798 | return MHD_YES; |
794 | connection_close_error (connection); | ||
795 | return MHD_NO; | ||
796 | } | 799 | } |
797 | fd = connection->socket_fd; | 800 | fd = connection->socket_fd; |
798 | p->fd = fd; | 801 | p->fd = fd; |
@@ -822,7 +825,8 @@ MHD_connection_get_pollfd (struct MHD_Connection *connection, struct MHD_Pollfd | |||
822 | if ((connection->read_closed) && | 825 | if ((connection->read_closed) && |
823 | (connection->read_buffer_offset == 0)) | 826 | (connection->read_buffer_offset == 0)) |
824 | { | 827 | { |
825 | connection->state = MHD_CONNECTION_CLOSED; | 828 | CONNECTION_CLOSE_ERROR (connection, |
829 | "Connection buffer to small for request\n"); | ||
826 | continue; | 830 | continue; |
827 | } | 831 | } |
828 | if ((connection->read_buffer_offset == connection->read_buffer_size) | 832 | if ((connection->read_buffer_offset == connection->read_buffer_size) |
@@ -883,7 +887,8 @@ MHD_connection_get_pollfd (struct MHD_Connection *connection, struct MHD_Pollfd | |||
883 | read buffer if needed, no size-check required */ | 887 | read buffer if needed, no size-check required */ |
884 | if (MHD_YES == connection->read_closed) | 888 | if (MHD_YES == connection->read_closed) |
885 | { | 889 | { |
886 | connection->state = MHD_CONNECTION_CLOSED; | 890 | CONNECTION_CLOSE_ERROR (connection, |
891 | "Connection closed while reading request\n"); | ||
887 | continue; | 892 | continue; |
888 | } | 893 | } |
889 | p->events |= MHD_POLL_ACTION_IN; | 894 | p->events |= MHD_POLL_ACTION_IN; |
@@ -923,10 +928,7 @@ MHD_connection_get_pollfd (struct MHD_Connection *connection, struct MHD_Pollfd | |||
923 | EXTRA_CHECK (0); | 928 | EXTRA_CHECK (0); |
924 | break; | 929 | break; |
925 | case MHD_CONNECTION_CLOSED: | 930 | case MHD_CONNECTION_CLOSED: |
926 | if (connection->socket_fd != -1) | ||
927 | connection_close_error (connection); | ||
928 | return MHD_YES; /* do nothing, not even reading */ | 931 | return MHD_YES; /* do nothing, not even reading */ |
929 | |||
930 | default: | 932 | default: |
931 | EXTRA_CHECK (0); | 933 | EXTRA_CHECK (0); |
932 | } | 934 | } |
@@ -1227,11 +1229,8 @@ call_connection_handler (struct MHD_Connection *connection) | |||
1227 | &connection->client_context)) | 1229 | &connection->client_context)) |
1228 | { | 1230 | { |
1229 | /* serious internal error, close connection */ | 1231 | /* serious internal error, close connection */ |
1230 | #if HAVE_MESSAGES | 1232 | CONNECTION_CLOSE_ERROR (connection, |
1231 | MHD_DLOG (connection->daemon, | 1233 | "Internal application error, closing connection.\n"); |
1232 | "Internal application error, closing connection.\n"); | ||
1233 | #endif | ||
1234 | connection_close_error (connection); | ||
1235 | return; | 1234 | return; |
1236 | } | 1235 | } |
1237 | } | 1236 | } |
@@ -1279,11 +1278,8 @@ process_request_body (struct MHD_Connection *connection) | |||
1279 | if (i == 0) | 1278 | if (i == 0) |
1280 | { | 1279 | { |
1281 | /* malformed encoding */ | 1280 | /* malformed encoding */ |
1282 | #if HAVE_MESSAGES | 1281 | CONNECTION_CLOSE_ERROR (connection, |
1283 | MHD_DLOG (connection->daemon, | 1282 | "Received malformed HTTP request (bad chunked encoding), closing connection.\n"); |
1284 | "Received malformed HTTP request (bad chunked encoding), closing connection.\n"); | ||
1285 | #endif | ||
1286 | connection_close_error (connection); | ||
1287 | return; | 1283 | return; |
1288 | } | 1284 | } |
1289 | available -= i; | 1285 | available -= i; |
@@ -1334,11 +1330,8 @@ process_request_body (struct MHD_Connection *connection) | |||
1334 | if (malformed) | 1330 | if (malformed) |
1335 | { | 1331 | { |
1336 | /* malformed encoding */ | 1332 | /* malformed encoding */ |
1337 | #if HAVE_MESSAGES | 1333 | CONNECTION_CLOSE_ERROR (connection, |
1338 | MHD_DLOG (connection->daemon, | 1334 | "Received malformed HTTP request (bad chunked encoding), closing connection.\n"); |
1339 | "Received malformed HTTP request (bad chunked encoding), closing connection.\n"); | ||
1340 | #endif | ||
1341 | connection_close_error (connection); | ||
1342 | return; | 1335 | return; |
1343 | } | 1336 | } |
1344 | i++; | 1337 | i++; |
@@ -1390,11 +1383,8 @@ process_request_body (struct MHD_Connection *connection) | |||
1390 | &connection->client_context)) | 1383 | &connection->client_context)) |
1391 | { | 1384 | { |
1392 | /* serious internal error, close connection */ | 1385 | /* serious internal error, close connection */ |
1393 | #if HAVE_MESSAGES | 1386 | CONNECTION_CLOSE_ERROR (connection, |
1394 | MHD_DLOG (connection->daemon, | 1387 | "Internal application error, closing connection.\n"); |
1395 | "Internal application error, closing connection.\n"); | ||
1396 | #endif | ||
1397 | connection_close_error (connection); | ||
1398 | return; | 1388 | return; |
1399 | } | 1389 | } |
1400 | if (processed > used) | 1390 | if (processed > used) |
@@ -1458,7 +1448,7 @@ do_read (struct MHD_Connection *connection) | |||
1458 | MHD_DLOG (connection->daemon, | 1448 | MHD_DLOG (connection->daemon, |
1459 | "Failed to receive data: %s\n", STRERROR (errno)); | 1449 | "Failed to receive data: %s\n", STRERROR (errno)); |
1460 | #endif | 1450 | #endif |
1461 | connection_close_error (connection); | 1451 | CONNECTION_CLOSE_ERROR (connection, NULL); |
1462 | return MHD_YES; | 1452 | return MHD_YES; |
1463 | } | 1453 | } |
1464 | if (bytes_read == 0) | 1454 | if (bytes_read == 0) |
@@ -1505,7 +1495,7 @@ do_write (struct MHD_Connection *connection) | |||
1505 | MHD_DLOG (connection->daemon, | 1495 | MHD_DLOG (connection->daemon, |
1506 | "Failed to send data: %s\n", STRERROR (errno)); | 1496 | "Failed to send data: %s\n", STRERROR (errno)); |
1507 | #endif | 1497 | #endif |
1508 | connection_close_error (connection); | 1498 | CONNECTION_CLOSE_ERROR (connection, NULL); |
1509 | return MHD_YES; | 1499 | return MHD_YES; |
1510 | } | 1500 | } |
1511 | #if DEBUG_SEND_DATA | 1501 | #if DEBUG_SEND_DATA |
@@ -1555,11 +1545,8 @@ process_header_line (struct MHD_Connection *connection, char *line) | |||
1555 | if (colon == NULL) | 1545 | if (colon == NULL) |
1556 | { | 1546 | { |
1557 | /* error in header line, die hard */ | 1547 | /* error in header line, die hard */ |
1558 | #if HAVE_MESSAGES | 1548 | CONNECTION_CLOSE_ERROR (connection, |
1559 | MHD_DLOG (connection->daemon, | 1549 | "Received malformed line (no colon), closing connection.\n"); |
1560 | "Received malformed line (no colon), closing connection.\n"); | ||
1561 | #endif | ||
1562 | connection->state = MHD_CONNECTION_CLOSED; | ||
1563 | return MHD_NO; | 1550 | return MHD_NO; |
1564 | } | 1551 | } |
1565 | /* zero-terminate header */ | 1552 | /* zero-terminate header */ |
@@ -1696,7 +1683,7 @@ parse_connection_headers (struct MHD_Connection *connection) | |||
1696 | "Failed to parse `%s' header `%s', closing connection.\n", | 1683 | "Failed to parse `%s' header `%s', closing connection.\n", |
1697 | MHD_HTTP_HEADER_CONTENT_LENGTH, clen); | 1684 | MHD_HTTP_HEADER_CONTENT_LENGTH, clen); |
1698 | #endif | 1685 | #endif |
1699 | connection->state = MHD_CONNECTION_CLOSED; | 1686 | CONNECTION_CLOSE_ERROR (connection, NULL); |
1700 | return; | 1687 | return; |
1701 | } | 1688 | } |
1702 | connection->remaining_upload_size = cval; | 1689 | connection->remaining_upload_size = cval; |
@@ -1726,15 +1713,15 @@ parse_connection_headers (struct MHD_Connection *connection) | |||
1726 | * implementations (multithreaded, external select, internal select) | 1713 | * implementations (multithreaded, external select, internal select) |
1727 | * call this function to handle reads. | 1714 | * call this function to handle reads. |
1728 | * | 1715 | * |
1729 | * @return MHD_YES if we should continue to process the | 1716 | * @return always MHD_YES (we should continue to process the |
1730 | * connection (not dead yet), MHD_NO if it died | 1717 | * connection) |
1731 | */ | 1718 | */ |
1732 | int | 1719 | int |
1733 | MHD_connection_handle_read (struct MHD_Connection *connection) | 1720 | MHD_connection_handle_read (struct MHD_Connection *connection) |
1734 | { | 1721 | { |
1735 | connection->last_activity = time (NULL); | 1722 | connection->last_activity = time (NULL); |
1736 | if (connection->state == MHD_CONNECTION_CLOSED) | 1723 | if (connection->state == MHD_CONNECTION_CLOSED) |
1737 | return MHD_NO; | 1724 | return MHD_YES; |
1738 | /* make sure "read" has a reasonable number of bytes | 1725 | /* make sure "read" has a reasonable number of bytes |
1739 | in buffer to use per system call (if possible) */ | 1726 | in buffer to use per system call (if possible) */ |
1740 | if (connection->read_buffer_offset + MHD_BUF_INC_SIZE > | 1727 | if (connection->read_buffer_offset + MHD_BUF_INC_SIZE > |
@@ -1767,9 +1754,7 @@ MHD_connection_handle_read (struct MHD_Connection *connection) | |||
1767 | } | 1754 | } |
1768 | break; | 1755 | break; |
1769 | case MHD_CONNECTION_CLOSED: | 1756 | case MHD_CONNECTION_CLOSED: |
1770 | if (connection->socket_fd != -1) | 1757 | return MHD_YES; |
1771 | connection_close_error (connection); | ||
1772 | return MHD_NO; | ||
1773 | default: | 1758 | default: |
1774 | /* shrink read buffer to how much is actually used */ | 1759 | /* shrink read buffer to how much is actually used */ |
1775 | MHD_pool_reallocate (connection->pool, | 1760 | MHD_pool_reallocate (connection->pool, |
@@ -1783,14 +1768,15 @@ MHD_connection_handle_read (struct MHD_Connection *connection) | |||
1783 | return MHD_YES; | 1768 | return MHD_YES; |
1784 | } | 1769 | } |
1785 | 1770 | ||
1771 | |||
1786 | /** | 1772 | /** |
1787 | * This function was created to handle writes to sockets when it has | 1773 | * This function was created to handle writes to sockets when it has |
1788 | * been determined that the socket can be written to. All | 1774 | * been determined that the socket can be written to. All |
1789 | * implementations (multithreaded, external select, internal select) | 1775 | * implementations (multithreaded, external select, internal select) |
1790 | * call this function | 1776 | * call this function |
1791 | * | 1777 | * |
1792 | * @return MHD_YES if we should continue to process the | 1778 | * @return always MHD_YES (we should continue to process the |
1793 | * connection (not dead yet), MHD_NO if it died | 1779 | * connection) |
1794 | */ | 1780 | */ |
1795 | int | 1781 | int |
1796 | MHD_connection_handle_write (struct MHD_Connection *connection) | 1782 | MHD_connection_handle_write (struct MHD_Connection *connection) |
@@ -1828,8 +1814,8 @@ MHD_connection_handle_write (struct MHD_Connection *connection) | |||
1828 | MHD_DLOG (connection->daemon, | 1814 | MHD_DLOG (connection->daemon, |
1829 | "Failed to send data: %s\n", STRERROR (errno)); | 1815 | "Failed to send data: %s\n", STRERROR (errno)); |
1830 | #endif | 1816 | #endif |
1831 | connection_close_error (connection); | 1817 | CONNECTION_CLOSE_ERROR (connection, NULL); |
1832 | return MHD_NO; | 1818 | return MHD_YES; |
1833 | } | 1819 | } |
1834 | #if DEBUG_SEND_DATA | 1820 | #if DEBUG_SEND_DATA |
1835 | FPRINTF (stderr, | 1821 | FPRINTF (stderr, |
@@ -1889,8 +1875,8 @@ MHD_connection_handle_write (struct MHD_Connection *connection) | |||
1889 | MHD_DLOG (connection->daemon, | 1875 | MHD_DLOG (connection->daemon, |
1890 | "Failed to send data: %s\n", STRERROR (errno)); | 1876 | "Failed to send data: %s\n", STRERROR (errno)); |
1891 | #endif | 1877 | #endif |
1892 | connection_close_error (connection); | 1878 | CONNECTION_CLOSE_ERROR (connection, NULL); |
1893 | return MHD_NO; | 1879 | return MHD_YES; |
1894 | } | 1880 | } |
1895 | connection->response_write_position += ret; | 1881 | connection->response_write_position += ret; |
1896 | if (connection->response_write_position == | 1882 | if (connection->response_write_position == |
@@ -1920,16 +1906,14 @@ MHD_connection_handle_write (struct MHD_Connection *connection) | |||
1920 | EXTRA_CHECK (0); | 1906 | EXTRA_CHECK (0); |
1921 | break; | 1907 | break; |
1922 | case MHD_CONNECTION_CLOSED: | 1908 | case MHD_CONNECTION_CLOSED: |
1923 | if (connection->socket_fd != -1) | 1909 | return MHD_YES; |
1924 | connection_close_error (connection); | ||
1925 | return MHD_NO; | ||
1926 | case MHD_TLS_CONNECTION_INIT: | 1910 | case MHD_TLS_CONNECTION_INIT: |
1927 | EXTRA_CHECK (0); | 1911 | EXTRA_CHECK (0); |
1928 | break; | 1912 | break; |
1929 | default: | 1913 | default: |
1930 | EXTRA_CHECK (0); | 1914 | EXTRA_CHECK (0); |
1931 | connection_close_error (connection); | 1915 | CONNECTION_CLOSE_ERROR (connection, "Internal error\n"); |
1932 | return MHD_NO; | 1916 | return MHD_YES; |
1933 | } | 1917 | } |
1934 | break; | 1918 | break; |
1935 | } | 1919 | } |
@@ -1948,6 +1932,7 @@ MHD_connection_handle_write (struct MHD_Connection *connection) | |||
1948 | int | 1932 | int |
1949 | MHD_connection_handle_idle (struct MHD_Connection *connection) | 1933 | MHD_connection_handle_idle (struct MHD_Connection *connection) |
1950 | { | 1934 | { |
1935 | struct MHD_Daemon *daemon; | ||
1951 | unsigned int timeout; | 1936 | unsigned int timeout; |
1952 | const char *end; | 1937 | const char *end; |
1953 | char *line; | 1938 | char *line; |
@@ -1968,13 +1953,14 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
1968 | continue; | 1953 | continue; |
1969 | if (connection->read_closed) | 1954 | if (connection->read_closed) |
1970 | { | 1955 | { |
1971 | connection->state = MHD_CONNECTION_CLOSED; | 1956 | CONNECTION_CLOSE_ERROR (connection, |
1957 | "Connection closed while reading request\n"); | ||
1972 | continue; | 1958 | continue; |
1973 | } | 1959 | } |
1974 | break; | 1960 | break; |
1975 | } | 1961 | } |
1976 | if (MHD_NO == parse_initial_message_line (connection, line)) | 1962 | if (MHD_NO == parse_initial_message_line (connection, line)) |
1977 | connection->state = MHD_CONNECTION_CLOSED; | 1963 | CONNECTION_CLOSE_ERROR (connection, NULL); |
1978 | else | 1964 | else |
1979 | connection->state = MHD_CONNECTION_URL_RECEIVED; | 1965 | connection->state = MHD_CONNECTION_URL_RECEIVED; |
1980 | continue; | 1966 | continue; |
@@ -1986,7 +1972,8 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
1986 | continue; | 1972 | continue; |
1987 | if (connection->read_closed) | 1973 | if (connection->read_closed) |
1988 | { | 1974 | { |
1989 | connection->state = MHD_CONNECTION_CLOSED; | 1975 | CONNECTION_CLOSE_ERROR (connection, |
1976 | "Connection closed while reading request\n"); | ||
1990 | continue; | 1977 | continue; |
1991 | } | 1978 | } |
1992 | break; | 1979 | break; |
@@ -2013,7 +2000,8 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2013 | continue; | 2000 | continue; |
2014 | if (connection->read_closed) | 2001 | if (connection->read_closed) |
2015 | { | 2002 | { |
2016 | connection->state = MHD_CONNECTION_CLOSED; | 2003 | CONNECTION_CLOSE_ERROR (connection, |
2004 | "Connection closed while reading request\n"); | ||
2017 | continue; | 2005 | continue; |
2018 | } | 2006 | } |
2019 | break; | 2007 | break; |
@@ -2088,7 +2076,8 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2088 | continue; | 2076 | continue; |
2089 | if (connection->read_closed) | 2077 | if (connection->read_closed) |
2090 | { | 2078 | { |
2091 | connection->state = MHD_CONNECTION_CLOSED; | 2079 | CONNECTION_CLOSE_ERROR (connection, |
2080 | "Connection closed while reading request\n"); | ||
2092 | continue; | 2081 | continue; |
2093 | } | 2082 | } |
2094 | break; | 2083 | break; |
@@ -2115,7 +2104,8 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2115 | continue; | 2104 | continue; |
2116 | if (connection->read_closed) | 2105 | if (connection->read_closed) |
2117 | { | 2106 | { |
2118 | connection->state = MHD_CONNECTION_CLOSED; | 2107 | CONNECTION_CLOSE_ERROR (connection, |
2108 | "Connection closed while reading request\n"); | ||
2119 | continue; | 2109 | continue; |
2120 | } | 2110 | } |
2121 | break; | 2111 | break; |
@@ -2138,11 +2128,8 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2138 | if (MHD_NO == build_header_response (connection)) | 2128 | if (MHD_NO == build_header_response (connection)) |
2139 | { | 2129 | { |
2140 | /* oops - close! */ | 2130 | /* oops - close! */ |
2141 | #if HAVE_MESSAGES | 2131 | CONNECTION_CLOSE_ERROR (connection, |
2142 | MHD_DLOG (connection->daemon, | 2132 | "Closing connection (failed to create response header)\n"); |
2143 | "Closing connection (failed to create response header)\n"); | ||
2144 | #endif | ||
2145 | connection->state = MHD_CONNECTION_CLOSED; | ||
2146 | continue; | 2133 | continue; |
2147 | } | 2134 | } |
2148 | connection->state = MHD_CONNECTION_HEADERS_SENDING; | 2135 | connection->state = MHD_CONNECTION_HEADERS_SENDING; |
@@ -2253,7 +2240,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2253 | (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))) | 2240 | (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))) |
2254 | { | 2241 | { |
2255 | /* http 1.0, version-less requests cannot be pipelined */ | 2242 | /* http 1.0, version-less requests cannot be pipelined */ |
2256 | connection->state = MHD_CONNECTION_CLOSED; | 2243 | MHD_connection_close (connection, MHD_REQUEST_TERMINATED_COMPLETED_OK); |
2257 | MHD_pool_destroy (connection->pool); | 2244 | MHD_pool_destroy (connection->pool); |
2258 | connection->pool = NULL; | 2245 | connection->pool = NULL; |
2259 | connection->read_buffer = NULL; | 2246 | connection->read_buffer = NULL; |
@@ -2271,9 +2258,28 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2271 | } | 2258 | } |
2272 | continue; | 2259 | continue; |
2273 | case MHD_CONNECTION_CLOSED: | 2260 | case MHD_CONNECTION_CLOSED: |
2274 | if (connection->socket_fd != -1) | 2261 | daemon = connection->daemon; |
2275 | connection_close_error (connection); | 2262 | DLL_remove (daemon->connections_head, |
2276 | break; | 2263 | daemon->connections_tail, |
2264 | connection); | ||
2265 | if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex)) | ||
2266 | { | ||
2267 | #if HAVE_MESSAGES | ||
2268 | MHD_DLOG (daemon, "Failed to acquire cleanup mutex\n"); | ||
2269 | #endif | ||
2270 | abort(); | ||
2271 | } | ||
2272 | DLL_insert (daemon->cleanup_head, | ||
2273 | daemon->cleanup_tail, | ||
2274 | connection); | ||
2275 | if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex)) | ||
2276 | { | ||
2277 | #if HAVE_MESSAGES | ||
2278 | MHD_DLOG (daemon, "Failed to release cleanup mutex\n"); | ||
2279 | #endif | ||
2280 | abort(); | ||
2281 | } | ||
2282 | return MHD_NO; | ||
2277 | default: | 2283 | default: |
2278 | EXTRA_CHECK (0); | 2284 | EXTRA_CHECK (0); |
2279 | break; | 2285 | break; |
@@ -2281,12 +2287,11 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2281 | break; | 2287 | break; |
2282 | } | 2288 | } |
2283 | timeout = connection->daemon->connection_timeout; | 2289 | timeout = connection->daemon->connection_timeout; |
2284 | if ((connection->socket_fd != -1) && | 2290 | if ( (timeout != 0) && |
2285 | (timeout != 0) && | 2291 | (timeout <= (time (NULL) - connection->last_activity)) ) |
2286 | (timeout <= (time (NULL) - connection->last_activity)) ) | ||
2287 | { | 2292 | { |
2288 | MHD_connection_close (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); | 2293 | MHD_connection_close (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); |
2289 | return MHD_NO; | 2294 | return MHD_YES; |
2290 | } | 2295 | } |
2291 | return MHD_YES; | 2296 | return MHD_YES; |
2292 | } | 2297 | } |
diff --git a/src/daemon/connection_https.c b/src/daemon/connection_https.c index 5487872e..e68ecbbe 100644 --- a/src/daemon/connection_https.c +++ b/src/daemon/connection_https.c | |||
@@ -33,23 +33,6 @@ | |||
33 | #include "reason_phrase.h" | 33 | #include "reason_phrase.h" |
34 | #include <gnutls/gnutls.h> | 34 | #include <gnutls/gnutls.h> |
35 | 35 | ||
36 | /** | ||
37 | * This function is called once a secure connection has been marked | ||
38 | * for closure. | ||
39 | * | ||
40 | * NOTE: Some code duplication with connection_close_error | ||
41 | * in connection.c | ||
42 | * | ||
43 | * @param connection: the connection to close | ||
44 | * @param termination_code: the termination code with which the notify completed callback function is called. | ||
45 | */ | ||
46 | static void | ||
47 | MHD_tls_connection_close (struct MHD_Connection *connection, | ||
48 | enum MHD_RequestTerminationCode termination_code) | ||
49 | { | ||
50 | gnutls_bye (connection->tls_session, GNUTLS_SHUT_RDWR); | ||
51 | MHD_connection_close (connection, termination_code); | ||
52 | } | ||
53 | 36 | ||
54 | 37 | ||
55 | /** | 38 | /** |
@@ -65,9 +48,8 @@ MHD_tls_connection_close (struct MHD_Connection *connection, | |||
65 | * Application data is forwarded to the underlying daemon for | 48 | * Application data is forwarded to the underlying daemon for |
66 | * processing. | 49 | * processing. |
67 | * | 50 | * |
68 | * @param connection : the source connection | 51 | * @param connection the source connection |
69 | * @return MHD_YES if we should continue to process the | 52 | * @return always MHD_YES (we should continue to process the connection) |
70 | * connection (not dead yet), MHD_NO if it died | ||
71 | */ | 53 | */ |
72 | static int | 54 | static int |
73 | MHD_tls_connection_handle_read (struct MHD_Connection *connection) | 55 | MHD_tls_connection_handle_read (struct MHD_Connection *connection) |
@@ -95,9 +77,9 @@ MHD_tls_connection_handle_read (struct MHD_Connection *connection) | |||
95 | MHD_DLOG (connection->daemon, | 77 | MHD_DLOG (connection->daemon, |
96 | "Error: received handshake message out of context\n"); | 78 | "Error: received handshake message out of context\n"); |
97 | #endif | 79 | #endif |
98 | MHD_tls_connection_close (connection, | 80 | MHD_connection_close (connection, |
99 | MHD_REQUEST_TERMINATED_WITH_ERROR); | 81 | MHD_REQUEST_TERMINATED_WITH_ERROR); |
100 | return MHD_NO; | 82 | return MHD_YES; |
101 | } | 83 | } |
102 | return MHD_connection_handle_read (connection); | 84 | return MHD_connection_handle_read (connection); |
103 | } | 85 | } |
@@ -109,8 +91,7 @@ MHD_tls_connection_handle_read (struct MHD_Connection *connection) | |||
109 | * will forward all write requests to the underlying daemon unless | 91 | * will forward all write requests to the underlying daemon unless |
110 | * the connection has been marked for closing. | 92 | * the connection has been marked for closing. |
111 | * | 93 | * |
112 | * @return MHD_connection_handle_write() if we should continue to | 94 | * @return always MHD_YES (we should continue to process the connection) |
113 | * process the connection (not dead yet), MHD_NO if it died | ||
114 | */ | 95 | */ |
115 | static int | 96 | static int |
116 | MHD_tls_connection_handle_write (struct MHD_Connection *connection) | 97 | MHD_tls_connection_handle_write (struct MHD_Connection *connection) |
@@ -142,9 +123,9 @@ MHD_tls_connection_handle_write (struct MHD_Connection *connection) | |||
142 | MHD_DLOG (connection->daemon, | 123 | MHD_DLOG (connection->daemon, |
143 | "Error: received handshake message out of context\n"); | 124 | "Error: received handshake message out of context\n"); |
144 | #endif | 125 | #endif |
145 | MHD_tls_connection_close (connection, | 126 | MHD_connection_close (connection, |
146 | MHD_REQUEST_TERMINATED_WITH_ERROR); | 127 | MHD_REQUEST_TERMINATED_WITH_ERROR); |
147 | return MHD_NO; | 128 | return MHD_YES; |
148 | } | 129 | } |
149 | return MHD_connection_handle_write (connection); | 130 | return MHD_connection_handle_write (connection); |
150 | } | 131 | } |
@@ -170,13 +151,9 @@ MHD_tls_connection_handle_idle (struct MHD_Connection *connection) | |||
170 | __FUNCTION__, MHD_state_to_string (connection->state)); | 151 | __FUNCTION__, MHD_state_to_string (connection->state)); |
171 | #endif | 152 | #endif |
172 | timeout = connection->daemon->connection_timeout; | 153 | timeout = connection->daemon->connection_timeout; |
173 | if ((connection->socket_fd != -1) && (timeout != 0) | 154 | if ( (timeout != 0) && (time (NULL) - timeout > connection->last_activity)) |
174 | && (time (NULL) - timeout > connection->last_activity)) | 155 | MHD_connection_close (connection, |
175 | { | 156 | MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); |
176 | MHD_tls_connection_close (connection, | ||
177 | MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); | ||
178 | return MHD_NO; | ||
179 | } | ||
180 | switch (connection->state) | 157 | switch (connection->state) |
181 | { | 158 | { |
182 | /* on newly created connections we might reach here before any reply has been received */ | 159 | /* on newly created connections we might reach here before any reply has been received */ |
@@ -184,14 +161,12 @@ MHD_tls_connection_handle_idle (struct MHD_Connection *connection) | |||
184 | return MHD_YES; | 161 | return MHD_YES; |
185 | /* close connection if necessary */ | 162 | /* close connection if necessary */ |
186 | case MHD_CONNECTION_CLOSED: | 163 | case MHD_CONNECTION_CLOSED: |
187 | if (connection->socket_fd != -1) | 164 | gnutls_bye (connection->tls_session, GNUTLS_SHUT_RDWR); |
188 | MHD_tls_connection_close (connection, | 165 | return MHD_connection_handle_idle (connection); |
189 | MHD_REQUEST_TERMINATED_COMPLETED_OK); | ||
190 | return MHD_NO; | ||
191 | default: | 166 | default: |
192 | if ( (0 != gnutls_record_check_pending (connection->tls_session)) && | 167 | if ( (0 != gnutls_record_check_pending (connection->tls_session)) && |
193 | (MHD_YES != MHD_tls_connection_handle_read (connection)) ) | 168 | (MHD_YES != MHD_tls_connection_handle_read (connection)) ) |
194 | return MHD_NO; | 169 | return MHD_YES; |
195 | return MHD_connection_handle_idle (connection); | 170 | return MHD_connection_handle_idle (connection); |
196 | } | 171 | } |
197 | return MHD_YES; | 172 | return MHD_YES; |
diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c index 6c6144be..0fa51260 100644 --- a/src/daemon/daemon.c +++ b/src/daemon/daemon.c | |||
@@ -150,7 +150,7 @@ struct MHD_IPCount | |||
150 | }; | 150 | }; |
151 | 151 | ||
152 | /** | 152 | /** |
153 | * Lock shared structure for IP connection counts | 153 | * Lock shared structure for IP connection counts and connection DLLs. |
154 | * | 154 | * |
155 | * @param daemon handle to daemon where lock is | 155 | * @param daemon handle to daemon where lock is |
156 | */ | 156 | */ |
@@ -167,7 +167,7 @@ MHD_ip_count_lock(struct MHD_Daemon *daemon) | |||
167 | } | 167 | } |
168 | 168 | ||
169 | /** | 169 | /** |
170 | * Unlock shared structure for IP connection counts | 170 | * Unlock shared structure for IP connection counts and connection DLLs. |
171 | * | 171 | * |
172 | * @param daemon handle to daemon where lock is | 172 | * @param daemon handle to daemon where lock is |
173 | */ | 173 | */ |
@@ -495,6 +495,7 @@ MHD_TLS_init (struct MHD_Daemon *daemon) | |||
495 | } | 495 | } |
496 | #endif | 496 | #endif |
497 | 497 | ||
498 | |||
498 | /** | 499 | /** |
499 | * Obtain the select sets for this daemon. | 500 | * Obtain the select sets for this daemon. |
500 | * | 501 | * |
@@ -513,7 +514,8 @@ MHD_get_fdset (struct MHD_Daemon *daemon, | |||
513 | fd_set * read_fd_set, | 514 | fd_set * read_fd_set, |
514 | fd_set * write_fd_set, fd_set * except_fd_set, int *max_fd) | 515 | fd_set * write_fd_set, fd_set * except_fd_set, int *max_fd) |
515 | { | 516 | { |
516 | struct MHD_Connection *con_itr; | 517 | struct MHD_Connection *pos; |
518 | struct MHD_Connection *next; | ||
517 | int fd; | 519 | int fd; |
518 | 520 | ||
519 | if ((daemon == NULL) || (read_fd_set == NULL) || (write_fd_set == NULL) | 521 | if ((daemon == NULL) || (read_fd_set == NULL) || (write_fd_set == NULL) |
@@ -528,15 +530,15 @@ MHD_get_fdset (struct MHD_Daemon *daemon, | |||
528 | if ((*max_fd) < fd) | 530 | if ((*max_fd) < fd) |
529 | *max_fd = fd; | 531 | *max_fd = fd; |
530 | 532 | ||
531 | con_itr = daemon->connections; | 533 | next = daemon->connections_head; |
532 | while (con_itr != NULL) | 534 | while (NULL != (pos = next)) |
533 | { | 535 | { |
534 | if (MHD_YES != MHD_connection_get_fdset (con_itr, | 536 | next = pos->next; |
537 | if (MHD_YES != MHD_connection_get_fdset (pos, | ||
535 | read_fd_set, | 538 | read_fd_set, |
536 | write_fd_set, | 539 | write_fd_set, |
537 | except_fd_set, max_fd)) | 540 | except_fd_set, max_fd)) |
538 | return MHD_NO; | 541 | return MHD_NO; |
539 | con_itr = con_itr->next; | ||
540 | } | 542 | } |
541 | #if DEBUG_CONNECT | 543 | #if DEBUG_CONNECT |
542 | MHD_DLOG (daemon, "Maximum socket in select set: %d\n", *max_fd); | 544 | MHD_DLOG (daemon, "Maximum socket in select set: %d\n", *max_fd); |
@@ -572,7 +574,8 @@ MHD_handle_connection (void *data) | |||
572 | #endif | 574 | #endif |
573 | 575 | ||
574 | timeout = con->daemon->connection_timeout; | 576 | timeout = con->daemon->connection_timeout; |
575 | while ((!con->daemon->shutdown) && (con->socket_fd != -1)) { | 577 | while ( (!con->daemon->shutdown) && (con->state != MHD_CONNECTION_CLOSED) ) |
578 | { | ||
576 | tvp = NULL; | 579 | tvp = NULL; |
577 | if (timeout > 0) | 580 | if (timeout > 0) |
578 | { | 581 | { |
@@ -624,17 +627,19 @@ MHD_handle_connection (void *data) | |||
624 | break; | 627 | break; |
625 | } | 628 | } |
626 | /* call appropriate connection handler if necessary */ | 629 | /* call appropriate connection handler if necessary */ |
627 | if ((con->socket_fd != -1) && (FD_ISSET (con->socket_fd, &rs))) | 630 | if (FD_ISSET (con->socket_fd, &rs)) |
628 | con->read_handler (con); | 631 | con->read_handler (con); |
629 | if ((con->socket_fd != -1) && (FD_ISSET (con->socket_fd, &ws))) | 632 | if (FD_ISSET (con->socket_fd, &ws)) |
630 | con->write_handler (con); | 633 | con->write_handler (con); |
631 | if (con->socket_fd != -1) | 634 | if (MHD_NO == con->idle_handler (con)) |
632 | con->idle_handler (con); | 635 | { |
636 | return NULL; | ||
637 | } | ||
633 | } | 638 | } |
634 | #ifdef HAVE_POLL_H | 639 | #ifdef HAVE_POLL_H |
635 | else | 640 | else |
636 | { | 641 | { |
637 | /* use poll */ | 642 | /* use poll */ |
638 | memset(&mp, 0, sizeof (struct MHD_Pollfd)); | 643 | memset(&mp, 0, sizeof (struct MHD_Pollfd)); |
639 | MHD_connection_get_pollfd(con, &mp); | 644 | MHD_connection_get_pollfd(con, &mp); |
640 | memset(&p, 0, sizeof (p)); | 645 | memset(&p, 0, sizeof (p)); |
@@ -666,21 +671,20 @@ MHD_handle_connection (void *data) | |||
666 | #endif | 671 | #endif |
667 | break; | 672 | break; |
668 | } | 673 | } |
669 | if ( (con->socket_fd != -1) && | 674 | if (0 != (p[0].revents & POLLIN)) |
670 | (0 != (p[0].revents & POLLIN)) ) | ||
671 | con->read_handler (con); | 675 | con->read_handler (con); |
672 | if ( (con->socket_fd != -1) && | 676 | if (0 != (p[0].revents & POLLOUT)) |
673 | (0 != (p[0].revents & POLLOUT)) ) | ||
674 | con->write_handler (con); | 677 | con->write_handler (con); |
675 | if (con->socket_fd != -1) | 678 | if (0 != (p[0].revents & (POLLERR | POLLHUP))) |
676 | con->idle_handler (con); | ||
677 | if ( (con->socket_fd != -1) && | ||
678 | (0 != (p[0].revents & (POLLERR | POLLHUP))) ) | ||
679 | MHD_connection_close (con, MHD_REQUEST_TERMINATED_WITH_ERROR); | 679 | MHD_connection_close (con, MHD_REQUEST_TERMINATED_WITH_ERROR); |
680 | if (MHD_NO == con->idle_handler (con)) | ||
681 | { | ||
682 | return NULL; /* "instant" termination, 'con' no longer valid! */ | ||
683 | } | ||
680 | } | 684 | } |
681 | #endif | 685 | #endif |
682 | } | 686 | } |
683 | if (con->socket_fd != -1) | 687 | if (con->state != MHD_CONNECTION_IN_CLEANUP) |
684 | { | 688 | { |
685 | #if DEBUG_CLOSE | 689 | #if DEBUG_CLOSE |
686 | #if HAVE_MESSAGES | 690 | #if HAVE_MESSAGES |
@@ -688,7 +692,9 @@ MHD_handle_connection (void *data) | |||
688 | "Processing thread terminating, closing connection\n"); | 692 | "Processing thread terminating, closing connection\n"); |
689 | #endif | 693 | #endif |
690 | #endif | 694 | #endif |
691 | MHD_connection_close (con, MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN); | 695 | if (con->state != MHD_CONNECTION_CLOSED) |
696 | MHD_connection_close (con, MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN); | ||
697 | con->idle_handler (con); | ||
692 | } | 698 | } |
693 | return NULL; | 699 | return NULL; |
694 | } | 700 | } |
@@ -706,8 +712,12 @@ recv_param_adapter (struct MHD_Connection *connection, | |||
706 | void *other, | 712 | void *other, |
707 | size_t i) | 713 | size_t i) |
708 | { | 714 | { |
709 | if (connection->socket_fd == -1) | 715 | if ( (connection->socket_fd == -1) || |
710 | return -1; | 716 | (connection->state == MHD_CONNECTION_CLOSED) ) |
717 | { | ||
718 | errno = ENOTCONN; | ||
719 | return -1; | ||
720 | } | ||
711 | if (0 != (connection->daemon->options & MHD_USE_SSL)) | 721 | if (0 != (connection->daemon->options & MHD_USE_SSL)) |
712 | return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL); | 722 | return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL); |
713 | return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL); | 723 | return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL); |
@@ -732,8 +742,12 @@ send_param_adapter (struct MHD_Connection *connection, | |||
732 | off_t left; | 742 | off_t left; |
733 | ssize_t ret; | 743 | ssize_t ret; |
734 | #endif | 744 | #endif |
735 | if (connection->socket_fd == -1) | 745 | if ( (connection->socket_fd == -1) || |
736 | return -1; | 746 | (connection->state == MHD_CONNECTION_CLOSED) ) |
747 | { | ||
748 | errno = ENOTCONN; | ||
749 | return -1; | ||
750 | } | ||
737 | if (0 != (connection->daemon->options & MHD_USE_SSL)) | 751 | if (0 != (connection->daemon->options & MHD_USE_SSL)) |
738 | return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL); | 752 | return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL); |
739 | #if LINUX | 753 | #if LINUX |
@@ -997,19 +1011,19 @@ MHD_add_connection (struct MHD_Daemon *daemon, | |||
997 | /* use non-blocking IO for gnutls */ | 1011 | /* use non-blocking IO for gnutls */ |
998 | socket_set_nonblocking (connection->socket_fd); | 1012 | socket_set_nonblocking (connection->socket_fd); |
999 | } | 1013 | } |
1000 | switch (connection->daemon->cred_type) | 1014 | switch (daemon->cred_type) |
1001 | { | 1015 | { |
1002 | /* set needed credentials for certificate authentication. */ | 1016 | /* set needed credentials for certificate authentication. */ |
1003 | case GNUTLS_CRD_CERTIFICATE: | 1017 | case GNUTLS_CRD_CERTIFICATE: |
1004 | gnutls_credentials_set (connection->tls_session, | 1018 | gnutls_credentials_set (connection->tls_session, |
1005 | GNUTLS_CRD_CERTIFICATE, | 1019 | GNUTLS_CRD_CERTIFICATE, |
1006 | connection->daemon->x509_cred); | 1020 | daemon->x509_cred); |
1007 | break; | 1021 | break; |
1008 | default: | 1022 | default: |
1009 | #if HAVE_MESSAGES | 1023 | #if HAVE_MESSAGES |
1010 | MHD_DLOG (connection->daemon, | 1024 | MHD_DLOG (connection->daemon, |
1011 | "Failed to setup TLS credentials: unknown credential type %d\n", | 1025 | "Failed to setup TLS credentials: unknown credential type %d\n", |
1012 | connection->daemon->cred_type); | 1026 | daemon->cred_type); |
1013 | #endif | 1027 | #endif |
1014 | SHUTDOWN (client_socket, SHUT_RDWR); | 1028 | SHUTDOWN (client_socket, SHUT_RDWR); |
1015 | CLOSE (client_socket); | 1029 | CLOSE (client_socket); |
@@ -1059,8 +1073,10 @@ MHD_add_connection (struct MHD_Daemon *daemon, | |||
1059 | return MHD_NO; | 1073 | return MHD_NO; |
1060 | } | 1074 | } |
1061 | } | 1075 | } |
1062 | connection->next = daemon->connections; | 1076 | /* FIXME: race with removal operation! */ |
1063 | daemon->connections = connection; | 1077 | DLL_insert (daemon->connections_head, |
1078 | daemon->connections_tail, | ||
1079 | connection); | ||
1064 | daemon->max_connections--; | 1080 | daemon->max_connections--; |
1065 | return MHD_YES; | 1081 | return MHD_YES; |
1066 | } | 1082 | } |
@@ -1113,10 +1129,11 @@ MHD_accept_connection (struct MHD_Daemon *daemon) | |||
1113 | addr, addrlen); | 1129 | addr, addrlen); |
1114 | } | 1130 | } |
1115 | 1131 | ||
1132 | |||
1116 | /** | 1133 | /** |
1117 | * Free resources associated with all closed connections. | 1134 | * Free resources associated with all closed connections. |
1118 | * (destroy responses, free buffers, etc.). A connection | 1135 | * (destroy responses, free buffers, etc.). All closed |
1119 | * is known to be closed if the socket_fd is -1. | 1136 | * connections are kept in the "cleanup" doubly-linked list. |
1120 | * | 1137 | * |
1121 | * @param daemon daemon to clean up | 1138 | * @param daemon daemon to clean up |
1122 | */ | 1139 | */ |
@@ -1124,59 +1141,61 @@ static void | |||
1124 | MHD_cleanup_connections (struct MHD_Daemon *daemon) | 1141 | MHD_cleanup_connections (struct MHD_Daemon *daemon) |
1125 | { | 1142 | { |
1126 | struct MHD_Connection *pos; | 1143 | struct MHD_Connection *pos; |
1127 | struct MHD_Connection *prev; | ||
1128 | void *unused; | 1144 | void *unused; |
1129 | int rc; | 1145 | int rc; |
1130 | 1146 | ||
1131 | pos = daemon->connections; | 1147 | if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex)) |
1132 | prev = NULL; | ||
1133 | while (pos != NULL) | ||
1134 | { | 1148 | { |
1135 | if ((pos->socket_fd == -1) || | ||
1136 | (((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && | ||
1137 | (daemon->shutdown) && (pos->socket_fd != -1)))) | ||
1138 | { | ||
1139 | if (prev == NULL) | ||
1140 | daemon->connections = pos->next; | ||
1141 | else | ||
1142 | prev->next = pos->next; | ||
1143 | if (0 != (pos->daemon->options & MHD_USE_THREAD_PER_CONNECTION)) | ||
1144 | { | ||
1145 | |||
1146 | if (0 != (rc = pthread_join (pos->pid, &unused))) | ||
1147 | { | ||
1148 | #if HAVE_MESSAGES | 1149 | #if HAVE_MESSAGES |
1149 | MHD_DLOG (daemon, "Failed to join a thread: %s\n", | 1150 | MHD_DLOG (daemon, "Failed to acquire cleanup mutex\n"); |
1150 | STRERROR (rc)); | ||
1151 | #endif | ||
1152 | abort(); | ||
1153 | } | ||
1154 | } | ||
1155 | MHD_pool_destroy (pos->pool); | ||
1156 | #if HTTPS_SUPPORT | ||
1157 | if (pos->tls_session != NULL) | ||
1158 | gnutls_deinit (pos->tls_session); | ||
1159 | #endif | 1151 | #endif |
1160 | MHD_ip_limit_del (daemon, (struct sockaddr*)pos->addr, pos->addr_len); | 1152 | abort(); |
1161 | if (pos->response != NULL) | 1153 | } |
1154 | while (NULL != (pos = daemon->cleanup_head)) | ||
1155 | { | ||
1156 | DLL_remove (daemon->cleanup_head, | ||
1157 | daemon->cleanup_tail, | ||
1158 | pos); | ||
1159 | if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && | ||
1160 | (MHD_NO == pos->thread_joined) ) | ||
1161 | { | ||
1162 | if (0 != (rc = pthread_join (pos->pid, &unused))) | ||
1162 | { | 1163 | { |
1163 | MHD_destroy_response (pos->response); | 1164 | #if HAVE_MESSAGES |
1164 | pos->response = NULL; | 1165 | MHD_DLOG (daemon, "Failed to join a thread: %s\n", |
1166 | STRERROR (rc)); | ||
1167 | #endif | ||
1168 | abort(); | ||
1165 | } | 1169 | } |
1166 | free (pos->addr); | 1170 | } |
1167 | free (pos); | 1171 | MHD_pool_destroy (pos->pool); |
1168 | daemon->max_connections++; | 1172 | #if HTTPS_SUPPORT |
1169 | if (prev == NULL) | 1173 | if (pos->tls_session != NULL) |
1170 | pos = daemon->connections; | 1174 | gnutls_deinit (pos->tls_session); |
1171 | else | 1175 | #endif |
1172 | pos = prev->next; | 1176 | MHD_ip_limit_del (daemon, (struct sockaddr*)pos->addr, pos->addr_len); |
1173 | continue; | 1177 | if (pos->response != NULL) |
1174 | } | 1178 | { |
1175 | prev = pos; | 1179 | MHD_destroy_response (pos->response); |
1176 | pos = pos->next; | 1180 | pos->response = NULL; |
1181 | } | ||
1182 | if (-1 != pos->socket_fd) | ||
1183 | CLOSE (pos->socket_fd); | ||
1184 | if (NULL != pos->addr) | ||
1185 | free (pos->addr); | ||
1186 | free (pos); | ||
1187 | daemon->max_connections++; | ||
1188 | } | ||
1189 | if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex)) | ||
1190 | { | ||
1191 | #if HAVE_MESSAGES | ||
1192 | MHD_DLOG (daemon, "Failed to release cleanup mutex\n"); | ||
1193 | #endif | ||
1194 | abort(); | ||
1177 | } | 1195 | } |
1178 | } | 1196 | } |
1179 | 1197 | ||
1198 | |||
1180 | /** | 1199 | /** |
1181 | * Obtain timeout value for select for this daemon | 1200 | * Obtain timeout value for select for this daemon |
1182 | * (only needed if connection timeout is used). The | 1201 | * (only needed if connection timeout is used). The |
@@ -1201,7 +1220,7 @@ MHD_get_timeout (struct MHD_Daemon *daemon, | |||
1201 | dto = daemon->connection_timeout; | 1220 | dto = daemon->connection_timeout; |
1202 | if (0 == dto) | 1221 | if (0 == dto) |
1203 | return MHD_NO; | 1222 | return MHD_NO; |
1204 | pos = daemon->connections; | 1223 | pos = daemon->connections_head; |
1205 | if (pos == NULL) | 1224 | if (pos == NULL) |
1206 | return MHD_NO; /* no connections */ | 1225 | return MHD_NO; /* no connections */ |
1207 | now = time (NULL); | 1226 | now = time (NULL); |
@@ -1238,6 +1257,7 @@ MHD_select (struct MHD_Daemon *daemon, | |||
1238 | int may_block) | 1257 | int may_block) |
1239 | { | 1258 | { |
1240 | struct MHD_Connection *pos; | 1259 | struct MHD_Connection *pos; |
1260 | struct MHD_Connection *next; | ||
1241 | int num_ready; | 1261 | int num_ready; |
1242 | fd_set rs; | 1262 | fd_set rs; |
1243 | fd_set ws; | 1263 | fd_set ws; |
@@ -1313,21 +1333,19 @@ MHD_select (struct MHD_Daemon *daemon, | |||
1313 | if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) | 1333 | if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) |
1314 | { | 1334 | { |
1315 | /* do not have a thread per connection, process all connections now */ | 1335 | /* do not have a thread per connection, process all connections now */ |
1316 | pos = daemon->connections; | 1336 | next = daemon->connections_head; |
1317 | while (pos != NULL) | 1337 | while (NULL != (pos = next)) |
1318 | { | 1338 | { |
1339 | next = pos->next; | ||
1319 | ds = pos->socket_fd; | 1340 | ds = pos->socket_fd; |
1320 | if (ds != -1) | 1341 | if (ds != -1) |
1321 | { | 1342 | { |
1322 | /* TODO call con->read handler */ | ||
1323 | if (FD_ISSET (ds, &rs)) | 1343 | if (FD_ISSET (ds, &rs)) |
1324 | pos->read_handler (pos); | 1344 | pos->read_handler (pos); |
1325 | if ((pos->socket_fd != -1) && (FD_ISSET (ds, &ws))) | 1345 | if (FD_ISSET (ds, &ws)) |
1326 | pos->write_handler (pos); | 1346 | pos->write_handler (pos); |
1327 | if (pos->socket_fd != -1) | 1347 | pos->idle_handler (pos); |
1328 | pos->idle_handler (pos); | ||
1329 | } | 1348 | } |
1330 | pos = pos->next; | ||
1331 | } | 1349 | } |
1332 | } | 1350 | } |
1333 | return MHD_YES; | 1351 | return MHD_YES; |
@@ -1349,9 +1367,10 @@ MHD_poll_all (struct MHD_Daemon *daemon, | |||
1349 | { | 1367 | { |
1350 | unsigned int num_connections; | 1368 | unsigned int num_connections; |
1351 | struct MHD_Connection *pos; | 1369 | struct MHD_Connection *pos; |
1370 | struct MHD_Connection *next; | ||
1352 | 1371 | ||
1353 | num_connections = 0; | 1372 | num_connections = 0; |
1354 | pos = daemon->connections; | 1373 | pos = daemon->connections_head; |
1355 | while (pos != NULL) | 1374 | while (pos != NULL) |
1356 | { | 1375 | { |
1357 | num_connections++; | 1376 | num_connections++; |
@@ -1385,7 +1404,7 @@ MHD_poll_all (struct MHD_Daemon *daemon, | |||
1385 | timeout = (ltimeout > INT_MAX) ? INT_MAX : (int) ltimeout; | 1404 | timeout = (ltimeout > INT_MAX) ? INT_MAX : (int) ltimeout; |
1386 | 1405 | ||
1387 | i = 0; | 1406 | i = 0; |
1388 | pos = daemon->connections; | 1407 | pos = daemon->connections_head; |
1389 | while (pos != NULL) | 1408 | while (pos != NULL) |
1390 | { | 1409 | { |
1391 | memset(&mp, 0, sizeof (struct MHD_Pollfd)); | 1410 | memset(&mp, 0, sizeof (struct MHD_Pollfd)); |
@@ -1413,9 +1432,10 @@ MHD_poll_all (struct MHD_Daemon *daemon, | |||
1413 | if (daemon->socket_fd < 0) | 1432 | if (daemon->socket_fd < 0) |
1414 | return MHD_YES; | 1433 | return MHD_YES; |
1415 | i = 0; | 1434 | i = 0; |
1416 | pos = daemon->connections; | 1435 | next = daemon->connections_head; |
1417 | while (pos != NULL) | 1436 | while (NULL != (pos = next)) |
1418 | { | 1437 | { |
1438 | next = pos->next; | ||
1419 | /* first, sanity checks */ | 1439 | /* first, sanity checks */ |
1420 | if (i >= num_connections) | 1440 | if (i >= num_connections) |
1421 | break; /* connection list changed somehow, retry later ... */ | 1441 | break; /* connection list changed somehow, retry later ... */ |
@@ -1427,11 +1447,9 @@ MHD_poll_all (struct MHD_Daemon *daemon, | |||
1427 | if (0 != (p[poll_server+i].revents & POLLIN)) | 1447 | if (0 != (p[poll_server+i].revents & POLLIN)) |
1428 | pos->read_handler (pos); | 1448 | pos->read_handler (pos); |
1429 | if (0 != (p[poll_server+i].revents & POLLOUT)) | 1449 | if (0 != (p[poll_server+i].revents & POLLOUT)) |
1430 | pos->write_handler (pos); | 1450 | pos->write_handler (pos); |
1431 | if (pos->socket_fd != -1) | 1451 | pos->idle_handler (pos); |
1432 | pos->idle_handler (pos); | ||
1433 | i++; | 1452 | i++; |
1434 | pos = pos->next; | ||
1435 | } | 1453 | } |
1436 | if ( (1 == poll_server) && | 1454 | if ( (1 == poll_server) && |
1437 | (0 != (p[0].revents & POLLIN)) ) | 1455 | (0 != (p[0].revents & POLLIN)) ) |
@@ -1729,18 +1747,22 @@ parse_options_va (struct MHD_Daemon *daemon, | |||
1729 | daemon->cred_type = va_arg (ap, gnutls_credentials_type_t); | 1747 | daemon->cred_type = va_arg (ap, gnutls_credentials_type_t); |
1730 | break; | 1748 | break; |
1731 | case MHD_OPTION_HTTPS_PRIORITIES: | 1749 | case MHD_OPTION_HTTPS_PRIORITIES: |
1732 | ret = gnutls_priority_init (&daemon->priority_cache, | 1750 | if (daemon->options & MHD_USE_SSL) |
1733 | pstr = va_arg (ap, const char*), | 1751 | { |
1734 | NULL); | 1752 | gnutls_priority_deinit (daemon->priority_cache); |
1753 | ret = gnutls_priority_init (&daemon->priority_cache, | ||
1754 | pstr = va_arg (ap, const char*), | ||
1755 | NULL); | ||
1735 | #if HAVE_MESSAGES | 1756 | #if HAVE_MESSAGES |
1736 | if (ret != GNUTLS_E_SUCCESS) | 1757 | if (ret != GNUTLS_E_SUCCESS) |
1737 | FPRINTF (stderr, | 1758 | FPRINTF (stderr, |
1738 | "Setting priorities to `%s' failed: %s\n", | 1759 | "Setting priorities to `%s' failed: %s\n", |
1739 | pstr, | 1760 | pstr, |
1740 | gnutls_strerror (ret)); | 1761 | gnutls_strerror (ret)); |
1741 | #endif | 1762 | #endif |
1742 | if (ret != GNUTLS_E_SUCCESS) | 1763 | if (ret != GNUTLS_E_SUCCESS) |
1743 | return MHD_NO; | 1764 | return MHD_NO; |
1765 | } | ||
1744 | break; | 1766 | break; |
1745 | #endif | 1767 | #endif |
1746 | #ifdef DAUTH_SUPPORT | 1768 | #ifdef DAUTH_SUPPORT |
@@ -2174,6 +2196,16 @@ MHD_start_daemon_va (unsigned int options, | |||
2174 | CLOSE (socket_fd); | 2196 | CLOSE (socket_fd); |
2175 | goto free_and_fail; | 2197 | goto free_and_fail; |
2176 | } | 2198 | } |
2199 | if (0 != pthread_mutex_init (&retVal->cleanup_connection_mutex, NULL)) | ||
2200 | { | ||
2201 | #if HAVE_MESSAGES | ||
2202 | MHD_DLOG (retVal, | ||
2203 | "MHD failed to initialize IP connection limit mutex\n"); | ||
2204 | #endif | ||
2205 | pthread_mutex_destroy (&retVal->cleanup_connection_mutex); | ||
2206 | CLOSE (socket_fd); | ||
2207 | goto free_and_fail; | ||
2208 | } | ||
2177 | 2209 | ||
2178 | #if HTTPS_SUPPORT | 2210 | #if HTTPS_SUPPORT |
2179 | /* initialize HTTPS daemon certificate aspects & send / recv functions */ | 2211 | /* initialize HTTPS daemon certificate aspects & send / recv functions */ |
@@ -2184,6 +2216,7 @@ MHD_start_daemon_va (unsigned int options, | |||
2184 | "Failed to initialize TLS support\n"); | 2216 | "Failed to initialize TLS support\n"); |
2185 | #endif | 2217 | #endif |
2186 | CLOSE (socket_fd); | 2218 | CLOSE (socket_fd); |
2219 | pthread_mutex_destroy (&retVal->cleanup_connection_mutex); | ||
2187 | pthread_mutex_destroy (&retVal->per_ip_connection_mutex); | 2220 | pthread_mutex_destroy (&retVal->per_ip_connection_mutex); |
2188 | goto free_and_fail; | 2221 | goto free_and_fail; |
2189 | } | 2222 | } |
@@ -2199,6 +2232,7 @@ MHD_start_daemon_va (unsigned int options, | |||
2199 | "Failed to create listen thread: %s\n", | 2232 | "Failed to create listen thread: %s\n", |
2200 | STRERROR (res_thread_create)); | 2233 | STRERROR (res_thread_create)); |
2201 | #endif | 2234 | #endif |
2235 | pthread_mutex_destroy (&retVal->cleanup_connection_mutex); | ||
2202 | pthread_mutex_destroy (&retVal->per_ip_connection_mutex); | 2236 | pthread_mutex_destroy (&retVal->per_ip_connection_mutex); |
2203 | CLOSE (socket_fd); | 2237 | CLOSE (socket_fd); |
2204 | goto free_and_fail; | 2238 | goto free_and_fail; |
@@ -2292,6 +2326,7 @@ thread_failed: | |||
2292 | if (i == 0) | 2326 | if (i == 0) |
2293 | { | 2327 | { |
2294 | CLOSE (socket_fd); | 2328 | CLOSE (socket_fd); |
2329 | pthread_mutex_destroy (&retVal->cleanup_connection_mutex); | ||
2295 | pthread_mutex_destroy (&retVal->per_ip_connection_mutex); | 2330 | pthread_mutex_destroy (&retVal->per_ip_connection_mutex); |
2296 | if (NULL != retVal->worker_pool) | 2331 | if (NULL != retVal->worker_pool) |
2297 | free (retVal->worker_pool); | 2332 | free (retVal->worker_pool); |
@@ -2319,27 +2354,45 @@ thread_failed: | |||
2319 | 2354 | ||
2320 | 2355 | ||
2321 | /** | 2356 | /** |
2322 | * Close all connections for the daemon | 2357 | * Close all connections for the daemon; must only be called after |
2358 | * all of the threads have been joined and there is no more concurrent | ||
2359 | * activity on the connection lists. | ||
2323 | * | 2360 | * |
2324 | * @param daemon daemon to close down | 2361 | * @param daemon daemon to close down |
2325 | */ | 2362 | */ |
2326 | static void | 2363 | static void |
2327 | MHD_close_connections (struct MHD_Daemon *daemon) | 2364 | close_all_connections (struct MHD_Daemon *daemon) |
2328 | { | 2365 | { |
2329 | while (daemon->connections != NULL) | 2366 | struct MHD_Connection *pos; |
2367 | void *unused; | ||
2368 | int rc; | ||
2369 | |||
2370 | if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) | ||
2330 | { | 2371 | { |
2331 | if (-1 != daemon->connections->socket_fd) | 2372 | while (NULL != (pos = daemon->connections_head)) |
2332 | { | 2373 | { |
2333 | #if DEBUG_CLOSE | 2374 | if (0 != (rc = pthread_join (pos->pid, &unused))) |
2375 | { | ||
2334 | #if HAVE_MESSAGES | 2376 | #if HAVE_MESSAGES |
2335 | MHD_DLOG (daemon, "MHD shutdown, closing active connections\n"); | 2377 | MHD_DLOG (daemon, "Failed to join a thread: %s\n", |
2378 | STRERROR (rc)); | ||
2336 | #endif | 2379 | #endif |
2337 | #endif | 2380 | abort(); |
2338 | MHD_connection_close (daemon->connections, | 2381 | } |
2339 | MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN); | 2382 | pos->thread_joined = MHD_YES; |
2340 | } | 2383 | } |
2341 | MHD_cleanup_connections (daemon); | ||
2342 | } | 2384 | } |
2385 | while (NULL != (pos = daemon->connections_head)) | ||
2386 | { | ||
2387 | pos->state = MHD_CONNECTION_CLOSED; | ||
2388 | DLL_remove (daemon->connections_head, | ||
2389 | daemon->connections_tail, | ||
2390 | pos); | ||
2391 | DLL_insert (daemon->cleanup_head, | ||
2392 | daemon->cleanup_tail, | ||
2393 | pos); | ||
2394 | } | ||
2395 | MHD_cleanup_connections (daemon); | ||
2343 | } | 2396 | } |
2344 | 2397 | ||
2345 | 2398 | ||
@@ -2387,7 +2440,7 @@ MHD_stop_daemon (struct MHD_Daemon *daemon) | |||
2387 | #endif | 2440 | #endif |
2388 | abort(); | 2441 | abort(); |
2389 | } | 2442 | } |
2390 | MHD_close_connections (&daemon->worker_pool[i]); | 2443 | close_all_connections (&daemon->worker_pool[i]); |
2391 | } | 2444 | } |
2392 | free (daemon->worker_pool); | 2445 | free (daemon->worker_pool); |
2393 | 2446 | ||
@@ -2404,7 +2457,7 @@ MHD_stop_daemon (struct MHD_Daemon *daemon) | |||
2404 | abort(); | 2457 | abort(); |
2405 | } | 2458 | } |
2406 | } | 2459 | } |
2407 | MHD_close_connections (daemon); | 2460 | close_all_connections (daemon); |
2408 | CLOSE (fd); | 2461 | CLOSE (fd); |
2409 | 2462 | ||
2410 | /* TLS clean up */ | 2463 | /* TLS clean up */ |
@@ -2437,7 +2490,7 @@ MHD_stop_daemon (struct MHD_Daemon *daemon) | |||
2437 | pthread_mutex_destroy (&daemon->nnc_lock); | 2490 | pthread_mutex_destroy (&daemon->nnc_lock); |
2438 | #endif | 2491 | #endif |
2439 | pthread_mutex_destroy (&daemon->per_ip_connection_mutex); | 2492 | pthread_mutex_destroy (&daemon->per_ip_connection_mutex); |
2440 | 2493 | pthread_mutex_destroy (&daemon->cleanup_connection_mutex); | |
2441 | free (daemon); | 2494 | free (daemon); |
2442 | } | 2495 | } |
2443 | 2496 | ||
diff --git a/src/daemon/internal.h b/src/daemon/internal.h index 9a3eb8cb..fcacc523 100644 --- a/src/daemon/internal.h +++ b/src/daemon/internal.h | |||
@@ -379,11 +379,15 @@ enum MHD_CONNECTION_STATE | |||
379 | MHD_CONNECTION_FOOTERS_SENT = MHD_CONNECTION_FOOTERS_SENDING + 1, | 379 | MHD_CONNECTION_FOOTERS_SENT = MHD_CONNECTION_FOOTERS_SENDING + 1, |
380 | 380 | ||
381 | /** | 381 | /** |
382 | * 19: This connection is closed (no more activity | 382 | * 19: This connection is to be closed. |
383 | * allowed). | ||
384 | */ | 383 | */ |
385 | MHD_CONNECTION_CLOSED = MHD_CONNECTION_FOOTERS_SENT + 1, | 384 | MHD_CONNECTION_CLOSED = MHD_CONNECTION_FOOTERS_SENT + 1, |
386 | 385 | ||
386 | /** | ||
387 | * 20: This connection is finished (only to be freed) | ||
388 | */ | ||
389 | MHD_CONNECTION_IN_CLEANUP = MHD_CONNECTION_CLOSED + 1, | ||
390 | |||
387 | /* | 391 | /* |
388 | * SSL/TLS connection states | 392 | * SSL/TLS connection states |
389 | */ | 393 | */ |
@@ -440,11 +444,16 @@ struct MHD_Connection | |||
440 | { | 444 | { |
441 | 445 | ||
442 | /** | 446 | /** |
443 | * This is a linked list. | 447 | * This is a doubly-linked list. |
444 | */ | 448 | */ |
445 | struct MHD_Connection *next; | 449 | struct MHD_Connection *next; |
446 | 450 | ||
447 | /** | 451 | /** |
452 | * This is a doubly-linked list. | ||
453 | */ | ||
454 | struct MHD_Connection *prev; | ||
455 | |||
456 | /** | ||
448 | * Reference to the MHD_Daemon struct. | 457 | * Reference to the MHD_Daemon struct. |
449 | */ | 458 | */ |
450 | struct MHD_Daemon *daemon; | 459 | struct MHD_Daemon *daemon; |
@@ -622,6 +631,11 @@ struct MHD_Connection | |||
622 | int read_closed; | 631 | int read_closed; |
623 | 632 | ||
624 | /** | 633 | /** |
634 | * Set to MHD_YES if the thread has been joined. | ||
635 | */ | ||
636 | int thread_joined; | ||
637 | |||
638 | /** | ||
625 | * State in the FSM for this connection. | 639 | * State in the FSM for this connection. |
626 | */ | 640 | */ |
627 | enum MHD_CONNECTION_STATE state; | 641 | enum MHD_CONNECTION_STATE state; |
@@ -747,9 +761,24 @@ struct MHD_Daemon | |||
747 | void *default_handler_cls; | 761 | void *default_handler_cls; |
748 | 762 | ||
749 | /** | 763 | /** |
750 | * Linked list of our current connections. | 764 | * Tail of doubly-linked list of our current, active connections. |
765 | */ | ||
766 | struct MHD_Connection *connections_head; | ||
767 | |||
768 | /** | ||
769 | * Tail of doubly-linked list of our current, active connections. | ||
770 | */ | ||
771 | struct MHD_Connection *connections_tail; | ||
772 | |||
773 | /** | ||
774 | * Tail of doubly-linked list of connections to clean up. | ||
751 | */ | 775 | */ |
752 | struct MHD_Connection *connections; | 776 | struct MHD_Connection *cleanup_head; |
777 | |||
778 | /** | ||
779 | * Tail of doubly-linked list of connections to clean up. | ||
780 | */ | ||
781 | struct MHD_Connection *cleanup_tail; | ||
753 | 782 | ||
754 | /** | 783 | /** |
755 | * Function to call to check if we should | 784 | * Function to call to check if we should |
@@ -847,11 +876,16 @@ struct MHD_Daemon | |||
847 | pthread_t pid; | 876 | pthread_t pid; |
848 | 877 | ||
849 | /** | 878 | /** |
850 | * Mutex for per-IP connection counts | 879 | * Mutex for per-IP connection counts. |
851 | */ | 880 | */ |
852 | pthread_mutex_t per_ip_connection_mutex; | 881 | pthread_mutex_t per_ip_connection_mutex; |
853 | 882 | ||
854 | /** | 883 | /** |
884 | * Mutex for (modifying) access to the "cleanup" connection DLL. | ||
885 | */ | ||
886 | pthread_mutex_t cleanup_connection_mutex; | ||
887 | |||
888 | /** | ||
855 | * Listen socket. | 889 | * Listen socket. |
856 | */ | 890 | */ |
857 | int socket_fd; | 891 | int socket_fd; |
@@ -966,5 +1000,44 @@ struct MHD_Daemon | |||
966 | #endif | 1000 | #endif |
967 | 1001 | ||
968 | 1002 | ||
1003 | /** | ||
1004 | * Insert an element at the head of a DLL. Assumes that head, tail and | ||
1005 | * element are structs with prev and next fields. | ||
1006 | * | ||
1007 | * @param head pointer to the head of the DLL | ||
1008 | * @param tail pointer to the tail of the DLL | ||
1009 | * @param element element to insert | ||
1010 | */ | ||
1011 | #define DLL_insert(head,tail,element) do { \ | ||
1012 | (element)->next = (head); \ | ||
1013 | (element)->prev = NULL; \ | ||
1014 | if ((tail) == NULL) \ | ||
1015 | (tail) = element; \ | ||
1016 | else \ | ||
1017 | (head)->prev = element; \ | ||
1018 | (head) = (element); } while (0) | ||
1019 | |||
1020 | |||
1021 | /** | ||
1022 | * Remove an element from a DLL. Assumes | ||
1023 | * that head, tail and element are structs | ||
1024 | * with prev and next fields. | ||
1025 | * | ||
1026 | * @param head pointer to the head of the DLL | ||
1027 | * @param tail pointer to the tail of the DLL | ||
1028 | * @param element element to remove | ||
1029 | */ | ||
1030 | #define DLL_remove(head,tail,element) do { \ | ||
1031 | if ((element)->prev == NULL) \ | ||
1032 | (head) = (element)->next; \ | ||
1033 | else \ | ||
1034 | (element)->prev->next = (element)->next; \ | ||
1035 | if ((element)->next == NULL) \ | ||
1036 | (tail) = (element)->prev; \ | ||
1037 | else \ | ||
1038 | (element)->next->prev = (element)->prev; \ | ||
1039 | (element)->next = NULL; \ | ||
1040 | (element)->prev = NULL; } while (0) | ||
1041 | |||
969 | 1042 | ||
970 | #endif | 1043 | #endif |