diff options
author | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2016-10-24 20:08:20 +0300 |
---|---|---|
committer | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2016-10-30 18:49:45 +0300 |
commit | 63abb11b52edbee5773edf6031e15408b6f722c6 (patch) | |
tree | bd9c9bd49f8320a0ea353c67f27a2513bc5d63fd | |
parent | f8cfc4f89f7b36394a733b462badd6d8b7f21495 (diff) | |
download | libmicrohttpd-63abb11b52edbee5773edf6031e15408b6f722c6.tar.gz libmicrohttpd-63abb11b52edbee5773edf6031e15408b6f722c6.zip |
Reworked "upgraded" closure logic: resources deallocated and sockets are closed
asynchronously only in daemon's thread and only when all data was forwarded and
application signaled about upgraded closure.
-rw-r--r-- | src/include/microhttpd.h | 2 | ||||
-rw-r--r-- | src/microhttpd/connection.c | 61 | ||||
-rw-r--r-- | src/microhttpd/connection.h | 10 | ||||
-rw-r--r-- | src/microhttpd/daemon.c | 342 | ||||
-rw-r--r-- | src/microhttpd/internal.h | 33 | ||||
-rw-r--r-- | src/microhttpd/response.c | 97 | ||||
-rw-r--r-- | src/microhttpd/test_upgrade.c | 5 | ||||
-rw-r--r-- | src/microhttpd/test_upgrade_ssl.c | 5 |
8 files changed, 324 insertions, 231 deletions
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h index efba0ee6..a099d47f 100644 --- a/src/include/microhttpd.h +++ b/src/include/microhttpd.h | |||
@@ -126,7 +126,7 @@ typedef intptr_t ssize_t; | |||
126 | * Current version of the library. | 126 | * Current version of the library. |
127 | * 0x01093001 = 1.9.30-1. | 127 | * 0x01093001 = 1.9.30-1. |
128 | */ | 128 | */ |
129 | #define MHD_VERSION 0x00095103 | 129 | #define MHD_VERSION 0x00095204 |
130 | 130 | ||
131 | /** | 131 | /** |
132 | * MHD-internal return code for "YES". | 132 | * MHD-internal return code for "YES". |
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c index 52b67b05..d3ccdf26 100644 --- a/src/microhttpd/connection.c +++ b/src/microhttpd/connection.c | |||
@@ -22,6 +22,7 @@ | |||
22 | * @brief Methods for managing connections | 22 | * @brief Methods for managing connections |
23 | * @author Daniel Pittman | 23 | * @author Daniel Pittman |
24 | * @author Christian Grothoff | 24 | * @author Christian Grothoff |
25 | * @author Karlson2k (Evgeny Grin) | ||
25 | */ | 26 | */ |
26 | 27 | ||
27 | #include "internal.h" | 28 | #include "internal.h" |
@@ -527,6 +528,63 @@ MHD_connection_close_ (struct MHD_Connection *connection, | |||
527 | 528 | ||
528 | 529 | ||
529 | /** | 530 | /** |
531 | * Stop TLS forwarding on upgraded connection and | ||
532 | * reflect remote disconnect state to socketpair. | ||
533 | * @remark In thread-per-connection mode this function | ||
534 | * can be called from any thread, in other modes this | ||
535 | * function must be called only from thread that process | ||
536 | * daemon's select()/poll()/etc. | ||
537 | * | ||
538 | * @param connection the upgraded connection | ||
539 | */ | ||
540 | void | ||
541 | MHD_connection_finish_forward_ (struct MHD_Connection *connection) | ||
542 | { | ||
543 | struct MHD_Daemon *daemon = connection->daemon; | ||
544 | struct MHD_UpgradeResponseHandle *urh = connection->urh; | ||
545 | |||
546 | if (0 == (daemon->options & MHD_USE_TLS)) | ||
547 | return; /* Nothing to do with non-TLS connection. */ | ||
548 | |||
549 | if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) | ||
550 | DLL_remove (daemon->urh_head, | ||
551 | daemon->urh_tail, | ||
552 | urh); | ||
553 | #if EPOLL_SUPPORT | ||
554 | if ( (0 != (daemon->options & MHD_USE_EPOLL)) && | ||
555 | (0 != epoll_ctl (daemon->epoll_upgrade_fd, | ||
556 | EPOLL_CTL_DEL, | ||
557 | connection->socket_fd, | ||
558 | NULL)) ) | ||
559 | { | ||
560 | MHD_PANIC (_("Failed to remove FD from epoll set\n")); | ||
561 | } | ||
562 | #endif /* EPOLL_SUPPORT */ | ||
563 | if (MHD_INVALID_SOCKET != urh->mhd.socket) | ||
564 | { | ||
565 | #if EPOLL_SUPPORT | ||
566 | if ( (0 != (daemon->options & MHD_USE_EPOLL)) && | ||
567 | (0 != epoll_ctl (daemon->epoll_upgrade_fd, | ||
568 | EPOLL_CTL_DEL, | ||
569 | urh->mhd.socket, | ||
570 | NULL)) ) | ||
571 | { | ||
572 | MHD_PANIC (_("Failed to remove FD from epoll set\n")); | ||
573 | } | ||
574 | #endif /* EPOLL_SUPPORT */ | ||
575 | /* Reflect remote disconnect to application by breaking | ||
576 | * socketpair connection. */ | ||
577 | shutdown (urh->mhd.socket, SHUT_RDWR); | ||
578 | } | ||
579 | /* Socketpair sockets will remain open as they will be | ||
580 | * used with MHD_UPGRADE_ACTION_CLOSE. They will be | ||
581 | * closed by MHD_cleanup_upgraded_connection_() during | ||
582 | * connection's final cleanup. | ||
583 | */ | ||
584 | } | ||
585 | |||
586 | |||
587 | /** | ||
530 | * A serious error occured, close the | 588 | * A serious error occured, close the |
531 | * connection (and notify the application). | 589 | * connection (and notify the application). |
532 | * | 590 | * |
@@ -3080,8 +3138,9 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
3080 | cleanup_connection (connection); | 3138 | cleanup_connection (connection); |
3081 | return MHD_NO; | 3139 | return MHD_NO; |
3082 | case MHD_CONNECTION_UPGRADE: | 3140 | case MHD_CONNECTION_UPGRADE: |
3083 | case MHD_CONNECTION_UPGRADE_CLOSED: | ||
3084 | return MHD_YES; /* keep open */ | 3141 | return MHD_YES; /* keep open */ |
3142 | case MHD_CONNECTION_UPGRADE_CLOSED: | ||
3143 | return MHD_YES; /* "Upgraded" connection should be closed in special way. */ | ||
3085 | default: | 3144 | default: |
3086 | EXTRA_CHECK (0); | 3145 | EXTRA_CHECK (0); |
3087 | break; | 3146 | break; |
diff --git a/src/microhttpd/connection.h b/src/microhttpd/connection.h index 0fce7346..a962a40c 100644 --- a/src/microhttpd/connection.h +++ b/src/microhttpd/connection.h | |||
@@ -22,6 +22,7 @@ | |||
22 | * @brief Methods for managing connections | 22 | * @brief Methods for managing connections |
23 | * @author Daniel Pittman | 23 | * @author Daniel Pittman |
24 | * @author Christian Grothoff | 24 | * @author Christian Grothoff |
25 | * @author Karlson2k (Evgeny Grin) | ||
25 | */ | 26 | */ |
26 | 27 | ||
27 | #ifndef CONNECTION_H | 28 | #ifndef CONNECTION_H |
@@ -97,6 +98,15 @@ MHD_connection_close_ (struct MHD_Connection *connection, | |||
97 | enum MHD_RequestTerminationCode termination_code); | 98 | enum MHD_RequestTerminationCode termination_code); |
98 | 99 | ||
99 | 100 | ||
101 | /** | ||
102 | * Stop TLS forwarding on upgraded connection and | ||
103 | * reflect remote disconnect state to socketpair. | ||
104 | * @param connection the upgraded connection | ||
105 | */ | ||
106 | void | ||
107 | MHD_connection_finish_forward_ (struct MHD_Connection *connection); | ||
108 | |||
109 | |||
100 | #ifdef EPOLL_SUPPORT | 110 | #ifdef EPOLL_SUPPORT |
101 | /** | 111 | /** |
102 | * Perform epoll processing, possibly moving the connection back into | 112 | * Perform epoll processing, possibly moving the connection back into |
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c index 2bce6d15..622ab34e 100644 --- a/src/microhttpd/daemon.c +++ b/src/microhttpd/daemon.c | |||
@@ -23,6 +23,7 @@ | |||
23 | * @brief A minimal-HTTP server library | 23 | * @brief A minimal-HTTP server library |
24 | * @author Daniel Pittman | 24 | * @author Daniel Pittman |
25 | * @author Christian Grothoff | 25 | * @author Christian Grothoff |
26 | * @author Karlson2k (Evgeny Grin) | ||
26 | */ | 27 | */ |
27 | #include "platform.h" | 28 | #include "platform.h" |
28 | #include "mhd_threads.h" | 29 | #include "mhd_threads.h" |
@@ -688,6 +689,7 @@ urh_to_fdset (struct MHD_UpgradeResponseHandle *urh, | |||
688 | fd_setsize)) ) | 689 | fd_setsize)) ) |
689 | return MHD_NO; | 690 | return MHD_NO; |
690 | if ( (0 == (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) && | 691 | if ( (0 == (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) && |
692 | (MHD_NO == urh->was_closed) && | ||
691 | (MHD_INVALID_SOCKET != urh->mhd.socket) && | 693 | (MHD_INVALID_SOCKET != urh->mhd.socket) && |
692 | (! MHD_add_to_fd_set_ (urh->mhd.socket, | 694 | (! MHD_add_to_fd_set_ (urh->mhd.socket, |
693 | ws, | 695 | ws, |
@@ -695,6 +697,7 @@ urh_to_fdset (struct MHD_UpgradeResponseHandle *urh, | |||
695 | fd_setsize)) ) | 697 | fd_setsize)) ) |
696 | return MHD_NO; | 698 | return MHD_NO; |
697 | if ( (urh->in_buffer_used < urh->in_buffer_size) && | 699 | if ( (urh->in_buffer_used < urh->in_buffer_size) && |
700 | (MHD_NO == urh->was_closed) && | ||
698 | (MHD_INVALID_SOCKET != urh->connection->socket_fd) && | 701 | (MHD_INVALID_SOCKET != urh->connection->socket_fd) && |
699 | (! MHD_add_to_fd_set_ (urh->connection->socket_fd, | 702 | (! MHD_add_to_fd_set_ (urh->connection->socket_fd, |
700 | rs, | 703 | rs, |
@@ -934,73 +937,19 @@ call_handlers (struct MHD_Connection *con, | |||
934 | void | 937 | void |
935 | MHD_cleanup_upgraded_connection_ (struct MHD_Connection *connection) | 938 | MHD_cleanup_upgraded_connection_ (struct MHD_Connection *connection) |
936 | { | 939 | { |
937 | struct MHD_Daemon *daemon = connection->daemon; | ||
938 | struct MHD_UpgradeResponseHandle *urh = connection->urh; | 940 | struct MHD_UpgradeResponseHandle *urh = connection->urh; |
939 | 941 | ||
940 | #if HTTPS_SUPPORT | 942 | /* Signal remote client the end of TLS connection by |
941 | if ( (NULL != urh) && | 943 | * gracefully closing TLS session. */ |
942 | (0 != (daemon->options & MHD_USE_TLS)) ) | 944 | if (0 != (connection->daemon->options & MHD_USE_TLS)) |
943 | { | 945 | gnutls_bye (connection->tls_session, |
944 | if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) | 946 | GNUTLS_SHUT_WR); |
945 | DLL_remove (daemon->urh_head, | 947 | |
946 | daemon->urh_tail, | 948 | if (MHD_INVALID_SOCKET != urh->mhd.socket) |
947 | urh); | 949 | MHD_socket_close_chk_ (urh->mhd.socket); |
948 | #if EPOLL_SUPPORT | 950 | |
949 | if (0 != (daemon->options & MHD_USE_EPOLL)) | 951 | if (MHD_INVALID_SOCKET != urh->app.socket) |
950 | { | 952 | MHD_socket_close_chk_ (urh->app.socket); |
951 | /* epoll documentation suggests that closing a FD | ||
952 | automatically removes it from the epoll set; however, | ||
953 | this is not true as if we fail to do manually remove it, | ||
954 | we are still seeing an event for this fd in epoll, | ||
955 | causing grief (use-after-free...) --- at least on my | ||
956 | system. */ | ||
957 | if (0 != epoll_ctl (daemon->epoll_upgrade_fd, | ||
958 | EPOLL_CTL_DEL, | ||
959 | connection->socket_fd, | ||
960 | NULL)) | ||
961 | MHD_PANIC (_("Failed to remove FD from epoll set\n")); | ||
962 | } | ||
963 | #endif /* EPOLL_SUPPORT */ | ||
964 | if (MHD_INVALID_SOCKET != urh->mhd.socket) | ||
965 | { | ||
966 | /* epoll documentation suggests that closing a FD | ||
967 | automatically removes it from the epoll set; however, | ||
968 | this is not true as if we fail to do manually remove it, | ||
969 | we are still seeing an event for this fd in epoll, | ||
970 | causing grief (use-after-free...) --- at least on my | ||
971 | system. */ | ||
972 | #if EPOLL_SUPPORT | ||
973 | if ( (0 != (daemon->options & MHD_USE_EPOLL)) && | ||
974 | (0 != epoll_ctl (daemon->epoll_upgrade_fd, | ||
975 | EPOLL_CTL_DEL, | ||
976 | urh->mhd.socket, | ||
977 | NULL)) ) | ||
978 | MHD_PANIC (_("Failed to remove FD from epoll set\n")); | ||
979 | #endif /* EPOLL_SUPPORT */ | ||
980 | MHD_socket_close_chk_ (urh->mhd.socket); | ||
981 | } | ||
982 | if (MHD_INVALID_SOCKET != urh->app.socket) | ||
983 | MHD_socket_close_chk_ (urh->app.socket); | ||
984 | } | ||
985 | #endif /* HTTPS_SUPPORT */ | ||
986 | if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) | ||
987 | { | ||
988 | /* resuming the connection will indirectly close it */ | ||
989 | MHD_resume_connection (connection); | ||
990 | #if HTTPS_SUPPORT | ||
991 | if (0 != (daemon->options & MHD_USE_TLS)) | ||
992 | { | ||
993 | gnutls_bye (connection->tls_session, | ||
994 | GNUTLS_SHUT_RDWR); | ||
995 | } | ||
996 | #endif | ||
997 | } | ||
998 | else | ||
999 | { | ||
1000 | /* the thread would no longer close it */ | ||
1001 | MHD_connection_close_ (connection, | ||
1002 | MHD_REQUEST_TERMINATED_COMPLETED_OK); | ||
1003 | } | ||
1004 | 953 | ||
1005 | connection->urh = NULL; | 954 | connection->urh = NULL; |
1006 | if (NULL != urh) | 955 | if (NULL != urh) |
@@ -1259,14 +1208,6 @@ process_urh (struct MHD_UpgradeResponseHandle *urh) | |||
1259 | urh->app.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | 1208 | urh->app.celi &= ~MHD_EPOLL_STATE_WRITE_READY; |
1260 | urh->mhd.celi &= ~MHD_EPOLL_STATE_READ_READY; | 1209 | urh->mhd.celi &= ~MHD_EPOLL_STATE_READ_READY; |
1261 | } | 1210 | } |
1262 | |||
1263 | /* cleanup connection if it was closed and all data was sent */ | ||
1264 | if ( (MHD_NO != urh->was_closed) && | ||
1265 | (0 == urh->out_buffer_size) && | ||
1266 | (0 == urh->out_buffer_used) ) | ||
1267 | { | ||
1268 | MHD_cleanup_upgraded_connection_ (urh->connection); | ||
1269 | } | ||
1270 | } | 1211 | } |
1271 | #endif | 1212 | #endif |
1272 | 1213 | ||
@@ -1292,7 +1233,8 @@ thread_main_connection_upgrade (struct MHD_Connection *con) | |||
1292 | if ( (0 != (daemon->options & MHD_USE_TLS)) && | 1233 | if ( (0 != (daemon->options & MHD_USE_TLS)) && |
1293 | (0 == (daemon->options & MHD_USE_POLL))) | 1234 | (0 == (daemon->options & MHD_USE_POLL))) |
1294 | { | 1235 | { |
1295 | while (MHD_CONNECTION_UPGRADE == con->state) | 1236 | while ( (MHD_CONNECTION_UPGRADE == con->state) || |
1237 | (0 != urh->out_buffer_used) ) | ||
1296 | { | 1238 | { |
1297 | /* use select */ | 1239 | /* use select */ |
1298 | fd_set rs; | 1240 | fd_set rs; |
@@ -1356,7 +1298,8 @@ thread_main_connection_upgrade (struct MHD_Connection *con) | |||
1356 | /* use poll() */ | 1298 | /* use poll() */ |
1357 | const unsigned int timeout = UINT_MAX; | 1299 | const unsigned int timeout = UINT_MAX; |
1358 | 1300 | ||
1359 | while (MHD_CONNECTION_UPGRADE == con->state) | 1301 | while ( (MHD_CONNECTION_UPGRADE == con->state) || |
1302 | (0 != urh->out_buffer_used) ) | ||
1360 | { | 1303 | { |
1361 | struct pollfd p[2]; | 1304 | struct pollfd p[2]; |
1362 | 1305 | ||
@@ -1410,6 +1353,10 @@ thread_main_connection_upgrade (struct MHD_Connection *con) | |||
1410 | #endif | 1353 | #endif |
1411 | /* end HTTPS */ | 1354 | /* end HTTPS */ |
1412 | #endif | 1355 | #endif |
1356 | /* TLS forwarding was finished. Cleanup socketpair. */ | ||
1357 | MHD_connection_finish_forward_ (con); | ||
1358 | /* Do not set 'urh->clean_ready' yet as 'urh' will be used | ||
1359 | * in connection thread for a little while. */ | ||
1413 | } | 1360 | } |
1414 | 1361 | ||
1415 | 1362 | ||
@@ -1456,7 +1403,7 @@ thread_main_handle_connection (void *data) | |||
1456 | const unsigned int timeout = daemon->connection_timeout; | 1403 | const unsigned int timeout = daemon->connection_timeout; |
1457 | _MHD_bool was_suspended = 0; | 1404 | _MHD_bool was_suspended = 0; |
1458 | 1405 | ||
1459 | if (MHD_NO != con->suspended) | 1406 | if (MHD_NO != con->suspended && NULL == con->urh) |
1460 | { | 1407 | { |
1461 | /* Connection was suspended, wait for resume. */ | 1408 | /* Connection was suspended, wait for resume. */ |
1462 | was_suspended = !0; | 1409 | was_suspended = !0; |
@@ -1721,7 +1668,11 @@ thread_main_handle_connection (void *data) | |||
1721 | goto exit; | 1668 | goto exit; |
1722 | } | 1669 | } |
1723 | #endif | 1670 | #endif |
1724 | if (MHD_CONNECTION_UPGRADE == con->state) | 1671 | /* Check for 'MHD_CONNECTION_UPGRADE_CLOSED' too: |
1672 | * application can finish with "upgraded" connection | ||
1673 | * before this thread process it for the first time. */ | ||
1674 | if ( (MHD_CONNECTION_UPGRADE == con->state) || | ||
1675 | (MHD_CONNECTION_UPGRADE_CLOSED == con->state) ) | ||
1725 | { | 1676 | { |
1726 | /* Normal HTTP processing is finished, | 1677 | /* Normal HTTP processing is finished, |
1727 | * notify application. */ | 1678 | * notify application. */ |
@@ -1734,13 +1685,17 @@ thread_main_handle_connection (void *data) | |||
1734 | con->client_aware = MHD_NO; | 1685 | con->client_aware = MHD_NO; |
1735 | 1686 | ||
1736 | thread_main_connection_upgrade (con); | 1687 | thread_main_connection_upgrade (con); |
1737 | #if HTTPS_SUPPORT | 1688 | /* MHD_connection_finish_forward_() was called by thread_main_connection_upgrade(). */ |
1738 | if (0 != (daemon->options & MHD_USE_TLS) ) | 1689 | |
1739 | break; | 1690 | /* "Upgraded" data will not be used in this thread from this point. */ |
1740 | #endif | 1691 | con->urh->clean_ready = MHD_YES; |
1692 | /* If 'urh->was_closed' set to MHD_YES, connection will be | ||
1693 | * moved immediately to cleanup list. Otherwise connection | ||
1694 | * will stay in suspended list until 'urh' will be marked | ||
1695 | * with 'was_closed' by application. */ | ||
1696 | MHD_resume_connection(con); | ||
1741 | 1697 | ||
1742 | /* skip usual clean up EXCEPT for the completion | 1698 | /* skip usual clean up */ |
1743 | notification (which must be done in this thread)! */ | ||
1744 | return (MHD_THRD_RTRN_TYPE_) 0; | 1699 | return (MHD_THRD_RTRN_TYPE_) 0; |
1745 | } | 1700 | } |
1746 | } | 1701 | } |
@@ -2459,6 +2414,8 @@ MHD_resume_connection (struct MHD_Connection *connection) | |||
2459 | /** | 2414 | /** |
2460 | * Run through the suspended connections and move any that are no | 2415 | * Run through the suspended connections and move any that are no |
2461 | * longer suspended back to the active state. | 2416 | * longer suspended back to the active state. |
2417 | * @remark To be called only from thread that process | ||
2418 | * daemon's select()/poll()/etc. | ||
2462 | * | 2419 | * |
2463 | * @param daemon daemon context | 2420 | * @param daemon daemon context |
2464 | * @return #MHD_YES if a connection was actually resumed | 2421 | * @return #MHD_YES if a connection was actually resumed |
@@ -2490,40 +2447,55 @@ resume_suspended_connections (struct MHD_Daemon *daemon) | |||
2490 | while (NULL != (pos = next)) | 2447 | while (NULL != (pos = next)) |
2491 | { | 2448 | { |
2492 | next = pos->next; | 2449 | next = pos->next; |
2493 | if (MHD_NO == pos->resuming) | 2450 | if ( (MHD_NO == pos->resuming) || |
2451 | ((NULL != pos->urh) && | ||
2452 | ((MHD_NO == pos->urh->was_closed) || (MHD_NO == pos->urh->clean_ready))) ) | ||
2494 | continue; | 2453 | continue; |
2495 | ret = MHD_YES; | 2454 | ret = MHD_YES; |
2496 | DLL_remove (daemon->suspended_connections_head, | 2455 | DLL_remove (daemon->suspended_connections_head, |
2497 | daemon->suspended_connections_tail, | 2456 | daemon->suspended_connections_tail, |
2498 | pos); | 2457 | pos); |
2499 | DLL_insert (daemon->connections_head, | 2458 | if (NULL == pos->urh) |
2500 | daemon->connections_tail, | ||
2501 | pos); | ||
2502 | if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) | ||
2503 | { | 2459 | { |
2504 | if (pos->connection_timeout == daemon->connection_timeout) | 2460 | DLL_insert (daemon->connections_head, |
2505 | XDLL_insert (daemon->normal_timeout_head, | 2461 | daemon->connections_tail, |
2506 | daemon->normal_timeout_tail, | 2462 | pos); |
2507 | pos); | 2463 | if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) |
2508 | else | 2464 | { |
2509 | XDLL_insert (daemon->manual_timeout_head, | 2465 | if (pos->connection_timeout == daemon->connection_timeout) |
2510 | daemon->manual_timeout_tail, | 2466 | XDLL_insert (daemon->normal_timeout_head, |
2511 | pos); | 2467 | daemon->normal_timeout_tail, |
2512 | } | 2468 | pos); |
2469 | else | ||
2470 | XDLL_insert (daemon->manual_timeout_head, | ||
2471 | daemon->manual_timeout_tail, | ||
2472 | pos); | ||
2473 | } | ||
2513 | #ifdef EPOLL_SUPPORT | 2474 | #ifdef EPOLL_SUPPORT |
2514 | if (0 != (daemon->options & MHD_USE_EPOLL)) | 2475 | if (0 != (daemon->options & MHD_USE_EPOLL)) |
2476 | { | ||
2477 | if (0 != (pos->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) | ||
2478 | MHD_PANIC ("Resumed connection was already in EREADY set\n"); | ||
2479 | /* we always mark resumed connections as ready, as we | ||
2480 | might have missed the edge poll event during suspension */ | ||
2481 | EDLL_insert (daemon->eready_head, | ||
2482 | daemon->eready_tail, | ||
2483 | pos); | ||
2484 | pos->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL; | ||
2485 | pos->epoll_state &= ~MHD_EPOLL_STATE_SUSPENDED; | ||
2486 | } | ||
2487 | #endif | ||
2488 | } | ||
2489 | else | ||
2515 | { | 2490 | { |
2516 | if (0 != (pos->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) | 2491 | /* Data forwarding was finished (for TLS connections) AND |
2517 | MHD_PANIC ("Resumed connection was already in EREADY set\n"); | 2492 | * application was closed upgraded connection. |
2518 | /* we always mark resumed connections as ready, as we | 2493 | * Insert connection into cleanup list. */ |
2519 | might have missed the edge poll event during suspension */ | 2494 | DLL_insert (daemon->cleanup_head, |
2520 | EDLL_insert (daemon->eready_head, | 2495 | daemon->cleanup_tail, |
2521 | daemon->eready_tail, | 2496 | pos); |
2522 | pos); | 2497 | |
2523 | pos->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL; | ||
2524 | pos->epoll_state &= ~MHD_EPOLL_STATE_SUSPENDED; | ||
2525 | } | 2498 | } |
2526 | #endif | ||
2527 | pos->suspended = MHD_NO; | 2499 | pos->suspended = MHD_NO; |
2528 | pos->resuming = MHD_NO; | 2500 | pos->resuming = MHD_NO; |
2529 | } | 2501 | } |
@@ -2735,6 +2707,8 @@ MHD_accept_connection (struct MHD_Daemon *daemon) | |||
2735 | * Free resources associated with all closed connections. | 2707 | * Free resources associated with all closed connections. |
2736 | * (destroy responses, free buffers, etc.). All closed | 2708 | * (destroy responses, free buffers, etc.). All closed |
2737 | * connections are kept in the "cleanup" doubly-linked list. | 2709 | * connections are kept in the "cleanup" doubly-linked list. |
2710 | * @remark To be called only from thread that | ||
2711 | * process daemon's select()/poll()/etc. | ||
2738 | * | 2712 | * |
2739 | * @param daemon daemon to clean up | 2713 | * @param daemon daemon to clean up |
2740 | */ | 2714 | */ |
@@ -2758,6 +2732,8 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon) | |||
2758 | (MHD_NO == pos->thread_joined) && | 2732 | (MHD_NO == pos->thread_joined) && |
2759 | (! MHD_join_thread_ (pos->pid)) ) | 2733 | (! MHD_join_thread_ (pos->pid)) ) |
2760 | MHD_PANIC (_("Failed to join a thread\n")); | 2734 | MHD_PANIC (_("Failed to join a thread\n")); |
2735 | if (NULL != pos->urh) | ||
2736 | MHD_cleanup_upgraded_connection_ (pos); | ||
2761 | MHD_pool_destroy (pos->pool); | 2737 | MHD_pool_destroy (pos->pool); |
2762 | #if HTTPS_SUPPORT | 2738 | #if HTTPS_SUPPORT |
2763 | if (NULL != pos->tls_session) | 2739 | if (NULL != pos->tls_session) |
@@ -3014,6 +2990,17 @@ MHD_run_from_select (struct MHD_Daemon *daemon, | |||
3014 | write_fd_set); | 2990 | write_fd_set); |
3015 | /* call generic forwarding function for passing data */ | 2991 | /* call generic forwarding function for passing data */ |
3016 | process_urh (urh); | 2992 | process_urh (urh); |
2993 | /* Finished forwarding? */ | ||
2994 | if ( (0 == urh->in_buffer_size) && | ||
2995 | (0 == urh->out_buffer_size) && | ||
2996 | (0 == urh->in_buffer_used) && | ||
2997 | (0 == urh->out_buffer_used) ) | ||
2998 | { | ||
2999 | MHD_connection_finish_forward_ (urh->connection); | ||
3000 | urh->clean_ready = MHD_YES; | ||
3001 | /* Resuming will move connection to cleanup list. */ | ||
3002 | MHD_resume_connection(urh->connection); | ||
3003 | } | ||
3017 | } | 3004 | } |
3018 | #endif | 3005 | #endif |
3019 | MHD_cleanup_connections (daemon); | 3006 | MHD_cleanup_connections (daemon); |
@@ -3367,28 +3354,45 @@ MHD_poll_all (struct MHD_Daemon *daemon, | |||
3367 | { | 3354 | { |
3368 | if (i >= num_connections) | 3355 | if (i >= num_connections) |
3369 | break; /* connection list changed somehow, retry later ... */ | 3356 | break; /* connection list changed somehow, retry later ... */ |
3357 | |||
3358 | /* Get next connection here as connection can be removed | ||
3359 | * from 'daemon->urh_head' list. */ | ||
3370 | urhn = urh->next; | 3360 | urhn = urh->next; |
3371 | if (p[poll_server+i].fd != urh->connection->socket_fd) | 3361 | /* Check for fd mismatch. FIXME: required for safety? */ |
3372 | continue; /* fd mismatch, something else happened, retry later ... */ | 3362 | if (p[poll_server+i].fd == urh->connection->socket_fd) |
3373 | if (0 != (p[poll_server+i].revents & POLLIN)) | 3363 | { |
3374 | urh->app.celi |= MHD_EPOLL_STATE_READ_READY; | 3364 | if (0 != (p[poll_server+i].revents & POLLIN)) |
3375 | if (0 != (p[poll_server+i].revents & POLLOUT)) | 3365 | urh->app.celi |= MHD_EPOLL_STATE_READ_READY; |
3376 | urh->app.celi |= MHD_EPOLL_STATE_WRITE_READY; | 3366 | if (0 != (p[poll_server+i].revents & POLLOUT)) |
3367 | urh->app.celi |= MHD_EPOLL_STATE_WRITE_READY; | ||
3368 | } | ||
3377 | i++; | 3369 | i++; |
3378 | if (p[poll_server+i].fd != urh->mhd.socket) | 3370 | /* Check for fd mismatch. FIXME: required for safety? */ |
3371 | if (p[poll_server+i].fd == urh->mhd.socket) | ||
3379 | { | 3372 | { |
3380 | /* fd mismatch, something else happened, retry later ... */ | 3373 | if (0 != (p[poll_server+i].revents & POLLIN)) |
3381 | /* may still be able to do something based on updates | 3374 | urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY; |
3382 | to socket_fd availability */ | 3375 | if (0 != (p[poll_server+i].revents & POLLOUT)) |
3383 | process_urh (urh); | 3376 | urh->mhd.celi |= MHD_EPOLL_STATE_WRITE_READY; |
3384 | continue; | ||
3385 | } | 3377 | } |
3386 | if (0 != (p[poll_server+i].revents & POLLIN)) | ||
3387 | urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY; | ||
3388 | if (0 != (p[poll_server+i].revents & POLLOUT)) | ||
3389 | urh->mhd.celi |= MHD_EPOLL_STATE_WRITE_READY; | ||
3390 | i++; | 3378 | i++; |
3391 | process_urh (urh); | 3379 | process_urh (urh); |
3380 | /* Finished forwarding? */ | ||
3381 | if ( (0 == urh->in_buffer_size) && | ||
3382 | (0 == urh->out_buffer_size) && | ||
3383 | (0 == urh->in_buffer_used) && | ||
3384 | (0 == urh->out_buffer_used) ) | ||
3385 | { | ||
3386 | /* MHD_connection_finish_forward_() will remove connection from | ||
3387 | * 'daemon->urh_head' list. */ | ||
3388 | MHD_connection_finish_forward_ (urh->connection); | ||
3389 | urh->clean_ready = MHD_YES; | ||
3390 | /* If 'urh->was_closed' set to MHD_YES, connection will be | ||
3391 | * moved immediately to cleanup list. Otherwise connection | ||
3392 | * will stay in suspended list until 'urh' will be marked | ||
3393 | * with 'was_closed' by application. */ | ||
3394 | MHD_resume_connection(urh->connection); | ||
3395 | } | ||
3392 | } | 3396 | } |
3393 | #endif | 3397 | #endif |
3394 | /* handle 'listen' FD */ | 3398 | /* handle 'listen' FD */ |
@@ -3530,12 +3534,11 @@ run_epoll_for_upgrade (struct MHD_Daemon *daemon) | |||
3530 | { | 3534 | { |
3531 | struct epoll_event events[MAX_EVENTS]; | 3535 | struct epoll_event events[MAX_EVENTS]; |
3532 | int num_events; | 3536 | int num_events; |
3533 | unsigned int i; | ||
3534 | unsigned int j; | ||
3535 | 3537 | ||
3536 | num_events = MAX_EVENTS; | 3538 | num_events = MAX_EVENTS; |
3537 | while (MAX_EVENTS == num_events) | 3539 | while (MAX_EVENTS == num_events) |
3538 | { | 3540 | { |
3541 | unsigned int i; | ||
3539 | /* update event masks */ | 3542 | /* update event masks */ |
3540 | num_events = epoll_wait (daemon->epoll_upgrade_fd, | 3543 | num_events = epoll_wait (daemon->epoll_upgrade_fd, |
3541 | events, | 3544 | events, |
@@ -3555,35 +3558,8 @@ run_epoll_for_upgrade (struct MHD_Daemon *daemon) | |||
3555 | } | 3558 | } |
3556 | for (i=0;i<(unsigned int) num_events;i++) | 3559 | for (i=0;i<(unsigned int) num_events;i++) |
3557 | { | 3560 | { |
3558 | struct UpgradeEpollHandle *ueh = events[i].data.ptr; | 3561 | struct UpgradeEpollHandle * const ueh = events[i].data.ptr; |
3559 | struct MHD_UpgradeResponseHandle *urh; | 3562 | struct MHD_UpgradeResponseHandle * const urh = ueh->urh; |
3560 | |||
3561 | if (NULL == ueh) | ||
3562 | continue; /* was killed, see below */ | ||
3563 | urh = ueh->urh; | ||
3564 | |||
3565 | /* In case we get two events for the same upgrade handle, | ||
3566 | squash them together (otherwise the first one may | ||
3567 | cause us to free the 'urh', and the second one then | ||
3568 | causes a use-after-free). */ | ||
3569 | for (j=i+1;j< (unsigned int) num_events;j++) | ||
3570 | { | ||
3571 | struct UpgradeEpollHandle *uehj = events[j].data.ptr; | ||
3572 | struct MHD_UpgradeResponseHandle *urhj; | ||
3573 | |||
3574 | if (NULL == uehj) | ||
3575 | continue; /* was killed, see below */ | ||
3576 | urhj = uehj->urh; | ||
3577 | |||
3578 | if (urh == urhj) /* yep, indeed the same! */ | ||
3579 | { | ||
3580 | if (0 != (events[j].events & EPOLLIN)) | ||
3581 | uehj->celi |= MHD_EPOLL_STATE_READ_READY; | ||
3582 | if (0 != (events[j].events & EPOLLOUT)) | ||
3583 | uehj->celi |= MHD_EPOLL_STATE_WRITE_READY; | ||
3584 | } | ||
3585 | events[j].data.ptr = NULL; /* kill this one */ | ||
3586 | } | ||
3587 | 3563 | ||
3588 | /* Update our state based on what is ready according to epoll() */ | 3564 | /* Update our state based on what is ready according to epoll() */ |
3589 | if (0 != (events[i].events & EPOLLIN)) | 3565 | if (0 != (events[i].events & EPOLLIN)) |
@@ -3591,8 +3567,21 @@ run_epoll_for_upgrade (struct MHD_Daemon *daemon) | |||
3591 | if (0 != (events[i].events & EPOLLOUT)) | 3567 | if (0 != (events[i].events & EPOLLOUT)) |
3592 | ueh->celi |= MHD_EPOLL_STATE_WRITE_READY; | 3568 | ueh->celi |= MHD_EPOLL_STATE_WRITE_READY; |
3593 | 3569 | ||
3594 | /* shuffle data based on buffers and FD readyness */ | ||
3595 | process_urh (urh); | 3570 | process_urh (urh); |
3571 | /* Finished forwarding? */ | ||
3572 | if ( (0 == urh->in_buffer_size) && | ||
3573 | (0 == urh->out_buffer_size) && | ||
3574 | (0 == urh->in_buffer_used) && | ||
3575 | (0 == urh->out_buffer_used) ) | ||
3576 | { | ||
3577 | MHD_connection_finish_forward_ (urh->connection); | ||
3578 | urh->clean_ready = MHD_YES; | ||
3579 | /* If 'urh->was_closed' set to MHD_YES, connection will be | ||
3580 | * moved immediately to cleanup list. Otherwise connection | ||
3581 | * will stay in suspended list until 'urh' will be marked | ||
3582 | * with 'was_closed' by application. */ | ||
3583 | MHD_resume_connection(urh->connection); | ||
3584 | } | ||
3596 | } | 3585 | } |
3597 | } | 3586 | } |
3598 | return MHD_YES; | 3587 | return MHD_YES; |
@@ -5403,18 +5392,23 @@ close_all_connections (struct MHD_Daemon *daemon) | |||
5403 | #ifdef HTTPS_SUPPORT | 5392 | #ifdef HTTPS_SUPPORT |
5404 | struct MHD_UpgradeResponseHandle *urh; | 5393 | struct MHD_UpgradeResponseHandle *urh; |
5405 | struct MHD_UpgradeResponseHandle *urhn; | 5394 | struct MHD_UpgradeResponseHandle *urhn; |
5395 | const _MHD_bool used_tls = (0 != (daemon->options & MHD_USE_TLS)); | ||
5396 | const _MHD_bool used_thr_p_c = (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)); | ||
5406 | #endif /* HTTPS_SUPPORT */ | 5397 | #endif /* HTTPS_SUPPORT */ |
5407 | 5398 | ||
5399 | #ifdef HTTPS_SUPPORT | ||
5408 | /* give upgraded HTTPS connections a chance to finish */ | 5400 | /* give upgraded HTTPS connections a chance to finish */ |
5409 | #if HTTPS_SUPPORT | 5401 | /* 'daemon->urh_head' is not used in thread-per-connection mode. */ |
5410 | for (urh = daemon->urh_head; NULL != urh; urh = urhn) | 5402 | for (urh = daemon->urh_head; NULL != urh; urh = urhn) |
5411 | { | 5403 | { |
5412 | urhn = urh->next; | 5404 | urhn = urh->next; |
5413 | /* call generic forwarding function for passing data | 5405 | /* call generic forwarding function for passing data |
5414 | with chance to detect that application is done; | 5406 | with chance to detect that application is done. */ |
5415 | fake read readyness just to be sure. */ | ||
5416 | urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY; | ||
5417 | process_urh (urh); | 5407 | process_urh (urh); |
5408 | MHD_connection_finish_forward_ (urh->connection); | ||
5409 | urh->clean_ready = MHD_YES; | ||
5410 | /* Resuming will move connection to cleanup list. */ | ||
5411 | MHD_resume_connection(urh->connection); | ||
5418 | } | 5412 | } |
5419 | #endif | 5413 | #endif |
5420 | 5414 | ||
@@ -5431,6 +5425,23 @@ close_all_connections (struct MHD_Daemon *daemon) | |||
5431 | traverse DLLs in peace... */ | 5425 | traverse DLLs in peace... */ |
5432 | if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) | 5426 | if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) |
5433 | MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); | 5427 | MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); |
5428 | #ifdef HTTPS_SUPPORT | ||
5429 | if (used_tls && used_thr_p_c) | ||
5430 | { | ||
5431 | struct MHD_Connection * susp; | ||
5432 | |||
5433 | susp = daemon->suspended_connections_head; | ||
5434 | while (NULL != susp) | ||
5435 | { | ||
5436 | if (NULL == susp->urh) /* "Upgraded" connection? */ | ||
5437 | MHD_PANIC (_("MHD_stop_daemon() called while we have suspended connections.\n")); | ||
5438 | else if (MHD_NO == susp->urh->clean_ready) | ||
5439 | shutdown (urh->app.socket, SHUT_RDWR); /* Wake thread by shutdown of app socket. */ | ||
5440 | susp = susp->next; | ||
5441 | } | ||
5442 | } | ||
5443 | else /* This 'else' is combined with next 'if'. */ | ||
5444 | #endif /* HTTPS_SUPPORT */ | ||
5434 | if (NULL != daemon->suspended_connections_head) | 5445 | if (NULL != daemon->suspended_connections_head) |
5435 | MHD_PANIC (_("MHD_stop_daemon() called while we have suspended connections.\n")); | 5446 | MHD_PANIC (_("MHD_stop_daemon() called while we have suspended connections.\n")); |
5436 | for (pos = daemon->connections_head; NULL != pos; pos = pos->next) | 5447 | for (pos = daemon->connections_head; NULL != pos; pos = pos->next) |
@@ -5465,6 +5476,17 @@ close_all_connections (struct MHD_Daemon *daemon) | |||
5465 | pos = pos->next; | 5476 | pos = pos->next; |
5466 | } | 5477 | } |
5467 | } | 5478 | } |
5479 | |||
5480 | #ifdef HTTPS_SUPPORT | ||
5481 | /* Finished threads with "upgraded" connections need to be moved | ||
5482 | * to cleanup list by resume_suspended_connections(). */ | ||
5483 | if (used_tls && used_thr_p_c) | ||
5484 | { | ||
5485 | daemon->resuming = MHD_YES; /* Force check for pending resume. */ | ||
5486 | resume_suspended_connections (daemon); | ||
5487 | } | ||
5488 | #endif /* HTTPS_SUPPORT */ | ||
5489 | |||
5468 | /* now that we're alone, move everyone to cleanup */ | 5490 | /* now that we're alone, move everyone to cleanup */ |
5469 | while (NULL != (pos = daemon->connections_head)) | 5491 | while (NULL != (pos = daemon->connections_head)) |
5470 | { | 5492 | { |
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h index 1f239f10..bb9974a9 100644 --- a/src/microhttpd/internal.h +++ b/src/microhttpd/internal.h | |||
@@ -1056,8 +1056,37 @@ struct MHD_UpgradeResponseHandle | |||
1056 | /** | 1056 | /** |
1057 | * Set to #MHD_YES after the application finished with the socket | 1057 | * Set to #MHD_YES after the application finished with the socket |
1058 | * by #MHD_UPGRADE_ACTION_CLOSE. | 1058 | * by #MHD_UPGRADE_ACTION_CLOSE. |
1059 | * | ||
1060 | * When BOTH @e was_closed (changed by command from application) | ||
1061 | * AND @e clean_ready (changed internally by MHD) are set to | ||
1062 | * #MHD_YES, function #MHD_resume_connection() will move this | ||
1063 | * connection to cleanup list. | ||
1064 | * @remark This flag could be changed from any thread. | ||
1059 | */ | 1065 | */ |
1060 | int was_closed; | 1066 | int was_closed; |
1067 | |||
1068 | /** | ||
1069 | * Set to #MHD_YES if connection is ready for cleanup. | ||
1070 | * | ||
1071 | * In TLS mode functions #MHD_connection_finish_forward_() must | ||
1072 | * be called before setting this flag to #MHD_YES. | ||
1073 | * | ||
1074 | * In thread-per-connection mode #MHD_YES in this flag means | ||
1075 | * that connection's thread exited or about to exit and will | ||
1076 | * not use MHD_Connection::urh data anymore. | ||
1077 | * | ||
1078 | * In any mode #MHD_YES in this flag also means that | ||
1079 | * MHD_Connection::urh data will not be used for socketpair | ||
1080 | * forwarding and forwarding itself is finished. | ||
1081 | * | ||
1082 | * When BOTH @e was_closed (changed by command from application) | ||
1083 | * AND @e clean_ready (changed internally by MHD) are set to | ||
1084 | * #MHD_YES, function #MHD_resume_connection() will move this | ||
1085 | * connection to cleanup list. | ||
1086 | * @remark This flag could be changed from thread that process | ||
1087 | * connection's recv(), send() and response. | ||
1088 | */ | ||
1089 | int clean_ready; | ||
1061 | }; | 1090 | }; |
1062 | 1091 | ||
1063 | 1092 | ||
@@ -1410,11 +1439,15 @@ struct MHD_Daemon | |||
1410 | #if HTTPS_SUPPORT | 1439 | #if HTTPS_SUPPORT |
1411 | /** | 1440 | /** |
1412 | * Head of DLL of upgrade response handles we are processing. | 1441 | * Head of DLL of upgrade response handles we are processing. |
1442 | * Used for upgraded TLS connections when thread-per-connection | ||
1443 | * is not used. | ||
1413 | */ | 1444 | */ |
1414 | struct MHD_UpgradeResponseHandle *urh_head; | 1445 | struct MHD_UpgradeResponseHandle *urh_head; |
1415 | 1446 | ||
1416 | /** | 1447 | /** |
1417 | * Tail of DLL of upgrade response handles we are processing. | 1448 | * Tail of DLL of upgrade response handles we are processing. |
1449 | * Used for upgraded TLS connections when thread-per-connection | ||
1450 | * is not used. | ||
1418 | */ | 1451 | */ |
1419 | struct MHD_UpgradeResponseHandle *urh_tail; | 1452 | struct MHD_UpgradeResponseHandle *urh_tail; |
1420 | 1453 | ||
diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c index b0fffe19..db77dc6d 100644 --- a/src/microhttpd/response.c +++ b/src/microhttpd/response.c | |||
@@ -21,6 +21,7 @@ | |||
21 | * @brief Methods for managing response objects | 21 | * @brief Methods for managing response objects |
22 | * @author Daniel Pittman | 22 | * @author Daniel Pittman |
23 | * @author Christian Grothoff | 23 | * @author Christian Grothoff |
24 | * @author Karlson2k (Evgeny Grin) | ||
24 | */ | 25 | */ |
25 | 26 | ||
26 | #define MHD_NO_DEPRECATION 1 | 27 | #define MHD_NO_DEPRECATION 1 |
@@ -626,66 +627,41 @@ MHD_upgrade_action (struct MHD_UpgradeResponseHandle *urh, | |||
626 | enum MHD_UpgradeAction action, | 627 | enum MHD_UpgradeAction action, |
627 | ...) | 628 | ...) |
628 | { | 629 | { |
629 | struct MHD_Connection *connection = urh->connection; | 630 | struct MHD_Connection *connection; |
630 | struct MHD_Daemon *daemon = connection->daemon; | 631 | struct MHD_Daemon *daemon; |
632 | if (NULL == urh) | ||
633 | return MHD_NO; | ||
634 | connection = urh->connection; | ||
635 | |||
636 | /* Precaution checks on external data. */ | ||
637 | if (NULL == connection) | ||
638 | return MHD_NO; | ||
639 | daemon = connection->daemon; | ||
640 | if (NULL == daemon) | ||
641 | return MHD_NO; | ||
631 | 642 | ||
632 | switch (action) | 643 | switch (action) |
633 | { | 644 | { |
634 | case MHD_UPGRADE_ACTION_CLOSE: | 645 | case MHD_UPGRADE_ACTION_CLOSE: |
646 | if (MHD_YES == urh->was_closed) | ||
647 | return MHD_NO; /* Already closed. */ | ||
648 | |||
635 | /* transition to special 'closed' state for start of cleanup */ | 649 | /* transition to special 'closed' state for start of cleanup */ |
650 | urh->was_closed = MHD_YES; | ||
636 | connection->state = MHD_CONNECTION_UPGRADE_CLOSED; | 651 | connection->state = MHD_CONNECTION_UPGRADE_CLOSED; |
652 | /* As soon as connection will be marked with BOTH | ||
653 | * 'urh->was_closed' AND 'urh->clean_ready', it will | ||
654 | * be moved to cleanup list by MHD_resume_connection(). */ | ||
655 | MHD_resume_connection (connection); | ||
637 | #if HTTPS_SUPPORT | 656 | #if HTTPS_SUPPORT |
638 | if (0 != (daemon->options & MHD_USE_TLS) ) | 657 | if (0 != (daemon->options & MHD_USE_TLS) ) |
639 | { | 658 | { |
640 | /* signal that app is done by shutdown() of 'app' socket */ | 659 | /* signal that app is done by shutdown() of 'app' socket */ |
660 | /* Application will not use anyway this socket after this command. */ | ||
641 | shutdown (urh->app.socket, | 661 | shutdown (urh->app.socket, |
642 | SHUT_RDWR); | 662 | SHUT_RDWR); |
643 | } | 663 | } |
644 | #endif | 664 | #endif /* HTTPS_SUPPORT */ |
645 | #if HTTPS_SUPPORT | ||
646 | if (0 != (daemon->options & MHD_USE_TLS) ) | ||
647 | { | ||
648 | urh->was_closed = MHD_YES; | ||
649 | /* connection and urh cleanup will be done as soon as outgoing | ||
650 | * data will be sent and 'was_closed' is detected */ | ||
651 | return MHD_YES; | ||
652 | } | ||
653 | #endif | ||
654 | /* Application is done with this connection, tear it down! */ | ||
655 | if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION) ) | ||
656 | { | ||
657 | /* need to finish connection clean up */ | ||
658 | MHD_cleanup_upgraded_connection_ (connection); | ||
659 | if (MHD_CONNECTION_IN_CLEANUP != connection->state) | ||
660 | { | ||
661 | #if DEBUG_CLOSE | ||
662 | #ifdef HAVE_MESSAGES | ||
663 | MHD_DLOG (connection->daemon, | ||
664 | _("Processing thread terminating. Closing connection\n")); | ||
665 | #endif | ||
666 | #endif | ||
667 | if (MHD_CONNECTION_CLOSED != connection->state) | ||
668 | MHD_connection_close_ (connection, | ||
669 | MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN); | ||
670 | connection->idle_handler (connection); | ||
671 | } | ||
672 | if (NULL != connection->response) | ||
673 | { | ||
674 | MHD_destroy_response (connection->response); | ||
675 | connection->response = NULL; | ||
676 | } | ||
677 | |||
678 | if (MHD_INVALID_SOCKET != connection->socket_fd) | ||
679 | { | ||
680 | shutdown (connection->socket_fd, | ||
681 | SHUT_WR); | ||
682 | MHD_socket_close_chk_ (connection->socket_fd); | ||
683 | connection->socket_fd = MHD_INVALID_SOCKET; | ||
684 | } | ||
685 | return MHD_YES; | ||
686 | } | ||
687 | /* 'upgraded' resources are not needed anymore - cleanup now */ | ||
688 | MHD_cleanup_upgraded_connection_ (connection); | ||
689 | return MHD_YES; | 665 | return MHD_YES; |
690 | default: | 666 | default: |
691 | /* we don't understand this one */ | 667 | /* we don't understand this one */ |
@@ -905,30 +881,25 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response, | |||
905 | DLL_insert (daemon->urh_head, | 881 | DLL_insert (daemon->urh_head, |
906 | daemon->urh_tail, | 882 | daemon->urh_tail, |
907 | urh); | 883 | urh); |
908 | /* Keep reference for later removal from the DLL */ | ||
909 | connection->urh = urh; | ||
910 | } | 884 | } |
885 | /* In thread-per-connection mode, thread will switch to forwarding once | ||
886 | * connection.urh is not NULL and connection.state == MHD_CONNECTION_UPGRADE. | ||
887 | */ | ||
911 | } | 888 | } |
912 | else | 889 | else |
913 | { | 890 | { |
914 | urh->app.socket = MHD_INVALID_SOCKET; | 891 | urh->app.socket = MHD_INVALID_SOCKET; |
915 | urh->mhd.socket = MHD_INVALID_SOCKET; | 892 | urh->mhd.socket = MHD_INVALID_SOCKET; |
893 | /* Non-TLS connection do not hold any additional resources. */ | ||
894 | urh->clean_ready = MHD_YES; | ||
916 | } | 895 | } |
917 | #endif | 896 | #endif |
918 | if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION) ) | 897 | connection->urh = urh; |
919 | { | 898 | /* As far as MHD's event loops are concerned, this connection is |
920 | /* Our caller will set 'connection->state' to | 899 | suspended; it will be resumed once application is done by the |
921 | MHD_CONNECTION_UPGRADE, thereby triggering the main method | 900 | #MHD_upgrade_action() function */ |
922 | of the thread to switch to bi-directional forwarding or exit. */ | 901 | MHD_suspend_connection (connection); |
923 | connection->urh = urh; | 902 | |
924 | } | ||
925 | else | ||
926 | { | ||
927 | /* As far as MHD's event loops are concerned, this connection is | ||
928 | suspended; it will be resumed once we are done in the | ||
929 | #MHD_upgrade_action() function */ | ||
930 | MHD_suspend_connection (connection); | ||
931 | } | ||
932 | /* hand over socket to application */ | 903 | /* hand over socket to application */ |
933 | response->upgrade_handler (response->upgrade_handler_cls, | 904 | response->upgrade_handler (response->upgrade_handler_cls, |
934 | connection, | 905 | connection, |
diff --git a/src/microhttpd/test_upgrade.c b/src/microhttpd/test_upgrade.c index b369fd70..965ecc00 100644 --- a/src/microhttpd/test_upgrade.c +++ b/src/microhttpd/test_upgrade.c | |||
@@ -60,9 +60,8 @@ test_upgrade (int flags, | |||
60 | struct sockaddr_in sa; | 60 | struct sockaddr_in sa; |
61 | 61 | ||
62 | done = 0; | 62 | done = 0; |
63 | if (0 == (flags & MHD_USE_THREAD_PER_CONNECTION)) | 63 | |
64 | flags |= MHD_USE_SUSPEND_RESUME; | 64 | d = MHD_start_daemon (flags | MHD_USE_DEBUG | MHD_USE_SUSPEND_RESUME, |
65 | d = MHD_start_daemon (flags | MHD_USE_DEBUG, | ||
66 | 1080, | 65 | 1080, |
67 | NULL, NULL, | 66 | NULL, NULL, |
68 | &ahc_upgrade, NULL, | 67 | &ahc_upgrade, NULL, |
diff --git a/src/microhttpd/test_upgrade_ssl.c b/src/microhttpd/test_upgrade_ssl.c index 07031cff..a72fad6d 100644 --- a/src/microhttpd/test_upgrade_ssl.c +++ b/src/microhttpd/test_upgrade_ssl.c | |||
@@ -138,9 +138,8 @@ test_upgrade (int flags, | |||
138 | pid_t pid; | 138 | pid_t pid; |
139 | 139 | ||
140 | done = 0; | 140 | done = 0; |
141 | if (0 == (flags & MHD_USE_THREAD_PER_CONNECTION)) | 141 | |
142 | flags |= MHD_USE_SUSPEND_RESUME; | 142 | d = MHD_start_daemon (flags | MHD_USE_DEBUG | MHD_USE_SUSPEND_RESUME |MHD_USE_TLS, |
143 | d = MHD_start_daemon (flags | MHD_USE_DEBUG | MHD_USE_TLS, | ||
144 | 1080, | 143 | 1080, |
145 | NULL, NULL, | 144 | NULL, NULL, |
146 | &ahc_upgrade, NULL, | 145 | &ahc_upgrade, NULL, |