aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeny Grin (Karlson2k) <k2k@narod.ru>2021-12-05 14:04:51 +0300
committerEvgeny Grin (Karlson2k) <k2k@narod.ru>2021-12-05 20:21:46 +0300
commit8cdc89b9c3652d5ed899305bc93b10ddf04dbebc (patch)
treecea4d1792fd835e5bb9669ffa4c0bdcc390c5cab
parent4e9c66466d1ce9ef036ca483fe7d0fc91b9966fb (diff)
downloadlibmicrohttpd-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.
-rw-r--r--src/microhttpd/daemon.c257
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
2862cleanup:
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