diff options
author | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2020-10-22 16:38:59 +0300 |
---|---|---|
committer | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2020-10-25 17:15:14 +0300 |
commit | 19b038f68272a423ae74c89427c8b5dcfc7ce1ae (patch) | |
tree | 090fcf01bb2a1c3cf6c17f6ad18f7f5a3f7cd41d | |
parent | 3460db01ec7e2b042296d7f703dfa344c893f5ea (diff) | |
download | libmicrohttpd-19b038f68272a423ae74c89427c8b5dcfc7ce1ae.tar.gz libmicrohttpd-19b038f68272a423ae74c89427c8b5dcfc7ce1ae.zip |
Fixed thread-safety for externally added connections
Fully re-implemented scheme of adding connections
from external thread (application)
-rw-r--r-- | src/microhttpd/daemon.c | 237 | ||||
-rw-r--r-- | src/microhttpd/internal.h | 21 |
2 files changed, 210 insertions, 48 deletions
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c index 7ffd93cd..c0be6bc0 100644 --- a/src/microhttpd/daemon.c +++ b/src/microhttpd/daemon.c | |||
@@ -2607,34 +2607,55 @@ new_connection_prepare_ (struct MHD_Daemon *daemon, | |||
2607 | 2607 | ||
2608 | 2608 | ||
2609 | /** | 2609 | /** |
2610 | * Close prepared, but not yet processed connection. | ||
2611 | * @param daemon the daemon | ||
2612 | * @param connection the connection to close | ||
2613 | */ | ||
2614 | static void | ||
2615 | new_connection_close_ (struct MHD_Daemon *daemon, | ||
2616 | struct MHD_Connection *connection) | ||
2617 | { | ||
2618 | mhd_assert (connection->daemon == daemon); | ||
2619 | mhd_assert (! connection->in_cleanup); | ||
2620 | mhd_assert (NULL == connection->next); | ||
2621 | mhd_assert (NULL == connection->nextX); | ||
2622 | #ifdef EPOLL_SUPPORT | ||
2623 | mhd_assert (NULL == connection->nextE); | ||
2624 | #endif /* EPOLL_SUPPORT */ | ||
2625 | |||
2626 | #ifdef HTTPS_SUPPORT | ||
2627 | if (NULL != connection->tls_session) | ||
2628 | { | ||
2629 | mhd_assert (0 != (daemon->options & MHD_USE_TLS)); | ||
2630 | gnutls_deinit (connection->tls_session); | ||
2631 | } | ||
2632 | #endif /* HTTPS_SUPPORT */ | ||
2633 | MHD_socket_close_chk_ (connection->socket_fd); | ||
2634 | MHD_ip_limit_del (daemon, | ||
2635 | connection->addr, | ||
2636 | connection->addr_len); | ||
2637 | free (connection->addr); | ||
2638 | free (connection); | ||
2639 | } | ||
2640 | |||
2641 | |||
2642 | /** | ||
2610 | * Finally insert the new connection to the list of connections | 2643 | * Finally insert the new connection to the list of connections |
2611 | * served by the daemon. | 2644 | * served by the daemon and start processing. |
2612 | * @remark To be called only from thread that process | 2645 | * @remark To be called only from thread that process |
2613 | * daemon's select()/poll()/etc. | 2646 | * daemon's select()/poll()/etc. |
2614 | * | 2647 | * |
2615 | * @param daemon daemon that manages the connection | 2648 | * @param daemon daemon that manages the connection |
2616 | * @param client_socket socket to manage (MHD will expect | ||
2617 | * to receive an HTTP request from this socket next). | ||
2618 | * @param addr IP address of the client | ||
2619 | * @param addrlen number of bytes in @a addr | ||
2620 | * @param external_add perform additional operations needed due | ||
2621 | * to the application calling us directly | ||
2622 | * @param connection the newly created connection | 2649 | * @param connection the newly created connection |
2623 | * @return #MHD_YES on success, #MHD_NO if this daemon could | 2650 | * @return #MHD_YES on success, #MHD_NO on error |
2624 | * not handle the connection (i.e. malloc failed, etc). | ||
2625 | * The socket will be closed in any case; 'errno' is | ||
2626 | * set to indicate further details about the error. | ||
2627 | */ | 2651 | */ |
2628 | static enum MHD_Result | 2652 | static enum MHD_Result |
2629 | new_connection_insert_ (struct MHD_Daemon *daemon, | 2653 | new_connection_process_ (struct MHD_Daemon *daemon, |
2630 | MHD_socket client_socket, | 2654 | struct MHD_Connection *connection) |
2631 | const struct sockaddr *addr, | ||
2632 | socklen_t addrlen, | ||
2633 | bool external_add, | ||
2634 | struct MHD_Connection *connection) | ||
2635 | { | 2655 | { |
2636 | int eno = 0; | 2656 | int eno = 0; |
2637 | 2657 | ||
2658 | mhd_assert (connection->daemon == daemon); | ||
2638 | /* Allocate memory pool in the processing thread so | 2659 | /* Allocate memory pool in the processing thread so |
2639 | * intensively used memory area is allocated in "good" | 2660 | * intensively used memory area is allocated in "good" |
2640 | * (for the thread) memory region. It is important with | 2661 | * (for the thread) memory region. It is important with |
@@ -2647,10 +2668,10 @@ new_connection_insert_ (struct MHD_Daemon *daemon, | |||
2647 | _ ("Error allocating memory: %s\n"), | 2668 | _ ("Error allocating memory: %s\n"), |
2648 | MHD_strerror_ (errno)); | 2669 | MHD_strerror_ (errno)); |
2649 | #endif | 2670 | #endif |
2650 | MHD_socket_close_chk_ (client_socket); | 2671 | MHD_socket_close_chk_ (connection->socket_fd); |
2651 | MHD_ip_limit_del (daemon, | 2672 | MHD_ip_limit_del (daemon, |
2652 | addr, | 2673 | connection->addr, |
2653 | addrlen); | 2674 | connection->addr_len); |
2654 | free (connection); | 2675 | free (connection); |
2655 | #if ENOMEM | 2676 | #if ENOMEM |
2656 | errno = ENOMEM; | 2677 | errno = ENOMEM; |
@@ -2721,15 +2742,15 @@ new_connection_insert_ (struct MHD_Daemon *daemon, | |||
2721 | #ifdef EPOLL_SUPPORT | 2742 | #ifdef EPOLL_SUPPORT |
2722 | if (0 != (daemon->options & MHD_USE_EPOLL)) | 2743 | if (0 != (daemon->options & MHD_USE_EPOLL)) |
2723 | { | 2744 | { |
2724 | if ((0 == (daemon->options & MHD_USE_TURBO)) || (external_add)) | 2745 | if (0 == (daemon->options & MHD_USE_TURBO)) |
2725 | { /* Do not manipulate EReady DL-list in 'external_add' mode. */ | 2746 | { |
2726 | struct epoll_event event; | 2747 | struct epoll_event event; |
2727 | 2748 | ||
2728 | event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET; | 2749 | event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET; |
2729 | event.data.ptr = connection; | 2750 | event.data.ptr = connection; |
2730 | if (0 != epoll_ctl (daemon->epoll_fd, | 2751 | if (0 != epoll_ctl (daemon->epoll_fd, |
2731 | EPOLL_CTL_ADD, | 2752 | EPOLL_CTL_ADD, |
2732 | client_socket, | 2753 | connection->socket_fd, |
2733 | &event)) | 2754 | &event)) |
2734 | { | 2755 | { |
2735 | eno = errno; | 2756 | eno = errno; |
@@ -2752,20 +2773,10 @@ new_connection_insert_ (struct MHD_Daemon *daemon, | |||
2752 | connection); | 2773 | connection); |
2753 | } | 2774 | } |
2754 | } | 2775 | } |
2755 | else /* This 'else' is combined with next 'if'. */ | ||
2756 | #endif | ||
2757 | if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && | ||
2758 | (external_add) && | ||
2759 | (MHD_ITC_IS_VALID_ (daemon->itc)) && | ||
2760 | (! MHD_itc_activate_ (daemon->itc, "n")) ) | ||
2761 | { | ||
2762 | #ifdef HAVE_MESSAGES | ||
2763 | MHD_DLOG (daemon, | ||
2764 | _ ( | ||
2765 | "Failed to signal new connection via inter-thread communication channel.\n")); | ||
2766 | #endif | 2776 | #endif |
2767 | } | 2777 | |
2768 | return MHD_YES; | 2778 | return MHD_YES; |
2779 | |||
2769 | cleanup: | 2780 | cleanup: |
2770 | if (NULL != daemon->notify_connection) | 2781 | if (NULL != daemon->notify_connection) |
2771 | daemon->notify_connection (daemon->notify_connection_cls, | 2782 | daemon->notify_connection (daemon->notify_connection_cls, |
@@ -2776,10 +2787,10 @@ cleanup: | |||
2776 | if (NULL != connection->tls_session) | 2787 | if (NULL != connection->tls_session) |
2777 | gnutls_deinit (connection->tls_session); | 2788 | gnutls_deinit (connection->tls_session); |
2778 | #endif /* HTTPS_SUPPORT */ | 2789 | #endif /* HTTPS_SUPPORT */ |
2779 | MHD_socket_close_chk_ (client_socket); | 2790 | MHD_socket_close_chk_ (connection->socket_fd); |
2780 | MHD_ip_limit_del (daemon, | 2791 | MHD_ip_limit_del (daemon, |
2781 | addr, | 2792 | connection->addr, |
2782 | addrlen); | 2793 | connection->addr_len); |
2783 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) | 2794 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) |
2784 | MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); | 2795 | MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); |
2785 | #endif | 2796 | #endif |
@@ -2880,8 +2891,82 @@ internal_add_connection (struct MHD_Daemon *daemon, | |||
2880 | non_blck, &connection)) | 2891 | non_blck, &connection)) |
2881 | return MHD_NO; | 2892 | return MHD_NO; |
2882 | 2893 | ||
2883 | return new_connection_insert_ (daemon, client_socket, addr, addrlen, | 2894 | if ((external_add) && |
2884 | external_add, connection); | 2895 | (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD))) |
2896 | { | ||
2897 | /* Connection is added externally and MHD is handling its own threads. */ | ||
2898 | MHD_mutex_lock_chk_ (&daemon->new_connections_mutex); | ||
2899 | DLL_insert (daemon->new_connections_head, | ||
2900 | daemon->new_connections_tail, | ||
2901 | connection); | ||
2902 | daemon->have_new = true; | ||
2903 | MHD_mutex_unlock_chk_ (&daemon->new_connections_mutex); | ||
2904 | |||
2905 | /* The rest of connection processing must be handled in | ||
2906 | * the daemon thread. */ | ||
2907 | if ((MHD_ITC_IS_VALID_ (daemon->itc)) && | ||
2908 | (! MHD_itc_activate_ (daemon->itc, "n"))) | ||
2909 | { | ||
2910 | #ifdef HAVE_MESSAGES | ||
2911 | MHD_DLOG (daemon, | ||
2912 | _ ("Failed to signal new connection via inter-thread " \ | ||
2913 | "communication channel.\n")); | ||
2914 | #endif | ||
2915 | } | ||
2916 | return MHD_YES; | ||
2917 | } | ||
2918 | |||
2919 | return new_connection_process_ (daemon, connection); | ||
2920 | } | ||
2921 | |||
2922 | |||
2923 | static void | ||
2924 | new_connections_list_process_ (struct MHD_Daemon *daemon) | ||
2925 | { | ||
2926 | struct MHD_Connection *local_head; | ||
2927 | struct MHD_Connection *local_tail; | ||
2928 | struct MHD_Connection *c; /**< Currently processed connection */ | ||
2929 | mhd_assert (daemon->have_new); | ||
2930 | mhd_assert (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)); | ||
2931 | |||
2932 | local_head = NULL; | ||
2933 | local_tail = NULL; | ||
2934 | |||
2935 | /* Move all new connections to the local DL-list to release the mutex | ||
2936 | * as quick as possible. */ | ||
2937 | MHD_mutex_lock_chk_ (&daemon->new_connections_mutex); | ||
2938 | mhd_assert (NULL != daemon->new_connections_head); | ||
2939 | do | ||
2940 | { /* Move connection in FIFO order. */ | ||
2941 | c = daemon->new_connections_tail; | ||
2942 | DLL_remove (daemon->new_connections_head, | ||
2943 | daemon->new_connections_tail, | ||
2944 | c); | ||
2945 | DLL_insert (local_head, | ||
2946 | local_tail, | ||
2947 | c); | ||
2948 | } while (NULL != daemon->new_connections_tail); | ||
2949 | daemon->have_new = false; | ||
2950 | MHD_mutex_unlock_chk_ (&daemon->new_connections_mutex); | ||
2951 | |||
2952 | /* Process new connections in FIFO order. */ | ||
2953 | do | ||
2954 | { | ||
2955 | c = local_tail; | ||
2956 | DLL_remove (local_head, | ||
2957 | local_tail, | ||
2958 | c); | ||
2959 | mhd_assert (daemon == c->daemon); | ||
2960 | if (MHD_NO == new_connection_process_ (daemon, c)) | ||
2961 | { | ||
2962 | #ifdef HAVE_MESSAGES | ||
2963 | MHD_DLOG (daemon, | ||
2964 | _ ("Failed to start serving new connection.\n")); | ||
2965 | #endif | ||
2966 | (void) 0; | ||
2967 | } | ||
2968 | } while (NULL != local_tail); | ||
2969 | |||
2885 | } | 2970 | } |
2886 | 2971 | ||
2887 | 2972 | ||
@@ -3710,6 +3795,10 @@ internal_run_from_select (struct MHD_Daemon *daemon, | |||
3710 | read_fd_set)) ) | 3795 | read_fd_set)) ) |
3711 | MHD_itc_clear_ (daemon->itc); | 3796 | MHD_itc_clear_ (daemon->itc); |
3712 | 3797 | ||
3798 | /* Process externally added connection if any */ | ||
3799 | if (daemon->have_new) | ||
3800 | new_connections_list_process_ (daemon); | ||
3801 | |||
3713 | /* select connection thread handling type */ | 3802 | /* select connection thread handling type */ |
3714 | if ( (MHD_INVALID_SOCKET != (ds = daemon->listen_fd)) && | 3803 | if ( (MHD_INVALID_SOCKET != (ds = daemon->listen_fd)) && |
3715 | (! daemon->was_quiesced) && | 3804 | (! daemon->was_quiesced) && |
@@ -4141,9 +4230,6 @@ MHD_poll_all (struct MHD_Daemon *daemon, | |||
4141 | return MHD_NO; | 4230 | return MHD_NO; |
4142 | } | 4231 | } |
4143 | 4232 | ||
4144 | /* Reset. New value will be set when connections are processed. */ | ||
4145 | daemon->data_already_pending = false; | ||
4146 | |||
4147 | /* handle ITC FD */ | 4233 | /* handle ITC FD */ |
4148 | /* do it before any other processing so | 4234 | /* do it before any other processing so |
4149 | new signals will be processed in next loop */ | 4235 | new signals will be processed in next loop */ |
@@ -4157,6 +4243,19 @@ MHD_poll_all (struct MHD_Daemon *daemon, | |||
4157 | free (p); | 4243 | free (p); |
4158 | return MHD_NO; | 4244 | return MHD_NO; |
4159 | } | 4245 | } |
4246 | |||
4247 | /* Process externally added connection if any */ | ||
4248 | if (daemon->have_new) | ||
4249 | new_connections_list_process_ (daemon); | ||
4250 | |||
4251 | /* handle 'listen' FD */ | ||
4252 | if ( (-1 != poll_listen) && | ||
4253 | (0 != (p[poll_listen].revents & POLLIN)) ) | ||
4254 | (void) MHD_accept_connection (daemon); | ||
4255 | |||
4256 | /* Reset. New value will be set when connections are processed. */ | ||
4257 | daemon->data_already_pending = false; | ||
4258 | |||
4160 | i = 0; | 4259 | i = 0; |
4161 | prev = daemon->connections_tail; | 4260 | prev = daemon->connections_tail; |
4162 | while (NULL != (pos = prev)) | 4261 | while (NULL != (pos = prev)) |
@@ -4209,10 +4308,6 @@ MHD_poll_all (struct MHD_Daemon *daemon, | |||
4209 | } | 4308 | } |
4210 | } | 4309 | } |
4211 | #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ | 4310 | #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ |
4212 | /* handle 'listen' FD */ | ||
4213 | if ( (-1 != poll_listen) && | ||
4214 | (0 != (p[poll_listen].revents & POLLIN)) ) | ||
4215 | (void) MHD_accept_connection (daemon); | ||
4216 | 4311 | ||
4217 | free (p); | 4312 | free (p); |
4218 | } | 4313 | } |
@@ -4294,6 +4389,11 @@ MHD_poll_listen_socket (struct MHD_Daemon *daemon, | |||
4294 | /* handle shutdown */ | 4389 | /* handle shutdown */ |
4295 | if (daemon->shutdown) | 4390 | if (daemon->shutdown) |
4296 | return MHD_NO; | 4391 | return MHD_NO; |
4392 | |||
4393 | /* Process externally added connection if any */ | ||
4394 | if (daemon->have_new) | ||
4395 | new_connections_list_process_ (daemon); | ||
4396 | |||
4297 | if ( (-1 != poll_listen) && | 4397 | if ( (-1 != poll_listen) && |
4298 | (0 != (p[poll_listen].revents & POLLIN)) ) | 4398 | (0 != (p[poll_listen].revents & POLLIN)) ) |
4299 | (void) MHD_accept_connection (daemon); | 4399 | (void) MHD_accept_connection (daemon); |
@@ -4739,6 +4839,10 @@ MHD_epoll (struct MHD_Daemon *daemon, | |||
4739 | } | 4839 | } |
4740 | } | 4840 | } |
4741 | 4841 | ||
4842 | /* Process externally added connection if any */ | ||
4843 | if (daemon->have_new) | ||
4844 | new_connections_list_process_ (daemon); | ||
4845 | |||
4742 | if (need_to_accept) | 4846 | if (need_to_accept) |
4743 | { | 4847 | { |
4744 | unsigned int series_length = 0; | 4848 | unsigned int series_length = 0; |
@@ -6633,6 +6737,18 @@ MHD_start_daemon_va (unsigned int flags, | |||
6633 | #endif /* ! HAVE_LISTEN_SHUTDOWN */ | 6737 | #endif /* ! HAVE_LISTEN_SHUTDOWN */ |
6634 | if (0 == daemon->worker_pool_size) | 6738 | if (0 == daemon->worker_pool_size) |
6635 | { | 6739 | { |
6740 | if (! MHD_mutex_init_ (&daemon->new_connections_mutex)) | ||
6741 | { | ||
6742 | #ifdef HAVE_MESSAGES | ||
6743 | MHD_DLOG (daemon, | ||
6744 | _ ("Failed to initialise mutex.\n")); | ||
6745 | #endif | ||
6746 | MHD_mutex_destroy_chk_ (&daemon->cleanup_connection_mutex); | ||
6747 | MHD_mutex_destroy_chk_ (&daemon->per_ip_connection_mutex); | ||
6748 | if (MHD_INVALID_SOCKET != listen_fd) | ||
6749 | MHD_socket_close_chk_ (listen_fd); | ||
6750 | goto free_and_fail; | ||
6751 | } | ||
6636 | if (! MHD_create_named_thread_ (&daemon->pid, | 6752 | if (! MHD_create_named_thread_ (&daemon->pid, |
6637 | (*pflags | 6753 | (*pflags |
6638 | & MHD_USE_THREAD_PER_CONNECTION) ? | 6754 | & MHD_USE_THREAD_PER_CONNECTION) ? |
@@ -6646,6 +6762,7 @@ MHD_start_daemon_va (unsigned int flags, | |||
6646 | _ ("Failed to create listen thread: %s\n"), | 6762 | _ ("Failed to create listen thread: %s\n"), |
6647 | MHD_strerror_ (errno)); | 6763 | MHD_strerror_ (errno)); |
6648 | #endif | 6764 | #endif |
6765 | MHD_mutex_destroy_chk_ (&daemon->new_connections_mutex); | ||
6649 | MHD_mutex_destroy_chk_ (&daemon->cleanup_connection_mutex); | 6766 | MHD_mutex_destroy_chk_ (&daemon->cleanup_connection_mutex); |
6650 | MHD_mutex_destroy_chk_ (&daemon->per_ip_connection_mutex); | 6767 | MHD_mutex_destroy_chk_ (&daemon->per_ip_connection_mutex); |
6651 | if (MHD_INVALID_SOCKET != listen_fd) | 6768 | if (MHD_INVALID_SOCKET != listen_fd) |
@@ -6685,7 +6802,14 @@ MHD_start_daemon_va (unsigned int flags, | |||
6685 | d->master = daemon; | 6802 | d->master = daemon; |
6686 | d->worker_pool_size = 0; | 6803 | d->worker_pool_size = 0; |
6687 | d->worker_pool = NULL; | 6804 | d->worker_pool = NULL; |
6688 | 6805 | if (! MHD_mutex_init_ (&d->new_connections_mutex)) | |
6806 | { | ||
6807 | #ifdef HAVE_MESSAGES | ||
6808 | MHD_DLOG (daemon, | ||
6809 | _ ("Failed to initialise mutex.\n")); | ||
6810 | #endif | ||
6811 | goto thread_failed; | ||
6812 | } | ||
6689 | if (0 != (*pflags & MHD_USE_ITC)) | 6813 | if (0 != (*pflags & MHD_USE_ITC)) |
6690 | { | 6814 | { |
6691 | if (! MHD_itc_init_ (d->itc)) | 6815 | if (! MHD_itc_init_ (d->itc)) |
@@ -6696,6 +6820,7 @@ MHD_start_daemon_va (unsigned int flags, | |||
6696 | "Failed to create worker inter-thread communication channel: %s\n"), | 6820 | "Failed to create worker inter-thread communication channel: %s\n"), |
6697 | MHD_itc_last_strerror_ () ); | 6821 | MHD_itc_last_strerror_ () ); |
6698 | #endif | 6822 | #endif |
6823 | MHD_mutex_destroy_chk_ (&d->new_connections_mutex); | ||
6699 | goto thread_failed; | 6824 | goto thread_failed; |
6700 | } | 6825 | } |
6701 | if ( (0 == (*pflags & (MHD_USE_POLL | MHD_USE_EPOLL))) && | 6826 | if ( (0 == (*pflags & (MHD_USE_POLL | MHD_USE_EPOLL))) && |
@@ -6707,6 +6832,7 @@ MHD_start_daemon_va (unsigned int flags, | |||
6707 | _ ( | 6832 | _ ( |
6708 | "File descriptor for worker inter-thread communication channel exceeds maximum value.\n")); | 6833 | "File descriptor for worker inter-thread communication channel exceeds maximum value.\n")); |
6709 | #endif | 6834 | #endif |
6835 | MHD_mutex_destroy_chk_ (&d->new_connections_mutex); | ||
6710 | MHD_itc_destroy_chk_ (d->itc); | 6836 | MHD_itc_destroy_chk_ (d->itc); |
6711 | goto thread_failed; | 6837 | goto thread_failed; |
6712 | } | 6838 | } |
@@ -6733,6 +6859,7 @@ MHD_start_daemon_va (unsigned int flags, | |||
6733 | { | 6859 | { |
6734 | if (MHD_ITC_IS_VALID_ (d->itc)) | 6860 | if (MHD_ITC_IS_VALID_ (d->itc)) |
6735 | MHD_itc_destroy_chk_ (d->itc); | 6861 | MHD_itc_destroy_chk_ (d->itc); |
6862 | MHD_mutex_destroy_chk_ (&d->new_connections_mutex); | ||
6736 | goto thread_failed; | 6863 | goto thread_failed; |
6737 | } | 6864 | } |
6738 | #endif | 6865 | #endif |
@@ -6745,6 +6872,7 @@ MHD_start_daemon_va (unsigned int flags, | |||
6745 | #endif | 6872 | #endif |
6746 | if (MHD_ITC_IS_VALID_ (d->itc)) | 6873 | if (MHD_ITC_IS_VALID_ (d->itc)) |
6747 | MHD_itc_destroy_chk_ (d->itc); | 6874 | MHD_itc_destroy_chk_ (d->itc); |
6875 | MHD_mutex_destroy_chk_ (&d->new_connections_mutex); | ||
6748 | goto thread_failed; | 6876 | goto thread_failed; |
6749 | } | 6877 | } |
6750 | 6878 | ||
@@ -6765,6 +6893,7 @@ MHD_start_daemon_va (unsigned int flags, | |||
6765 | MHD_mutex_destroy_chk_ (&d->cleanup_connection_mutex); | 6893 | MHD_mutex_destroy_chk_ (&d->cleanup_connection_mutex); |
6766 | if (MHD_ITC_IS_VALID_ (d->itc)) | 6894 | if (MHD_ITC_IS_VALID_ (d->itc)) |
6767 | MHD_itc_destroy_chk_ (d->itc); | 6895 | MHD_itc_destroy_chk_ (d->itc); |
6896 | MHD_mutex_destroy_chk_ (&d->new_connections_mutex); | ||
6768 | goto thread_failed; | 6897 | goto thread_failed; |
6769 | } | 6898 | } |
6770 | } | 6899 | } |
@@ -6879,6 +7008,17 @@ close_all_connections (struct MHD_Daemon *daemon) | |||
6879 | mhd_assert (NULL == daemon->worker_pool); | 7008 | mhd_assert (NULL == daemon->worker_pool); |
6880 | #endif | 7009 | #endif |
6881 | mhd_assert (daemon->shutdown); | 7010 | mhd_assert (daemon->shutdown); |
7011 | |||
7012 | /* Remove externally added new connections that are | ||
7013 | * not processed by the daemon thread. */ | ||
7014 | while (NULL != (pos = daemon->new_connections_tail)) | ||
7015 | { | ||
7016 | mhd_assert (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)); | ||
7017 | DLL_remove (daemon->new_connections_head, | ||
7018 | daemon->new_connections_tail, | ||
7019 | pos); | ||
7020 | new_connection_close_ (daemon, pos); | ||
7021 | } | ||
6882 | /* give upgraded HTTPS connections a chance to finish */ | 7022 | /* give upgraded HTTPS connections a chance to finish */ |
6883 | /* 'daemon->urh_head' is not used in thread-per-connection mode. */ | 7023 | /* 'daemon->urh_head' is not used in thread-per-connection mode. */ |
6884 | for (urh = daemon->urh_tail; NULL != urh; urh = urhn) | 7024 | for (urh = daemon->urh_tail; NULL != urh; urh = urhn) |
@@ -7126,6 +7266,7 @@ MHD_stop_daemon (struct MHD_Daemon *daemon) | |||
7126 | } | 7266 | } |
7127 | if (MHD_ITC_IS_VALID_ (daemon->itc)) | 7267 | if (MHD_ITC_IS_VALID_ (daemon->itc)) |
7128 | MHD_itc_destroy_chk_ (daemon->itc); | 7268 | MHD_itc_destroy_chk_ (daemon->itc); |
7269 | MHD_mutex_destroy_chk_ (&daemon->new_connections_mutex); | ||
7129 | 7270 | ||
7130 | #ifdef EPOLL_SUPPORT | 7271 | #ifdef EPOLL_SUPPORT |
7131 | if ( (0 != (daemon->options & MHD_USE_EPOLL)) && | 7272 | if ( (0 != (daemon->options & MHD_USE_EPOLL)) && |
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h index 5fb3da3d..3b044984 100644 --- a/src/microhttpd/internal.h +++ b/src/microhttpd/internal.h | |||
@@ -1302,6 +1302,16 @@ struct MHD_Daemon | |||
1302 | void *default_handler_cls; | 1302 | void *default_handler_cls; |
1303 | 1303 | ||
1304 | /** | 1304 | /** |
1305 | * Head of doubly-linked list of new, externally added connections. | ||
1306 | */ | ||
1307 | struct MHD_Connection *new_connections_head; | ||
1308 | |||
1309 | /** | ||
1310 | * Tail of doubly-linked list of new, externally added connections. | ||
1311 | */ | ||
1312 | struct MHD_Connection *new_connections_tail; | ||
1313 | |||
1314 | /** | ||
1305 | * Head of doubly-linked list of our current, active connections. | 1315 | * Head of doubly-linked list of our current, active connections. |
1306 | */ | 1316 | */ |
1307 | struct MHD_Connection *connections_head; | 1317 | struct MHD_Connection *connections_head; |
@@ -1516,6 +1526,11 @@ struct MHD_Daemon | |||
1516 | * "manual_timeout" DLLs. | 1526 | * "manual_timeout" DLLs. |
1517 | */ | 1527 | */ |
1518 | MHD_mutex_ cleanup_connection_mutex; | 1528 | MHD_mutex_ cleanup_connection_mutex; |
1529 | |||
1530 | /** | ||
1531 | * Mutex for any access to the "new connections" DL-list. | ||
1532 | */ | ||
1533 | MHD_mutex_ new_connections_mutex; | ||
1519 | #endif | 1534 | #endif |
1520 | 1535 | ||
1521 | /** | 1536 | /** |
@@ -1601,6 +1616,12 @@ struct MHD_Daemon | |||
1601 | volatile bool resuming; | 1616 | volatile bool resuming; |
1602 | 1617 | ||
1603 | /** | 1618 | /** |
1619 | * Indicate that new connections in @e new_connections_head list | ||
1620 | * need to be processed. | ||
1621 | */ | ||
1622 | volatile bool have_new; | ||
1623 | |||
1624 | /** | ||
1604 | * 'True' if some data is already waiting to be processed. | 1625 | * 'True' if some data is already waiting to be processed. |
1605 | * If set to 'true' - zero timeout for select()/poll*() | 1626 | * If set to 'true' - zero timeout for select()/poll*() |
1606 | * is used. | 1627 | * is used. |