aboutsummaryrefslogtreecommitdiff
path: root/src/microhttpd/daemon.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/microhttpd/daemon.c')
-rw-r--r--src/microhttpd/daemon.c237
1 files changed, 189 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 */
2614static void
2615new_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 */
2628static enum MHD_Result 2652static enum MHD_Result
2629new_connection_insert_ (struct MHD_Daemon *daemon, 2653new_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
2769cleanup: 2780cleanup:
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
2923static void
2924new_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)) &&