| /* |
| This file is part of libmicrohttpd |
| Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff |
| |
| This library is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Lesser General Public |
| License as published by the Free Software Foundation; either |
| version 2.1 of the License, or (at your option) any later version. |
| |
| This library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Lesser General Public License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public |
| License along with this library; if not, write to the Free Software |
| Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| /** |
| * @file lib/connection_cleanup.c |
| * @brief function to clean up completed connections |
| * @author Christian Grothoff |
| */ |
| #include "internal.h" |
| #include "connection_cleanup.h" |
| #include "daemon_ip_limit.h" |
| |
| |
| #ifdef UPGRADE_SUPPORT |
| /** |
| * Finally cleanup upgrade-related resources. It should |
| * be called when TLS buffers have been drained and |
| * application signaled MHD by #MHD_UPGRADE_ACTION_CLOSE. |
| * |
| * @param connection handle to the upgraded connection to clean |
| */ |
| static void |
| connection_cleanup_upgraded (struct MHD_Connection *connection) |
| { |
| struct MHD_UpgradeResponseHandle *urh = connection->request.urh; |
| |
| if (NULL == urh) |
| return; |
| #ifdef HTTPS_SUPPORT |
| /* Signal remote client the end of TLS connection by |
| * gracefully closing TLS session. */ |
| { |
| struct MHD_TLS_Plugin *tls; |
| |
| if (NULL != (tls = connection->daemon->tls_api)) |
| (void) tls->shutdown_connection (tls->cls, |
| connection->tls_cs); |
| } |
| if (MHD_INVALID_SOCKET != urh->mhd.socket) |
| MHD_socket_close_chk_ (urh->mhd.socket); |
| if (MHD_INVALID_SOCKET != urh->app.socket) |
| MHD_socket_close_chk_ (urh->app.socket); |
| #endif /* HTTPS_SUPPORT */ |
| connection->request.urh = NULL; |
| free (urh); |
| } |
| |
| |
| #endif /* UPGRADE_SUPPORT */ |
| |
| |
| /** |
| * Free resources associated with all closed connections. (destroy |
| * responses, free buffers, etc.). All closed connections are kept in |
| * the "cleanup" doubly-linked list. |
| * |
| * @remark To be called only from thread that process daemon's |
| * select()/poll()/etc. |
| * |
| * @param daemon daemon to clean up |
| */ |
| void |
| MHD_connection_cleanup_ (struct MHD_Daemon *daemon) |
| { |
| struct MHD_Connection *pos; |
| |
| MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); |
| while (NULL != (pos = daemon->cleanup_tail)) |
| { |
| DLL_remove (daemon->cleanup_head, |
| daemon->cleanup_tail, |
| pos); |
| MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); |
| |
| if ( (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_mode) && |
| (! pos->thread_joined) && |
| (! MHD_join_thread_ (pos->pid.handle)) ) |
| MHD_PANIC (_ ("Failed to join a thread.\n")); |
| #ifdef UPGRADE_SUPPORT |
| connection_cleanup_upgraded (pos); |
| #endif /* UPGRADE_SUPPORT */ |
| MHD_pool_destroy (pos->pool); |
| #ifdef HTTPS_SUPPORT |
| { |
| struct MHD_TLS_Plugin *tls; |
| |
| if (NULL != (tls = daemon->tls_api)) |
| tls->teardown_connection (tls->cls, |
| pos->tls_cs); |
| } |
| #endif /* HTTPS_SUPPORT */ |
| |
| /* clean up the connection */ |
| if (NULL != daemon->notify_connection_cb) |
| daemon->notify_connection_cb (daemon->notify_connection_cb_cls, |
| pos, |
| MHD_CONNECTION_NOTIFY_CLOSED); |
| MHD_ip_limit_del (daemon, |
| (const struct sockaddr *) &pos->addr, |
| pos->addr_len); |
| #ifdef EPOLL_SUPPORT |
| if (MHD_ELS_EPOLL == daemon->event_loop_syscall) |
| { |
| if (0 != (pos->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) |
| { |
| EDLL_remove (daemon->eready_head, |
| daemon->eready_tail, |
| pos); |
| pos->epoll_state &= ~MHD_EPOLL_STATE_IN_EREADY_EDLL; |
| } |
| if ( (-1 != daemon->epoll_fd) && |
| (0 != (pos->epoll_state & MHD_EPOLL_STATE_IN_EPOLL_SET)) ) |
| { |
| /* epoll documentation suggests that closing a FD |
| automatically removes it from the epoll set; however, |
| this is not true as if we fail to do manually remove it, |
| we are still seeing an event for this fd in epoll, |
| causing grief (use-after-free...) --- at least on my |
| system. */if (0 != epoll_ctl (daemon->epoll_fd, |
| EPOLL_CTL_DEL, |
| pos->socket_fd, |
| NULL)) |
| MHD_PANIC (_ ("Failed to remove FD from epoll set.\n")); |
| pos->epoll_state &= ~MHD_EPOLL_STATE_IN_EPOLL_SET; |
| } |
| } |
| #endif |
| if (NULL != pos->request.response) |
| { |
| MHD_response_queue_for_destroy (pos->request.response); |
| pos->request.response = NULL; |
| } |
| if (MHD_INVALID_SOCKET != pos->socket_fd) |
| MHD_socket_close_chk_ (pos->socket_fd); |
| free (pos); |
| |
| MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); |
| daemon->connections--; |
| daemon->at_limit = false; |
| } |
| MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); |
| } |
| |
| |
| /* end of connection_cleanup.c */ |