diff options
author | Christian Grothoff <christian@grothoff.org> | 2013-07-04 15:29:56 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2013-07-04 15:29:56 +0000 |
commit | 9fe0e9d41112f2a75ee4d9461f1b93b59131029d (patch) | |
tree | 1744c5d4172917dcd38002e67baa095db95a0215 /src | |
parent | 21f9a70d53a472e0c3894099308ca040d401209a (diff) | |
download | libmicrohttpd-9fe0e9d41112f2a75ee4d9461f1b93b59131029d.tar.gz libmicrohttpd-9fe0e9d41112f2a75ee4d9461f1b93b59131029d.zip |
Adding support for using epoll for the MHD event loop
Diffstat (limited to 'src')
-rw-r--r-- | src/include/microhttpd.h | 14 | ||||
-rw-r--r-- | src/microhttpd/connection.c | 297 | ||||
-rw-r--r-- | src/microhttpd/connection.h | 32 | ||||
-rw-r--r-- | src/microhttpd/daemon.c | 1149 | ||||
-rw-r--r-- | src/microhttpd/internal.h | 285 | ||||
-rw-r--r-- | src/microhttpd/memorypool.c | 9 | ||||
-rw-r--r-- | src/testcurl/Makefile.am | 4 | ||||
-rw-r--r-- | src/testcurl/perf_get.c | 13 | ||||
-rw-r--r-- | src/testcurl/perf_get_concurrent.c | 4 | ||||
-rw-r--r-- | src/testcurl/test_get.c | 9 | ||||
-rw-r--r-- | src/testcurl/test_quiesce.c | 76 | ||||
-rw-r--r-- | src/testcurl/test_start_stop.c | 4 |
12 files changed, 1410 insertions, 486 deletions
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h index 5c87c721..318a8424 100644 --- a/src/include/microhttpd.h +++ b/src/include/microhttpd.h | |||
@@ -356,8 +356,11 @@ enum MHD_FLAG | |||
356 | MHD_USE_SELECT_INTERNALLY = 8, | 356 | MHD_USE_SELECT_INTERNALLY = 8, |
357 | 357 | ||
358 | /** | 358 | /** |
359 | * Run using the IPv6 protocol (otherwise, MHD will | 359 | * Run using the IPv6 protocol (otherwise, MHD will just support |
360 | * just support IPv4). | 360 | * IPv4). If you want MHD to support IPv4 and IPv6 using a single |
361 | * socket, pass MHD_USE_DUAL_STACK, otherwise, if you only pass | ||
362 | * this option, MHD will try to bind to IPv6-only (resulting in | ||
363 | * no IPv4 support). | ||
361 | */ | 364 | */ |
362 | MHD_USE_IPv6 = 16, | 365 | MHD_USE_IPv6 = 16, |
363 | 366 | ||
@@ -428,7 +431,12 @@ enum MHD_FLAG | |||
428 | * specify it), if 'MHD_USE_NO_LISTEN_SOCKET' is specified. In | 431 | * specify it), if 'MHD_USE_NO_LISTEN_SOCKET' is specified. In |
429 | * "external" select mode, this option is always simply ignored. | 432 | * "external" select mode, this option is always simply ignored. |
430 | */ | 433 | */ |
431 | MHD_USE_PIPE_FOR_SHUTDOWN = 1024 | 434 | MHD_USE_PIPE_FOR_SHUTDOWN = 1024, |
435 | |||
436 | /** | ||
437 | * Use a single socket for IPv4 and IPv6. | ||
438 | */ | ||
439 | MHD_USE_DUAL_STACK = MHD_USE_IPv6 | 2048 | ||
432 | 440 | ||
433 | }; | 441 | }; |
434 | 442 | ||
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c index 4d651a39..e54ae1b6 100644 --- a/src/microhttpd/connection.c +++ b/src/microhttpd/connection.c | |||
@@ -318,8 +318,9 @@ MHD_connection_close (struct MHD_Connection *connection, | |||
318 | 318 | ||
319 | daemon = connection->daemon; | 319 | daemon = connection->daemon; |
320 | SHUTDOWN (connection->socket_fd, | 320 | SHUTDOWN (connection->socket_fd, |
321 | (connection->read_closed == MHD_YES) ? SHUT_WR : SHUT_RDWR); | 321 | (MHD_YES == connection->read_closed) ? SHUT_WR : SHUT_RDWR); |
322 | connection->state = MHD_CONNECTION_CLOSED; | 322 | connection->state = MHD_CONNECTION_CLOSED; |
323 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; | ||
323 | if ( (NULL != daemon->notify_completed) && | 324 | if ( (NULL != daemon->notify_completed) && |
324 | (MHD_YES == connection->client_aware) ) | 325 | (MHD_YES == connection->client_aware) ) |
325 | daemon->notify_completed (daemon->notify_completed_cls, | 326 | daemon->notify_completed (daemon->notify_completed_cls, |
@@ -745,8 +746,8 @@ build_header_response (struct MHD_Connection *connection) | |||
745 | kind = MHD_FOOTER_KIND; | 746 | kind = MHD_FOOTER_KIND; |
746 | off = 0; | 747 | off = 0; |
747 | } | 748 | } |
748 | must_add_close = ( (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED) && | 749 | must_add_close = ( (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state) && |
749 | (connection->read_closed == MHD_YES) && | 750 | (MHD_YES == connection->read_closed) && |
750 | (0 == strcasecmp (connection->version, | 751 | (0 == strcasecmp (connection->version, |
751 | MHD_HTTP_VERSION_1_1)) && | 752 | MHD_HTTP_VERSION_1_1)) && |
752 | (NULL == MHD_get_response_header (connection->response, | 753 | (NULL == MHD_get_response_header (connection->response, |
@@ -853,87 +854,16 @@ transmit_error_response (struct MHD_Connection *connection, | |||
853 | 854 | ||
854 | 855 | ||
855 | /** | 856 | /** |
856 | * Add "fd" to the "fd_set". If "fd" is | 857 | * Update the 'event_loop_info' field of this connection based on the state |
857 | * greater than "*max", set "*max" to fd. | 858 | * that the connection is now in. May also close the connection or |
858 | * | 859 | * perform other updates to the connection if needed to prepare for |
859 | * @param fd file descriptor to add to the set | 860 | * the next round of the event loop. |
860 | * @param set set to modify | ||
861 | * @param max_fd maximum value to potentially update | ||
862 | */ | ||
863 | static void | ||
864 | add_to_fd_set (int fd, | ||
865 | fd_set *set, | ||
866 | int *max_fd) | ||
867 | { | ||
868 | FD_SET (fd, set); | ||
869 | if ( (NULL != max_fd) && | ||
870 | (fd > *max_fd) ) | ||
871 | *max_fd = fd; | ||
872 | } | ||
873 | |||
874 | |||
875 | /** | ||
876 | * Obtain the select sets for this connection. The given | ||
877 | * sets (and the maximum) are updated and must have | ||
878 | * already been initialized. | ||
879 | * | ||
880 | * @param connection connetion to get select sets for | ||
881 | * @param read_fd_set read set to initialize | ||
882 | * @param write_fd_set write set to initialize | ||
883 | * @param except_fd_set except set to initialize (never changed) | ||
884 | * @param max_fd where to store largest FD put into any set | ||
885 | * @return MHD_YES on success | ||
886 | */ | ||
887 | int | ||
888 | MHD_connection_get_fdset (struct MHD_Connection *connection, | ||
889 | fd_set *read_fd_set, | ||
890 | fd_set *write_fd_set, | ||
891 | fd_set *except_fd_set, | ||
892 | int *max_fd) | ||
893 | { | ||
894 | int ret; | ||
895 | struct MHD_Pollfd p; | ||
896 | |||
897 | /* we use the 'poll fd' as a convenient way to re-use code | ||
898 | when determining the select sets */ | ||
899 | memset (&p, 0, sizeof(struct MHD_Pollfd)); | ||
900 | ret = MHD_connection_get_pollfd (connection, &p); | ||
901 | if ( (MHD_YES == ret) && (p.fd >= 0) ) { | ||
902 | if (0 != (p.events & MHD_POLL_ACTION_IN)) | ||
903 | add_to_fd_set(p.fd, read_fd_set, max_fd); | ||
904 | if (0 != (p.events & MHD_POLL_ACTION_OUT)) | ||
905 | add_to_fd_set(p.fd, write_fd_set, max_fd); | ||
906 | } | ||
907 | return ret; | ||
908 | } | ||
909 | |||
910 | |||
911 | /** | ||
912 | * Obtain the pollfd for this connection | ||
913 | * | 861 | * |
914 | * @param connection connetion to get poll set for | 862 | * @param connection connetion to get poll set for |
915 | * @param p where to store the polling information | ||
916 | * @return MHD_YES on success. If return MHD_YES and p->fd < 0, this | ||
917 | * connection is not waiting for any read or write events | ||
918 | */ | 863 | */ |
919 | int | 864 | static void |
920 | MHD_connection_get_pollfd (struct MHD_Connection *connection, | 865 | MHD_connection_update_event_loop_info (struct MHD_Connection *connection) |
921 | struct MHD_Pollfd *p) | ||
922 | { | 866 | { |
923 | int fd; | ||
924 | |||
925 | if (NULL == connection->pool) | ||
926 | connection->pool = MHD_pool_create (connection->daemon->pool_size); | ||
927 | if (NULL == connection->pool) | ||
928 | { | ||
929 | CONNECTION_CLOSE_ERROR (connection, | ||
930 | "Failed to create memory pool!\n"); | ||
931 | return MHD_YES; | ||
932 | } | ||
933 | fd = connection->socket_fd; | ||
934 | p->fd = fd; | ||
935 | if (-1 == fd) | ||
936 | return MHD_YES; | ||
937 | while (1) | 867 | while (1) |
938 | { | 868 | { |
939 | #if DEBUG_STATES | 869 | #if DEBUG_STATES |
@@ -945,9 +875,9 @@ MHD_connection_get_pollfd (struct MHD_Connection *connection, | |||
945 | #if HTTPS_SUPPORT | 875 | #if HTTPS_SUPPORT |
946 | case MHD_TLS_CONNECTION_INIT: | 876 | case MHD_TLS_CONNECTION_INIT: |
947 | if (0 == gnutls_record_get_direction (connection->tls_session)) | 877 | if (0 == gnutls_record_get_direction (connection->tls_session)) |
948 | p->events |= MHD_POLL_ACTION_IN; | 878 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; |
949 | else | 879 | else |
950 | p->events |= MHD_POLL_ACTION_OUT; | 880 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; |
951 | break; | 881 | break; |
952 | #endif | 882 | #endif |
953 | case MHD_CONNECTION_INIT: | 883 | case MHD_CONNECTION_INIT: |
@@ -955,15 +885,8 @@ MHD_connection_get_pollfd (struct MHD_Connection *connection, | |||
955 | case MHD_CONNECTION_HEADER_PART_RECEIVED: | 885 | case MHD_CONNECTION_HEADER_PART_RECEIVED: |
956 | /* while reading headers, we always grow the | 886 | /* while reading headers, we always grow the |
957 | read buffer if needed, no size-check required */ | 887 | read buffer if needed, no size-check required */ |
958 | if ((connection->read_closed) && | 888 | if ( (connection->read_buffer_offset == connection->read_buffer_size) && |
959 | (0 == connection->read_buffer_offset)) | 889 | (MHD_NO == try_grow_read_buffer (connection)) ) |
960 | { | ||
961 | CONNECTION_CLOSE_ERROR (connection, | ||
962 | "Connection buffer to small for request\n"); | ||
963 | continue; | ||
964 | } | ||
965 | if ((connection->read_buffer_offset == connection->read_buffer_size) | ||
966 | && (MHD_NO == try_grow_read_buffer (connection))) | ||
967 | { | 890 | { |
968 | transmit_error_response (connection, | 891 | transmit_error_response (connection, |
969 | (connection->url != NULL) | 892 | (connection->url != NULL) |
@@ -972,18 +895,19 @@ MHD_connection_get_pollfd (struct MHD_Connection *connection, | |||
972 | REQUEST_TOO_BIG); | 895 | REQUEST_TOO_BIG); |
973 | continue; | 896 | continue; |
974 | } | 897 | } |
975 | if (MHD_NO == connection->read_closed) | 898 | if (MHD_NO == connection->read_closed) |
976 | p->events |= MHD_POLL_ACTION_IN; | 899 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; |
900 | else | ||
901 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; | ||
977 | break; | 902 | break; |
978 | case MHD_CONNECTION_HEADERS_RECEIVED: | 903 | case MHD_CONNECTION_HEADERS_RECEIVED: |
979 | /* we should never get here */ | ||
980 | EXTRA_CHECK (0); | 904 | EXTRA_CHECK (0); |
981 | break; | 905 | break; |
982 | case MHD_CONNECTION_HEADERS_PROCESSED: | 906 | case MHD_CONNECTION_HEADERS_PROCESSED: |
983 | EXTRA_CHECK (0); | 907 | EXTRA_CHECK (0); |
984 | break; | 908 | break; |
985 | case MHD_CONNECTION_CONTINUE_SENDING: | 909 | case MHD_CONNECTION_CONTINUE_SENDING: |
986 | p->events |= MHD_POLL_ACTION_OUT; | 910 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; |
987 | break; | 911 | break; |
988 | case MHD_CONNECTION_CONTINUE_SENT: | 912 | case MHD_CONNECTION_CONTINUE_SENT: |
989 | if (connection->read_buffer_offset == connection->read_buffer_size) | 913 | if (connection->read_buffer_offset == connection->read_buffer_size) |
@@ -1010,9 +934,11 @@ MHD_connection_get_pollfd (struct MHD_Connection *connection, | |||
1010 | continue; | 934 | continue; |
1011 | } | 935 | } |
1012 | } | 936 | } |
1013 | if ((connection->read_buffer_offset < connection->read_buffer_size) | 937 | if ( (connection->read_buffer_offset < connection->read_buffer_size) && |
1014 | && (MHD_NO == connection->read_closed)) | 938 | (MHD_NO == connection->read_closed) ) |
1015 | p->events |= MHD_POLL_ACTION_IN; | 939 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; |
940 | else | ||
941 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; | ||
1016 | break; | 942 | break; |
1017 | case MHD_CONNECTION_BODY_RECEIVED: | 943 | case MHD_CONNECTION_BODY_RECEIVED: |
1018 | case MHD_CONNECTION_FOOTER_PART_RECEIVED: | 944 | case MHD_CONNECTION_FOOTER_PART_RECEIVED: |
@@ -1024,50 +950,49 @@ MHD_connection_get_pollfd (struct MHD_Connection *connection, | |||
1024 | NULL); | 950 | NULL); |
1025 | continue; | 951 | continue; |
1026 | } | 952 | } |
1027 | p->events |= MHD_POLL_ACTION_IN; | 953 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; |
1028 | /* transition to FOOTERS_RECEIVED | 954 | /* transition to FOOTERS_RECEIVED |
1029 | happens in read handler */ | 955 | happens in read handler */ |
1030 | break; | 956 | break; |
1031 | case MHD_CONNECTION_FOOTERS_RECEIVED: | 957 | case MHD_CONNECTION_FOOTERS_RECEIVED: |
1032 | /* no socket action, wait for client | 958 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; |
1033 | to provide response */ | ||
1034 | break; | 959 | break; |
1035 | case MHD_CONNECTION_HEADERS_SENDING: | 960 | case MHD_CONNECTION_HEADERS_SENDING: |
1036 | /* headers in buffer, keep writing */ | 961 | /* headers in buffer, keep writing */ |
1037 | p->events |= MHD_POLL_ACTION_OUT; | 962 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; |
1038 | break; | 963 | break; |
1039 | case MHD_CONNECTION_HEADERS_SENT: | 964 | case MHD_CONNECTION_HEADERS_SENT: |
1040 | EXTRA_CHECK (0); | 965 | EXTRA_CHECK (0); |
1041 | break; | 966 | break; |
1042 | case MHD_CONNECTION_NORMAL_BODY_READY: | 967 | case MHD_CONNECTION_NORMAL_BODY_READY: |
1043 | p->events |= MHD_POLL_ACTION_OUT; | 968 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; |
1044 | break; | 969 | break; |
1045 | case MHD_CONNECTION_NORMAL_BODY_UNREADY: | 970 | case MHD_CONNECTION_NORMAL_BODY_UNREADY: |
1046 | /* not ready, no socket action */ | 971 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; |
1047 | break; | 972 | break; |
1048 | case MHD_CONNECTION_CHUNKED_BODY_READY: | 973 | case MHD_CONNECTION_CHUNKED_BODY_READY: |
1049 | p->events |= MHD_POLL_ACTION_OUT; | 974 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; |
1050 | break; | 975 | break; |
1051 | case MHD_CONNECTION_CHUNKED_BODY_UNREADY: | 976 | case MHD_CONNECTION_CHUNKED_BODY_UNREADY: |
1052 | /* not ready, no socket action */ | 977 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; |
1053 | break; | 978 | break; |
1054 | case MHD_CONNECTION_BODY_SENT: | 979 | case MHD_CONNECTION_BODY_SENT: |
1055 | EXTRA_CHECK (0); | 980 | EXTRA_CHECK (0); |
1056 | break; | 981 | break; |
1057 | case MHD_CONNECTION_FOOTERS_SENDING: | 982 | case MHD_CONNECTION_FOOTERS_SENDING: |
1058 | p->events |= MHD_POLL_ACTION_OUT; | 983 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; |
1059 | break; | 984 | break; |
1060 | case MHD_CONNECTION_FOOTERS_SENT: | 985 | case MHD_CONNECTION_FOOTERS_SENT: |
1061 | EXTRA_CHECK (0); | 986 | EXTRA_CHECK (0); |
1062 | break; | 987 | break; |
1063 | case MHD_CONNECTION_CLOSED: | 988 | case MHD_CONNECTION_CLOSED: |
1064 | return MHD_YES; /* do nothing, not even reading */ | 989 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; |
990 | return; /* do nothing, not even reading */ | ||
1065 | default: | 991 | default: |
1066 | EXTRA_CHECK (0); | 992 | EXTRA_CHECK (0); |
1067 | } | 993 | } |
1068 | break; | 994 | break; |
1069 | } | 995 | } |
1070 | return MHD_YES; | ||
1071 | } | 996 | } |
1072 | 997 | ||
1073 | 998 | ||
@@ -1888,10 +1813,41 @@ parse_connection_headers (struct MHD_Connection *connection) | |||
1888 | 1813 | ||
1889 | 1814 | ||
1890 | /** | 1815 | /** |
1816 | * Update the 'last_activity' field of the connection to the current time | ||
1817 | * and move the connection to the head of the 'normal_timeout' list if | ||
1818 | * the timeout for the connection uses the default value. | ||
1819 | * | ||
1820 | * @param connection the connection that saw some activity | ||
1821 | */ | ||
1822 | static void | ||
1823 | update_last_activity (struct MHD_Connection *connection) | ||
1824 | { | ||
1825 | struct MHD_Daemon *daemon = connection->daemon; | ||
1826 | |||
1827 | connection->last_activity = MHD_monotonic_time(); | ||
1828 | if (connection->connection_timeout != daemon->connection_timeout) | ||
1829 | return; /* custom timeout, no need to move it in DLL */ | ||
1830 | |||
1831 | /* move connection to head of timeout list (by remove + add operation) */ | ||
1832 | if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && | ||
1833 | (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) ) | ||
1834 | MHD_PANIC ("Failed to acquire cleanup mutex\n"); | ||
1835 | XDLL_remove (daemon->normal_timeout_head, | ||
1836 | daemon->normal_timeout_tail, | ||
1837 | connection); | ||
1838 | XDLL_insert (daemon->normal_timeout_head, | ||
1839 | daemon->normal_timeout_tail, | ||
1840 | connection); | ||
1841 | if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && | ||
1842 | (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex)) ) | ||
1843 | MHD_PANIC ("Failed to release cleanup mutex\n"); | ||
1844 | } | ||
1845 | |||
1846 | |||
1847 | |||
1848 | /** | ||
1891 | * This function handles a particular connection when it has been | 1849 | * This function handles a particular connection when it has been |
1892 | * determined that there is data to be read off a socket. All | 1850 | * determined that there is data to be read off a socket. |
1893 | * implementations (multithreaded, external select, internal select) | ||
1894 | * call this function to handle reads. | ||
1895 | * | 1851 | * |
1896 | * @param connection connection to handle | 1852 | * @param connection connection to handle |
1897 | * @return always MHD_YES (we should continue to process the | 1853 | * @return always MHD_YES (we should continue to process the |
@@ -1900,7 +1856,7 @@ parse_connection_headers (struct MHD_Connection *connection) | |||
1900 | int | 1856 | int |
1901 | MHD_connection_handle_read (struct MHD_Connection *connection) | 1857 | MHD_connection_handle_read (struct MHD_Connection *connection) |
1902 | { | 1858 | { |
1903 | connection->last_activity = MHD_monotonic_time(); | 1859 | update_last_activity (connection); |
1904 | if (connection->state == MHD_CONNECTION_CLOSED) | 1860 | if (connection->state == MHD_CONNECTION_CLOSED) |
1905 | return MHD_YES; | 1861 | return MHD_YES; |
1906 | /* make sure "read" has a reasonable number of bytes | 1862 | /* make sure "read" has a reasonable number of bytes |
@@ -1953,9 +1909,7 @@ MHD_connection_handle_read (struct MHD_Connection *connection) | |||
1953 | 1909 | ||
1954 | /** | 1910 | /** |
1955 | * This function was created to handle writes to sockets when it has | 1911 | * This function was created to handle writes to sockets when it has |
1956 | * been determined that the socket can be written to. All | 1912 | * been determined that the socket can be written to. |
1957 | * implementations (multithreaded, external select, internal select) | ||
1958 | * call this function | ||
1959 | * | 1913 | * |
1960 | * @param connection connection to handle | 1914 | * @param connection connection to handle |
1961 | * @return always MHD_YES (we should continue to process the | 1915 | * @return always MHD_YES (we should continue to process the |
@@ -1966,7 +1920,8 @@ MHD_connection_handle_write (struct MHD_Connection *connection) | |||
1966 | { | 1920 | { |
1967 | struct MHD_Response *response; | 1921 | struct MHD_Response *response; |
1968 | int ret; | 1922 | int ret; |
1969 | connection->last_activity = MHD_monotonic_time(); | 1923 | |
1924 | update_last_activity (connection); | ||
1970 | while (1) | 1925 | while (1) |
1971 | { | 1926 | { |
1972 | #if DEBUG_STATES | 1927 | #if DEBUG_STATES |
@@ -2111,9 +2066,7 @@ MHD_connection_handle_write (struct MHD_Connection *connection) | |||
2111 | 2066 | ||
2112 | /** | 2067 | /** |
2113 | * This function was created to handle per-connection processing that | 2068 | * This function was created to handle per-connection processing that |
2114 | * has to happen even if the socket cannot be read or written to. All | 2069 | * has to happen even if the socket cannot be read or written to. |
2115 | * implementations (multithreaded, external select, internal select) | ||
2116 | * call this function. | ||
2117 | * | 2070 | * |
2118 | * @param connection connection to handle | 2071 | * @param connection connection to handle |
2119 | * @return MHD_YES if we should continue to process the | 2072 | * @return MHD_YES if we should continue to process the |
@@ -2122,7 +2075,7 @@ MHD_connection_handle_write (struct MHD_Connection *connection) | |||
2122 | int | 2075 | int |
2123 | MHD_connection_handle_idle (struct MHD_Connection *connection) | 2076 | MHD_connection_handle_idle (struct MHD_Connection *connection) |
2124 | { | 2077 | { |
2125 | struct MHD_Daemon *daemon; | 2078 | struct MHD_Daemon *daemon = connection->daemon; |
2126 | unsigned int timeout; | 2079 | unsigned int timeout; |
2127 | const char *end; | 2080 | const char *end; |
2128 | int rend; | 2081 | int rend; |
@@ -2131,18 +2084,18 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2131 | while (1) | 2084 | while (1) |
2132 | { | 2085 | { |
2133 | #if DEBUG_STATES | 2086 | #if DEBUG_STATES |
2134 | MHD_DLOG (connection->daemon, "%s: state: %s\n", | 2087 | MHD_DLOG (daemon, "%s: state: %s\n", |
2135 | __FUNCTION__, MHD_state_to_string (connection->state)); | 2088 | __FUNCTION__, MHD_state_to_string (connection->state)); |
2136 | #endif | 2089 | #endif |
2137 | switch (connection->state) | 2090 | switch (connection->state) |
2138 | { | 2091 | { |
2139 | case MHD_CONNECTION_INIT: | 2092 | case MHD_CONNECTION_INIT: |
2140 | line = get_next_header_line (connection); | 2093 | line = get_next_header_line (connection); |
2141 | if (line == NULL) | 2094 | if (NULL == line) |
2142 | { | 2095 | { |
2143 | if (connection->state != MHD_CONNECTION_INIT) | 2096 | if (MHD_CONNECTION_INIT != connection->state) |
2144 | continue; | 2097 | continue; |
2145 | if (connection->read_closed) | 2098 | if (MHD_YES == connection->read_closed) |
2146 | { | 2099 | { |
2147 | CONNECTION_CLOSE_ERROR (connection, | 2100 | CONNECTION_CLOSE_ERROR (connection, |
2148 | NULL); | 2101 | NULL); |
@@ -2159,9 +2112,9 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2159 | line = get_next_header_line (connection); | 2112 | line = get_next_header_line (connection); |
2160 | if (line == NULL) | 2113 | if (line == NULL) |
2161 | { | 2114 | { |
2162 | if (connection->state != MHD_CONNECTION_URL_RECEIVED) | 2115 | if (MHD_CONNECTION_URL_RECEIVED != connection->state) |
2163 | continue; | 2116 | continue; |
2164 | if (connection->read_closed) | 2117 | if (MHD_YES == connection->read_closed) |
2165 | { | 2118 | { |
2166 | CONNECTION_CLOSE_ERROR (connection, | 2119 | CONNECTION_CLOSE_ERROR (connection, |
2167 | NULL); | 2120 | NULL); |
@@ -2189,7 +2142,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2189 | { | 2142 | { |
2190 | if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED) | 2143 | if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED) |
2191 | continue; | 2144 | continue; |
2192 | if (connection->read_closed) | 2145 | if (MHD_YES == connection->read_closed) |
2193 | { | 2146 | { |
2194 | CONNECTION_CLOSE_ERROR (connection, | 2147 | CONNECTION_CLOSE_ERROR (connection, |
2195 | NULL); | 2148 | NULL); |
@@ -2232,7 +2185,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2232 | /* force close, in case client still tries to upload... */ | 2185 | /* force close, in case client still tries to upload... */ |
2233 | connection->read_closed = MHD_YES; | 2186 | connection->read_closed = MHD_YES; |
2234 | } | 2187 | } |
2235 | connection->state = (connection->remaining_upload_size == 0) | 2188 | connection->state = (0 == connection->remaining_upload_size) |
2236 | ? MHD_CONNECTION_FOOTERS_RECEIVED : MHD_CONNECTION_CONTINUE_SENT; | 2189 | ? MHD_CONNECTION_FOOTERS_RECEIVED : MHD_CONNECTION_CONTINUE_SENT; |
2237 | continue; | 2190 | continue; |
2238 | case MHD_CONNECTION_CONTINUE_SENDING: | 2191 | case MHD_CONNECTION_CONTINUE_SENDING: |
@@ -2269,7 +2222,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2269 | { | 2222 | { |
2270 | if (connection->state != MHD_CONNECTION_BODY_RECEIVED) | 2223 | if (connection->state != MHD_CONNECTION_BODY_RECEIVED) |
2271 | continue; | 2224 | continue; |
2272 | if (connection->read_closed) | 2225 | if (MHD_YES == connection->read_closed) |
2273 | { | 2226 | { |
2274 | CONNECTION_CLOSE_ERROR (connection, | 2227 | CONNECTION_CLOSE_ERROR (connection, |
2275 | NULL); | 2228 | NULL); |
@@ -2297,7 +2250,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2297 | { | 2250 | { |
2298 | if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED) | 2251 | if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED) |
2299 | continue; | 2252 | continue; |
2300 | if (connection->read_closed) | 2253 | if (MHD_YES == connection->read_closed) |
2301 | { | 2254 | { |
2302 | CONNECTION_CLOSE_ERROR (connection, | 2255 | CONNECTION_CLOSE_ERROR (connection, |
2303 | NULL); | 2256 | NULL); |
@@ -2421,11 +2374,10 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2421 | ( (end != NULL) && (0 == strcasecmp (end, "close")) ) ); | 2374 | ( (end != NULL) && (0 == strcasecmp (end, "close")) ) ); |
2422 | MHD_destroy_response (connection->response); | 2375 | MHD_destroy_response (connection->response); |
2423 | connection->response = NULL; | 2376 | connection->response = NULL; |
2424 | if (connection->daemon->notify_completed != NULL) | 2377 | if (daemon->notify_completed != NULL) |
2425 | connection->daemon->notify_completed (connection->daemon-> | 2378 | daemon->notify_completed (daemon->notify_completed_cls, |
2426 | notify_completed_cls, | 2379 | connection, |
2427 | connection, | 2380 | &connection->client_context, |
2428 | &connection->client_context, | ||
2429 | MHD_REQUEST_TERMINATED_COMPLETED_OK); | 2381 | MHD_REQUEST_TERMINATED_COMPLETED_OK); |
2430 | connection->client_aware = MHD_NO; | 2382 | connection->client_aware = MHD_NO; |
2431 | end = | 2383 | end = |
@@ -2478,21 +2430,26 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2478 | MHD_destroy_response (connection->response); | 2430 | MHD_destroy_response (connection->response); |
2479 | connection->response = NULL; | 2431 | connection->response = NULL; |
2480 | } | 2432 | } |
2481 | daemon = connection->daemon; | 2433 | if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && |
2482 | if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex)) | 2434 | (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) ) |
2483 | { | 2435 | MHD_PANIC ("Failed to acquire cleanup mutex\n"); |
2484 | MHD_PANIC ("Failed to acquire cleanup mutex\n"); | 2436 | if (connection->connection_timeout == daemon->connection_timeout) |
2485 | } | 2437 | XDLL_remove (daemon->normal_timeout_head, |
2438 | daemon->normal_timeout_tail, | ||
2439 | connection); | ||
2440 | else | ||
2441 | XDLL_remove (daemon->manual_timeout_head, | ||
2442 | daemon->manual_timeout_tail, | ||
2443 | connection); | ||
2486 | DLL_remove (daemon->connections_head, | 2444 | DLL_remove (daemon->connections_head, |
2487 | daemon->connections_tail, | 2445 | daemon->connections_tail, |
2488 | connection); | 2446 | connection); |
2489 | DLL_insert (daemon->cleanup_head, | 2447 | DLL_insert (daemon->cleanup_head, |
2490 | daemon->cleanup_tail, | 2448 | daemon->cleanup_tail, |
2491 | connection); | 2449 | connection); |
2492 | if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex)) | 2450 | if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && |
2493 | { | 2451 | (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex)) ) |
2494 | MHD_PANIC ("Failed to release cleanup mutex\n"); | 2452 | MHD_PANIC ("Failed to release cleanup mutex\n"); |
2495 | } | ||
2496 | return MHD_NO; | 2453 | return MHD_NO; |
2497 | default: | 2454 | default: |
2498 | EXTRA_CHECK (0); | 2455 | EXTRA_CHECK (0); |
@@ -2507,6 +2464,32 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2507 | MHD_connection_close (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); | 2464 | MHD_connection_close (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); |
2508 | return MHD_YES; | 2465 | return MHD_YES; |
2509 | } | 2466 | } |
2467 | MHD_connection_update_event_loop_info (connection); | ||
2468 | switch (connection->event_loop_info) | ||
2469 | { | ||
2470 | case MHD_EVENT_LOOP_INFO_READ: | ||
2471 | if (0 != (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) | ||
2472 | EDLL_insert (daemon->eready_head, | ||
2473 | daemon->eready_tail, | ||
2474 | connection); | ||
2475 | break; | ||
2476 | case MHD_EVENT_LOOP_INFO_WRITE: | ||
2477 | if (0 != (connection->epoll_state & MHD_EPOLL_STATE_WRITE_READY)) | ||
2478 | EDLL_insert (daemon->eready_head, | ||
2479 | daemon->eready_tail, | ||
2480 | connection); | ||
2481 | break; | ||
2482 | case MHD_EVENT_LOOP_INFO_BLOCK: | ||
2483 | /* we should look at this connection again in the next iteration | ||
2484 | of the event loop, as we're waiting on the application */ | ||
2485 | EDLL_insert (daemon->eready_head, | ||
2486 | daemon->eready_tail, | ||
2487 | connection); | ||
2488 | break; | ||
2489 | case MHD_EVENT_LOOP_INFO_CLEANUP: | ||
2490 | /* This connection is finished, nothing left to do */ | ||
2491 | break; | ||
2492 | } | ||
2510 | return MHD_YES; | 2493 | return MHD_YES; |
2511 | } | 2494 | } |
2512 | 2495 | ||
@@ -2582,13 +2565,37 @@ MHD_set_connection_option (struct MHD_Connection *connection, | |||
2582 | ...) | 2565 | ...) |
2583 | { | 2566 | { |
2584 | va_list ap; | 2567 | va_list ap; |
2568 | struct MHD_Daemon *daemon; | ||
2585 | 2569 | ||
2570 | daemon = connection->daemon; | ||
2586 | switch (option) | 2571 | switch (option) |
2587 | { | 2572 | { |
2588 | case MHD_CONNECTION_OPTION_TIMEOUT: | 2573 | case MHD_CONNECTION_OPTION_TIMEOUT: |
2574 | if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && | ||
2575 | (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) ) | ||
2576 | MHD_PANIC ("Failed to acquire cleanup mutex\n"); | ||
2577 | if (connection->connection_timeout == daemon->connection_timeout) | ||
2578 | XDLL_remove (daemon->normal_timeout_head, | ||
2579 | daemon->normal_timeout_tail, | ||
2580 | connection); | ||
2581 | else | ||
2582 | XDLL_remove (daemon->manual_timeout_head, | ||
2583 | daemon->manual_timeout_tail, | ||
2584 | connection); | ||
2589 | va_start (ap, option); | 2585 | va_start (ap, option); |
2590 | connection->connection_timeout = va_arg (ap, unsigned int); | 2586 | connection->connection_timeout = va_arg (ap, unsigned int); |
2591 | va_end (ap); | 2587 | va_end (ap); |
2588 | if (connection->connection_timeout == daemon->connection_timeout) | ||
2589 | XDLL_insert (daemon->normal_timeout_head, | ||
2590 | daemon->normal_timeout_tail, | ||
2591 | connection); | ||
2592 | else | ||
2593 | XDLL_insert (daemon->manual_timeout_head, | ||
2594 | daemon->manual_timeout_tail, | ||
2595 | connection); | ||
2596 | if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && | ||
2597 | (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex)) ) | ||
2598 | MHD_PANIC ("Failed to release cleanup mutex\n"); | ||
2592 | return MHD_YES; | 2599 | return MHD_YES; |
2593 | default: | 2600 | default: |
2594 | return MHD_NO; | 2601 | return MHD_NO; |
diff --git a/src/microhttpd/connection.h b/src/microhttpd/connection.h index e639691f..985f29ed 100644 --- a/src/microhttpd/connection.h +++ b/src/microhttpd/connection.h | |||
@@ -31,38 +31,6 @@ | |||
31 | 31 | ||
32 | 32 | ||
33 | /** | 33 | /** |
34 | * Obtain the select sets for this connection. The given | ||
35 | * sets (and the maximum) are updated and must have | ||
36 | * already been initialized. | ||
37 | * | ||
38 | * @param connection connetion to get select sets for | ||
39 | * @param read_fd_set read set to initialize | ||
40 | * @param write_fd_set write set to initialize | ||
41 | * @param except_fd_set except set to initialize (never changed) | ||
42 | * @param max_fd where to store largest FD put into any set | ||
43 | * @return MHD_YES on success | ||
44 | */ | ||
45 | int | ||
46 | MHD_connection_get_fdset (struct MHD_Connection *connection, | ||
47 | fd_set * read_fd_set, | ||
48 | fd_set * write_fd_set, | ||
49 | fd_set * except_fd_set, int *max_fd); | ||
50 | |||
51 | |||
52 | /** | ||
53 | * Obtain the pollfd for this connection. The poll interface allows large | ||
54 | * file descriptors. Select goes stupid when the fd overflows fdset (which | ||
55 | * is fixed). | ||
56 | * | ||
57 | * @param connection connetion to get poll set for | ||
58 | * @param p where to store the polling information | ||
59 | */ | ||
60 | int | ||
61 | MHD_connection_get_pollfd (struct MHD_Connection *connection, | ||
62 | struct MHD_Pollfd *p); | ||
63 | |||
64 | |||
65 | /** | ||
66 | * Set callbacks for this connection to those for HTTP. | 34 | * Set callbacks for this connection to those for HTTP. |
67 | * | 35 | * |
68 | * @param connection connection to initialize | 36 | * @param connection connection to initialize |
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c index ef69d14b..28ce1d80 100644 --- a/src/microhttpd/daemon.c +++ b/src/microhttpd/daemon.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of libmicrohttpd | 2 | This file is part of libmicrohttpd |
3 | (C) 2007, 2008, 2009, 2010, 2011, 2012 Daniel Pittman and Christian Grothoff | 3 | (C) 2007-2013 Daniel Pittman and Christian Grothoff |
4 | 4 | ||
5 | This library is free software; you can redistribute it and/or | 5 | This library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public | 6 | modify it under the terms of the GNU Lesser General Public |
@@ -39,7 +39,6 @@ | |||
39 | 39 | ||
40 | #if HTTPS_SUPPORT | 40 | #if HTTPS_SUPPORT |
41 | #include "connection_https.h" | 41 | #include "connection_https.h" |
42 | #include <gnutls/gnutls.h> | ||
43 | #include <gcrypt.h> | 42 | #include <gcrypt.h> |
44 | #endif | 43 | #endif |
45 | 44 | ||
@@ -178,7 +177,7 @@ struct MHD_IPCount | |||
178 | * @param daemon handle to daemon where lock is | 177 | * @param daemon handle to daemon where lock is |
179 | */ | 178 | */ |
180 | static void | 179 | static void |
181 | MHD_ip_count_lock(struct MHD_Daemon *daemon) | 180 | MHD_ip_count_lock (struct MHD_Daemon *daemon) |
182 | { | 181 | { |
183 | if (0 != pthread_mutex_lock(&daemon->per_ip_connection_mutex)) | 182 | if (0 != pthread_mutex_lock(&daemon->per_ip_connection_mutex)) |
184 | { | 183 | { |
@@ -193,7 +192,7 @@ MHD_ip_count_lock(struct MHD_Daemon *daemon) | |||
193 | * @param daemon handle to daemon where lock is | 192 | * @param daemon handle to daemon where lock is |
194 | */ | 193 | */ |
195 | static void | 194 | static void |
196 | MHD_ip_count_unlock(struct MHD_Daemon *daemon) | 195 | MHD_ip_count_unlock (struct MHD_Daemon *daemon) |
197 | { | 196 | { |
198 | if (0 != pthread_mutex_unlock(&daemon->per_ip_connection_mutex)) | 197 | if (0 != pthread_mutex_unlock(&daemon->per_ip_connection_mutex)) |
199 | { | 198 | { |
@@ -212,7 +211,7 @@ MHD_ip_count_unlock(struct MHD_Daemon *daemon) | |||
212 | * @return -1, 0 or 1 depending on result of compare | 211 | * @return -1, 0 or 1 depending on result of compare |
213 | */ | 212 | */ |
214 | static int | 213 | static int |
215 | MHD_ip_addr_compare(const void *a1, const void *a2) | 214 | MHD_ip_addr_compare (const void *a1, const void *a2) |
216 | { | 215 | { |
217 | return memcmp (a1, a2, offsetof (struct MHD_IPCount, count)); | 216 | return memcmp (a1, a2, offsetof (struct MHD_IPCount, count)); |
218 | } | 217 | } |
@@ -227,9 +226,9 @@ MHD_ip_addr_compare(const void *a1, const void *a2) | |||
227 | * @return MHD_YES on success and MHD_NO otherwise (e.g., invalid address type) | 226 | * @return MHD_YES on success and MHD_NO otherwise (e.g., invalid address type) |
228 | */ | 227 | */ |
229 | static int | 228 | static int |
230 | MHD_ip_addr_to_key(const struct sockaddr *addr, | 229 | MHD_ip_addr_to_key (const struct sockaddr *addr, |
231 | socklen_t addrlen, | 230 | socklen_t addrlen, |
232 | struct MHD_IPCount *key) | 231 | struct MHD_IPCount *key) |
233 | { | 232 | { |
234 | memset(key, 0, sizeof(*key)); | 233 | memset(key, 0, sizeof(*key)); |
235 | 234 | ||
@@ -268,9 +267,9 @@ MHD_ip_addr_to_key(const struct sockaddr *addr, | |||
268 | * Also returns MHD_NO if fails to allocate memory. | 267 | * Also returns MHD_NO if fails to allocate memory. |
269 | */ | 268 | */ |
270 | static int | 269 | static int |
271 | MHD_ip_limit_add(struct MHD_Daemon *daemon, | 270 | MHD_ip_limit_add (struct MHD_Daemon *daemon, |
272 | const struct sockaddr *addr, | 271 | const struct sockaddr *addr, |
273 | socklen_t addrlen) | 272 | socklen_t addrlen) |
274 | { | 273 | { |
275 | struct MHD_IPCount *key; | 274 | struct MHD_IPCount *key; |
276 | void **nodep; | 275 | void **nodep; |
@@ -332,9 +331,9 @@ MHD_ip_limit_add(struct MHD_Daemon *daemon, | |||
332 | * @param addrlen number of bytes in addr | 331 | * @param addrlen number of bytes in addr |
333 | */ | 332 | */ |
334 | static void | 333 | static void |
335 | MHD_ip_limit_del(struct MHD_Daemon *daemon, | 334 | MHD_ip_limit_del (struct MHD_Daemon *daemon, |
336 | const struct sockaddr *addr, | 335 | const struct sockaddr *addr, |
337 | socklen_t addrlen) | 336 | socklen_t addrlen) |
338 | { | 337 | { |
339 | struct MHD_IPCount search_key; | 338 | struct MHD_IPCount search_key; |
340 | struct MHD_IPCount *found_key; | 339 | struct MHD_IPCount *found_key; |
@@ -392,7 +391,11 @@ recv_tls_adapter (struct MHD_Connection *connection, void *other, size_t i) | |||
392 | { | 391 | { |
393 | int res; | 392 | int res; |
394 | 393 | ||
395 | connection->tls_read_ready = MHD_NO; | 394 | if (MHD_YES == connection->tls_read_ready) |
395 | { | ||
396 | connection->daemon->num_tls_read_ready--; | ||
397 | connection->tls_read_ready = MHD_NO; | ||
398 | } | ||
396 | res = gnutls_record_recv (connection->tls_session, other, i); | 399 | res = gnutls_record_recv (connection->tls_session, other, i); |
397 | if ( (GNUTLS_E_AGAIN == res) || | 400 | if ( (GNUTLS_E_AGAIN == res) || |
398 | (GNUTLS_E_INTERRUPTED == res) ) | 401 | (GNUTLS_E_INTERRUPTED == res) ) |
@@ -404,12 +407,15 @@ recv_tls_adapter (struct MHD_Connection *connection, void *other, size_t i) | |||
404 | { | 407 | { |
405 | /* Likely 'GNUTLS_E_INVALID_SESSION' (client communication | 408 | /* Likely 'GNUTLS_E_INVALID_SESSION' (client communication |
406 | disrupted); set errno to something caller will interpret | 409 | disrupted); set errno to something caller will interpret |
407 | correctly as a hard error*/ | 410 | correctly as a hard error */ |
408 | errno = EPIPE; | 411 | errno = EPIPE; |
409 | return res; | 412 | return res; |
410 | } | 413 | } |
411 | if (res == i) | 414 | if (res == i) |
412 | connection->tls_read_ready = MHD_YES; | 415 | { |
416 | connection->tls_read_ready = MHD_YES; | ||
417 | connection->daemon->num_tls_read_ready++; | ||
418 | } | ||
413 | return res; | 419 | return res; |
414 | } | 420 | } |
415 | 421 | ||
@@ -515,6 +521,26 @@ MHD_TLS_init (struct MHD_Daemon *daemon) | |||
515 | 521 | ||
516 | 522 | ||
517 | /** | 523 | /** |
524 | * Add "fd" to the "fd_set". If "fd" is | ||
525 | * greater than "*max", set "*max" to fd. | ||
526 | * | ||
527 | * @param fd file descriptor to add to the set | ||
528 | * @param set set to modify | ||
529 | * @param max_fd maximum value to potentially update | ||
530 | */ | ||
531 | static void | ||
532 | add_to_fd_set (int fd, | ||
533 | fd_set *set, | ||
534 | int *max_fd) | ||
535 | { | ||
536 | FD_SET (fd, set); | ||
537 | if ( (NULL != max_fd) && | ||
538 | (fd > *max_fd) ) | ||
539 | *max_fd = fd; | ||
540 | } | ||
541 | |||
542 | |||
543 | /** | ||
518 | * Obtain the select sets for this daemon. | 544 | * Obtain the select sets for this daemon. |
519 | * | 545 | * |
520 | * @param daemon daemon to get sets from | 546 | * @param daemon daemon to get sets from |
@@ -546,6 +572,20 @@ MHD_get_fdset (struct MHD_Daemon *daemon, | |||
546 | || (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) | 572 | || (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) |
547 | || (0 != (daemon->options & MHD_USE_POLL))) | 573 | || (0 != (daemon->options & MHD_USE_POLL))) |
548 | return MHD_NO; | 574 | return MHD_NO; |
575 | #if EPOLL_SUPPORT | ||
576 | if (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) | ||
577 | { | ||
578 | /* we're in epoll mode, use the epoll FD as a stand-in for | ||
579 | the entire event set */ | ||
580 | |||
581 | if (daemon->epoll_fd >= FD_SETSIZE) | ||
582 | return MHD_NO; /* poll fd too big, fail hard */ | ||
583 | FD_SET (daemon->epoll_fd, read_fd_set); | ||
584 | if ((*max_fd) < daemon->epoll_fd) | ||
585 | *max_fd = daemon->epoll_fd; | ||
586 | return MHD_YES; | ||
587 | } | ||
588 | #endif | ||
549 | fd = daemon->socket_fd; | 589 | fd = daemon->socket_fd; |
550 | if (-1 != fd) | 590 | if (-1 != fd) |
551 | { | 591 | { |
@@ -555,11 +595,23 @@ MHD_get_fdset (struct MHD_Daemon *daemon, | |||
555 | *max_fd = fd; | 595 | *max_fd = fd; |
556 | } | 596 | } |
557 | for (pos = daemon->connections_head; NULL != pos; pos = pos->next) | 597 | for (pos = daemon->connections_head; NULL != pos; pos = pos->next) |
558 | if (MHD_YES != MHD_connection_get_fdset (pos, | 598 | { |
559 | read_fd_set, | 599 | switch (pos->event_loop_info) |
560 | write_fd_set, | 600 | { |
561 | except_fd_set, max_fd)) | 601 | case MHD_EVENT_LOOP_INFO_READ: |
562 | return MHD_NO; | 602 | add_to_fd_set (pos->socket_fd, read_fd_set, max_fd); |
603 | break; | ||
604 | case MHD_EVENT_LOOP_INFO_WRITE: | ||
605 | add_to_fd_set (pos->socket_fd, write_fd_set, max_fd); | ||
606 | break; | ||
607 | case MHD_EVENT_LOOP_INFO_BLOCK: | ||
608 | /* not in any FD set */ | ||
609 | break; | ||
610 | case MHD_EVENT_LOOP_INFO_CLEANUP: | ||
611 | /* this should never happen */ | ||
612 | break; | ||
613 | } | ||
614 | } | ||
563 | #if DEBUG_CONNECT | 615 | #if DEBUG_CONNECT |
564 | MHD_DLOG (daemon, "Maximum socket in select set: %d\n", *max_fd); | 616 | MHD_DLOG (daemon, "Maximum socket in select set: %d\n", *max_fd); |
565 | #endif | 617 | #endif |
@@ -581,14 +633,12 @@ MHD_handle_connection (void *data) | |||
581 | int num_ready; | 633 | int num_ready; |
582 | fd_set rs; | 634 | fd_set rs; |
583 | fd_set ws; | 635 | fd_set ws; |
584 | fd_set es; | ||
585 | int max; | 636 | int max; |
586 | struct timeval tv; | 637 | struct timeval tv; |
587 | struct timeval *tvp; | 638 | struct timeval *tvp; |
588 | unsigned int timeout; | 639 | unsigned int timeout; |
589 | time_t now; | 640 | time_t now; |
590 | #ifdef HAVE_POLL_H | 641 | #ifdef HAVE_POLL_H |
591 | struct MHD_Pollfd mp; | ||
592 | struct pollfd p[1]; | 642 | struct pollfd p[1]; |
593 | #endif | 643 | #endif |
594 | 644 | ||
@@ -607,14 +657,6 @@ MHD_handle_connection (void *data) | |||
607 | tv.tv_usec = 0; | 657 | tv.tv_usec = 0; |
608 | tvp = &tv; | 658 | tvp = &tv; |
609 | } | 659 | } |
610 | if ( (MHD_CONNECTION_NORMAL_BODY_UNREADY == con->state) || | ||
611 | (MHD_CONNECTION_CHUNKED_BODY_UNREADY == con->state) ) | ||
612 | { | ||
613 | /* do not block (we're waiting for our callback to succeed) */ | ||
614 | tv.tv_sec = 0; | ||
615 | tv.tv_usec = 0; | ||
616 | tvp = &tv; | ||
617 | } | ||
618 | #if HTTPS_SUPPORT | 660 | #if HTTPS_SUPPORT |
619 | if (MHD_YES == con->tls_read_ready) | 661 | if (MHD_YES == con->tls_read_ready) |
620 | { | 662 | { |
@@ -629,10 +671,25 @@ MHD_handle_connection (void *data) | |||
629 | /* use select */ | 671 | /* use select */ |
630 | FD_ZERO (&rs); | 672 | FD_ZERO (&rs); |
631 | FD_ZERO (&ws); | 673 | FD_ZERO (&ws); |
632 | FD_ZERO (&es); | ||
633 | max = 0; | 674 | max = 0; |
634 | MHD_connection_get_fdset (con, &rs, &ws, &es, &max); | 675 | switch (con->event_loop_info) |
635 | num_ready = SELECT (max + 1, &rs, &ws, &es, tvp); | 676 | { |
677 | case MHD_EVENT_LOOP_INFO_READ: | ||
678 | add_to_fd_set (con->socket_fd, &rs, &max); | ||
679 | break; | ||
680 | case MHD_EVENT_LOOP_INFO_WRITE: | ||
681 | add_to_fd_set (con->socket_fd, &ws, &max); | ||
682 | break; | ||
683 | case MHD_EVENT_LOOP_INFO_BLOCK: | ||
684 | tv.tv_sec = 0; | ||
685 | tv.tv_usec = 0; | ||
686 | tvp = &tv; | ||
687 | break; | ||
688 | case MHD_EVENT_LOOP_INFO_CLEANUP: | ||
689 | /* how did we get here!? */ | ||
690 | goto exit; | ||
691 | } | ||
692 | num_ready = SELECT (max + 1, &rs, &ws, NULL, tvp); | ||
636 | if (num_ready < 0) | 693 | if (num_ready < 0) |
637 | { | 694 | { |
638 | if (EINTR == errno) | 695 | if (EINTR == errno) |
@@ -648,7 +705,7 @@ MHD_handle_connection (void *data) | |||
648 | /* call appropriate connection handler if necessary */ | 705 | /* call appropriate connection handler if necessary */ |
649 | if ( (FD_ISSET (con->socket_fd, &rs)) | 706 | if ( (FD_ISSET (con->socket_fd, &rs)) |
650 | #if HTTPS_SUPPORT | 707 | #if HTTPS_SUPPORT |
651 | || (MHD_YES == con->tls_read_ready) | 708 | || (MHD_YES == con->tls_read_ready) |
652 | #endif | 709 | #endif |
653 | ) | 710 | ) |
654 | con->read_handler (con); | 711 | con->read_handler (con); |
@@ -661,16 +718,26 @@ MHD_handle_connection (void *data) | |||
661 | else | 718 | else |
662 | { | 719 | { |
663 | /* use poll */ | 720 | /* use poll */ |
664 | memset(&mp, 0, sizeof (struct MHD_Pollfd)); | 721 | memset (&p, 0, sizeof (p)); |
665 | MHD_connection_get_pollfd(con, &mp); | 722 | p[0].fd = con->socket_fd; |
666 | memset(&p, 0, sizeof (p)); | 723 | switch (con->event_loop_info) |
667 | p[0].fd = mp.fd; | 724 | { |
668 | if (mp.events & MHD_POLL_ACTION_IN) | 725 | case MHD_EVENT_LOOP_INFO_READ: |
669 | p[0].events |= POLLIN; | 726 | p[0].events |= POLLIN; |
670 | if (mp.events & MHD_POLL_ACTION_OUT) | 727 | break; |
671 | p[0].events |= POLLOUT; | 728 | case MHD_EVENT_LOOP_INFO_WRITE: |
672 | if (poll (p, | 729 | p[0].events |= POLLOUT; |
673 | 1, | 730 | break; |
731 | case MHD_EVENT_LOOP_INFO_BLOCK: | ||
732 | tv.tv_sec = 0; | ||
733 | tv.tv_usec = 0; | ||
734 | tvp = &tv; | ||
735 | break; | ||
736 | case MHD_EVENT_LOOP_INFO_CLEANUP: | ||
737 | /* how did we get here!? */ | ||
738 | goto exit; | ||
739 | } | ||
740 | if (poll (p, 1, | ||
674 | (NULL == tvp) ? -1 : tv.tv_sec * 1000) < 0) | 741 | (NULL == tvp) ? -1 : tv.tv_sec * 1000) < 0) |
675 | { | 742 | { |
676 | if (EINTR == errno) | 743 | if (EINTR == errno) |
@@ -732,15 +799,23 @@ recv_param_adapter (struct MHD_Connection *connection, | |||
732 | void *other, | 799 | void *other, |
733 | size_t i) | 800 | size_t i) |
734 | { | 801 | { |
802 | ssize_t ret; | ||
803 | |||
735 | if ( (-1 == connection->socket_fd) || | 804 | if ( (-1 == connection->socket_fd) || |
736 | (MHD_CONNECTION_CLOSED == connection->state) ) | 805 | (MHD_CONNECTION_CLOSED == connection->state) ) |
737 | { | 806 | { |
738 | errno = ENOTCONN; | 807 | errno = ENOTCONN; |
739 | return -1; | 808 | return -1; |
740 | } | 809 | } |
741 | if (0 != (connection->daemon->options & MHD_USE_SSL)) | 810 | ret = RECV (connection->socket_fd, other, i, MSG_NOSIGNAL); |
742 | return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL); | 811 | #if EPOLL_SUPPORT |
743 | return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL); | 812 | if (ret < i) |
813 | { | ||
814 | /* partial read --- no longer read-ready */ | ||
815 | connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY; | ||
816 | } | ||
817 | #endif | ||
818 | return ret; | ||
744 | } | 819 | } |
745 | 820 | ||
746 | 821 | ||
@@ -757,12 +832,13 @@ send_param_adapter (struct MHD_Connection *connection, | |||
757 | const void *other, | 832 | const void *other, |
758 | size_t i) | 833 | size_t i) |
759 | { | 834 | { |
835 | ssize_t ret; | ||
760 | #if LINUX | 836 | #if LINUX |
761 | int fd; | 837 | int fd; |
762 | off_t offset; | 838 | off_t offset; |
763 | off_t left; | 839 | off_t left; |
764 | ssize_t ret; | ||
765 | #endif | 840 | #endif |
841 | |||
766 | if ( (-1 == connection->socket_fd) || | 842 | if ( (-1 == connection->socket_fd) || |
767 | (MHD_CONNECTION_CLOSED == connection->state) ) | 843 | (MHD_CONNECTION_CLOSED == connection->state) ) |
768 | { | 844 | { |
@@ -786,7 +862,16 @@ send_param_adapter (struct MHD_Connection *connection, | |||
786 | fd, | 862 | fd, |
787 | &offset, | 863 | &offset, |
788 | (size_t) left))) | 864 | (size_t) left))) |
789 | return ret; | 865 | { |
866 | #if EPOLL_SUPPORT | ||
867 | if (ret < left) | ||
868 | { | ||
869 | /* partial write --- no longer write-ready */ | ||
870 | connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
871 | } | ||
872 | #endif | ||
873 | return ret; | ||
874 | } | ||
790 | if ( (EINTR == errno) || (EAGAIN == errno) ) | 875 | if ( (EINTR == errno) || (EAGAIN == errno) ) |
791 | return 0; | 876 | return 0; |
792 | if ( (EINVAL == errno) || (EBADF == errno) ) | 877 | if ( (EINVAL == errno) || (EBADF == errno) ) |
@@ -797,7 +882,15 @@ send_param_adapter (struct MHD_Connection *connection, | |||
797 | http://lists.gnu.org/archive/html/libmicrohttpd/2011-02/msg00015.html */ | 882 | http://lists.gnu.org/archive/html/libmicrohttpd/2011-02/msg00015.html */ |
798 | } | 883 | } |
799 | #endif | 884 | #endif |
800 | return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL); | 885 | ret = SEND (connection->socket_fd, other, i, MSG_NOSIGNAL); |
886 | #if EPOLL_SUPPORT | ||
887 | if (ret < i) | ||
888 | { | ||
889 | /* partial write --- no longer write-ready */ | ||
890 | connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
891 | } | ||
892 | #endif | ||
893 | return ret; | ||
801 | } | 894 | } |
802 | 895 | ||
803 | 896 | ||
@@ -890,13 +983,31 @@ MHD_add_connection (struct MHD_Daemon *daemon, | |||
890 | { | 983 | { |
891 | struct MHD_Connection *connection; | 984 | struct MHD_Connection *connection; |
892 | int res_thread_create; | 985 | int res_thread_create; |
986 | unsigned int i; | ||
893 | #if OSX | 987 | #if OSX |
894 | static int on = 1; | 988 | static int on = 1; |
895 | #endif | 989 | #endif |
990 | |||
991 | if (NULL != daemon->worker_pool) | ||
992 | { | ||
993 | /* have a pool, try to find a pool with capacity; we use the | ||
994 | socket as the initial offset into the pool for load | ||
995 | balancing */ | ||
996 | for (i=0;i<daemon->worker_pool_size;i++) | ||
997 | if (0 < daemon->worker_pool[(i + client_socket) % daemon->worker_pool_size].max_connections) | ||
998 | return MHD_add_connection (&daemon->worker_pool[(i + client_socket) % daemon->worker_pool_size], | ||
999 | client_socket, | ||
1000 | addr, addrlen); | ||
1001 | /* all pools are at their connection limit, must refuse */ | ||
1002 | SHUTDOWN (client_socket, SHUT_RDWR); | ||
1003 | if (0 != CLOSE (client_socket)) | ||
1004 | MHD_PANIC ("close failed\n"); | ||
1005 | return MHD_NO; | ||
1006 | } | ||
896 | 1007 | ||
897 | #ifndef WINDOWS | 1008 | #ifndef WINDOWS |
898 | if ( (client_socket >= FD_SETSIZE) && | 1009 | if ( (client_socket >= FD_SETSIZE) && |
899 | (0 == (daemon->options & MHD_USE_POLL)) ) | 1010 | (0 == (daemon->options & (MHD_USE_POLL | MHD_USE_EPOLL_LINUX_ONLY))) ) |
900 | { | 1011 | { |
901 | #if HAVE_MESSAGES | 1012 | #if HAVE_MESSAGES |
902 | MHD_DLOG (daemon, | 1013 | MHD_DLOG (daemon, |
@@ -905,7 +1016,8 @@ MHD_add_connection (struct MHD_Daemon *daemon, | |||
905 | FD_SETSIZE); | 1016 | FD_SETSIZE); |
906 | #endif | 1017 | #endif |
907 | SHUTDOWN (client_socket, SHUT_RDWR); | 1018 | SHUTDOWN (client_socket, SHUT_RDWR); |
908 | CLOSE (client_socket); | 1019 | if (0 != CLOSE (client_socket)) |
1020 | MHD_PANIC ("close failed\n"); | ||
909 | return MHD_NO; | 1021 | return MHD_NO; |
910 | } | 1022 | } |
911 | #endif | 1023 | #endif |
@@ -925,7 +1037,8 @@ MHD_add_connection (struct MHD_Daemon *daemon, | |||
925 | "Server reached connection limit (closing inbound connection)\n"); | 1037 | "Server reached connection limit (closing inbound connection)\n"); |
926 | #endif | 1038 | #endif |
927 | SHUTDOWN (client_socket, SHUT_RDWR); | 1039 | SHUTDOWN (client_socket, SHUT_RDWR); |
928 | CLOSE (client_socket); | 1040 | if (0 != CLOSE (client_socket)) |
1041 | MHD_PANIC ("close failed\n"); | ||
929 | return MHD_NO; | 1042 | return MHD_NO; |
930 | } | 1043 | } |
931 | 1044 | ||
@@ -940,9 +1053,10 @@ MHD_add_connection (struct MHD_Daemon *daemon, | |||
940 | #endif | 1053 | #endif |
941 | #endif | 1054 | #endif |
942 | SHUTDOWN (client_socket, SHUT_RDWR); | 1055 | SHUTDOWN (client_socket, SHUT_RDWR); |
943 | CLOSE (client_socket); | 1056 | if (0 != CLOSE (client_socket)) |
1057 | MHD_PANIC ("close failed\n"); | ||
944 | MHD_ip_limit_del (daemon, addr, addrlen); | 1058 | MHD_ip_limit_del (daemon, addr, addrlen); |
945 | return MHD_YES; | 1059 | return MHD_NO; |
946 | } | 1060 | } |
947 | 1061 | ||
948 | #if OSX | 1062 | #if OSX |
@@ -963,13 +1077,29 @@ MHD_add_connection (struct MHD_Daemon *daemon, | |||
963 | STRERROR (errno)); | 1077 | STRERROR (errno)); |
964 | #endif | 1078 | #endif |
965 | SHUTDOWN (client_socket, SHUT_RDWR); | 1079 | SHUTDOWN (client_socket, SHUT_RDWR); |
966 | CLOSE (client_socket); | 1080 | if (0 != CLOSE (client_socket)) |
1081 | MHD_PANIC ("close failed\n"); | ||
967 | MHD_ip_limit_del (daemon, addr, addrlen); | 1082 | MHD_ip_limit_del (daemon, addr, addrlen); |
968 | return MHD_NO; | 1083 | return MHD_NO; |
969 | } | 1084 | } |
970 | memset (connection, 0, sizeof (struct MHD_Connection)); | 1085 | memset (connection, 0, sizeof (struct MHD_Connection)); |
1086 | connection->pool = MHD_pool_create (daemon->pool_size); | ||
1087 | if (NULL == connection->pool) | ||
1088 | { | ||
1089 | #if HAVE_MESSAGES | ||
1090 | MHD_DLOG (daemon, | ||
1091 | "Error allocating memory: %s\n", | ||
1092 | STRERROR (errno)); | ||
1093 | #endif | ||
1094 | SHUTDOWN (client_socket, SHUT_RDWR); | ||
1095 | if (0 != CLOSE (client_socket)) | ||
1096 | MHD_PANIC ("close failed\n"); | ||
1097 | MHD_ip_limit_del (daemon, addr, addrlen); | ||
1098 | free (connection); | ||
1099 | return MHD_NO; | ||
1100 | } | ||
1101 | |||
971 | connection->connection_timeout = daemon->connection_timeout; | 1102 | connection->connection_timeout = daemon->connection_timeout; |
972 | connection->pool = NULL; | ||
973 | if (NULL == (connection->addr = malloc (addrlen))) | 1103 | if (NULL == (connection->addr = malloc (addrlen))) |
974 | { | 1104 | { |
975 | #if HAVE_MESSAGES | 1105 | #if HAVE_MESSAGES |
@@ -978,8 +1108,10 @@ MHD_add_connection (struct MHD_Daemon *daemon, | |||
978 | STRERROR (errno)); | 1108 | STRERROR (errno)); |
979 | #endif | 1109 | #endif |
980 | SHUTDOWN (client_socket, SHUT_RDWR); | 1110 | SHUTDOWN (client_socket, SHUT_RDWR); |
981 | CLOSE (client_socket); | 1111 | if (0 != CLOSE (client_socket)) |
1112 | MHD_PANIC ("close failed\n"); | ||
982 | MHD_ip_limit_del (daemon, addr, addrlen); | 1113 | MHD_ip_limit_del (daemon, addr, addrlen); |
1114 | MHD_pool_destroy (connection->pool); | ||
983 | free (connection); | 1115 | free (connection); |
984 | return MHD_NO; | 1116 | return MHD_NO; |
985 | } | 1117 | } |
@@ -988,7 +1120,7 @@ MHD_add_connection (struct MHD_Daemon *daemon, | |||
988 | connection->socket_fd = client_socket; | 1120 | connection->socket_fd = client_socket; |
989 | connection->daemon = daemon; | 1121 | connection->daemon = daemon; |
990 | connection->last_activity = MHD_monotonic_time(); | 1122 | connection->last_activity = MHD_monotonic_time(); |
991 | 1123 | ||
992 | /* set default connection handlers */ | 1124 | /* set default connection handlers */ |
993 | MHD_set_http_callbacks_ (connection); | 1125 | MHD_set_http_callbacks_ (connection); |
994 | connection->recv_cls = &recv_param_adapter; | 1126 | connection->recv_cls = &recv_param_adapter; |
@@ -1050,7 +1182,8 @@ MHD_add_connection (struct MHD_Daemon *daemon, | |||
1050 | daemon->cred_type); | 1182 | daemon->cred_type); |
1051 | #endif | 1183 | #endif |
1052 | SHUTDOWN (client_socket, SHUT_RDWR); | 1184 | SHUTDOWN (client_socket, SHUT_RDWR); |
1053 | CLOSE (client_socket); | 1185 | if (0 != CLOSE (client_socket)) |
1186 | MHD_PANIC ("close failed\n"); | ||
1054 | MHD_ip_limit_del (daemon, addr, addrlen); | 1187 | MHD_ip_limit_del (daemon, addr, addrlen); |
1055 | free (connection->addr); | 1188 | free (connection->addr); |
1056 | free (connection); | 1189 | free (connection); |
@@ -1065,16 +1198,22 @@ MHD_add_connection (struct MHD_Daemon *daemon, | |||
1065 | (gnutls_push_func) &send_param_adapter); | 1198 | (gnutls_push_func) &send_param_adapter); |
1066 | 1199 | ||
1067 | if (daemon->https_mem_trust) | 1200 | if (daemon->https_mem_trust) |
1068 | gnutls_certificate_server_set_request(connection->tls_session, GNUTLS_CERT_REQUEST); | 1201 | gnutls_certificate_server_set_request (connection->tls_session, |
1202 | GNUTLS_CERT_REQUEST); | ||
1069 | } | 1203 | } |
1070 | #endif | 1204 | #endif |
1071 | 1205 | ||
1072 | if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex)) | 1206 | if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && |
1207 | (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) ) | ||
1073 | MHD_PANIC ("Failed to acquire cleanup mutex\n"); | 1208 | MHD_PANIC ("Failed to acquire cleanup mutex\n"); |
1209 | XDLL_insert (daemon->normal_timeout_head, | ||
1210 | daemon->normal_timeout_tail, | ||
1211 | connection); | ||
1074 | DLL_insert (daemon->connections_head, | 1212 | DLL_insert (daemon->connections_head, |
1075 | daemon->connections_tail, | 1213 | daemon->connections_tail, |
1076 | connection); | 1214 | connection); |
1077 | if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex)) | 1215 | if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && |
1216 | (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex)) ) | ||
1078 | MHD_PANIC ("Failed to release cleanup mutex\n"); | 1217 | MHD_PANIC ("Failed to release cleanup mutex\n"); |
1079 | 1218 | ||
1080 | /* attempt to create handler thread */ | 1219 | /* attempt to create handler thread */ |
@@ -1088,27 +1227,58 @@ MHD_add_connection (struct MHD_Daemon *daemon, | |||
1088 | MHD_DLOG (daemon, "Failed to create a thread: %s\n", | 1227 | MHD_DLOG (daemon, "Failed to create a thread: %s\n", |
1089 | STRERROR (res_thread_create)); | 1228 | STRERROR (res_thread_create)); |
1090 | #endif | 1229 | #endif |
1091 | SHUTDOWN (client_socket, SHUT_RDWR); | 1230 | goto cleanup; |
1092 | CLOSE (client_socket); | ||
1093 | MHD_ip_limit_del (daemon, addr, addrlen); | ||
1094 | if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex)) | ||
1095 | { | ||
1096 | MHD_PANIC ("Failed to acquire cleanup mutex\n"); | ||
1097 | } | ||
1098 | DLL_remove (daemon->connections_head, | ||
1099 | daemon->connections_tail, | ||
1100 | connection); | ||
1101 | if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex)) | ||
1102 | { | ||
1103 | MHD_PANIC ("Failed to release cleanup mutex\n"); | ||
1104 | } | ||
1105 | free (connection->addr); | ||
1106 | free (connection); | ||
1107 | return MHD_NO; | ||
1108 | } | 1231 | } |
1109 | } | 1232 | } |
1110 | daemon->max_connections--; | 1233 | #if EPOLL_SUPPORT |
1234 | if (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) | ||
1235 | { | ||
1236 | struct epoll_event event; | ||
1237 | |||
1238 | event.events = EPOLLIN | EPOLLOUT | EPOLLET; | ||
1239 | event.data.ptr = connection; | ||
1240 | if (0 != epoll_ctl (daemon->epoll_fd, | ||
1241 | EPOLL_CTL_ADD, | ||
1242 | client_socket, | ||
1243 | &event)) | ||
1244 | { | ||
1245 | #if HAVE_MESSAGES | ||
1246 | if (0 != (daemon->options & MHD_USE_DEBUG)) | ||
1247 | MHD_DLOG (daemon, | ||
1248 | "Call to epoll_ctl failed: %s\n", | ||
1249 | STRERROR (errno)); | ||
1250 | #endif | ||
1251 | goto cleanup; | ||
1252 | } | ||
1253 | daemon->listen_socket_in_epoll = MHD_YES; | ||
1254 | |||
1255 | } | ||
1256 | #endif | ||
1257 | daemon->max_connections--; | ||
1111 | return MHD_YES; | 1258 | return MHD_YES; |
1259 | #if HTTPS_SUPPORT || EPOLL_SUPPORT | ||
1260 | cleanup: | ||
1261 | SHUTDOWN (client_socket, SHUT_RDWR); | ||
1262 | if (0 != CLOSE (client_socket)) | ||
1263 | MHD_PANIC ("close failed\n"); | ||
1264 | MHD_ip_limit_del (daemon, addr, addrlen); | ||
1265 | if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && | ||
1266 | (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) ) | ||
1267 | MHD_PANIC ("Failed to acquire cleanup mutex\n"); | ||
1268 | DLL_remove (daemon->connections_head, | ||
1269 | daemon->connections_tail, | ||
1270 | connection); | ||
1271 | XDLL_remove (daemon->normal_timeout_head, | ||
1272 | daemon->normal_timeout_tail, | ||
1273 | connection); | ||
1274 | if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && | ||
1275 | (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex)) ) | ||
1276 | MHD_PANIC ("Failed to release cleanup mutex\n"); | ||
1277 | MHD_pool_destroy (connection->pool); | ||
1278 | free (connection->addr); | ||
1279 | free (connection); | ||
1280 | return MHD_NO; | ||
1281 | #endif | ||
1112 | } | 1282 | } |
1113 | 1283 | ||
1114 | 1284 | ||
@@ -1118,7 +1288,11 @@ MHD_add_connection (struct MHD_Daemon *daemon, | |||
1118 | * accept policy callback. | 1288 | * accept policy callback. |
1119 | * | 1289 | * |
1120 | * @param daemon handle with the listen socket | 1290 | * @param daemon handle with the listen socket |
1121 | * @return MHD_YES on success | 1291 | * @return MHD_YES on success (connections denied by policy or due |
1292 | * to 'out of memory' and similar errors) are still considered | ||
1293 | * successful as far as MHD_accept_connection is concerned); | ||
1294 | * a return code of MHD_NO only refers to the actual | ||
1295 | * 'accept' system call. | ||
1122 | */ | 1296 | */ |
1123 | static int | 1297 | static int |
1124 | MHD_accept_connection (struct MHD_Daemon *daemon) | 1298 | MHD_accept_connection (struct MHD_Daemon *daemon) |
@@ -1143,14 +1317,9 @@ MHD_accept_connection (struct MHD_Daemon *daemon) | |||
1143 | s = accept4 (fd, addr, &addrlen, SOCK_CLOEXEC); | 1317 | s = accept4 (fd, addr, &addrlen, SOCK_CLOEXEC); |
1144 | need_fcntl = MHD_NO; | 1318 | need_fcntl = MHD_NO; |
1145 | #else | 1319 | #else |
1146 | s = -1; | 1320 | s = ACCEPT (fd, addr, &addrlen); |
1147 | need_fcntl = MHD_YES; | 1321 | need_fcntl = MHD_YES; |
1148 | #endif | 1322 | #endif |
1149 | if (-1 == s) | ||
1150 | { | ||
1151 | s = ACCEPT (fd, addr, &addrlen); | ||
1152 | need_fcntl = MHD_YES; | ||
1153 | } | ||
1154 | if ((-1 == s) || (addrlen <= 0)) | 1323 | if ((-1 == s) || (addrlen <= 0)) |
1155 | { | 1324 | { |
1156 | #if HAVE_MESSAGES | 1325 | #if HAVE_MESSAGES |
@@ -1163,11 +1332,13 @@ MHD_accept_connection (struct MHD_Daemon *daemon) | |||
1163 | if (-1 != s) | 1332 | if (-1 != s) |
1164 | { | 1333 | { |
1165 | SHUTDOWN (s, SHUT_RDWR); | 1334 | SHUTDOWN (s, SHUT_RDWR); |
1166 | CLOSE (s); | 1335 | if (0 != CLOSE (s)) |
1336 | MHD_PANIC ("close failed\n"); | ||
1167 | /* just in case */ | 1337 | /* just in case */ |
1168 | } | 1338 | } |
1169 | return MHD_NO; | 1339 | return MHD_NO; |
1170 | } | 1340 | } |
1341 | #if !HAVE_ACCEPT4 | ||
1171 | if (MHD_YES == need_fcntl) | 1342 | if (MHD_YES == need_fcntl) |
1172 | { | 1343 | { |
1173 | /* make socket non-inheritable */ | 1344 | /* make socket non-inheritable */ |
@@ -1198,13 +1369,15 @@ MHD_accept_connection (struct MHD_Daemon *daemon) | |||
1198 | } | 1369 | } |
1199 | #endif | 1370 | #endif |
1200 | } | 1371 | } |
1372 | #endif | ||
1201 | #if HAVE_MESSAGES | 1373 | #if HAVE_MESSAGES |
1202 | #if DEBUG_CONNECT | 1374 | #if DEBUG_CONNECT |
1203 | MHD_DLOG (daemon, "Accepted connection on socket %d\n", s); | 1375 | MHD_DLOG (daemon, "Accepted connection on socket %d\n", s); |
1204 | #endif | 1376 | #endif |
1205 | #endif | 1377 | #endif |
1206 | return MHD_add_connection (daemon, s, | 1378 | (void) MHD_add_connection (daemon, s, |
1207 | addr, addrlen); | 1379 | addr, addrlen); |
1380 | return MHD_YES; | ||
1208 | } | 1381 | } |
1209 | 1382 | ||
1210 | 1383 | ||
@@ -1222,10 +1395,9 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon) | |||
1222 | void *unused; | 1395 | void *unused; |
1223 | int rc; | 1396 | int rc; |
1224 | 1397 | ||
1225 | if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex)) | 1398 | if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && |
1226 | { | 1399 | (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) ) |
1227 | MHD_PANIC ("Failed to acquire cleanup mutex\n"); | 1400 | MHD_PANIC ("Failed to acquire cleanup mutex\n"); |
1228 | } | ||
1229 | while (NULL != (pos = daemon->cleanup_head)) | 1401 | while (NULL != (pos = daemon->cleanup_head)) |
1230 | { | 1402 | { |
1231 | DLL_remove (daemon->cleanup_head, | 1403 | DLL_remove (daemon->cleanup_head, |
@@ -1245,22 +1417,39 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon) | |||
1245 | gnutls_deinit (pos->tls_session); | 1417 | gnutls_deinit (pos->tls_session); |
1246 | #endif | 1418 | #endif |
1247 | MHD_ip_limit_del (daemon, (struct sockaddr*)pos->addr, pos->addr_len); | 1419 | MHD_ip_limit_del (daemon, (struct sockaddr*)pos->addr, pos->addr_len); |
1420 | #if EPOLL_SUPPORT | ||
1421 | if ( (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) && | ||
1422 | (-1 != daemon->epoll_fd) ) | ||
1423 | { | ||
1424 | /* epoll documentation suggests that closing a FD | ||
1425 | automatically removes it from the epoll set; however, | ||
1426 | this is not true as if we fail to do manually remove it, | ||
1427 | we are still seeing an event for this fd in epoll, | ||
1428 | causing grief (use-after-free...) --- at least on my | ||
1429 | system. */ | ||
1430 | if (0 != epoll_ctl (daemon->epoll_fd, | ||
1431 | EPOLL_CTL_DEL, | ||
1432 | pos->socket_fd, | ||
1433 | NULL)) | ||
1434 | MHD_PANIC ("Failed to remove FD from epoll set\n"); | ||
1435 | } | ||
1436 | #endif | ||
1248 | if (NULL != pos->response) | 1437 | if (NULL != pos->response) |
1249 | { | 1438 | { |
1250 | MHD_destroy_response (pos->response); | 1439 | MHD_destroy_response (pos->response); |
1251 | pos->response = NULL; | 1440 | pos->response = NULL; |
1252 | } | 1441 | } |
1253 | if (-1 != pos->socket_fd) | 1442 | if ( (-1 != pos->socket_fd) && |
1254 | CLOSE (pos->socket_fd); | 1443 | (0 != CLOSE (pos->socket_fd)) ) |
1444 | MHD_PANIC ("close failed\n"); | ||
1255 | if (NULL != pos->addr) | 1445 | if (NULL != pos->addr) |
1256 | free (pos->addr); | 1446 | free (pos->addr); |
1257 | free (pos); | 1447 | free (pos); |
1258 | daemon->max_connections++; | 1448 | daemon->max_connections++; |
1259 | } | 1449 | } |
1260 | if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex)) | 1450 | if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && |
1261 | { | 1451 | (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex)) ) |
1262 | MHD_PANIC ("Failed to release cleanup mutex\n"); | 1452 | MHD_PANIC ("Failed to release cleanup mutex\n"); |
1263 | } | ||
1264 | } | 1453 | } |
1265 | 1454 | ||
1266 | 1455 | ||
@@ -1292,17 +1481,20 @@ MHD_get_timeout (struct MHD_Daemon *daemon, | |||
1292 | #endif | 1481 | #endif |
1293 | return MHD_NO; | 1482 | return MHD_NO; |
1294 | } | 1483 | } |
1295 | have_timeout = MHD_NO; | 1484 | |
1296 | for (pos = daemon->connections_head; NULL != pos; pos = pos->next) | ||
1297 | { | ||
1298 | #if HTTPS_SUPPORT | 1485 | #if HTTPS_SUPPORT |
1299 | if (MHD_YES == pos->tls_read_ready) | 1486 | if (0 != daemon->num_tls_read_ready) |
1300 | { | 1487 | { |
1301 | earliest_deadline = 0; | 1488 | /* if there is any TLS connection with data ready for |
1302 | have_timeout = MHD_YES; | 1489 | reading, we must not block in the event loop */ |
1303 | break; | 1490 | *timeout = 0; |
1304 | } | 1491 | return MHD_YES; |
1492 | } | ||
1305 | #endif | 1493 | #endif |
1494 | |||
1495 | have_timeout = MHD_NO; | ||
1496 | for (pos = daemon->manual_timeout_head; NULL != pos; pos = pos->nextX) | ||
1497 | { | ||
1306 | if (0 != pos->connection_timeout) | 1498 | if (0 != pos->connection_timeout) |
1307 | { | 1499 | { |
1308 | if ( (! have_timeout) || | 1500 | if ( (! have_timeout) || |
@@ -1316,6 +1508,22 @@ MHD_get_timeout (struct MHD_Daemon *daemon, | |||
1316 | have_timeout = MHD_YES; | 1508 | have_timeout = MHD_YES; |
1317 | } | 1509 | } |
1318 | } | 1510 | } |
1511 | /* normal timeouts are sorted, so we only need to look at the 'head' */ | ||
1512 | pos = daemon->normal_timeout_head; | ||
1513 | if ( (NULL != pos) && | ||
1514 | (0 != pos->connection_timeout) ) | ||
1515 | { | ||
1516 | if ( (! have_timeout) || | ||
1517 | (earliest_deadline > pos->last_activity + pos->connection_timeout) ) | ||
1518 | earliest_deadline = pos->last_activity + pos->connection_timeout; | ||
1519 | #if HTTPS_SUPPORT | ||
1520 | if ( (0 != (daemon->options & MHD_USE_SSL)) && | ||
1521 | (0 != gnutls_record_check_pending (pos->tls_session)) ) | ||
1522 | earliest_deadline = 0; | ||
1523 | #endif | ||
1524 | have_timeout = MHD_YES; | ||
1525 | } | ||
1526 | |||
1319 | if (MHD_NO == have_timeout) | 1527 | if (MHD_NO == have_timeout) |
1320 | return MHD_NO; | 1528 | return MHD_NO; |
1321 | now = MHD_monotonic_time(); | 1529 | now = MHD_monotonic_time(); |
@@ -1356,10 +1564,23 @@ MHD_run_from_select (struct MHD_Daemon *daemon, | |||
1356 | struct MHD_Connection *pos; | 1564 | struct MHD_Connection *pos; |
1357 | struct MHD_Connection *next; | 1565 | struct MHD_Connection *next; |
1358 | 1566 | ||
1567 | #if EPOLL_SUPPORT | ||
1568 | if (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) | ||
1569 | { | ||
1570 | /* we're in epoll mode, the epoll FD stands for | ||
1571 | the entire event set! */ | ||
1572 | if (daemon->epoll_fd >= FD_SETSIZE) | ||
1573 | return MHD_NO; /* poll fd too big, fail hard */ | ||
1574 | if (FD_ISSET (daemon->epoll_fd, read_fd_set)) | ||
1575 | return MHD_run (daemon); | ||
1576 | return MHD_YES; | ||
1577 | } | ||
1578 | #endif | ||
1579 | |||
1359 | /* select connection thread handling type */ | 1580 | /* select connection thread handling type */ |
1360 | if ( (-1 != (ds = daemon->socket_fd)) && | 1581 | if ( (-1 != (ds = daemon->socket_fd)) && |
1361 | (FD_ISSET (ds, read_fd_set)) ) | 1582 | (FD_ISSET (ds, read_fd_set)) ) |
1362 | MHD_accept_connection (daemon); | 1583 | (void) MHD_accept_connection (daemon); |
1363 | /* drain signaling pipe to avoid spinning select */ | 1584 | /* drain signaling pipe to avoid spinning select */ |
1364 | if ( (-1 != daemon->wpipe[0]) && | 1585 | if ( (-1 != daemon->wpipe[0]) && |
1365 | (FD_ISSET (daemon->wpipe[0], read_fd_set)) ) | 1586 | (FD_ISSET (daemon->wpipe[0], read_fd_set)) ) |
@@ -1373,18 +1594,30 @@ MHD_run_from_select (struct MHD_Daemon *daemon, | |||
1373 | { | 1594 | { |
1374 | next = pos->next; | 1595 | next = pos->next; |
1375 | ds = pos->socket_fd; | 1596 | ds = pos->socket_fd; |
1376 | if (ds != -1) | 1597 | if (-1 == ds) |
1377 | { | 1598 | continue; |
1378 | if ( (FD_ISSET (ds, read_fd_set)) | 1599 | switch (pos->event_loop_info) |
1600 | { | ||
1601 | case MHD_EVENT_LOOP_INFO_READ: | ||
1602 | if ( (FD_ISSET (ds, read_fd_set)) | ||
1379 | #if HTTPS_SUPPORT | 1603 | #if HTTPS_SUPPORT |
1380 | || (MHD_YES == pos->tls_read_ready) | 1604 | || (MHD_YES == pos->tls_read_ready) |
1381 | #endif | 1605 | #endif |
1382 | ) | 1606 | ) |
1383 | pos->read_handler (pos); | 1607 | pos->read_handler (pos); |
1384 | if (FD_ISSET (ds, write_fd_set)) | 1608 | break; |
1385 | pos->write_handler (pos); | 1609 | case MHD_EVENT_LOOP_INFO_WRITE: |
1386 | pos->idle_handler (pos); | 1610 | if (FD_ISSET (ds, write_fd_set)) |
1387 | } | 1611 | pos->write_handler (pos); |
1612 | break; | ||
1613 | case MHD_EVENT_LOOP_INFO_BLOCK: | ||
1614 | /* only idle handler */ | ||
1615 | break; | ||
1616 | case MHD_EVENT_LOOP_INFO_CLEANUP: | ||
1617 | /* should never happen */ | ||
1618 | break; | ||
1619 | } | ||
1620 | pos->idle_handler (pos); | ||
1388 | } | 1621 | } |
1389 | } | 1622 | } |
1390 | return MHD_YES; | 1623 | return MHD_YES; |
@@ -1502,11 +1735,11 @@ MHD_poll_all (struct MHD_Daemon *daemon, | |||
1502 | /* count number of connections and thus determine poll set size */ | 1735 | /* count number of connections and thus determine poll set size */ |
1503 | num_connections = 0; | 1736 | num_connections = 0; |
1504 | for (pos = daemon->connections_head; NULL != pos; pos = pos->next) | 1737 | for (pos = daemon->connections_head; NULL != pos; pos = pos->next) |
1505 | num_connections++; | 1738 | if ( (MHD_EVENT_LOOP_INFO_READ == pos->event_loop_info) || |
1506 | 1739 | (MHD_EVENT_LOOP_INFO_WRITE == pos->event_loop_info) ) | |
1740 | num_connections++; | ||
1507 | { | 1741 | { |
1508 | struct pollfd p[2 + num_connections]; | 1742 | struct pollfd p[2 + num_connections]; |
1509 | struct MHD_Pollfd mp; | ||
1510 | MHD_UNSIGNED_LONG_LONG ltimeout; | 1743 | MHD_UNSIGNED_LONG_LONG ltimeout; |
1511 | unsigned int i; | 1744 | unsigned int i; |
1512 | int timeout; | 1745 | int timeout; |
@@ -1544,13 +1777,22 @@ MHD_poll_all (struct MHD_Daemon *daemon, | |||
1544 | i = 0; | 1777 | i = 0; |
1545 | for (pos = daemon->connections_head; NULL != pos; pos = pos->next) | 1778 | for (pos = daemon->connections_head; NULL != pos; pos = pos->next) |
1546 | { | 1779 | { |
1547 | memset(&mp, 0, sizeof (struct MHD_Pollfd)); | 1780 | p[poll_server+i].fd = pos->socket_fd; |
1548 | MHD_connection_get_pollfd (pos, &mp); | 1781 | switch (pos->event_loop_info) |
1549 | p[poll_server+i].fd = mp.fd; | 1782 | { |
1550 | if (mp.events & MHD_POLL_ACTION_IN) | 1783 | case MHD_EVENT_LOOP_INFO_READ: |
1551 | p[poll_server+i].events |= POLLIN; | 1784 | p[poll_server+i].events |= POLLIN; |
1552 | if (mp.events & MHD_POLL_ACTION_OUT) | 1785 | break; |
1553 | p[poll_server+i].events |= POLLOUT; | 1786 | case MHD_EVENT_LOOP_INFO_WRITE: |
1787 | p[poll_server+i].events |= POLLOUT; | ||
1788 | break; | ||
1789 | case MHD_EVENT_LOOP_INFO_BLOCK: | ||
1790 | /* not in poll */ | ||
1791 | break; | ||
1792 | case MHD_EVENT_LOOP_INFO_CLEANUP: | ||
1793 | /* should never happen */ | ||
1794 | break; | ||
1795 | } | ||
1554 | i++; | 1796 | i++; |
1555 | } | 1797 | } |
1556 | if (0 == poll_server + num_connections) | 1798 | if (0 == poll_server + num_connections) |
@@ -1574,24 +1816,44 @@ MHD_poll_all (struct MHD_Daemon *daemon, | |||
1574 | while (NULL != (pos = next)) | 1816 | while (NULL != (pos = next)) |
1575 | { | 1817 | { |
1576 | next = pos->next; | 1818 | next = pos->next; |
1577 | /* first, sanity checks */ | 1819 | switch (pos->event_loop_info) |
1578 | if (i >= num_connections) | 1820 | { |
1579 | break; /* connection list changed somehow, retry later ... */ | 1821 | case MHD_EVENT_LOOP_INFO_READ: |
1580 | MHD_connection_get_pollfd (pos, &mp); | 1822 | /* first, sanity checks */ |
1581 | if (p[poll_server+i].fd != mp.fd) | 1823 | if (i >= num_connections) |
1582 | break; /* fd mismatch, something else happened, retry later ... */ | 1824 | break; /* connection list changed somehow, retry later ... */ |
1583 | 1825 | if (p[poll_server+i].fd != pos->socket_fd) | |
1584 | /* normal handling */ | 1826 | break; /* fd mismatch, something else happened, retry later ... */ |
1585 | if (0 != (p[poll_server+i].revents & POLLIN)) | 1827 | /* normal handling */ |
1586 | pos->read_handler (pos); | 1828 | if (0 != (p[poll_server+i].revents & POLLIN)) |
1587 | if (0 != (p[poll_server+i].revents & POLLOUT)) | 1829 | pos->read_handler (pos); |
1588 | pos->write_handler (pos); | 1830 | pos->idle_handler (pos); |
1589 | pos->idle_handler (pos); | 1831 | i++; |
1590 | i++; | 1832 | break; |
1833 | case MHD_EVENT_LOOP_INFO_WRITE: | ||
1834 | /* first, sanity checks */ | ||
1835 | if (i >= num_connections) | ||
1836 | break; /* connection list changed somehow, retry later ... */ | ||
1837 | if (p[poll_server+i].fd != pos->socket_fd) | ||
1838 | break; /* fd mismatch, something else happened, retry later ... */ | ||
1839 | /* normal handling */ | ||
1840 | if (0 != (p[poll_server+i].revents & POLLOUT)) | ||
1841 | pos->write_handler (pos); | ||
1842 | pos->idle_handler (pos); | ||
1843 | i++; | ||
1844 | break; | ||
1845 | case MHD_EVENT_LOOP_INFO_BLOCK: | ||
1846 | pos->idle_handler (pos); | ||
1847 | break; | ||
1848 | case MHD_EVENT_LOOP_INFO_CLEANUP: | ||
1849 | /* should never happen */ | ||
1850 | break; | ||
1851 | } | ||
1591 | } | 1852 | } |
1853 | /* handle 'listen' FD */ | ||
1592 | if ( (-1 != poll_listen) && | 1854 | if ( (-1 != poll_listen) && |
1593 | (0 != (p[poll_listen].revents & POLLIN)) ) | 1855 | (0 != (p[poll_listen].revents & POLLIN)) ) |
1594 | MHD_accept_connection (daemon); | 1856 | (void) MHD_accept_connection (daemon); |
1595 | } | 1857 | } |
1596 | return MHD_YES; | 1858 | return MHD_YES; |
1597 | } | 1859 | } |
@@ -1651,7 +1913,7 @@ MHD_poll_listen_socket (struct MHD_Daemon *daemon, | |||
1651 | return MHD_NO; | 1913 | return MHD_NO; |
1652 | if ( (-1 != poll_listen) && | 1914 | if ( (-1 != poll_listen) && |
1653 | (0 != (p[poll_listen].revents & POLLIN)) ) | 1915 | (0 != (p[poll_listen].revents & POLLIN)) ) |
1654 | MHD_accept_connection (daemon); | 1916 | (void) MHD_accept_connection (daemon); |
1655 | return MHD_YES; | 1917 | return MHD_YES; |
1656 | } | 1918 | } |
1657 | #endif | 1919 | #endif |
@@ -1681,6 +1943,204 @@ MHD_poll (struct MHD_Daemon *daemon, | |||
1681 | } | 1943 | } |
1682 | 1944 | ||
1683 | 1945 | ||
1946 | #if EPOLL_SUPPORT | ||
1947 | |||
1948 | /** | ||
1949 | * How many events to we process at most per epoll call? Trade-off | ||
1950 | * between required stack-size and number of system calls we have to | ||
1951 | * make; 128 should be way enough to avoid more than one system call | ||
1952 | * for most scenarios, and still be moderate in stack size | ||
1953 | * consumption. Embedded systems might want to choose a smaller value | ||
1954 | * --- but why use 'epoll' on such a system in the first place? | ||
1955 | */ | ||
1956 | #define MAX_EVENTS 128 | ||
1957 | |||
1958 | |||
1959 | /** | ||
1960 | * Do 'epoll'-based processing (this function is allowed to | ||
1961 | * block). | ||
1962 | * | ||
1963 | * @param daemon daemon to run poll loop for | ||
1964 | * @param may_block YES if blocking, NO if non-blocking | ||
1965 | * @return MHD_NO on serious errors, MHD_YES on success | ||
1966 | */ | ||
1967 | static int | ||
1968 | MHD_epoll (struct MHD_Daemon *daemon, | ||
1969 | int may_block) | ||
1970 | { | ||
1971 | struct MHD_Connection *pos; | ||
1972 | struct MHD_Connection *next; | ||
1973 | struct epoll_event events[MAX_EVENTS]; | ||
1974 | struct epoll_event event; | ||
1975 | int timeout_ms; | ||
1976 | MHD_UNSIGNED_LONG_LONG timeout_ll; | ||
1977 | int num_events; | ||
1978 | unsigned int i; | ||
1979 | |||
1980 | if (-1 == daemon->epoll_fd) | ||
1981 | return MHD_NO; /* we're down! */ | ||
1982 | if (MHD_YES == daemon->shutdown) | ||
1983 | return MHD_NO; | ||
1984 | if ( (-1 != daemon->socket_fd) && | ||
1985 | (0 != daemon->max_connections) && | ||
1986 | (MHD_NO == daemon->listen_socket_in_epoll) ) | ||
1987 | { | ||
1988 | event.events = EPOLLIN; | ||
1989 | event.data.ptr = daemon; | ||
1990 | if (0 != epoll_ctl (daemon->epoll_fd, | ||
1991 | EPOLL_CTL_ADD, | ||
1992 | daemon->socket_fd, | ||
1993 | &event)) | ||
1994 | { | ||
1995 | #if HAVE_MESSAGES | ||
1996 | if (0 != (daemon->options & MHD_USE_DEBUG)) | ||
1997 | MHD_DLOG (daemon, | ||
1998 | "Call to epoll_ctl failed: %s\n", | ||
1999 | STRERROR (errno)); | ||
2000 | #endif | ||
2001 | return MHD_NO; | ||
2002 | } | ||
2003 | daemon->listen_socket_in_epoll = MHD_YES; | ||
2004 | } | ||
2005 | if ( (MHD_YES == daemon->listen_socket_in_epoll) && | ||
2006 | (0 == daemon->max_connections) ) | ||
2007 | { | ||
2008 | /* we're at the connection limit, disable listen socket | ||
2009 | for event loop for now */ | ||
2010 | if (0 != epoll_ctl (daemon->epoll_fd, | ||
2011 | EPOLL_CTL_DEL, | ||
2012 | daemon->socket_fd, | ||
2013 | NULL)) | ||
2014 | MHD_PANIC ("Failed to remove listen FD from epoll set\n"); | ||
2015 | daemon->listen_socket_in_epoll = MHD_NO; | ||
2016 | } | ||
2017 | if (MHD_YES == may_block) | ||
2018 | { | ||
2019 | if (MHD_YES == MHD_get_timeout (daemon, | ||
2020 | &timeout_ll)) | ||
2021 | { | ||
2022 | if (timeout_ll >= (MHD_UNSIGNED_LONG_LONG) INT_MAX) | ||
2023 | timeout_ms = INT_MAX; | ||
2024 | else | ||
2025 | timeout_ms = (int) timeout_ll; | ||
2026 | } | ||
2027 | else | ||
2028 | timeout_ms = -1; | ||
2029 | } | ||
2030 | else | ||
2031 | timeout_ms = 0; | ||
2032 | |||
2033 | /* drain 'epoll' event queue; need to iterate as we get at most | ||
2034 | MAX_EVENTS in one system call here; in practice this should | ||
2035 | pretty much mean only one round, but better an extra loop here | ||
2036 | than unfair behavior... */ | ||
2037 | num_events = MAX_EVENTS; | ||
2038 | while (MAX_EVENTS == num_events) | ||
2039 | { | ||
2040 | /* update event masks */ | ||
2041 | num_events = epoll_wait (daemon->epoll_fd, | ||
2042 | events, MAX_EVENTS, timeout_ms); | ||
2043 | if (-1 == num_events) | ||
2044 | { | ||
2045 | if (EINTR == errno) | ||
2046 | return MHD_YES; | ||
2047 | #if HAVE_MESSAGES | ||
2048 | if (0 != (daemon->options & MHD_USE_DEBUG)) | ||
2049 | MHD_DLOG (daemon, | ||
2050 | "Call to epoll_wait failed: %s\n", | ||
2051 | STRERROR (errno)); | ||
2052 | #endif | ||
2053 | return MHD_NO; | ||
2054 | } | ||
2055 | for (i=0;i<num_events;i++) | ||
2056 | { | ||
2057 | if (NULL == events[i].data.ptr) | ||
2058 | continue; /* shutdown signal! */ | ||
2059 | if (daemon != events[i].data.ptr) | ||
2060 | { | ||
2061 | /* this is an event relating to a 'normal' connection, | ||
2062 | remember the event and if appropriate mark the | ||
2063 | connection as 'eready'. */ | ||
2064 | pos = events[i].data.ptr; | ||
2065 | if (0 != (events[i].events & EPOLLIN)) | ||
2066 | { | ||
2067 | pos->epoll_state |= MHD_EPOLL_STATE_READ_READY; | ||
2068 | if ( (MHD_EVENT_LOOP_INFO_READ == pos->event_loop_info) && | ||
2069 | (0 == (pos->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL) ) ) | ||
2070 | { | ||
2071 | EDLL_insert (daemon->eready_head, | ||
2072 | daemon->eready_tail, | ||
2073 | pos); | ||
2074 | pos->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL; | ||
2075 | } | ||
2076 | } | ||
2077 | if (0 != (events[i].events & EPOLLOUT)) | ||
2078 | { | ||
2079 | pos->epoll_state |= MHD_EPOLL_STATE_WRITE_READY; | ||
2080 | if ( (MHD_EVENT_LOOP_INFO_WRITE == pos->event_loop_info) && | ||
2081 | (0 == (pos->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL) ) ) | ||
2082 | { | ||
2083 | EDLL_insert (daemon->eready_head, | ||
2084 | daemon->eready_tail, | ||
2085 | pos); | ||
2086 | pos->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL; | ||
2087 | } | ||
2088 | } | ||
2089 | } | ||
2090 | else /* must be listen socket */ | ||
2091 | { | ||
2092 | /* run 'accept' until it fails or we are not allowed to take | ||
2093 | on more connections */ | ||
2094 | while ( (MHD_YES == MHD_accept_connection (daemon)) && | ||
2095 | (0 != daemon->max_connections) ) ; | ||
2096 | } | ||
2097 | } | ||
2098 | } | ||
2099 | |||
2100 | /* process events for connections */ | ||
2101 | while (NULL != (pos = daemon->eready_tail)) | ||
2102 | { | ||
2103 | EDLL_remove (daemon->eready_head, | ||
2104 | daemon->eready_tail, | ||
2105 | pos); | ||
2106 | pos->epoll_state -= MHD_EPOLL_STATE_IN_EREADY_EDLL; | ||
2107 | if (MHD_EVENT_LOOP_INFO_READ == pos->event_loop_info) | ||
2108 | pos->read_handler (pos); | ||
2109 | if (MHD_EVENT_LOOP_INFO_WRITE == pos->event_loop_info) | ||
2110 | pos->write_handler (pos); | ||
2111 | pos->idle_handler (pos); | ||
2112 | } | ||
2113 | /* Finally, handle timed-out connections; we need to do this here | ||
2114 | as the epoll mechanism won't call the 'idle_handler' on everything, | ||
2115 | as the other event loops do. As timeouts do not get an explicit | ||
2116 | event, we need to find those connections that might have timed out | ||
2117 | here. | ||
2118 | |||
2119 | Connections with custom timeouts must all be looked at, as we | ||
2120 | do not bother to sort that (presumably very short) list. */ | ||
2121 | next = daemon->manual_timeout_head; | ||
2122 | while (NULL != (pos = next)) | ||
2123 | { | ||
2124 | next = pos->nextX; | ||
2125 | pos->idle_handler (pos); | ||
2126 | } | ||
2127 | /* Connections with the default timeout are sorted by prepending | ||
2128 | them to the head of the list whenever we touch the connection; | ||
2129 | thus it sufficies to iterate from the tail until the first | ||
2130 | connection is NOT timed out */ | ||
2131 | next = daemon->normal_timeout_tail; | ||
2132 | while (NULL != (pos = next)) | ||
2133 | { | ||
2134 | next = pos->prevX; | ||
2135 | pos->idle_handler (pos); | ||
2136 | if (MHD_CONNECTION_CLOSED != pos->state) | ||
2137 | break; /* sorted by timeout, no need to visit the rest! */ | ||
2138 | } | ||
2139 | return MHD_YES; | ||
2140 | } | ||
2141 | #endif | ||
2142 | |||
2143 | |||
1684 | /** | 2144 | /** |
1685 | * Run webserver operations (without blocking unless | 2145 | * Run webserver operations (without blocking unless |
1686 | * in client callbacks). This method should be called | 2146 | * in client callbacks). This method should be called |
@@ -1702,10 +2162,14 @@ MHD_run (struct MHD_Daemon *daemon) | |||
1702 | (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) || | 2162 | (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) || |
1703 | (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY)) ) | 2163 | (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY)) ) |
1704 | return MHD_NO; | 2164 | return MHD_NO; |
1705 | if (0 == (daemon->options & MHD_USE_POLL)) | 2165 | if (0 != (daemon->options & MHD_USE_POLL)) |
1706 | MHD_select (daemon, MHD_NO); | ||
1707 | else | ||
1708 | MHD_poll (daemon, MHD_NO); | 2166 | MHD_poll (daemon, MHD_NO); |
2167 | #if EPOLL_SUPPORT | ||
2168 | else if (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) | ||
2169 | MHD_epoll (daemon, MHD_NO); | ||
2170 | #endif | ||
2171 | else | ||
2172 | MHD_select (daemon, MHD_NO); | ||
1709 | MHD_cleanup_connections (daemon); | 2173 | MHD_cleanup_connections (daemon); |
1710 | return MHD_YES; | 2174 | return MHD_YES; |
1711 | } | 2175 | } |
@@ -1725,10 +2189,14 @@ MHD_select_thread (void *cls) | |||
1725 | 2189 | ||
1726 | while (MHD_YES != daemon->shutdown) | 2190 | while (MHD_YES != daemon->shutdown) |
1727 | { | 2191 | { |
1728 | if (0 == (daemon->options & MHD_USE_POLL)) | 2192 | if (0 != (daemon->options & MHD_USE_POLL)) |
1729 | MHD_select (daemon, MHD_YES); | 2193 | MHD_poll (daemon, MHD_YES); |
2194 | #if EPOLL_SUPPORT | ||
2195 | else if (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) | ||
2196 | MHD_epoll (daemon, MHD_YES); | ||
2197 | #endif | ||
1730 | else | 2198 | else |
1731 | MHD_poll (daemon, MHD_YES); | 2199 | MHD_select (daemon, MHD_YES); |
1732 | MHD_cleanup_connections (daemon); | 2200 | MHD_cleanup_connections (daemon); |
1733 | } | 2201 | } |
1734 | return NULL; | 2202 | return NULL; |
@@ -1784,10 +2252,50 @@ MHD_quiesce_daemon (struct MHD_Daemon *daemon) | |||
1784 | int ret; | 2252 | int ret; |
1785 | 2253 | ||
1786 | ret = daemon->socket_fd; | 2254 | ret = daemon->socket_fd; |
2255 | if (-1 == ret) | ||
2256 | return -1; | ||
2257 | if ( (-1 == daemon->wpipe[1]) && | ||
2258 | (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY)) ) | ||
2259 | { | ||
2260 | #if HAVE_MESSAGES | ||
2261 | MHD_DLOG (daemon, | ||
2262 | "Using MHD_quiesce_daemon in this mode requires MHD_USE_PIPE_FOR_SHUTDOWN\n"); | ||
2263 | #endif | ||
2264 | return -1; | ||
2265 | } | ||
2266 | |||
1787 | if (NULL != daemon->worker_pool) | 2267 | if (NULL != daemon->worker_pool) |
1788 | for (i = 0; i < daemon->worker_pool_size; i++) | 2268 | for (i = 0; i < daemon->worker_pool_size; i++) |
1789 | daemon->worker_pool[i].socket_fd = -1; | 2269 | { |
2270 | daemon->worker_pool[i].socket_fd = -1; | ||
2271 | #if EPOLL_SUPPORT | ||
2272 | if ( (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) && | ||
2273 | (-1 != daemon->worker_pool[i].epoll_fd) && | ||
2274 | (MHD_YES == daemon->worker_pool[i].listen_socket_in_epoll) ) | ||
2275 | { | ||
2276 | if (0 != epoll_ctl (daemon->worker_pool[i].epoll_fd, | ||
2277 | EPOLL_CTL_DEL, | ||
2278 | ret, | ||
2279 | NULL)) | ||
2280 | MHD_PANIC ("Failed to remove listen FD from epoll set\n"); | ||
2281 | daemon->worker_pool[i].listen_socket_in_epoll = MHD_NO; | ||
2282 | } | ||
2283 | #endif | ||
2284 | } | ||
1790 | daemon->socket_fd = -1; | 2285 | daemon->socket_fd = -1; |
2286 | #if EPOLL_SUPPORT | ||
2287 | if ( (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) && | ||
2288 | (-1 != daemon->epoll_fd) && | ||
2289 | (MHD_YES == daemon->listen_socket_in_epoll) ) | ||
2290 | { | ||
2291 | if (0 != epoll_ctl (daemon->epoll_fd, | ||
2292 | EPOLL_CTL_DEL, | ||
2293 | ret, | ||
2294 | NULL)) | ||
2295 | MHD_PANIC ("Failed to remove listen FD from epoll set\n"); | ||
2296 | daemon->listen_socket_in_epoll = MHD_NO; | ||
2297 | } | ||
2298 | #endif | ||
1791 | return ret; | 2299 | return ret; |
1792 | } | 2300 | } |
1793 | 2301 | ||
@@ -2157,6 +2665,54 @@ create_socket (int domain, int type, int protocol) | |||
2157 | } | 2665 | } |
2158 | 2666 | ||
2159 | 2667 | ||
2668 | #if EPOLL_SUPPORT | ||
2669 | /** | ||
2670 | * Setup epoll FD for the daemon and initialize it to listen | ||
2671 | * on the listen FD. | ||
2672 | * | ||
2673 | * @param daemon daemon to initialize for epoll | ||
2674 | * @return MHD_YES on success, MHD_NO on failure | ||
2675 | */ | ||
2676 | static int | ||
2677 | setup_epoll_to_listen (struct MHD_Daemon *daemon) | ||
2678 | { | ||
2679 | struct epoll_event event; | ||
2680 | |||
2681 | daemon->epoll_fd = epoll_create1 (EPOLL_CLOEXEC); | ||
2682 | if (-1 == daemon->epoll_fd) | ||
2683 | { | ||
2684 | #if HAVE_MESSAGES | ||
2685 | if (0 != (daemon->options & MHD_USE_DEBUG)) | ||
2686 | MHD_DLOG (daemon, | ||
2687 | "Call to epoll_create1 failed: %s\n", | ||
2688 | STRERROR (errno)); | ||
2689 | #endif | ||
2690 | return MHD_NO; | ||
2691 | } | ||
2692 | if (-1 == daemon->socket_fd) | ||
2693 | return MHD_YES; /* non-listening daemon */ | ||
2694 | event.events = EPOLLIN; | ||
2695 | event.data.ptr = daemon; | ||
2696 | if (0 != epoll_ctl (daemon->epoll_fd, | ||
2697 | EPOLL_CTL_ADD, | ||
2698 | daemon->socket_fd, | ||
2699 | &event)) | ||
2700 | { | ||
2701 | #if HAVE_MESSAGES | ||
2702 | if (0 != (daemon->options & MHD_USE_DEBUG)) | ||
2703 | MHD_DLOG (daemon, | ||
2704 | "Call to epoll_ctl failed: %s\n", | ||
2705 | STRERROR (errno)); | ||
2706 | #endif | ||
2707 | return MHD_NO; | ||
2708 | } | ||
2709 | daemon->listen_socket_in_epoll = MHD_YES; | ||
2710 | return MHD_YES; | ||
2711 | } | ||
2712 | #endif | ||
2713 | |||
2714 | |||
2715 | |||
2160 | /** | 2716 | /** |
2161 | * Start a webserver on the given port. | 2717 | * Start a webserver on the given port. |
2162 | * | 2718 | * |
@@ -2209,6 +2765,9 @@ MHD_start_daemon_va (unsigned int flags, | |||
2209 | if (NULL == (daemon = malloc (sizeof (struct MHD_Daemon)))) | 2765 | if (NULL == (daemon = malloc (sizeof (struct MHD_Daemon)))) |
2210 | return NULL; | 2766 | return NULL; |
2211 | memset (daemon, 0, sizeof (struct MHD_Daemon)); | 2767 | memset (daemon, 0, sizeof (struct MHD_Daemon)); |
2768 | #if EPOLL_SUPPORT | ||
2769 | daemon->epoll_fd = -1; | ||
2770 | #endif | ||
2212 | /* try to open listen socket */ | 2771 | /* try to open listen socket */ |
2213 | #if HTTPS_SUPPORT | 2772 | #if HTTPS_SUPPORT |
2214 | if (0 != (flags & MHD_USE_SSL)) | 2773 | if (0 != (flags & MHD_USE_SSL)) |
@@ -2236,10 +2795,12 @@ MHD_start_daemon_va (unsigned int flags, | |||
2236 | daemon->custom_error_log_cls = stderr; | 2795 | daemon->custom_error_log_cls = stderr; |
2237 | #endif | 2796 | #endif |
2238 | #ifdef HAVE_LISTEN_SHUTDOWN | 2797 | #ifdef HAVE_LISTEN_SHUTDOWN |
2239 | use_pipe = (0 != (daemon->options & MHD_USE_NO_LISTEN_SOCKET)); | 2798 | use_pipe = (0 != (daemon->options & (MHD_USE_NO_LISTEN_SOCKET | MHD_USE_PIPE_FOR_SHUTDOWN))); |
2240 | #else | 2799 | #else |
2241 | use_pipe = 1; /* yes, must use pipe to signal shutdown */ | 2800 | use_pipe = 1; /* yes, must use pipe to signal shutdown */ |
2242 | #endif | 2801 | #endif |
2802 | if (0 == (flags & (MHD_USE_SELECT_INTERNALLY | MHD_USE_THREAD_PER_CONNECTION))) | ||
2803 | use_pipe = 0; /* useless if we are using 'external' select */ | ||
2243 | if ( (use_pipe) && | 2804 | if ( (use_pipe) && |
2244 | (0 != PIPE (daemon->wpipe)) ) | 2805 | (0 != PIPE (daemon->wpipe)) ) |
2245 | { | 2806 | { |
@@ -2259,8 +2820,10 @@ MHD_start_daemon_va (unsigned int flags, | |||
2259 | MHD_DLOG (daemon, | 2820 | MHD_DLOG (daemon, |
2260 | "file descriptor for control pipe exceeds maximum value\n"); | 2821 | "file descriptor for control pipe exceeds maximum value\n"); |
2261 | #endif | 2822 | #endif |
2262 | CLOSE (daemon->wpipe[0]); | 2823 | if (0 != CLOSE (daemon->wpipe[0])) |
2263 | CLOSE (daemon->wpipe[1]); | 2824 | MHD_PANIC ("close failed\n"); |
2825 | if (0 != CLOSE (daemon->wpipe[1])) | ||
2826 | MHD_PANIC ("close failed\n"); | ||
2264 | free (daemon); | 2827 | free (daemon); |
2265 | return NULL; | 2828 | return NULL; |
2266 | } | 2829 | } |
@@ -2291,7 +2854,7 @@ MHD_start_daemon_va (unsigned int flags, | |||
2291 | #ifdef DAUTH_SUPPORT | 2854 | #ifdef DAUTH_SUPPORT |
2292 | if (daemon->nonce_nc_size > 0) | 2855 | if (daemon->nonce_nc_size > 0) |
2293 | { | 2856 | { |
2294 | if ( ( (size_t) (daemon->nonce_nc_size * sizeof(struct MHD_NonceNc))) / | 2857 | if ( ( (size_t) (daemon->nonce_nc_size * sizeof (struct MHD_NonceNc))) / |
2295 | sizeof(struct MHD_NonceNc) != daemon->nonce_nc_size) | 2858 | sizeof(struct MHD_NonceNc) != daemon->nonce_nc_size) |
2296 | { | 2859 | { |
2297 | #if HAVE_MESSAGES | 2860 | #if HAVE_MESSAGES |
@@ -2305,7 +2868,7 @@ MHD_start_daemon_va (unsigned int flags, | |||
2305 | free (daemon); | 2868 | free (daemon); |
2306 | return NULL; | 2869 | return NULL; |
2307 | } | 2870 | } |
2308 | daemon->nnc = malloc (daemon->nonce_nc_size * sizeof(struct MHD_NonceNc)); | 2871 | daemon->nnc = malloc (daemon->nonce_nc_size * sizeof (struct MHD_NonceNc)); |
2309 | if (NULL == daemon->nnc) | 2872 | if (NULL == daemon->nnc) |
2310 | { | 2873 | { |
2311 | #if HAVE_MESSAGES | 2874 | #if HAVE_MESSAGES |
@@ -2359,6 +2922,32 @@ MHD_start_daemon_va (unsigned int flags, | |||
2359 | goto free_and_fail; | 2922 | goto free_and_fail; |
2360 | } | 2923 | } |
2361 | #endif | 2924 | #endif |
2925 | #if EPOLL_SUPPORT | ||
2926 | if ( (0 != (flags & MHD_USE_EPOLL_LINUX_ONLY)) && | ||
2927 | (0 == daemon->worker_pool_size) && | ||
2928 | (0 == (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) ) | ||
2929 | { | ||
2930 | if (0 != (flags & MHD_USE_THREAD_PER_CONNECTION)) | ||
2931 | { | ||
2932 | #if HAVE_MESSAGES | ||
2933 | MHD_DLOG (daemon, | ||
2934 | "Combining MHD_USE_THREAD_PER_CONNECTION and MHD_USE_EPOLL_LINUX_ONLY is not supported.\n"); | ||
2935 | #endif | ||
2936 | goto free_and_fail; | ||
2937 | } | ||
2938 | if (MHD_YES != setup_epoll_to_listen (daemon)) | ||
2939 | goto free_and_fail; | ||
2940 | } | ||
2941 | #else | ||
2942 | if (0 != (flags & MHD_USE_EPOLL_LINUX_ONLY)) | ||
2943 | { | ||
2944 | #if HAVE_MESSAGES | ||
2945 | MHD_DLOG (daemon, | ||
2946 | "epoll is not supported on this platform by this build.\n"); | ||
2947 | #endif | ||
2948 | goto free_and_fail; | ||
2949 | } | ||
2950 | #endif | ||
2362 | if ( (-1 == daemon->socket_fd) && | 2951 | if ( (-1 == daemon->socket_fd) && |
2363 | (0 == (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) ) | 2952 | (0 == (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) ) |
2364 | { | 2953 | { |
@@ -2377,10 +2966,11 @@ MHD_start_daemon_va (unsigned int flags, | |||
2377 | #endif | 2966 | #endif |
2378 | goto free_and_fail; | 2967 | goto free_and_fail; |
2379 | } | 2968 | } |
2380 | if ((SETSOCKOPT (socket_fd, | 2969 | if ( (0 > SETSOCKOPT (socket_fd, |
2381 | SOL_SOCKET, | 2970 | SOL_SOCKET, |
2382 | SO_REUSEADDR, | 2971 | SO_REUSEADDR, |
2383 | &on, sizeof (on)) < 0) && ((flags & MHD_USE_DEBUG) != 0)) | 2972 | &on, sizeof (on))) && |
2973 | (0 != (flags & MHD_USE_DEBUG)) ) | ||
2384 | { | 2974 | { |
2385 | #if HAVE_MESSAGES | 2975 | #if HAVE_MESSAGES |
2386 | MHD_DLOG (daemon, | 2976 | MHD_DLOG (daemon, |
@@ -2423,25 +3013,31 @@ MHD_start_daemon_va (unsigned int flags, | |||
2423 | } | 3013 | } |
2424 | daemon->socket_fd = socket_fd; | 3014 | daemon->socket_fd = socket_fd; |
2425 | 3015 | ||
2426 | if (0 != (flags & MHD_USE_IPv6)) | 3016 | if ( (0 != (flags & MHD_USE_IPv6)) && |
3017 | (0 == (flags & MHD_USE_DUAL_STACK)) ) | ||
2427 | { | 3018 | { |
2428 | #ifdef IPPROTO_IPV6 | 3019 | #ifdef IPPROTO_IPV6 |
2429 | #ifdef IPV6_V6ONLY | 3020 | #ifdef IPV6_V6ONLY |
2430 | /* Note: "IPV6_V6ONLY" is declared by Windows Vista ff., see "IPPROTO_IPV6 Socket Options" | 3021 | /* Note: "IPV6_V6ONLY" is declared by Windows Vista ff., see "IPPROTO_IPV6 Socket Options" |
2431 | (http://msdn.microsoft.com/en-us/library/ms738574%28v=VS.85%29.aspx); | 3022 | (http://msdn.microsoft.com/en-us/library/ms738574%28v=VS.85%29.aspx); |
2432 | and may also be missing on older POSIX systems; good luck if you have any of those, | 3023 | and may also be missing on older POSIX systems; good luck if you have any of those, |
2433 | your IPv6 socket may then also bind against IPv4... */ | 3024 | your IPv6 socket may then also bind against IPv4 anyway... */ |
2434 | #ifndef WINDOWS | 3025 | #ifndef WINDOWS |
2435 | const int on = 1; | 3026 | const int on = 1; |
2436 | setsockopt (socket_fd, | ||
2437 | IPPROTO_IPV6, IPV6_V6ONLY, | ||
2438 | &on, sizeof (on)); | ||
2439 | #else | 3027 | #else |
2440 | const char on = 1; | 3028 | const char on = 1; |
2441 | setsockopt (socket_fd, | ||
2442 | IPPROTO_IPV6, IPV6_V6ONLY, | ||
2443 | &on, sizeof (on)); | ||
2444 | #endif | 3029 | #endif |
3030 | if ( (0 > SETSOCKOPT (socket_fd, | ||
3031 | IPPROTO_IPV6, IPV6_V6ONLY, | ||
3032 | &on, sizeof (on))) && | ||
3033 | (0 != (flags & MHD_USE_DEBUG)) ) | ||
3034 | { | ||
3035 | #if HAVE_MESSAGES | ||
3036 | MHD_DLOG (daemon, | ||
3037 | "setsockopt failed: %s\n", | ||
3038 | STRERROR (errno)); | ||
3039 | #endif | ||
3040 | } | ||
2445 | #endif | 3041 | #endif |
2446 | #endif | 3042 | #endif |
2447 | } | 3043 | } |
@@ -2454,11 +3050,26 @@ MHD_start_daemon_va (unsigned int flags, | |||
2454 | (unsigned int) port, | 3050 | (unsigned int) port, |
2455 | STRERROR (errno)); | 3051 | STRERROR (errno)); |
2456 | #endif | 3052 | #endif |
2457 | CLOSE (socket_fd); | 3053 | if (0 != CLOSE (socket_fd)) |
3054 | MHD_PANIC ("close failed\n"); | ||
2458 | goto free_and_fail; | 3055 | goto free_and_fail; |
2459 | } | 3056 | } |
2460 | 3057 | #if EPOLL_SUPPORT | |
2461 | if (LISTEN (socket_fd, 20) < 0) | 3058 | if (0 != (flags & MHD_USE_EPOLL_LINUX_ONLY)) |
3059 | { | ||
3060 | int sk_flags = fcntl (socket_fd, F_GETFL); | ||
3061 | if (0 != fcntl (socket_fd, F_SETFL, sk_flags | O_NONBLOCK)) | ||
3062 | { | ||
3063 | MHD_DLOG (daemon, | ||
3064 | "Failed to make listen socket non-blocking: %s\n", | ||
3065 | STRERROR (errno)); | ||
3066 | if (0 != CLOSE (socket_fd)) | ||
3067 | MHD_PANIC ("close failed\n"); | ||
3068 | goto free_and_fail; | ||
3069 | } | ||
3070 | } | ||
3071 | #endif | ||
3072 | if (LISTEN (socket_fd, 32) < 0) | ||
2462 | { | 3073 | { |
2463 | #if HAVE_MESSAGES | 3074 | #if HAVE_MESSAGES |
2464 | if (0 != (flags & MHD_USE_DEBUG)) | 3075 | if (0 != (flags & MHD_USE_DEBUG)) |
@@ -2466,7 +3077,8 @@ MHD_start_daemon_va (unsigned int flags, | |||
2466 | "Failed to listen for connections: %s\n", | 3077 | "Failed to listen for connections: %s\n", |
2467 | STRERROR (errno)); | 3078 | STRERROR (errno)); |
2468 | #endif | 3079 | #endif |
2469 | CLOSE (socket_fd); | 3080 | if (0 != CLOSE (socket_fd)) |
3081 | MHD_PANIC ("close failed\n"); | ||
2470 | goto free_and_fail; | 3082 | goto free_and_fail; |
2471 | } | 3083 | } |
2472 | } | 3084 | } |
@@ -2476,7 +3088,7 @@ MHD_start_daemon_va (unsigned int flags, | |||
2476 | } | 3088 | } |
2477 | #ifndef WINDOWS | 3089 | #ifndef WINDOWS |
2478 | if ( (socket_fd >= FD_SETSIZE) && | 3090 | if ( (socket_fd >= FD_SETSIZE) && |
2479 | (0 == (flags & MHD_USE_POLL)) ) | 3091 | (0 == (flags & (MHD_USE_POLL | MHD_USE_EPOLL_LINUX_ONLY)) ) ) |
2480 | { | 3092 | { |
2481 | #if HAVE_MESSAGES | 3093 | #if HAVE_MESSAGES |
2482 | if ((flags & MHD_USE_DEBUG) != 0) | 3094 | if ((flags & MHD_USE_DEBUG) != 0) |
@@ -2485,7 +3097,8 @@ MHD_start_daemon_va (unsigned int flags, | |||
2485 | socket_fd, | 3097 | socket_fd, |
2486 | FD_SETSIZE); | 3098 | FD_SETSIZE); |
2487 | #endif | 3099 | #endif |
2488 | CLOSE (socket_fd); | 3100 | if (0 != CLOSE (socket_fd)) |
3101 | MHD_PANIC ("close failed\n"); | ||
2489 | goto free_and_fail; | 3102 | goto free_and_fail; |
2490 | } | 3103 | } |
2491 | #endif | 3104 | #endif |
@@ -2496,8 +3109,9 @@ MHD_start_daemon_va (unsigned int flags, | |||
2496 | MHD_DLOG (daemon, | 3109 | MHD_DLOG (daemon, |
2497 | "MHD failed to initialize IP connection limit mutex\n"); | 3110 | "MHD failed to initialize IP connection limit mutex\n"); |
2498 | #endif | 3111 | #endif |
2499 | if (-1 != socket_fd) | 3112 | if ( (-1 != socket_fd) && |
2500 | CLOSE (socket_fd); | 3113 | (0 != CLOSE (socket_fd)) ) |
3114 | MHD_PANIC ("close failed\n"); | ||
2501 | goto free_and_fail; | 3115 | goto free_and_fail; |
2502 | } | 3116 | } |
2503 | if (0 != pthread_mutex_init (&daemon->cleanup_connection_mutex, NULL)) | 3117 | if (0 != pthread_mutex_init (&daemon->cleanup_connection_mutex, NULL)) |
@@ -2507,8 +3121,9 @@ MHD_start_daemon_va (unsigned int flags, | |||
2507 | "MHD failed to initialize IP connection limit mutex\n"); | 3121 | "MHD failed to initialize IP connection limit mutex\n"); |
2508 | #endif | 3122 | #endif |
2509 | pthread_mutex_destroy (&daemon->cleanup_connection_mutex); | 3123 | pthread_mutex_destroy (&daemon->cleanup_connection_mutex); |
2510 | if (-1 != socket_fd) | 3124 | if ( (-1 != socket_fd) && |
2511 | CLOSE (socket_fd); | 3125 | (0 != CLOSE (socket_fd)) ) |
3126 | MHD_PANIC ("close failed\n"); | ||
2512 | goto free_and_fail; | 3127 | goto free_and_fail; |
2513 | } | 3128 | } |
2514 | 3129 | ||
@@ -2520,8 +3135,9 @@ MHD_start_daemon_va (unsigned int flags, | |||
2520 | MHD_DLOG (daemon, | 3135 | MHD_DLOG (daemon, |
2521 | "Failed to initialize TLS support\n"); | 3136 | "Failed to initialize TLS support\n"); |
2522 | #endif | 3137 | #endif |
2523 | if (-1 != socket_fd) | 3138 | if ( (-1 != socket_fd) && |
2524 | CLOSE (socket_fd); | 3139 | (0 != CLOSE (socket_fd)) ) |
3140 | MHD_PANIC ("close failed\n"); | ||
2525 | pthread_mutex_destroy (&daemon->cleanup_connection_mutex); | 3141 | pthread_mutex_destroy (&daemon->cleanup_connection_mutex); |
2526 | pthread_mutex_destroy (&daemon->per_ip_connection_mutex); | 3142 | pthread_mutex_destroy (&daemon->per_ip_connection_mutex); |
2527 | goto free_and_fail; | 3143 | goto free_and_fail; |
@@ -2541,8 +3157,9 @@ MHD_start_daemon_va (unsigned int flags, | |||
2541 | #endif | 3157 | #endif |
2542 | pthread_mutex_destroy (&daemon->cleanup_connection_mutex); | 3158 | pthread_mutex_destroy (&daemon->cleanup_connection_mutex); |
2543 | pthread_mutex_destroy (&daemon->per_ip_connection_mutex); | 3159 | pthread_mutex_destroy (&daemon->per_ip_connection_mutex); |
2544 | if (-1 != socket_fd) | 3160 | if ( (-1 != socket_fd) && |
2545 | CLOSE (socket_fd); | 3161 | (0 != CLOSE (socket_fd)) ) |
3162 | MHD_PANIC ("close failed\n"); | ||
2546 | goto free_and_fail; | 3163 | goto free_and_fail; |
2547 | } | 3164 | } |
2548 | if ( (daemon->worker_pool_size > 0) && | 3165 | if ( (daemon->worker_pool_size > 0) && |
@@ -2596,8 +3213,8 @@ MHD_start_daemon_va (unsigned int flags, | |||
2596 | { | 3213 | { |
2597 | /* Create copy of the Daemon object for each worker */ | 3214 | /* Create copy of the Daemon object for each worker */ |
2598 | struct MHD_Daemon *d = &daemon->worker_pool[i]; | 3215 | struct MHD_Daemon *d = &daemon->worker_pool[i]; |
2599 | memcpy (d, daemon, sizeof (struct MHD_Daemon)); | ||
2600 | 3216 | ||
3217 | memcpy (d, daemon, sizeof (struct MHD_Daemon)); | ||
2601 | /* Adjust pooling params for worker daemons; note that memcpy() | 3218 | /* Adjust pooling params for worker daemons; note that memcpy() |
2602 | has already copied MHD_USE_SELECT_INTERNALLY thread model into | 3219 | has already copied MHD_USE_SELECT_INTERNALLY thread model into |
2603 | the worker threads. */ | 3220 | the worker threads. */ |
@@ -2611,7 +3228,11 @@ MHD_start_daemon_va (unsigned int flags, | |||
2611 | d->max_connections = conns_per_thread; | 3228 | d->max_connections = conns_per_thread; |
2612 | if (i < leftover_conns) | 3229 | if (i < leftover_conns) |
2613 | ++d->max_connections; | 3230 | ++d->max_connections; |
2614 | 3231 | #if EPOLL_SUPPORT | |
3232 | if ( (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) && | ||
3233 | (MHD_YES != setup_epoll_to_listen (d)) ) | ||
3234 | goto thread_failed; | ||
3235 | #endif | ||
2615 | /* Must init cleanup connection mutex for each worker */ | 3236 | /* Must init cleanup connection mutex for each worker */ |
2616 | if (0 != pthread_mutex_init (&d->cleanup_connection_mutex, NULL)) | 3237 | if (0 != pthread_mutex_init (&d->cleanup_connection_mutex, NULL)) |
2617 | { | 3238 | { |
@@ -2623,7 +3244,8 @@ MHD_start_daemon_va (unsigned int flags, | |||
2623 | } | 3244 | } |
2624 | 3245 | ||
2625 | /* Spawn the worker thread */ | 3246 | /* Spawn the worker thread */ |
2626 | if (0 != (res_thread_create = create_thread (&d->pid, daemon, &MHD_select_thread, d))) | 3247 | if (0 != (res_thread_create = |
3248 | create_thread (&d->pid, daemon, &MHD_select_thread, d))) | ||
2627 | { | 3249 | { |
2628 | #if HAVE_MESSAGES | 3250 | #if HAVE_MESSAGES |
2629 | MHD_DLOG (daemon, | 3251 | MHD_DLOG (daemon, |
@@ -2646,8 +3268,9 @@ thread_failed: | |||
2646 | MHD_USE_SELECT_INTERNALLY mode. */ | 3268 | MHD_USE_SELECT_INTERNALLY mode. */ |
2647 | if (0 == i) | 3269 | if (0 == i) |
2648 | { | 3270 | { |
2649 | if (-1 != socket_fd) | 3271 | if ( (-1 != socket_fd) && |
2650 | CLOSE (socket_fd); | 3272 | (0 != CLOSE (socket_fd)) ) |
3273 | MHD_PANIC ("close failed\n"); | ||
2651 | pthread_mutex_destroy (&daemon->cleanup_connection_mutex); | 3274 | pthread_mutex_destroy (&daemon->cleanup_connection_mutex); |
2652 | pthread_mutex_destroy (&daemon->per_ip_connection_mutex); | 3275 | pthread_mutex_destroy (&daemon->per_ip_connection_mutex); |
2653 | if (NULL != daemon->worker_pool) | 3276 | if (NULL != daemon->worker_pool) |
@@ -2666,6 +3289,8 @@ thread_failed: | |||
2666 | free_and_fail: | 3289 | free_and_fail: |
2667 | /* clean up basic memory state in 'daemon' and return NULL to | 3290 | /* clean up basic memory state in 'daemon' and return NULL to |
2668 | indicate failure */ | 3291 | indicate failure */ |
3292 | if (-1 != daemon->epoll_fd) | ||
3293 | close (daemon->epoll_fd); | ||
2669 | #ifdef DAUTH_SUPPORT | 3294 | #ifdef DAUTH_SUPPORT |
2670 | free (daemon->nnc); | 3295 | free (daemon->nnc); |
2671 | pthread_mutex_destroy (&daemon->nnc_lock); | 3296 | pthread_mutex_destroy (&daemon->nnc_lock); |
@@ -2680,6 +3305,37 @@ thread_failed: | |||
2680 | 3305 | ||
2681 | 3306 | ||
2682 | /** | 3307 | /** |
3308 | * Close the given connection, remove it from all of its | ||
3309 | * DLLs and move it into the cleanup queue. | ||
3310 | * | ||
3311 | * @param pos connection to move to cleanup | ||
3312 | */ | ||
3313 | static void | ||
3314 | close_connection (struct MHD_Connection *pos) | ||
3315 | { | ||
3316 | struct MHD_Daemon *daemon = pos->daemon; | ||
3317 | |||
3318 | MHD_connection_close (pos, | ||
3319 | MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN); | ||
3320 | if (pos->connection_timeout == pos->daemon->connection_timeout) | ||
3321 | XDLL_remove (daemon->normal_timeout_head, | ||
3322 | daemon->normal_timeout_tail, | ||
3323 | pos); | ||
3324 | else | ||
3325 | XDLL_remove (daemon->manual_timeout_head, | ||
3326 | daemon->manual_timeout_tail, | ||
3327 | pos); | ||
3328 | DLL_remove (daemon->connections_head, | ||
3329 | daemon->connections_tail, | ||
3330 | pos); | ||
3331 | pos->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; | ||
3332 | DLL_insert (daemon->cleanup_head, | ||
3333 | daemon->cleanup_tail, | ||
3334 | pos); | ||
3335 | } | ||
3336 | |||
3337 | |||
3338 | /** | ||
2683 | * Close all connections for the daemon; must only be called after | 3339 | * Close all connections for the daemon; must only be called after |
2684 | * all of the threads have been joined and there is no more concurrent | 3340 | * all of the threads have been joined and there is no more concurrent |
2685 | * activity on the connection lists. | 3341 | * activity on the connection lists. |
@@ -2695,47 +3351,61 @@ close_all_connections (struct MHD_Daemon *daemon) | |||
2695 | 3351 | ||
2696 | /* first, make sure all threads are aware of shutdown; need to | 3352 | /* first, make sure all threads are aware of shutdown; need to |
2697 | traverse DLLs in peace... */ | 3353 | traverse DLLs in peace... */ |
2698 | if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex)) | 3354 | if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && |
2699 | { | 3355 | (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) ) |
2700 | MHD_PANIC ("Failed to acquire cleanup mutex\n"); | 3356 | MHD_PANIC ("Failed to acquire cleanup mutex\n"); |
2701 | } | 3357 | for (pos = daemon->connections_head; NULL != pos; pos = pos->nextX) |
2702 | for (pos = daemon->connections_head; NULL != pos; pos = pos->next) | ||
2703 | SHUTDOWN (pos->socket_fd, | 3358 | SHUTDOWN (pos->socket_fd, |
2704 | (pos->read_closed == MHD_YES) ? SHUT_WR : SHUT_RDWR); | 3359 | (pos->read_closed == MHD_YES) ? SHUT_WR : SHUT_RDWR); |
2705 | if (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex)) | 3360 | if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && |
2706 | { | 3361 | (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex)) ) |
2707 | MHD_PANIC ("Failed to release cleanup mutex\n"); | 3362 | MHD_PANIC ("Failed to release cleanup mutex\n"); |
2708 | } | ||
2709 | 3363 | ||
2710 | /* now, collect threads */ | 3364 | /* now, collect threads from thread pool */ |
2711 | if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) | 3365 | if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) |
2712 | { | 3366 | { |
2713 | while (NULL != (pos = daemon->connections_head)) | 3367 | while (NULL != (pos = daemon->connections_head)) |
2714 | { | 3368 | { |
2715 | if (0 != (rc = pthread_join (pos->pid, &unused))) | 3369 | if (0 != (rc = pthread_join (pos->pid, &unused))) |
2716 | { | 3370 | MHD_PANIC ("Failed to join a thread\n"); |
2717 | MHD_PANIC ("Failed to join a thread\n"); | ||
2718 | } | ||
2719 | pos->thread_joined = MHD_YES; | 3371 | pos->thread_joined = MHD_YES; |
2720 | } | 3372 | } |
2721 | } | 3373 | } |
2722 | 3374 | ||
2723 | /* now that we're alone, move everyone to cleanup */ | 3375 | /* now that we're alone, move everyone to cleanup */ |
2724 | while (NULL != (pos = daemon->connections_head)) | 3376 | while (NULL != (pos = daemon->connections_head)) |
2725 | { | 3377 | close_connection (pos); |
2726 | MHD_connection_close (pos, | ||
2727 | MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN); | ||
2728 | DLL_remove (daemon->connections_head, | ||
2729 | daemon->connections_tail, | ||
2730 | pos); | ||
2731 | DLL_insert (daemon->cleanup_head, | ||
2732 | daemon->cleanup_tail, | ||
2733 | pos); | ||
2734 | } | ||
2735 | MHD_cleanup_connections (daemon); | 3378 | MHD_cleanup_connections (daemon); |
2736 | } | 3379 | } |
2737 | 3380 | ||
2738 | 3381 | ||
3382 | #if EPOLL_SUPPORT | ||
3383 | /** | ||
3384 | * Shutdown 'epoll' event loop by adding 'wpipe' to its event set. | ||
3385 | * | ||
3386 | * @param daemon daemon of which the epoll instance must be signalled | ||
3387 | */ | ||
3388 | static void | ||
3389 | epoll_shutdown (struct MHD_Daemon *daemon) | ||
3390 | { | ||
3391 | struct epoll_event event; | ||
3392 | |||
3393 | if (-1 == daemon->wpipe[1]) | ||
3394 | { | ||
3395 | /* wpipe was required in this mode, how could this happen? */ | ||
3396 | MHD_PANIC ("Internal error\n"); | ||
3397 | } | ||
3398 | event.events = EPOLLOUT; | ||
3399 | event.data.ptr = NULL; | ||
3400 | if (0 != epoll_ctl (daemon->epoll_fd, | ||
3401 | EPOLL_CTL_ADD, | ||
3402 | daemon->wpipe[1], | ||
3403 | &event)) | ||
3404 | MHD_PANIC ("Failed to add wpipe to epoll set to signal termination\n"); | ||
3405 | } | ||
3406 | #endif | ||
3407 | |||
3408 | |||
2739 | /** | 3409 | /** |
2740 | * Shutdown an http daemon | 3410 | * Shutdown an http daemon |
2741 | * | 3411 | * |
@@ -2762,6 +3432,12 @@ MHD_stop_daemon (struct MHD_Daemon *daemon) | |||
2762 | { | 3432 | { |
2763 | daemon->worker_pool[i].shutdown = MHD_YES; | 3433 | daemon->worker_pool[i].shutdown = MHD_YES; |
2764 | daemon->worker_pool[i].socket_fd = -1; | 3434 | daemon->worker_pool[i].socket_fd = -1; |
3435 | #if EPOLL_SUPPORT | ||
3436 | if ( (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) && | ||
3437 | (-1 != daemon->worker_pool[i].epoll_fd) && | ||
3438 | (-1 == fd) ) | ||
3439 | epoll_shutdown (&daemon->worker_pool[i]); | ||
3440 | #endif | ||
2765 | } | 3441 | } |
2766 | } | 3442 | } |
2767 | if (-1 != daemon->wpipe[1]) | 3443 | if (-1 != daemon->wpipe[1]) |
@@ -2777,6 +3453,13 @@ MHD_stop_daemon (struct MHD_Daemon *daemon) | |||
2777 | (void) SHUTDOWN (fd, SHUT_RDWR); | 3453 | (void) SHUTDOWN (fd, SHUT_RDWR); |
2778 | } | 3454 | } |
2779 | #endif | 3455 | #endif |
3456 | #if EPOLL_SUPPORT | ||
3457 | if ( (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) && | ||
3458 | (-1 != daemon->epoll_fd) && | ||
3459 | (-1 == fd) ) | ||
3460 | epoll_shutdown (daemon); | ||
3461 | #endif | ||
3462 | |||
2780 | #if DEBUG_CLOSE | 3463 | #if DEBUG_CLOSE |
2781 | #if HAVE_MESSAGES | 3464 | #if HAVE_MESSAGES |
2782 | MHD_DLOG (daemon, "MHD listen socket shutdown\n"); | 3465 | MHD_DLOG (daemon, "MHD listen socket shutdown\n"); |
@@ -2790,12 +3473,13 @@ MHD_stop_daemon (struct MHD_Daemon *daemon) | |||
2790 | /* MHD_USE_NO_LISTEN_SOCKET disables thread pools, hence we need to check */ | 3473 | /* MHD_USE_NO_LISTEN_SOCKET disables thread pools, hence we need to check */ |
2791 | for (i = 0; i < daemon->worker_pool_size; ++i) | 3474 | for (i = 0; i < daemon->worker_pool_size; ++i) |
2792 | { | 3475 | { |
2793 | if (0 != (rc = pthread_join (daemon->worker_pool[i].pid, &unused))) | 3476 | if (0 != (rc = pthread_join (daemon->worker_pool[i].pid, &unused))) |
2794 | { | 3477 | MHD_PANIC ("Failed to join a thread\n"); |
2795 | MHD_PANIC ("Failed to join a thread\n"); | 3478 | close_all_connections (&daemon->worker_pool[i]); |
2796 | } | ||
2797 | close_all_connections (&daemon->worker_pool[i]); | ||
2798 | pthread_mutex_destroy (&daemon->worker_pool[i].cleanup_connection_mutex); | 3479 | pthread_mutex_destroy (&daemon->worker_pool[i].cleanup_connection_mutex); |
3480 | if ( (-1 != daemon->worker_pool[i].epoll_fd) && | ||
3481 | (0 != CLOSE (daemon->worker_pool[i].epoll_fd)) ) | ||
3482 | MHD_PANIC ("close failed\n"); | ||
2799 | } | 3483 | } |
2800 | free (daemon->worker_pool); | 3484 | free (daemon->worker_pool); |
2801 | } | 3485 | } |
@@ -2813,8 +3497,9 @@ MHD_stop_daemon (struct MHD_Daemon *daemon) | |||
2813 | } | 3497 | } |
2814 | } | 3498 | } |
2815 | close_all_connections (daemon); | 3499 | close_all_connections (daemon); |
2816 | if (-1 != fd) | 3500 | if ( (-1 != fd) && |
2817 | (void) CLOSE (fd); | 3501 | (0 != CLOSE (fd)) ) |
3502 | MHD_PANIC ("close failed\n"); | ||
2818 | 3503 | ||
2819 | /* TLS clean up */ | 3504 | /* TLS clean up */ |
2820 | #if HTTPS_SUPPORT | 3505 | #if HTTPS_SUPPORT |
@@ -2825,6 +3510,12 @@ MHD_stop_daemon (struct MHD_Daemon *daemon) | |||
2825 | gnutls_certificate_free_credentials (daemon->x509_cred); | 3510 | gnutls_certificate_free_credentials (daemon->x509_cred); |
2826 | } | 3511 | } |
2827 | #endif | 3512 | #endif |
3513 | #if EPOLL_SUPPORT | ||
3514 | if ( (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) && | ||
3515 | (-1 != daemon->epoll_fd) && | ||
3516 | (0 != CLOSE (daemon->epoll_fd)) ) | ||
3517 | MHD_PANIC ("close failed\n"); | ||
3518 | #endif | ||
2828 | 3519 | ||
2829 | #ifdef DAUTH_SUPPORT | 3520 | #ifdef DAUTH_SUPPORT |
2830 | free (daemon->nnc); | 3521 | free (daemon->nnc); |
@@ -2835,8 +3526,10 @@ MHD_stop_daemon (struct MHD_Daemon *daemon) | |||
2835 | 3526 | ||
2836 | if (-1 != daemon->wpipe[1]) | 3527 | if (-1 != daemon->wpipe[1]) |
2837 | { | 3528 | { |
2838 | (void) CLOSE (daemon->wpipe[0]); | 3529 | if (0 != CLOSE (daemon->wpipe[0])) |
2839 | (void) CLOSE (daemon->wpipe[1]); | 3530 | MHD_PANIC ("close failed\n"); |
3531 | if (0 != CLOSE (daemon->wpipe[1])) | ||
3532 | MHD_PANIC ("close failed\n"); | ||
2840 | } | 3533 | } |
2841 | free (daemon); | 3534 | free (daemon); |
2842 | } | 3535 | } |
@@ -2858,8 +3551,16 @@ MHD_get_daemon_info (struct MHD_Daemon *daemon, | |||
2858 | { | 3551 | { |
2859 | switch (infoType) | 3552 | switch (infoType) |
2860 | { | 3553 | { |
3554 | case MHD_DAEMON_INFO_KEY_SIZE: | ||
3555 | return NULL; /* no longer supported */ | ||
3556 | case MHD_DAEMON_INFO_MAC_KEY_SIZE: | ||
3557 | return NULL; /* no longer supported */ | ||
2861 | case MHD_DAEMON_INFO_LISTEN_FD: | 3558 | case MHD_DAEMON_INFO_LISTEN_FD: |
2862 | return (const union MHD_DaemonInfo *) &daemon->socket_fd; | 3559 | return (const union MHD_DaemonInfo *) &daemon->socket_fd; |
3560 | #if EPOLL_SUPPORT | ||
3561 | case MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY: | ||
3562 | return (const union MHD_DaemonInfo *) &daemon->epoll_fd; | ||
3563 | #endif | ||
2863 | default: | 3564 | default: |
2864 | return NULL; | 3565 | return NULL; |
2865 | }; | 3566 | }; |
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h index 88f7c5d3..4603050a 100644 --- a/src/microhttpd/internal.h +++ b/src/microhttpd/internal.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of libmicrohttpd | 2 | This file is part of libmicrohttpd |
3 | (C) 2007, 2008, 2009, 2010, 2011, 2012 Daniel Pittman and Christian Grothoff | 3 | (C) 2007-2013 Daniel Pittman and Christian Grothoff |
4 | 4 | ||
5 | This library is free software; you can redistribute it and/or | 5 | This library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public | 6 | modify it under the terms of the GNU Lesser General Public |
@@ -32,6 +32,10 @@ | |||
32 | #if HTTPS_SUPPORT | 32 | #if HTTPS_SUPPORT |
33 | #include <gnutls/gnutls.h> | 33 | #include <gnutls/gnutls.h> |
34 | #endif | 34 | #endif |
35 | #if EPOLL_SUPPORT | ||
36 | #include <sys/epoll.h> | ||
37 | #endif | ||
38 | |||
35 | 39 | ||
36 | /** | 40 | /** |
37 | * Should we perform additional sanity checks at runtime (on our internal | 41 | * Should we perform additional sanity checks at runtime (on our internal |
@@ -69,63 +73,67 @@ extern void *mhd_panic_cls; | |||
69 | #define MHD_PANIC(msg) mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL) | 73 | #define MHD_PANIC(msg) mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL) |
70 | #endif | 74 | #endif |
71 | 75 | ||
76 | |||
72 | /** | 77 | /** |
73 | * Events we care about with respect to poll/select | 78 | * State of the socket with respect to epoll (bitmask). |
74 | * for file descriptors. | ||
75 | */ | 79 | */ |
76 | enum MHD_PollActions | 80 | enum MHD_EpollState |
77 | { | 81 | { |
82 | |||
78 | /** | 83 | /** |
79 | * No event interests us. | 84 | * The socket is not involved with a defined state in epoll right |
85 | * now. | ||
80 | */ | 86 | */ |
81 | MHD_POLL_ACTION_NOTHING = 0, | 87 | MHD_EPOLL_STATE_UNREADY = 0, |
82 | 88 | ||
83 | /** | 89 | /** |
84 | * We would like to read. | 90 | * epoll told us that data was ready for reading, and we did |
91 | * not consume all of it yet. | ||
85 | */ | 92 | */ |
86 | MHD_POLL_ACTION_IN = 1, | 93 | MHD_EPOLL_STATE_READ_READY = 1, |
87 | 94 | ||
88 | /** | 95 | /** |
89 | * We would like to write. | 96 | * epoll told us that space was available for writing, and we did |
90 | */ | 97 | * not consume all of it yet. |
91 | MHD_POLL_ACTION_OUT = 2 | 98 | */ |
99 | MHD_EPOLL_STATE_WRITE_READY = 2, | ||
100 | |||
101 | /** | ||
102 | * Is this connection currently in the 'eready' EDLL? | ||
103 | */ | ||
104 | MHD_EPOLL_STATE_IN_EREADY_EDLL = 4 | ||
105 | |||
92 | }; | 106 | }; |
93 | 107 | ||
94 | 108 | ||
95 | /** | 109 | /** |
96 | * State of the socket with respect to epoll. | 110 | * What is this connection waiting for? |
97 | */ | 111 | */ |
98 | enum MHD_EpollState | 112 | enum MHD_ConnectionEventLoopInfo |
99 | { | 113 | { |
100 | |||
101 | /** | 114 | /** |
102 | * | 115 | * We are waiting to be able to read. |
103 | */ | 116 | */ |
104 | MHD_EPOLL_STATE_NOTHING = 0 | 117 | MHD_EVENT_LOOP_INFO_READ = 0, |
105 | 118 | ||
119 | /** | ||
120 | * We are waiting to be able to write. | ||
121 | */ | ||
122 | MHD_EVENT_LOOP_INFO_WRITE = 1, | ||
106 | 123 | ||
124 | /** | ||
125 | * We are waiting for the application to provide data. | ||
126 | */ | ||
127 | MHD_EVENT_LOOP_INFO_BLOCK = 2, | ||
107 | 128 | ||
129 | /** | ||
130 | * We are finished and are awaiting cleanup. | ||
131 | */ | ||
132 | MHD_EVENT_LOOP_INFO_CLEANUP = 3 | ||
108 | }; | 133 | }; |
109 | 134 | ||
110 | 135 | ||
111 | /** | 136 | /** |
112 | * Socket descriptor and events we care about. | ||
113 | */ | ||
114 | struct MHD_Pollfd | ||
115 | { | ||
116 | /** | ||
117 | * Socket descriptor. | ||
118 | */ | ||
119 | int fd; | ||
120 | |||
121 | /** | ||
122 | * Which events do we care about for this socket? | ||
123 | */ | ||
124 | enum MHD_PollActions events; | ||
125 | }; | ||
126 | |||
127 | |||
128 | /** | ||
129 | * Maximum length of a nonce in digest authentication. 32(MD5 Hex) + | 137 | * Maximum length of a nonce in digest authentication. 32(MD5 Hex) + |
130 | * 8(Timestamp Hex) + 1(NULL); hence 41 should suffice, but Opera | 138 | * 8(Timestamp Hex) + 1(NULL); hence 41 should suffice, but Opera |
131 | * (already) takes more (see Mantis #1633), so we've increased the | 139 | * (already) takes more (see Mantis #1633), so we've increased the |
@@ -477,17 +485,39 @@ typedef ssize_t (*TransmitCallback) (struct MHD_Connection * conn, | |||
477 | struct MHD_Connection | 485 | struct MHD_Connection |
478 | { | 486 | { |
479 | 487 | ||
488 | #if EPOLL_SUPPORT | ||
480 | /** | 489 | /** |
481 | * This is a doubly-linked list. | 490 | * Next pointer for the EDLL listing connections that are epoll-ready. |
491 | */ | ||
492 | struct MHD_Connection *nextE; | ||
493 | |||
494 | /** | ||
495 | * Previous pointer for the EDLL listing connections that are epoll-ready. | ||
496 | */ | ||
497 | struct MHD_Connection *prevE; | ||
498 | #endif | ||
499 | |||
500 | /** | ||
501 | * Next pointer for the DLL describing our IO state. | ||
482 | */ | 502 | */ |
483 | struct MHD_Connection *next; | 503 | struct MHD_Connection *next; |
484 | 504 | ||
485 | /** | 505 | /** |
486 | * This is a doubly-linked list. | 506 | * Previous pointer for the DLL describing our IO state. |
487 | */ | 507 | */ |
488 | struct MHD_Connection *prev; | 508 | struct MHD_Connection *prev; |
489 | 509 | ||
490 | /** | 510 | /** |
511 | * Next pointer for the XDLL organizing connections by timeout. | ||
512 | */ | ||
513 | struct MHD_Connection *nextX; | ||
514 | |||
515 | /** | ||
516 | * Previous pointer for the XDLL organizing connections by timeout. | ||
517 | */ | ||
518 | struct MHD_Connection *prevX; | ||
519 | |||
520 | /** | ||
491 | * Reference to the MHD_Daemon struct. | 521 | * Reference to the MHD_Daemon struct. |
492 | */ | 522 | */ |
493 | struct MHD_Daemon *daemon; | 523 | struct MHD_Daemon *daemon; |
@@ -667,11 +697,10 @@ struct MHD_Connection | |||
667 | int socket_fd; | 697 | int socket_fd; |
668 | 698 | ||
669 | /** | 699 | /** |
670 | * Has this socket been closed for reading (i.e. | 700 | * Has this socket been closed for reading (i.e. other side closed |
671 | * other side closed the connection)? If so, | 701 | * the connection)? If so, we must completely close the connection |
672 | * we must completely close the connection once | 702 | * once we are done sending our response (and stop trying to read |
673 | * we are done sending our response (and stop | 703 | * from this socket). |
674 | * trying to read from this socket). | ||
675 | */ | 704 | */ |
676 | int read_closed; | 705 | int read_closed; |
677 | 706 | ||
@@ -680,12 +709,24 @@ struct MHD_Connection | |||
680 | */ | 709 | */ |
681 | int thread_joined; | 710 | int thread_joined; |
682 | 711 | ||
712 | #if EPOLL_SUPPORT | ||
713 | /** | ||
714 | * What is the state of this socket in relation to epoll? | ||
715 | */ | ||
716 | enum MHD_EpollState epoll_state; | ||
717 | #endif | ||
718 | |||
683 | /** | 719 | /** |
684 | * State in the FSM for this connection. | 720 | * State in the FSM for this connection. |
685 | */ | 721 | */ |
686 | enum MHD_CONNECTION_STATE state; | 722 | enum MHD_CONNECTION_STATE state; |
687 | 723 | ||
688 | /** | 724 | /** |
725 | * What is this connection waiting for? | ||
726 | */ | ||
727 | enum MHD_ConnectionEventLoopInfo event_loop_info; | ||
728 | |||
729 | /** | ||
689 | * HTTP response code. Only valid if response object | 730 | * HTTP response code. Only valid if response object |
690 | * is already set. | 731 | * is already set. |
691 | */ | 732 | */ |
@@ -797,7 +838,11 @@ typedef size_t (*UnescapeCallback)(void *cls, | |||
797 | 838 | ||
798 | 839 | ||
799 | /** | 840 | /** |
800 | * State kept for each MHD daemon. | 841 | * State kept for each MHD daemon. All connections are kept in two |
842 | * doubly-linked lists. The first one reflects the state of the | ||
843 | * connection in terms of what operations we are waiting for (read, | ||
844 | * write, locally blocked, cleanup) whereas the second is about its | ||
845 | * timeout state (default or custom). | ||
801 | */ | 846 | */ |
802 | struct MHD_Daemon | 847 | struct MHD_Daemon |
803 | { | 848 | { |
@@ -813,7 +858,7 @@ struct MHD_Daemon | |||
813 | void *default_handler_cls; | 858 | void *default_handler_cls; |
814 | 859 | ||
815 | /** | 860 | /** |
816 | * Tail of doubly-linked list of our current, active connections. | 861 | * Head of doubly-linked list of our current, active connections. |
817 | */ | 862 | */ |
818 | struct MHD_Connection *connections_head; | 863 | struct MHD_Connection *connections_head; |
819 | 864 | ||
@@ -823,7 +868,7 @@ struct MHD_Daemon | |||
823 | struct MHD_Connection *connections_tail; | 868 | struct MHD_Connection *connections_tail; |
824 | 869 | ||
825 | /** | 870 | /** |
826 | * Tail of doubly-linked list of connections to clean up. | 871 | * Head of doubly-linked list of connections to clean up. |
827 | */ | 872 | */ |
828 | struct MHD_Connection *cleanup_head; | 873 | struct MHD_Connection *cleanup_head; |
829 | 874 | ||
@@ -832,10 +877,54 @@ struct MHD_Daemon | |||
832 | */ | 877 | */ |
833 | struct MHD_Connection *cleanup_tail; | 878 | struct MHD_Connection *cleanup_tail; |
834 | 879 | ||
880 | #if EPOLL_SUPPORT | ||
881 | /** | ||
882 | * Head of EDLL of connections ready for processing (in epoll mode). | ||
883 | */ | ||
884 | struct MHD_Connection *eready_head; | ||
885 | |||
886 | /** | ||
887 | * Tail of EDLL of connections ready for processing (in epoll mode) | ||
888 | */ | ||
889 | struct MHD_Connection *eready_tail; | ||
890 | #endif | ||
891 | |||
892 | /** | ||
893 | * Head of the XDLL of ALL connections with a default ('normal') | ||
894 | * timeout, sorted by timeout (earliest at the tail, most recently | ||
895 | * used connection at the head). MHD can just look at the tail of | ||
896 | * this list to determine the timeout for all of its elements; | ||
897 | * whenever there is an event of a connection, the connection is | ||
898 | * moved back to the tail of the list. | ||
899 | * | ||
900 | * All connections by default start in this list; if a custom | ||
901 | * timeout that does not match 'connection_timeout' is set, they | ||
902 | * are moved to the 'manual_timeout_head'-XDLL. | ||
903 | */ | ||
904 | struct MHD_Connection *normal_timeout_head; | ||
905 | |||
906 | /** | ||
907 | * Tail of the XDLL of ALL connections with a default timeout, | ||
908 | * sorted by timeout (earliest timeout at the tail). | ||
909 | */ | ||
910 | struct MHD_Connection *normal_timeout_tail; | ||
911 | |||
912 | /** | ||
913 | * Head of the XDLL of ALL connections with a non-default/custom | ||
914 | * timeout, unsorted. MHD will do a O(n) scan over this list to | ||
915 | * determine the current timeout. | ||
916 | */ | ||
917 | struct MHD_Connection *manual_timeout_head; | ||
918 | |||
835 | /** | 919 | /** |
836 | * Function to call to check if we should | 920 | * Tail of the XDLL of ALL connections with a non-default/custom |
837 | * accept or reject an incoming request. | 921 | * timeout, unsorted. |
838 | * May be NULL. | 922 | */ |
923 | struct MHD_Connection *manual_timeout_tail; | ||
924 | |||
925 | /** | ||
926 | * Function to call to check if we should accept or reject an | ||
927 | * incoming request. May be NULL. | ||
839 | */ | 928 | */ |
840 | MHD_AcceptPolicyCallback apc; | 929 | MHD_AcceptPolicyCallback apc; |
841 | 930 | ||
@@ -942,6 +1031,19 @@ struct MHD_Daemon | |||
942 | */ | 1031 | */ |
943 | int socket_fd; | 1032 | int socket_fd; |
944 | 1033 | ||
1034 | #if EPOLL_SUPPORT | ||
1035 | /** | ||
1036 | * File descriptor associated with our epoll loop. | ||
1037 | */ | ||
1038 | int epoll_fd; | ||
1039 | |||
1040 | /** | ||
1041 | * MHD_YES if the listen socket is in the 'epoll' set, | ||
1042 | * MHD_NO if not. | ||
1043 | */ | ||
1044 | int listen_socket_in_epoll; | ||
1045 | #endif | ||
1046 | |||
945 | /** | 1047 | /** |
946 | * Pipe we use to signal shutdown, unless | 1048 | * Pipe we use to signal shutdown, unless |
947 | * 'HAVE_LISTEN_SHUTDOWN' is defined AND we have a listen | 1049 | * 'HAVE_LISTEN_SHUTDOWN' is defined AND we have a listen |
@@ -1018,6 +1120,14 @@ struct MHD_Daemon | |||
1018 | */ | 1120 | */ |
1019 | const char *https_mem_trust; | 1121 | const char *https_mem_trust; |
1020 | 1122 | ||
1123 | /** | ||
1124 | * For how many connections do we have 'tls_read_ready' set to MHD_YES? | ||
1125 | * Used to avoid O(n) traversal over all connections when determining | ||
1126 | * event-loop timeout (as it needs to be zero if there is any connection | ||
1127 | * which might have ready data within TLS). | ||
1128 | */ | ||
1129 | unsigned int num_tls_read_ready; | ||
1130 | |||
1021 | #endif | 1131 | #endif |
1022 | 1132 | ||
1023 | #ifdef DAUTH_SUPPORT | 1133 | #ifdef DAUTH_SUPPORT |
@@ -1099,10 +1209,93 @@ struct MHD_Daemon | |||
1099 | (element)->prev = NULL; } while (0) | 1209 | (element)->prev = NULL; } while (0) |
1100 | 1210 | ||
1101 | 1211 | ||
1212 | |||
1213 | /** | ||
1214 | * Insert an element at the head of a XDLL. Assumes that head, tail and | ||
1215 | * element are structs with prevX and nextX fields. | ||
1216 | * | ||
1217 | * @param head pointer to the head of the XDLL | ||
1218 | * @param tail pointer to the tail of the XDLL | ||
1219 | * @param element element to insert | ||
1220 | */ | ||
1221 | #define XDLL_insert(head,tail,element) do { \ | ||
1222 | (element)->nextX = (head); \ | ||
1223 | (element)->prevX = NULL; \ | ||
1224 | if ((tail) == NULL) \ | ||
1225 | (tail) = element; \ | ||
1226 | else \ | ||
1227 | (head)->prevX = element; \ | ||
1228 | (head) = (element); } while (0) | ||
1229 | |||
1230 | |||
1231 | /** | ||
1232 | * Remove an element from a XDLL. Assumes | ||
1233 | * that head, tail and element are structs | ||
1234 | * with prevX and nextX fields. | ||
1235 | * | ||
1236 | * @param head pointer to the head of the XDLL | ||
1237 | * @param tail pointer to the tail of the XDLL | ||
1238 | * @param element element to remove | ||
1239 | */ | ||
1240 | #define XDLL_remove(head,tail,element) do { \ | ||
1241 | if ((element)->prevX == NULL) \ | ||
1242 | (head) = (element)->nextX; \ | ||
1243 | else \ | ||
1244 | (element)->prevX->nextX = (element)->nextX; \ | ||
1245 | if ((element)->nextX == NULL) \ | ||
1246 | (tail) = (element)->prevX; \ | ||
1247 | else \ | ||
1248 | (element)->nextX->prevX = (element)->prevX; \ | ||
1249 | (element)->nextX = NULL; \ | ||
1250 | (element)->prevX = NULL; } while (0) | ||
1251 | |||
1252 | |||
1253 | /** | ||
1254 | * Insert an element at the head of a EDLL. Assumes that head, tail and | ||
1255 | * element are structs with prevE and nextE fields. | ||
1256 | * | ||
1257 | * @param head pointer to the head of the EDLL | ||
1258 | * @param tail pointer to the tail of the EDLL | ||
1259 | * @param element element to insert | ||
1260 | */ | ||
1261 | #define EDLL_insert(head,tail,element) do { \ | ||
1262 | (element)->nextE = (head); \ | ||
1263 | (element)->prevE = NULL; \ | ||
1264 | if ((tail) == NULL) \ | ||
1265 | (tail) = element; \ | ||
1266 | else \ | ||
1267 | (head)->prevE = element; \ | ||
1268 | (head) = (element); } while (0) | ||
1269 | |||
1270 | |||
1271 | /** | ||
1272 | * Remove an element from a EDLL. Assumes | ||
1273 | * that head, tail and element are structs | ||
1274 | * with prevE and nextE fields. | ||
1275 | * | ||
1276 | * @param head pointer to the head of the EDLL | ||
1277 | * @param tail pointer to the tail of the EDLL | ||
1278 | * @param element element to remove | ||
1279 | */ | ||
1280 | #define EDLL_remove(head,tail,element) do { \ | ||
1281 | if ((element)->prevE == NULL) \ | ||
1282 | (head) = (element)->nextE; \ | ||
1283 | else \ | ||
1284 | (element)->prevE->nextE = (element)->nextE; \ | ||
1285 | if ((element)->nextE == NULL) \ | ||
1286 | (tail) = (element)->prevE; \ | ||
1287 | else \ | ||
1288 | (element)->nextE->prevE = (element)->prevE; \ | ||
1289 | (element)->nextE = NULL; \ | ||
1290 | (element)->prevE = NULL; } while (0) | ||
1291 | |||
1292 | |||
1102 | /** | 1293 | /** |
1103 | * Equivalent to time(NULL) but tries to use some sort of monotonic | 1294 | * Equivalent to time(NULL) but tries to use some sort of monotonic |
1104 | * clock that isn't affected by someone setting the system real time | 1295 | * clock that isn't affected by someone setting the system real time |
1105 | * clock. | 1296 | * clock. |
1297 | * | ||
1298 | * @return 'current' time | ||
1106 | */ | 1299 | */ |
1107 | time_t MHD_monotonic_time(void); | 1300 | time_t MHD_monotonic_time(void); |
1108 | 1301 | ||
diff --git a/src/microhttpd/memorypool.c b/src/microhttpd/memorypool.c index bd7c0c3a..db347056 100644 --- a/src/microhttpd/memorypool.c +++ b/src/microhttpd/memorypool.c | |||
@@ -90,10 +90,13 @@ MHD_pool_create (size_t max) | |||
90 | 90 | ||
91 | pool = malloc (sizeof (struct MemoryPool)); | 91 | pool = malloc (sizeof (struct MemoryPool)); |
92 | if (pool == NULL) | 92 | if (pool == NULL) |
93 | return NULL; | 93 | return NULL; |
94 | #ifdef MAP_ANONYMOUS | 94 | #ifdef MAP_ANONYMOUS |
95 | pool->memory = MMAP (NULL, max, PROT_READ | PROT_WRITE, | 95 | if (max <= 32 * 1024) |
96 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | 96 | pool->memory = MAP_FAILED; |
97 | else | ||
98 | pool->memory = MMAP (NULL, max, PROT_READ | PROT_WRITE, | ||
99 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | ||
97 | #else | 100 | #else |
98 | pool->memory = MAP_FAILED; | 101 | pool->memory = MAP_FAILED; |
99 | #endif | 102 | #endif |
diff --git a/src/testcurl/Makefile.am b/src/testcurl/Makefile.am index 61bc5169..329950fa 100644 --- a/src/testcurl/Makefile.am +++ b/src/testcurl/Makefile.am | |||
@@ -28,8 +28,8 @@ endif | |||
28 | 28 | ||
29 | check_PROGRAMS = \ | 29 | check_PROGRAMS = \ |
30 | test_start_stop \ | 30 | test_start_stop \ |
31 | test_get \ | ||
32 | test_quiesce \ | 31 | test_quiesce \ |
32 | test_get \ | ||
33 | test_get_sendfile \ | 33 | test_get_sendfile \ |
34 | test_urlparse \ | 34 | test_urlparse \ |
35 | test_put \ | 35 | test_put \ |
@@ -52,6 +52,8 @@ check_PROGRAMS = \ | |||
52 | $(CURL_FORK_TEST) \ | 52 | $(CURL_FORK_TEST) \ |
53 | perf_get $(PERF_GET_CONCURRENT) | 53 | perf_get $(PERF_GET_CONCURRENT) |
54 | 54 | ||
55 | |||
56 | |||
55 | if HAVE_POSTPROCESSOR | 57 | if HAVE_POSTPROCESSOR |
56 | check_PROGRAMS += \ | 58 | check_PROGRAMS += \ |
57 | test_post \ | 59 | test_post \ |
diff --git a/src/testcurl/perf_get.c b/src/testcurl/perf_get.c index 77c3193e..54f383ca 100644 --- a/src/testcurl/perf_get.c +++ b/src/testcurl/perf_get.c | |||
@@ -219,7 +219,8 @@ testInternalGet (int port, int poll_flag) | |||
219 | } | 219 | } |
220 | curl_easy_cleanup (c); | 220 | curl_easy_cleanup (c); |
221 | } | 221 | } |
222 | stop (poll_flag ? "internal poll" : "internal select"); | 222 | stop (poll_flag == MHD_USE_POLL ? "internal poll" : |
223 | poll_flag == MHD_USE_EPOLL_LINUX_ONLY ? "internal epoll" : "internal select"); | ||
223 | MHD_stop_daemon (d); | 224 | MHD_stop_daemon (d); |
224 | if (cbc.pos != strlen ("/hello_world")) | 225 | if (cbc.pos != strlen ("/hello_world")) |
225 | return 4; | 226 | return 4; |
@@ -278,7 +279,8 @@ testMultithreadedGet (int port, int poll_flag) | |||
278 | } | 279 | } |
279 | curl_easy_cleanup (c); | 280 | curl_easy_cleanup (c); |
280 | } | 281 | } |
281 | stop (poll_flag ? "thread with poll" : "thread with select"); | 282 | stop ((poll_flag & MHD_USE_POLL) ? "thread with poll" : |
283 | (poll_flag & MHD_USE_EPOLL_LINUX_ONLY) ? "thread with epoll" : "thread with select"); | ||
282 | MHD_stop_daemon (d); | 284 | MHD_stop_daemon (d); |
283 | if (cbc.pos != strlen ("/hello_world")) | 285 | if (cbc.pos != strlen ("/hello_world")) |
284 | return 64; | 286 | return 64; |
@@ -337,7 +339,8 @@ testMultithreadedPoolGet (int port, int poll_flag) | |||
337 | } | 339 | } |
338 | curl_easy_cleanup (c); | 340 | curl_easy_cleanup (c); |
339 | } | 341 | } |
340 | stop (poll_flag ? "thread pool with poll" : "thread pool with select"); | 342 | stop (0 != (poll_flag & MHD_USE_POLL) ? "thread pool with poll" : |
343 | 0 != (poll_flag & MHD_USE_EPOLL_LINUX_ONLY) ? "thread pool with epoll" : "thread pool with select"); | ||
341 | MHD_stop_daemon (d); | 344 | MHD_stop_daemon (d); |
342 | if (cbc.pos != strlen ("/hello_world")) | 345 | if (cbc.pos != strlen ("/hello_world")) |
343 | return 64; | 346 | return 64; |
@@ -507,6 +510,10 @@ main (int argc, char *const *argv) | |||
507 | errorCount += testMultithreadedGet (port++, MHD_USE_POLL); | 510 | errorCount += testMultithreadedGet (port++, MHD_USE_POLL); |
508 | errorCount += testMultithreadedPoolGet (port++, MHD_USE_POLL); | 511 | errorCount += testMultithreadedPoolGet (port++, MHD_USE_POLL); |
509 | #endif | 512 | #endif |
513 | #if EPOLL_SUPPORT | ||
514 | errorCount += testInternalGet (port++, MHD_USE_EPOLL_LINUX_ONLY); | ||
515 | errorCount += testMultithreadedPoolGet (port++, MHD_USE_EPOLL_LINUX_ONLY); | ||
516 | #endif | ||
510 | MHD_destroy_response (response); | 517 | MHD_destroy_response (response); |
511 | if (errorCount != 0) | 518 | if (errorCount != 0) |
512 | fprintf (stderr, "Error (code: %u)\n", errorCount); | 519 | fprintf (stderr, "Error (code: %u)\n", errorCount); |
diff --git a/src/testcurl/perf_get_concurrent.c b/src/testcurl/perf_get_concurrent.c index 85086bbe..15616ad5 100644 --- a/src/testcurl/perf_get_concurrent.c +++ b/src/testcurl/perf_get_concurrent.c | |||
@@ -336,6 +336,10 @@ main (int argc, char *const *argv) | |||
336 | errorCount += testMultithreadedGet (port++, MHD_USE_POLL); | 336 | errorCount += testMultithreadedGet (port++, MHD_USE_POLL); |
337 | errorCount += testMultithreadedPoolGet (port++, MHD_USE_POLL); | 337 | errorCount += testMultithreadedPoolGet (port++, MHD_USE_POLL); |
338 | #endif | 338 | #endif |
339 | #if EPOLL_SUPPORT | ||
340 | errorCount += testInternalGet (port++, MHD_USE_EPOLL_LINUX_ONLY); | ||
341 | errorCount += testMultithreadedPoolGet (port++, MHD_USE_EPOLL_LINUX_ONLY); | ||
342 | #endif | ||
339 | MHD_destroy_response (response); | 343 | MHD_destroy_response (response); |
340 | if (errorCount != 0) | 344 | if (errorCount != 0) |
341 | fprintf (stderr, "Error (code: %u)\n", errorCount); | 345 | fprintf (stderr, "Error (code: %u)\n", errorCount); |
diff --git a/src/testcurl/test_get.c b/src/testcurl/test_get.c index 45122cdb..ad9cbe14 100644 --- a/src/testcurl/test_get.c +++ b/src/testcurl/test_get.c | |||
@@ -145,6 +145,7 @@ testInternalGet (int poll_flag) | |||
145 | return 0; | 145 | return 0; |
146 | } | 146 | } |
147 | 147 | ||
148 | |||
148 | static int | 149 | static int |
149 | testMultithreadedGet (int poll_flag) | 150 | testMultithreadedGet (int poll_flag) |
150 | { | 151 | { |
@@ -194,6 +195,7 @@ testMultithreadedGet (int poll_flag) | |||
194 | return 0; | 195 | return 0; |
195 | } | 196 | } |
196 | 197 | ||
198 | |||
197 | static int | 199 | static int |
198 | testMultithreadedPoolGet (int poll_flag) | 200 | testMultithreadedPoolGet (int poll_flag) |
199 | { | 201 | { |
@@ -244,6 +246,7 @@ testMultithreadedPoolGet (int poll_flag) | |||
244 | return 0; | 246 | return 0; |
245 | } | 247 | } |
246 | 248 | ||
249 | |||
247 | static int | 250 | static int |
248 | testExternalGet () | 251 | testExternalGet () |
249 | { | 252 | { |
@@ -366,6 +369,7 @@ testExternalGet () | |||
366 | return 0; | 369 | return 0; |
367 | } | 370 | } |
368 | 371 | ||
372 | |||
369 | static int | 373 | static int |
370 | testUnknownPortGet (int poll_flag) | 374 | testUnknownPortGet (int poll_flag) |
371 | { | 375 | { |
@@ -506,6 +510,11 @@ main (int argc, char *const *argv) | |||
506 | errorCount += testUnknownPortGet (MHD_USE_POLL); | 510 | errorCount += testUnknownPortGet (MHD_USE_POLL); |
507 | errorCount += testStopRace (MHD_USE_POLL); | 511 | errorCount += testStopRace (MHD_USE_POLL); |
508 | #endif | 512 | #endif |
513 | #if EPOLL_SUPPORT | ||
514 | errorCount += testInternalGet (MHD_USE_EPOLL_LINUX_ONLY); | ||
515 | errorCount += testMultithreadedPoolGet (MHD_USE_EPOLL_LINUX_ONLY); | ||
516 | errorCount += testUnknownPortGet (MHD_USE_EPOLL_LINUX_ONLY); | ||
517 | #endif | ||
509 | if (errorCount != 0) | 518 | if (errorCount != 0) |
510 | fprintf (stderr, "Error (code: %u)\n", errorCount); | 519 | fprintf (stderr, "Error (code: %u)\n", errorCount); |
511 | curl_global_cleanup (); | 520 | curl_global_cleanup (); |
diff --git a/src/testcurl/test_quiesce.c b/src/testcurl/test_quiesce.c index 4755de92..dc131439 100644 --- a/src/testcurl/test_quiesce.c +++ b/src/testcurl/test_quiesce.c | |||
@@ -31,6 +31,8 @@ | |||
31 | #include <stdlib.h> | 31 | #include <stdlib.h> |
32 | #include <string.h> | 32 | #include <string.h> |
33 | #include <time.h> | 33 | #include <time.h> |
34 | #include <sys/types.h> | ||
35 | #include <sys/wait.h> | ||
34 | 36 | ||
35 | #ifndef WINDOWS | 37 | #ifndef WINDOWS |
36 | #include <unistd.h> | 38 | #include <unistd.h> |
@@ -38,7 +40,7 @@ | |||
38 | #endif | 40 | #endif |
39 | 41 | ||
40 | static int oneone; | 42 | static int oneone; |
41 | static int done; | 43 | |
42 | 44 | ||
43 | struct CBC | 45 | struct CBC |
44 | { | 46 | { |
@@ -47,6 +49,7 @@ struct CBC | |||
47 | size_t size; | 49 | size_t size; |
48 | }; | 50 | }; |
49 | 51 | ||
52 | |||
50 | static size_t | 53 | static size_t |
51 | copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) | 54 | copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) |
52 | { | 55 | { |
@@ -59,6 +62,7 @@ copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) | |||
59 | return size * nmemb; | 62 | return size * nmemb; |
60 | } | 63 | } |
61 | 64 | ||
65 | |||
62 | static int | 66 | static int |
63 | ahc_echo (void *cls, | 67 | ahc_echo (void *cls, |
64 | struct MHD_Connection *connection, | 68 | struct MHD_Connection *connection, |
@@ -91,24 +95,28 @@ ahc_echo (void *cls, | |||
91 | return ret; | 95 | return ret; |
92 | } | 96 | } |
93 | 97 | ||
94 | void request_completed (void *cls, struct MHD_Connection *connection, | 98 | |
95 | void **con_cls, enum MHD_RequestTerminationCode code) | 99 | static void |
100 | request_completed (void *cls, struct MHD_Connection *connection, | ||
101 | void **con_cls, enum MHD_RequestTerminationCode code) | ||
96 | { | 102 | { |
97 | int *done = (int *)cls; | 103 | int *done = (int *)cls; |
98 | *done = 1; | 104 | *done = 1; |
99 | } | 105 | } |
100 | 106 | ||
101 | void ServeOneRequest(int fd) | 107 | |
108 | static void | ||
109 | ServeOneRequest(int fd) | ||
102 | { | 110 | { |
103 | struct MHD_Daemon *d; | 111 | struct MHD_Daemon *d; |
104 | fd_set rs; | 112 | fd_set rs; |
105 | fd_set ws; | 113 | fd_set ws; |
106 | fd_set es; | 114 | fd_set es; |
107 | int max; | 115 | int max; |
108 | struct CURLMsg *msg; | ||
109 | time_t start; | 116 | time_t start; |
110 | struct timeval tv; | 117 | struct timeval tv; |
111 | int done = 0; | 118 | int done = 0; |
119 | |||
112 | d = MHD_start_daemon (MHD_USE_DEBUG, | 120 | d = MHD_start_daemon (MHD_USE_DEBUG, |
113 | 1082, NULL, NULL, &ahc_echo, "GET", | 121 | 1082, NULL, NULL, &ahc_echo, "GET", |
114 | MHD_OPTION_LISTEN_SOCKET, fd, | 122 | MHD_OPTION_LISTEN_SOCKET, fd, |
@@ -140,9 +148,12 @@ void ServeOneRequest(int fd) | |||
140 | _exit(0); | 148 | _exit(0); |
141 | } | 149 | } |
142 | 150 | ||
143 | CURL *setupCURL(void *cbc) | 151 | |
152 | static CURL * | ||
153 | setupCURL (void *cbc) | ||
144 | { | 154 | { |
145 | CURL *c; | 155 | CURL *c; |
156 | |||
146 | c = curl_easy_init (); | 157 | c = curl_easy_init (); |
147 | curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11080/hello_world"); | 158 | curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11080/hello_world"); |
148 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); | 159 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); |
@@ -162,6 +173,7 @@ CURL *setupCURL(void *cbc) | |||
162 | return c; | 173 | return c; |
163 | } | 174 | } |
164 | 175 | ||
176 | |||
165 | static int | 177 | static int |
166 | testGet (int type, int pool_count, int poll_flag) | 178 | testGet (int type, int pool_count, int poll_flag) |
167 | { | 179 | { |
@@ -171,18 +183,17 @@ testGet (int type, int pool_count, int poll_flag) | |||
171 | struct CBC cbc; | 183 | struct CBC cbc; |
172 | CURLcode errornum; | 184 | CURLcode errornum; |
173 | int fd; | 185 | int fd; |
174 | pid_t pid; | ||
175 | 186 | ||
176 | cbc.buf = buf; | 187 | cbc.buf = buf; |
177 | cbc.size = 2048; | 188 | cbc.size = 2048; |
178 | cbc.pos = 0; | 189 | cbc.pos = 0; |
179 | if (pool_count > 0) { | 190 | if (pool_count > 0) { |
180 | d = MHD_start_daemon (type | MHD_USE_DEBUG | poll_flag, | 191 | d = MHD_start_daemon (type | MHD_USE_DEBUG | MHD_USE_PIPE_FOR_SHUTDOWN | poll_flag, |
181 | 11080, NULL, NULL, &ahc_echo, "GET", | 192 | 11080, NULL, NULL, &ahc_echo, "GET", |
182 | MHD_OPTION_THREAD_POOL_SIZE, pool_count, MHD_OPTION_END); | 193 | MHD_OPTION_THREAD_POOL_SIZE, pool_count, MHD_OPTION_END); |
183 | 194 | ||
184 | } else { | 195 | } else { |
185 | d = MHD_start_daemon (type | MHD_USE_DEBUG | poll_flag, | 196 | d = MHD_start_daemon (type | MHD_USE_DEBUG | MHD_USE_PIPE_FOR_SHUTDOWN | poll_flag, |
186 | 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); | 197 | 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); |
187 | } | 198 | } |
188 | if (d == NULL) | 199 | if (d == NULL) |
@@ -211,12 +222,12 @@ testGet (int type, int pool_count, int poll_flag) | |||
211 | return 8; | 222 | return 8; |
212 | } | 223 | } |
213 | 224 | ||
214 | fd = MHD_quiesce_daemon(d); | 225 | fd = MHD_quiesce_daemon (d); |
215 | 226 | if (fork() == 0) | |
216 | if (fork() == 0) { | 227 | { |
217 | ServeOneRequest(fd); | 228 | ServeOneRequest (fd); |
218 | _exit(1); | 229 | _exit(1); |
219 | } | 230 | } |
220 | 231 | ||
221 | cbc.pos = 0; | 232 | cbc.pos = 0; |
222 | if (CURLE_OK != (errornum = curl_easy_perform (c))) | 233 | if (CURLE_OK != (errornum = curl_easy_perform (c))) |
@@ -225,25 +236,28 @@ testGet (int type, int pool_count, int poll_flag) | |||
225 | "curl_easy_perform failed: `%s'\n", | 236 | "curl_easy_perform failed: `%s'\n", |
226 | curl_easy_strerror (errornum)); | 237 | curl_easy_strerror (errornum)); |
227 | curl_easy_cleanup (c); | 238 | curl_easy_cleanup (c); |
239 | MHD_stop_daemon (d); | ||
228 | return 2; | 240 | return 2; |
229 | } | 241 | } |
230 | 242 | ||
231 | waitpid(-1, NULL, 0); | 243 | waitpid(-1, NULL, 0); |
232 | 244 | ||
233 | if (cbc.pos != strlen ("/hello_world")) { | 245 | if (cbc.pos != strlen ("/hello_world")) |
234 | fprintf(stderr, "%s\n", cbc.buf); | 246 | { |
235 | curl_easy_cleanup (c); | 247 | fprintf(stderr, "%s\n", cbc.buf); |
236 | MHD_stop_daemon (d); | 248 | curl_easy_cleanup (c); |
237 | close(fd); | 249 | MHD_stop_daemon (d); |
238 | return 4; | 250 | close(fd); |
239 | } | 251 | return 4; |
240 | if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) { | 252 | } |
241 | fprintf(stderr, "%s\n", cbc.buf); | 253 | if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) |
242 | curl_easy_cleanup (c); | 254 | { |
243 | MHD_stop_daemon (d); | 255 | fprintf(stderr, "%s\n", cbc.buf); |
244 | close(fd); | 256 | curl_easy_cleanup (c); |
245 | return 8; | 257 | MHD_stop_daemon (d); |
246 | } | 258 | close(fd); |
259 | return 8; | ||
260 | } | ||
247 | 261 | ||
248 | /* at this point, the forked server quit, and the new | 262 | /* at this point, the forked server quit, and the new |
249 | * server has quiesced, so new requests should fail | 263 | * server has quiesced, so new requests should fail |
@@ -408,6 +422,10 @@ main (int argc, char *const *argv) | |||
408 | errorCount += testGet (MHD_USE_THREAD_PER_CONNECTION, 0, MHD_USE_POLL); | 422 | errorCount += testGet (MHD_USE_THREAD_PER_CONNECTION, 0, MHD_USE_POLL); |
409 | errorCount += testGet (MHD_USE_SELECT_INTERNALLY, 4, MHD_USE_POLL); | 423 | errorCount += testGet (MHD_USE_SELECT_INTERNALLY, 4, MHD_USE_POLL); |
410 | #endif | 424 | #endif |
425 | #if EPOLL_SUPPORT | ||
426 | errorCount += testGet (MHD_USE_SELECT_INTERNALLY, 0, MHD_USE_EPOLL_LINUX_ONLY); | ||
427 | errorCount += testGet (MHD_USE_SELECT_INTERNALLY, 4, MHD_USE_EPOLL_LINUX_ONLY); | ||
428 | #endif | ||
411 | if (errorCount != 0) | 429 | if (errorCount != 0) |
412 | fprintf (stderr, "Error (code: %u)\n", errorCount); | 430 | fprintf (stderr, "Error (code: %u)\n", errorCount); |
413 | curl_global_cleanup (); | 431 | curl_global_cleanup (); |
diff --git a/src/testcurl/test_start_stop.c b/src/testcurl/test_start_stop.c index 8dca4cd5..b3be9937 100644 --- a/src/testcurl/test_start_stop.c +++ b/src/testcurl/test_start_stop.c | |||
@@ -110,6 +110,10 @@ main (int argc, char *const *argv) | |||
110 | errorCount += testMultithreadedGet (MHD_USE_POLL); | 110 | errorCount += testMultithreadedGet (MHD_USE_POLL); |
111 | errorCount += testMultithreadedPoolGet (MHD_USE_POLL); | 111 | errorCount += testMultithreadedPoolGet (MHD_USE_POLL); |
112 | #endif | 112 | #endif |
113 | #if EPOLL_SUPPORT | ||
114 | errorCount += testInternalGet (MHD_USE_EPOLL_LINUX_ONLY); | ||
115 | errorCount += testMultithreadedPoolGet (MHD_USE_EPOLL_LINUX_ONLY); | ||
116 | #endif | ||
113 | if (errorCount != 0) | 117 | if (errorCount != 0) |
114 | fprintf (stderr, "Error (code: %u)\n", errorCount); | 118 | fprintf (stderr, "Error (code: %u)\n", errorCount); |
115 | return errorCount != 0; /* 0 == pass */ | 119 | return errorCount != 0; /* 0 == pass */ |