diff options
author | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2021-12-05 14:04:51 +0300 |
---|---|---|
committer | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2021-12-05 20:21:46 +0300 |
commit | 8cdc89b9c3652d5ed899305bc93b10ddf04dbebc (patch) | |
tree | cea4d1792fd835e5bb9669ffa4c0bdcc390c5cab /src | |
parent | 4e9c66466d1ce9ef036ca483fe7d0fc91b9966fb (diff) | |
download | libmicrohttpd-8cdc89b9c3652d5ed899305bc93b10ddf04dbebc.tar.gz libmicrohttpd-8cdc89b9c3652d5ed899305bc93b10ddf04dbebc.zip |
new_connection_process_(): fixed handling of errors
Function fully restructured for clear handling of failed paths.
Fixed notification of connection termination without matching
notification of start of the connection (if reached daemon's
connections limit).
Fixed possible (but virtually unreachable) reset of the list of
connections if reached daemon's connections limit.
Fixed missed decrement of number of connections in case of any handled
failure.
Diffstat (limited to 'src')
-rw-r--r-- | src/microhttpd/daemon.c | 257 |
1 files changed, 131 insertions, 126 deletions
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c index b320177a..a96ec9ae 100644 --- a/src/microhttpd/daemon.c +++ b/src/microhttpd/daemon.c | |||
@@ -2736,166 +2736,171 @@ new_connection_process_ (struct MHD_Daemon *daemon, | |||
2736 | * NUMA and/or complex cache hierarchy. */ | 2736 | * NUMA and/or complex cache hierarchy. */ |
2737 | connection->pool = MHD_pool_create (daemon->pool_size); | 2737 | connection->pool = MHD_pool_create (daemon->pool_size); |
2738 | if (NULL == connection->pool) | 2738 | if (NULL == connection->pool) |
2739 | { | 2739 | { /* 'pool' creation failed */ |
2740 | #ifdef HAVE_MESSAGES | 2740 | #ifdef HAVE_MESSAGES |
2741 | MHD_DLOG (daemon, | 2741 | MHD_DLOG (daemon, |
2742 | _ ("Error allocating memory: %s\n"), | 2742 | _ ("Error allocating memory: %s\n"), |
2743 | MHD_strerror_ (errno)); | 2743 | MHD_strerror_ (errno)); |
2744 | #endif | 2744 | #endif |
2745 | MHD_socket_close_chk_ (connection->socket_fd); | ||
2746 | MHD_ip_limit_del (daemon, | ||
2747 | connection->addr, | ||
2748 | connection->addr_len); | ||
2749 | free (connection); | ||
2750 | #if ENOMEM | 2745 | #if ENOMEM |
2751 | errno = ENOMEM; | 2746 | eno = ENOMEM; |
2752 | #endif | 2747 | #endif |
2753 | return MHD_NO; | 2748 | (void) 0; /* Mute possible compiler warning */ |
2754 | } | 2749 | } |
2755 | 2750 | else | |
2756 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) | 2751 | { /* 'pool' creation succeed */ |
2757 | MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); | 2752 | MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); |
2758 | #endif | 2753 | /* Firm check under lock. */ |
2759 | /* Firm check under lock. */ | 2754 | if (daemon->connections >= daemon->connection_limit) |
2760 | if (daemon->connections >= daemon->connection_limit) | 2755 | { /* Connections limit */ |
2761 | { | ||
2762 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) | ||
2763 | MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); | ||
2764 | #endif | ||
2765 | /* above connection limit - reject */ | ||
2766 | #ifdef HAVE_MESSAGES | 2756 | #ifdef HAVE_MESSAGES |
2767 | MHD_DLOG (daemon, | 2757 | MHD_DLOG (daemon, |
2768 | _ ( | 2758 | _ ("Server reached connection limit. " |
2769 | "Server reached connection limit. Closing inbound connection.\n")); | 2759 | "Closing inbound connection.\n")); |
2770 | #endif | 2760 | #endif |
2771 | #if ENFILE | 2761 | #if ENFILE |
2772 | eno = ENFILE; | 2762 | eno = ENFILE; |
2773 | #endif | ||
2774 | goto cleanup; | ||
2775 | } | ||
2776 | daemon->connections++; | ||
2777 | if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) | ||
2778 | { | ||
2779 | XDLL_insert (daemon->normal_timeout_head, | ||
2780 | daemon->normal_timeout_tail, | ||
2781 | connection); | ||
2782 | } | ||
2783 | DLL_insert (daemon->connections_head, | ||
2784 | daemon->connections_tail, | ||
2785 | connection); | ||
2786 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) | ||
2787 | MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); | ||
2788 | #endif | 2763 | #endif |
2789 | if (NULL != daemon->notify_connection) | 2764 | (void) 0; /* Mute possible compiler warning */ |
2790 | daemon->notify_connection (daemon->notify_connection_cls, | 2765 | } |
2791 | connection, | 2766 | else |
2792 | &connection->socket_context, | 2767 | { /* Have space for new connection */ |
2793 | MHD_CONNECTION_NOTIFY_STARTED); | 2768 | daemon->connections++; |
2794 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) | 2769 | DLL_insert (daemon->connections_head, |
2795 | /* attempt to create handler thread */ | 2770 | daemon->connections_tail, |
2796 | if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) | 2771 | connection); |
2797 | { | 2772 | if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) |
2798 | if (! MHD_create_named_thread_ (&connection->pid, | 2773 | { |
2799 | "MHD-connection", | 2774 | XDLL_insert (daemon->normal_timeout_head, |
2800 | daemon->thread_stack_size, | 2775 | daemon->normal_timeout_tail, |
2801 | &thread_main_handle_connection, | 2776 | connection); |
2802 | connection)) | 2777 | } |
2803 | { | 2778 | MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); |
2804 | eno = errno; | 2779 | if (NULL != daemon->notify_connection) |
2780 | daemon->notify_connection (daemon->notify_connection_cls, | ||
2781 | connection, | ||
2782 | &connection->socket_context, | ||
2783 | MHD_CONNECTION_NOTIFY_STARTED); | ||
2784 | #ifdef MHD_USE_THREADS | ||
2785 | if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) | ||
2786 | { | ||
2787 | mhd_assert (0 == (daemon->options & MHD_USE_EPOLL)); | ||
2788 | if (! MHD_create_named_thread_ (&connection->pid, | ||
2789 | "MHD-connection", | ||
2790 | daemon->thread_stack_size, | ||
2791 | &thread_main_handle_connection, | ||
2792 | connection)) | ||
2793 | { | ||
2794 | eno = errno; | ||
2805 | #ifdef HAVE_MESSAGES | 2795 | #ifdef HAVE_MESSAGES |
2806 | #ifdef EAGAIN | 2796 | #ifdef EAGAIN |
2807 | if (EAGAIN == eno) | 2797 | if (EAGAIN == eno) |
2808 | MHD_DLOG (daemon, | 2798 | MHD_DLOG (daemon, |
2809 | _ ("Failed to create a new thread because it would have " \ | 2799 | _ ("Failed to create a new thread because it would " |
2810 | "exceeded the system limit on the number of threads or " \ | 2800 | "have exceeded the system limit on the number of " |
2811 | "no system resources available.\n")); | 2801 | "threads or no system resources available.\n")); |
2812 | else | 2802 | else |
2813 | #endif /* EAGAIN */ | 2803 | #endif /* EAGAIN */ |
2814 | MHD_DLOG (daemon, | 2804 | MHD_DLOG (daemon, |
2815 | _ ("Failed to create a thread: %s\n"), | 2805 | _ ("Failed to create a thread: %s\n"), |
2816 | MHD_strerror_ (eno)); | 2806 | MHD_strerror_ (eno)); |
2817 | #endif /* HAVE_MESSAGES */ | 2807 | #endif /* HAVE_MESSAGES */ |
2818 | goto cleanup; | 2808 | } |
2819 | } | 2809 | else /* New thread has been created successfully */ |
2820 | } | 2810 | return MHD_YES; /* *** Function success exit point *** */ |
2821 | else | 2811 | } |
2822 | connection->pid = daemon->pid; | 2812 | else |
2823 | #endif | 2813 | #else /* ! MHD_USE_THREADS */ |
2814 | if (1) | ||
2815 | #endif /* ! MHD_USE_THREADS */ | ||
2816 | { /* No 'thread-per-connection' */ | ||
2817 | #ifdef MHD_USE_THREADS | ||
2818 | connection->pid = daemon->pid; | ||
2819 | #endif /* MHD_USE_THREADS */ | ||
2824 | #ifdef EPOLL_SUPPORT | 2820 | #ifdef EPOLL_SUPPORT |
2825 | if (0 != (daemon->options & MHD_USE_EPOLL)) | 2821 | if (0 != (daemon->options & MHD_USE_EPOLL)) |
2826 | { | 2822 | { |
2827 | if (0 == (daemon->options & MHD_USE_TURBO)) | 2823 | if (0 == (daemon->options & MHD_USE_TURBO)) |
2828 | { | 2824 | { |
2829 | struct epoll_event event; | 2825 | struct epoll_event event; |
2826 | |||
2827 | event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET; | ||
2828 | event.data.ptr = connection; | ||
2829 | if (0 != epoll_ctl (daemon->epoll_fd, | ||
2830 | EPOLL_CTL_ADD, | ||
2831 | connection->socket_fd, | ||
2832 | &event)) | ||
2833 | { | ||
2834 | eno = errno; | ||
2835 | #ifdef HAVE_MESSAGES | ||
2836 | MHD_DLOG (daemon, | ||
2837 | _ ("Call to epoll_ctl failed: %s\n"), | ||
2838 | MHD_socket_last_strerr_ ()); | ||
2839 | #endif | ||
2840 | } | ||
2841 | else | ||
2842 | { /* 'socket_fd' has been added to 'epool' */ | ||
2843 | connection->epoll_state |= MHD_EPOLL_STATE_IN_EPOLL_SET; | ||
2844 | |||
2845 | return MHD_YES; /* *** Function success exit point *** */ | ||
2846 | } | ||
2847 | } | ||
2848 | else | ||
2849 | { | ||
2850 | connection->epoll_state |= MHD_EPOLL_STATE_READ_READY | ||
2851 | | MHD_EPOLL_STATE_WRITE_READY | ||
2852 | | MHD_EPOLL_STATE_IN_EREADY_EDLL; | ||
2853 | EDLL_insert (daemon->eready_head, | ||
2854 | daemon->eready_tail, | ||
2855 | connection); | ||
2830 | 2856 | ||
2831 | event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET; | 2857 | return MHD_YES; /* *** Function success exit point *** */ |
2832 | event.data.ptr = connection; | 2858 | } |
2833 | if (0 != epoll_ctl (daemon->epoll_fd, | 2859 | } |
2834 | EPOLL_CTL_ADD, | 2860 | else /* No 'epoll' */ |
2835 | connection->socket_fd, | 2861 | #endif /* EPOLL_SUPPORT */ |
2836 | &event)) | 2862 | return MHD_YES; /* *** Function success exit point *** */ |
2863 | } | ||
2864 | |||
2865 | /* ** Below is a cleanup path ** */ | ||
2866 | if (NULL != daemon->notify_connection) | ||
2867 | daemon->notify_connection (daemon->notify_connection_cls, | ||
2868 | connection, | ||
2869 | &connection->socket_context, | ||
2870 | MHD_CONNECTION_NOTIFY_CLOSED); | ||
2871 | MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); | ||
2872 | if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) | ||
2837 | { | 2873 | { |
2838 | eno = errno; | 2874 | XDLL_remove (daemon->normal_timeout_head, |
2839 | #ifdef HAVE_MESSAGES | 2875 | daemon->normal_timeout_tail, |
2840 | MHD_DLOG (daemon, | 2876 | connection); |
2841 | _ ("Call to epoll_ctl failed: %s\n"), | ||
2842 | MHD_socket_last_strerr_ ()); | ||
2843 | #endif | ||
2844 | goto cleanup; | ||
2845 | } | 2877 | } |
2846 | connection->epoll_state |= MHD_EPOLL_STATE_IN_EPOLL_SET; | 2878 | DLL_remove (daemon->connections_head, |
2847 | } | 2879 | daemon->connections_tail, |
2848 | else | 2880 | connection); |
2849 | { | 2881 | daemon->connections--; |
2850 | connection->epoll_state |= MHD_EPOLL_STATE_READ_READY | 2882 | MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); |
2851 | | MHD_EPOLL_STATE_WRITE_READY | ||
2852 | | MHD_EPOLL_STATE_IN_EREADY_EDLL; | ||
2853 | EDLL_insert (daemon->eready_head, | ||
2854 | daemon->eready_tail, | ||
2855 | connection); | ||
2856 | } | 2883 | } |
2884 | MHD_pool_destroy (connection->pool); | ||
2857 | } | 2885 | } |
2858 | #endif | 2886 | /* Free resources allocated before the call of this functions */ |
2859 | |||
2860 | return MHD_YES; | ||
2861 | |||
2862 | cleanup: | ||
2863 | if (NULL != daemon->notify_connection) | ||
2864 | daemon->notify_connection (daemon->notify_connection_cls, | ||
2865 | connection, | ||
2866 | &connection->socket_context, | ||
2867 | MHD_CONNECTION_NOTIFY_CLOSED); | ||
2868 | #ifdef HTTPS_SUPPORT | 2887 | #ifdef HTTPS_SUPPORT |
2869 | if (NULL != connection->tls_session) | 2888 | if (NULL != connection->tls_session) |
2870 | gnutls_deinit (connection->tls_session); | 2889 | gnutls_deinit (connection->tls_session); |
2871 | #endif /* HTTPS_SUPPORT */ | 2890 | #endif /* HTTPS_SUPPORT */ |
2872 | MHD_socket_close_chk_ (connection->socket_fd); | ||
2873 | MHD_ip_limit_del (daemon, | 2891 | MHD_ip_limit_del (daemon, |
2874 | connection->addr, | 2892 | connection->addr, |
2875 | connection->addr_len); | 2893 | connection->addr_len); |
2876 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) | ||
2877 | MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); | ||
2878 | #endif | ||
2879 | if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) | ||
2880 | { | ||
2881 | XDLL_remove (daemon->normal_timeout_head, | ||
2882 | daemon->normal_timeout_tail, | ||
2883 | connection); | ||
2884 | } | ||
2885 | DLL_remove (daemon->connections_head, | ||
2886 | daemon->connections_tail, | ||
2887 | connection); | ||
2888 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) | ||
2889 | MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); | ||
2890 | #endif | ||
2891 | MHD_pool_destroy (connection->pool); | ||
2892 | free (connection->addr); | 2894 | free (connection->addr); |
2895 | MHD_socket_close_chk_ (connection->socket_fd); | ||
2893 | free (connection); | 2896 | free (connection); |
2894 | if (0 != eno) | 2897 | if (0 != eno) |
2895 | errno = eno; | 2898 | errno = eno; |
2899 | #ifdef EINVAL | ||
2896 | else | 2900 | else |
2897 | errno = EINVAL; | 2901 | errno = EINVAL; |
2898 | return MHD_NO; | 2902 | #endif /* EINVAL */ |
2903 | return MHD_NO; /* *** Function failure exit point *** */ | ||
2899 | } | 2904 | } |
2900 | 2905 | ||
2901 | 2906 | ||