From 2b78707adef689631d8de77ec55eefba7d642ad2 Mon Sep 17 00:00:00 2001 From: "Evgeny Grin (Karlson2k)" Date: Tue, 20 Aug 2024 10:59:00 +0200 Subject: [PATCH] Re-designed connection closing --- src/mhd2/conn_data_process.c | 16 +- src/mhd2/daemon_add_conn.c | 6 +- src/mhd2/events_process.c | 36 ++-- src/mhd2/mhd_connection.h | 8 +- src/mhd2/stream_funcs.c | 27 ++- src/mhd2/stream_funcs.h | 46 +++-- src/mhd2/stream_process_request.c | 2 +- src/mhd2/stream_process_request.h | 6 +- src/mhd2/stream_process_states.c | 279 +++++++++++++++--------------- 9 files changed, 225 insertions(+), 201 deletions(-) diff --git a/src/mhd2/conn_data_process.c b/src/mhd2/conn_data_process.c index 3b39fe0d..7c873504 100644 --- a/src/mhd2/conn_data_process.c +++ b/src/mhd2/conn_data_process.c @@ -49,16 +49,20 @@ MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool mhd_conn_process_recv_send_data (struct MHD_Connection *restrict c) { + /* The "send-ready" state is known if system polling call is edge-triggered + (it always checks for both send- and recv-ready) or if connection needs + sending (therefore "send-ready" was explicitly checked by sockets polling + call). */ const bool send_ready_state_known = ((mhd_D_IS_USING_EDGE_TRIG (c->daemon)) || - (0 != (MHD_EVENT_LOOP_INFO_WRITE & c->event_loop_info))); + (0 != (MHD_EVENT_LOOP_INFO_SEND & c->event_loop_info))); const bool has_sock_err = (0 != (mhd_SOCKET_NET_STATE_ERROR_READY & c->sk_ready)); bool data_processed; data_processed = false; - if (0 != (MHD_EVENT_LOOP_INFO_READ & c->event_loop_info)) + if (0 != (MHD_EVENT_LOOP_INFO_RECV & c->event_loop_info)) { bool use_recv; use_recv = (0 != (mhd_SOCKET_NET_STATE_RECV_READY & c->sk_ready)); @@ -74,7 +78,7 @@ mhd_conn_process_recv_send_data (struct MHD_Connection *restrict c) } } - if (0 != (MHD_EVENT_LOOP_INFO_WRITE & c->event_loop_info)) + if (0 != (MHD_EVENT_LOOP_INFO_SEND & c->event_loop_info)) { bool use_send; /* Perform sending if: @@ -107,8 +111,8 @@ mhd_conn_process_recv_send_data (struct MHD_Connection *restrict c) if (! force_close) { /* No need to check value of 'ret' here as closed connection - * cannot be in MHD_EVENT_LOOP_INFO_WRITE state. */ - if ( (MHD_EVENT_LOOP_INFO_WRITE == c->event_loop_info) && + * cannot be in MHD_EVENT_LOOP_INFO_SEND state. */ + if ( (MHD_EVENT_LOOP_INFO_SEND == c->event_loop_info) && write_ready) { MHD_connection_handle_write (c); @@ -172,7 +176,7 @@ mhd_conn_process_recv_send_data (struct MHD_Connection *restrict c) c->daemon->data_already_pending = true; #ifdef HTTPS_SUPPORT else if ( (c->tls_read_ready) && - (0 != (MHD_EVENT_LOOP_INFO_READ & c->event_loop_info)) ) + (0 != (MHD_EVENT_LOOP_INFO_RECV & c->event_loop_info)) ) c->daemon->data_already_pending = true; #endif /* HTTPS_SUPPORT */ } diff --git a/src/mhd2/daemon_add_conn.c b/src/mhd2/daemon_add_conn.c index d72996aa..69f7e562 100644 --- a/src/mhd2/daemon_add_conn.c +++ b/src/mhd2/daemon_add_conn.c @@ -83,7 +83,7 @@ connection_set_initial_state (struct MHD_Connection *restrict c) mhd_assert (MHD_CONNECTION_INIT == c->state); c->conn_reuse = mhd_CONN_KEEPALIVE_POSSIBLE; - c->event_loop_info = MHD_EVENT_LOOP_INFO_READ; + c->event_loop_info = MHD_EVENT_LOOP_INFO_RECV; memset (&c->rq, 0, sizeof(c->rq)); memset (&c->rp, 0, sizeof(c->rp)); @@ -203,7 +203,7 @@ new_connection_prepare_ (struct MHD_Daemon *restrict daemon, #endif /* MHD_USE_THREADS */ connection->daemon = daemon; connection->connection_timeout_ms = daemon->conns.cfg.timeout; - connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; + connection->event_loop_info = MHD_EVENT_LOOP_INFO_RECV; if (0 != connection->connection_timeout_ms) connection->last_activity = MHD_monotonic_msec_counter (); @@ -918,7 +918,7 @@ mhd_daemon_accept_connection (struct MHD_Daemon *restrict daemon) MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void mhd_conn_close_final (struct MHD_Connection *restrict c) { - mhd_assert (c->dbg.pre_closed); + mhd_assert (c->dbg.closing_started); mhd_assert (c->dbg.pre_cleaned); mhd_assert (NULL == c->rp.response); mhd_assert (! c->rq.app_aware); diff --git a/src/mhd2/events_process.c b/src/mhd2/events_process.c index 6e2fddcf..40a9ac6a 100644 --- a/src/mhd2/events_process.c +++ b/src/mhd2/events_process.c @@ -99,7 +99,7 @@ update_conn_net_status (struct MHD_Daemon *restrict d, if ((0 != (((unsigned int) c->sk_ready) & ((unsigned int) c->event_loop_info) - & (MHD_EVENT_LOOP_INFO_READ | MHD_EVENT_LOOP_INFO_WRITE))) + & (MHD_EVENT_LOOP_INFO_RECV | MHD_EVENT_LOOP_INFO_SEND))) || err_state) mhd_conn_mark_ready (c, d); else @@ -246,7 +246,10 @@ daemon_process_all_active_conns (struct MHD_Daemon *restrict d) struct MHD_Connection *next; next = mhd_DLINKEDL_GET_NEXT (c, proc_ready); /* The current connection can be closed */ if (! mhd_conn_process_recv_send_data (c)) + { + mhd_conn_pre_clean (c); mhd_conn_close_final (c); + } c = next; } @@ -259,14 +262,19 @@ close_all_daemon_conns (struct MHD_Daemon *d) { struct MHD_Connection *c; - for (c = mhd_DLINKEDL_GET_LAST (&(d->conns),all_conn); - NULL != c; - c = mhd_DLINKEDL_GET_LAST (&(d->conns),all_conn)) + if (! mhd_D_HAS_THR_PER_CONN (d)) { - mhd_conn_pre_close_d_shutdown (c); - mhd_conn_pre_clean (c); - mhd_conn_close_final (c); + for (c = mhd_DLINKEDL_GET_LAST (&(d->conns),all_conn); + NULL != c; + c = mhd_DLINKEDL_GET_LAST (&(d->conns),all_conn)) + { + mhd_conn_pre_close_d_shutdown (c); + mhd_conn_pre_clean (c); + mhd_conn_close_final (c); + } } + else + mhd_assert (0 && "Not implemented yet"); } @@ -370,12 +378,12 @@ select_update_fdsets (struct MHD_Daemon *restrict d, { mhd_assert (MHD_CONNECTION_CLOSED != c->state); - if (0 != (c->event_loop_info & MHD_EVENT_LOOP_INFO_READ)) + if (0 != (c->event_loop_info & MHD_EVENT_LOOP_INFO_RECV)) fd_set_wrap (c->socket_fd, rfds, &ret, d); - if (0 != (c->event_loop_info & MHD_EVENT_LOOP_INFO_WRITE)) + if (0 != (c->event_loop_info & MHD_EVENT_LOOP_INFO_SEND)) fd_set_wrap (c->socket_fd, wfds, &ret, @@ -620,9 +628,9 @@ poll_update_fds (struct MHD_Daemon *restrict d, d->events.data.poll.fds[i_c].fd = c->socket_fd; d->events.data.poll.rel[i_c].connection = c; events = 0; - if (0 != (c->event_loop_info & MHD_EVENT_LOOP_INFO_READ)) + if (0 != (c->event_loop_info & MHD_EVENT_LOOP_INFO_RECV)) events |= MHD_POLL_IN; - if (0 != (c->event_loop_info & MHD_EVENT_LOOP_INFO_WRITE)) + if (0 != (c->event_loop_info & MHD_EVENT_LOOP_INFO_SEND)) events |= MHD_POLL_OUT; d->events.data.poll.fds[i_c].events = (short) events; @@ -736,20 +744,20 @@ poll_update_statuses_from_fds (struct MHD_Daemon *restrict d, if (0 != (revents & POLLHUP)) { /* This can be a disconnect OR remote side set SHUT_WR */ recv_ready = true; /* Check the socket by reading */ - if (0 == (c->event_loop_info & MHD_EVENT_LOOP_INFO_READ)) + if (0 == (c->event_loop_info & MHD_EVENT_LOOP_INFO_RECV)) err_state = true; /* The socket will not be checked by reading, the only way to avoid spinning */ } #endif if (0 != (revents & (MHD_POLLPRI | MHD_POLLRDBAND))) { /* Statuses were not requested, but returned */ if (! recv_ready || - (0 == (c->event_loop_info & MHD_EVENT_LOOP_INFO_READ))) + (0 == (c->event_loop_info & MHD_EVENT_LOOP_INFO_RECV))) err_state = true; /* The socket will not be read, the only way to avoid spinning */ } if (0 != (revents & MHD_POLLWRBAND)) { /* Status was not requested, but returned */ if (! send_ready || - (0 == (c->event_loop_info & MHD_EVENT_LOOP_INFO_WRITE))) + (0 == (c->event_loop_info & MHD_EVENT_LOOP_INFO_SEND))) err_state = true; /* The socket will not be written, the only way to avoid spinning */ } diff --git a/src/mhd2/mhd_connection.h b/src/mhd2/mhd_connection.h index e0049a96..d9702785 100644 --- a/src/mhd2/mhd_connection.h +++ b/src/mhd2/mhd_connection.h @@ -79,13 +79,13 @@ enum MHD_FIXED_FLAGS_ENUM_ MHD_ConnectionEventLoopInfo * We are waiting to be able to read. * The same value as #mhd_SOCKET_NET_STATE_RECV_READY */ - MHD_EVENT_LOOP_INFO_READ = 1 << 0 + MHD_EVENT_LOOP_INFO_RECV = 1 << 0 , /** * We are waiting to be able to write. * The same value as #mhd_SOCKET_NET_STATE_SEND_READY */ - MHD_EVENT_LOOP_INFO_WRITE = 1 << 1 + MHD_EVENT_LOOP_INFO_SEND = 1 << 1 , /** * We are waiting for the application to provide data. @@ -99,7 +99,7 @@ enum MHD_FIXED_FLAGS_ENUM_ MHD_ConnectionEventLoopInfo }; #define MHD_EVENT_LOOP_INFO_PROCESS_READ \ - (MHD_EVENT_LOOP_INFO_READ | MHD_EVENT_LOOP_INFO_PROCESS) + (MHD_EVENT_LOOP_INFO_RECV | MHD_EVENT_LOOP_INFO_PROCESS) /** @@ -343,7 +343,7 @@ enum MHD_FIXED_ENUM_ MHD_CONNECTION_STATE struct mhd_ConnDebugData { - bool pre_closed; + bool closing_started; bool pre_cleaned; }; diff --git a/src/mhd2/stream_funcs.c b/src/mhd2/stream_funcs.c index 4b0043e0..a3e56428 100644 --- a/src/mhd2/stream_funcs.c +++ b/src/mhd2/stream_funcs.c @@ -500,11 +500,11 @@ mhd_stream_finish_req_serving (struct MHD_Connection *restrict c, /* Next function will notify client and set connection * state to "PRE-CLOSING" */ /* Later response and memory pool will be destroyed */ - mhd_conn_pre_close (c, - c->stop_with_error ? - mhd_CONN_CLOSE_ERR_REPLY_SENT : - mhd_CONN_CLOSE_HTTP_COMPLETED, - NULL); + mhd_conn_start_closing (c, + c->stop_with_error ? + mhd_CONN_CLOSE_ERR_REPLY_SENT : + mhd_CONN_CLOSE_HTTP_COMPLETED, + NULL); } else { @@ -539,7 +539,7 @@ mhd_stream_finish_req_serving (struct MHD_Connection *restrict c, c->state = MHD_CONNECTION_INIT; c->event_loop_info = (0 == c->read_buffer_offset) ? - MHD_EVENT_LOOP_INFO_READ : MHD_EVENT_LOOP_INFO_PROCESS; + MHD_EVENT_LOOP_INFO_RECV : MHD_EVENT_LOOP_INFO_PROCESS; memset (&c->rq, 0, sizeof(c->rq)); @@ -572,7 +572,7 @@ mhd_stream_finish_req_serving (struct MHD_Connection *restrict c, MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool -mhd_stream_check_timedout (struct MHD_Connection *restrict c) +mhd_stream_is_timeout_expired (struct MHD_Connection *restrict c) { const uint_fast64_t timeout = c->connection_timeout_ms; uint_fast64_t now; @@ -649,9 +649,9 @@ mhd_stream_update_activity_mark (struct MHD_Connection *restrict c) MHD_INTERNAL MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_CSTR_ (3) void -mhd_conn_pre_close (struct MHD_Connection *restrict c, - enum mhd_ConnCloseReason reason, - const char *log_msg) +mhd_conn_start_closing (struct MHD_Connection *restrict c, + enum mhd_ConnCloseReason reason, + const char *log_msg) { bool close_hard; enum MHD_RequestEndedCode end_code; @@ -781,7 +781,7 @@ mhd_conn_pre_close (struct MHD_Connection *restrict c, { /* Use abortive closing, send RST to remote to indicate a problem */ (void) mhd_socket_set_hard_close (c->socket_fd); - c->state = MHD_CONNECTION_CLOSED; + c->state = MHD_CONNECTION_PRE_CLOSING; c->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; } else @@ -832,7 +832,7 @@ mhd_conn_pre_close (struct MHD_Connection *restrict c, } #ifndef NDEBUG - c->dbg.pre_closed = true; + c->dbg.closing_started = true; #endif } @@ -843,7 +843,7 @@ mhd_conn_pre_clean (struct MHD_Connection *restrict c) { // TODO: support suspended connections - mhd_assert (c->dbg.pre_closed); + mhd_assert (c->dbg.closing_started); mhd_assert (! c->dbg.pre_cleaned); mhd_conn_mark_unready (c, c->daemon); @@ -857,7 +857,6 @@ mhd_conn_pre_clean (struct MHD_Connection *restrict c) if (NULL != c->rq.cntn.lbuf.data) mhd_daemon_free_lbuf (c->daemon, &(c->rq.cntn.lbuf)); - c->rq.cntn.lbuf.data = NULL; if (NULL != c->rp.response) mhd_response_dec_use_count (c->rp.response); c->rp.response = NULL; diff --git a/src/mhd2/stream_funcs.h b/src/mhd2/stream_funcs.h index 78ff4307..d73c95c7 100644 --- a/src/mhd2/stream_funcs.h +++ b/src/mhd2/stream_funcs.h @@ -135,13 +135,14 @@ mhd_stream_update_activity_mark (struct MHD_Connection *restrict c) MHD_FN_PAR_NONNULL_ALL_; /** - * Update last activity mark to the current time.. + * Check whether connection's timeout is expired. * @param c the connection to update - * @return 'true' if connection has not been timed out, + * @return 'true' if connection timeout expired and connection needs to be + * closed, * 'false' otherwise */ MHD_INTERNAL bool -mhd_stream_check_timedout (struct MHD_Connection *restrict c) +mhd_stream_is_timeout_expired (struct MHD_Connection *restrict c) MHD_FN_PAR_NONNULL_ALL_; /** @@ -234,24 +235,35 @@ enum mhd_ConnCloseReason /** - * Prepare connection for closing. + * Start closing of the connection. + * + * Application is notified about connection closing (if callback is set), + * the socket is shut downed for sending and the connection is marked for + * closing. The real resource deallocation and socket closing are performed + * later. + * + * As no resources are deallocated by this function, it is safe to call it + * "deep" in the code. Upon return all connection resources still could be used, + * pointers can be dereferenced etc. The real cleanup is performed when + * connection state is processed by #mhd_conn_process_data(). + * * @param c the connection for pre-closing * @param reason the reason for closing * @param log_msg the message for the log */ MHD_INTERNAL void -mhd_conn_pre_close (struct MHD_Connection *restrict c, - enum mhd_ConnCloseReason reason, - const char *log_msg) +mhd_conn_start_closing (struct MHD_Connection *restrict c, + enum mhd_ConnCloseReason reason, + const char *log_msg) MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_CSTR_ (3); /** * Abort the stream and log message */ #ifdef HAVE_LOG_FUNCTIONALITY -# define mhd_STREAM_ABORT(c,r,m) (mhd_conn_pre_close ((c),(r),(m))) +# define mhd_STREAM_ABORT(c,r,m) (mhd_conn_start_closing ((c),(r),(m))) #else /* ! HAVE_LOG_FUNCTIONALITY */ -# define mhd_STREAM_ABORT(c,r,m) (mhd_conn_pre_close ((c),(r),NULL)) +# define mhd_STREAM_ABORT(c,r,m) (mhd_conn_start_closing ((c),(r),NULL)) #endif /* ! HAVE_LOG_FUNCTIONALITY */ /** @@ -260,7 +272,7 @@ MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_CSTR_ (3); * @param c the connection for pre-closing */ #define mhd_conn_pre_close_app_abort(c) \ - mhd_conn_pre_close ((c), mhd_CONN_CLOSE_APP_ABORTED, NULL) + mhd_conn_start_closing ((c), mhd_CONN_CLOSE_APP_ABORTED, NULL) /** * Perform initial clean-up and mark for closing. @@ -268,7 +280,7 @@ MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_CSTR_ (3); * @param c the connection for pre-closing */ #define mhd_conn_pre_close_skt_err(c) \ - mhd_conn_pre_close ((c), mhd_CONN_CLOSE_SOCKET_ERR, NULL) + mhd_conn_start_closing ((c), mhd_CONN_CLOSE_SOCKET_ERR, NULL) /** * Perform initial clean-up and mark for closing. @@ -276,7 +288,7 @@ MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_CSTR_ (3); * @param c the connection for pre-closing */ #define mhd_conn_pre_close_req_finished(c) \ - mhd_conn_pre_close ((c), mhd_CONN_CLOSE_HTTP_COMPLETED, NULL) + mhd_conn_start_closing ((c), mhd_CONN_CLOSE_HTTP_COMPLETED, NULL) /** * Perform initial clean-up and mark for closing. @@ -284,7 +296,7 @@ MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_CSTR_ (3); * @param c the connection for pre-closing */ #define mhd_conn_pre_close_timedout(c) \ - mhd_conn_pre_close ((c), mhd_CONN_CLOSE_TIMEDOUT, NULL) + mhd_conn_start_closing ((c), mhd_CONN_CLOSE_TIMEDOUT, NULL) /** * Perform initial clean-up and mark for closing. @@ -292,11 +304,13 @@ MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_CSTR_ (3); * @param c the connection for pre-closing */ #define mhd_conn_pre_close_d_shutdown(c) \ - mhd_conn_pre_close ((c), mhd_CONN_CLOSE_DAEMON_SHUTDOWN, NULL) + mhd_conn_start_closing ((c), mhd_CONN_CLOSE_DAEMON_SHUTDOWN, NULL) /** - * Perform initial connection cleanup. - * The connection must be prepared for closing. + * Perform initial connection cleanup after start of the connection closing + * procedure. + * This cleanup should be performed in the same thread that processes + * the connection recv/send/data. * @param c the connection for pre-closing */ MHD_INTERNAL void diff --git a/src/mhd2/stream_process_request.c b/src/mhd2/stream_process_request.c index 0cee3e34..c8b2d567 100644 --- a/src/mhd2/stream_process_request.c +++ b/src/mhd2/stream_process_request.c @@ -3760,7 +3760,7 @@ mhd_stream_check_and_grow_read_buffer_space (struct MHD_Connection *restrict c) */ bool rbuff_grow_required; - mhd_assert (0 != (MHD_EVENT_LOOP_INFO_READ & c->event_loop_info)); + mhd_assert (0 != (MHD_EVENT_LOOP_INFO_RECV & c->event_loop_info)); mhd_assert (! c->discard_request); rbuff_grow_required = (c->read_buffer_offset == c->read_buffer_size); diff --git a/src/mhd2/stream_process_request.h b/src/mhd2/stream_process_request.h index 00147aec..748d71b3 100644 --- a/src/mhd2/stream_process_request.h +++ b/src/mhd2/stream_process_request.h @@ -168,7 +168,7 @@ MHD_FN_PAR_NONNULL_ (1); * * @param c the connection to process * @return true if advanced to the next state, - * false if more data needed or connection is suspended or aborted + * false if more data needed or connection is suspended */ MHD_INTERNAL bool mhd_stream_process_request_body (struct MHD_Connection *restrict c) @@ -179,7 +179,7 @@ MHD_FN_PAR_NONNULL_ALL_; * Advance to the next state, handle errors. * @param c the connection to process * @return true if advanced to the next state, - * false if connection is suspended or aborted + * false if connection is suspended */ MHD_INTERNAL bool mhd_stream_call_app_final_upload_cb (struct MHD_Connection *restrict c) @@ -190,7 +190,7 @@ MHD_FN_PAR_NONNULL_ALL_; * Advance to the next state, handle errors. * @param c the connection to process * @return true if advanced to the next state, - * false if connection is suspended or aborted + * false if connection is suspended */ MHD_INTERNAL bool mhd_stream_process_req_recv_finished (struct MHD_Connection *restrict c) diff --git a/src/mhd2/stream_process_states.c b/src/mhd2/stream_process_states.c index 4707bf49..1370eae2 100644 --- a/src/mhd2/stream_process_states.c +++ b/src/mhd2/stream_process_states.c @@ -76,127 +76,128 @@ update_active_state (struct MHD_Connection *restrict c) } } #endif /* HTTPS_SUPPORT */ - while (1) + switch (c->state) { - switch (c->state) - { - case MHD_CONNECTION_INIT: - case MHD_CONNECTION_REQ_LINE_RECEIVING: - c->event_loop_info = MHD_EVENT_LOOP_INFO_READ; - break; - case MHD_CONNECTION_REQ_LINE_RECEIVED: - mhd_assert (0 && "Impossible value"); - MHD_UNREACHABLE_; - break; - case MHD_CONNECTION_REQ_HEADERS_RECEIVING: - c->event_loop_info = MHD_EVENT_LOOP_INFO_READ; - break; - case MHD_CONNECTION_HEADERS_RECEIVED: - case MHD_CONNECTION_HEADERS_PROCESSED: - mhd_assert (0 && "Impossible value"); - MHD_UNREACHABLE_; - break; - case MHD_CONNECTION_CONTINUE_SENDING: - c->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; - break; - case MHD_CONNECTION_BODY_RECEIVING: - c->event_loop_info = MHD_EVENT_LOOP_INFO_READ; - break; - case MHD_CONNECTION_BODY_RECEIVED: - mhd_assert (0 && "Impossible value"); - MHD_UNREACHABLE_; - break; - case MHD_CONNECTION_FOOTERS_RECEIVING: - c->event_loop_info = MHD_EVENT_LOOP_INFO_READ; - break; - case MHD_CONNECTION_FOOTERS_RECEIVED: - mhd_assert (0 && "Impossible value"); - MHD_UNREACHABLE_; - break; - case MHD_CONNECTION_FULL_REQ_RECEIVED: - mhd_assert (0 && "Should not be possible"); - c->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS; - break; - case MHD_CONNECTION_REQ_RECV_FINISHED: - mhd_assert (0 && "Impossible value"); - MHD_UNREACHABLE_; - break; - case MHD_CONNECTION_START_REPLY: - mhd_assert (0 && "Impossible value"); - MHD_UNREACHABLE_; - break; - case MHD_CONNECTION_HEADERS_SENDING: - /* headers in buffer, keep writing */ - c->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; - break; - case MHD_CONNECTION_HEADERS_SENT: - mhd_assert (0 && "Impossible value"); - MHD_UNREACHABLE_; - break; - case MHD_CONNECTION_UNCHUNKED_BODY_UNREADY: - mhd_assert (0 && "Should not be possible"); - c->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS; - break; - case MHD_CONNECTION_UNCHUNKED_BODY_READY: - c->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; - break; - case MHD_CONNECTION_CHUNKED_BODY_UNREADY: - mhd_assert (0 && "Should not be possible"); - c->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS; - break; - case MHD_CONNECTION_CHUNKED_BODY_READY: - c->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; - break; - case MHD_CONNECTION_CHUNKED_BODY_SENT: - mhd_assert (0 && "Impossible value"); - MHD_UNREACHABLE_; - break; - case MHD_CONNECTION_FOOTERS_SENDING: - c->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; - break; - case MHD_CONNECTION_FULL_REPLY_SENT: - mhd_assert (0 && "Impossible value"); - MHD_UNREACHABLE_; - break; - case MHD_CONNECTION_CLOSED: - c->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; - return false; /* do nothing, not even reading */ + case MHD_CONNECTION_INIT: + case MHD_CONNECTION_REQ_LINE_RECEIVING: + c->event_loop_info = MHD_EVENT_LOOP_INFO_RECV; + break; + case MHD_CONNECTION_REQ_LINE_RECEIVED: + mhd_assert (0 && "Impossible value"); + MHD_UNREACHABLE_; + break; + case MHD_CONNECTION_REQ_HEADERS_RECEIVING: + c->event_loop_info = MHD_EVENT_LOOP_INFO_RECV; + break; + case MHD_CONNECTION_HEADERS_RECEIVED: + case MHD_CONNECTION_HEADERS_PROCESSED: + mhd_assert (0 && "Impossible value"); + MHD_UNREACHABLE_; + break; + case MHD_CONNECTION_CONTINUE_SENDING: + c->event_loop_info = MHD_EVENT_LOOP_INFO_SEND; + break; + case MHD_CONNECTION_BODY_RECEIVING: + c->event_loop_info = MHD_EVENT_LOOP_INFO_RECV; + break; + case MHD_CONNECTION_BODY_RECEIVED: + mhd_assert (0 && "Impossible value"); + MHD_UNREACHABLE_; + break; + case MHD_CONNECTION_FOOTERS_RECEIVING: + c->event_loop_info = MHD_EVENT_LOOP_INFO_RECV; + break; + case MHD_CONNECTION_FOOTERS_RECEIVED: + mhd_assert (0 && "Impossible value"); + MHD_UNREACHABLE_; + break; + case MHD_CONNECTION_FULL_REQ_RECEIVED: + mhd_assert (0 && "Should not be possible"); + c->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS; + break; + case MHD_CONNECTION_REQ_RECV_FINISHED: + mhd_assert (0 && "Impossible value"); + MHD_UNREACHABLE_; + break; + case MHD_CONNECTION_START_REPLY: + mhd_assert (0 && "Impossible value"); + MHD_UNREACHABLE_; + break; + case MHD_CONNECTION_HEADERS_SENDING: + /* headers in buffer, keep writing */ + c->event_loop_info = MHD_EVENT_LOOP_INFO_SEND; + break; + case MHD_CONNECTION_HEADERS_SENT: + mhd_assert (0 && "Impossible value"); + MHD_UNREACHABLE_; + break; + case MHD_CONNECTION_UNCHUNKED_BODY_UNREADY: + mhd_assert (0 && "Should not be possible"); + c->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS; + break; + case MHD_CONNECTION_UNCHUNKED_BODY_READY: + c->event_loop_info = MHD_EVENT_LOOP_INFO_SEND; + break; + case MHD_CONNECTION_CHUNKED_BODY_UNREADY: + mhd_assert (0 && "Should not be possible"); + c->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS; + break; + case MHD_CONNECTION_CHUNKED_BODY_READY: + c->event_loop_info = MHD_EVENT_LOOP_INFO_SEND; + break; + case MHD_CONNECTION_CHUNKED_BODY_SENT: + mhd_assert (0 && "Impossible value"); + MHD_UNREACHABLE_; + break; + case MHD_CONNECTION_FOOTERS_SENDING: + c->event_loop_info = MHD_EVENT_LOOP_INFO_SEND; + break; + case MHD_CONNECTION_FULL_REPLY_SENT: + mhd_assert (0 && "Impossible value"); + MHD_UNREACHABLE_; + break; + case MHD_CONNECTION_PRE_CLOSING: + mhd_assert (0 && "Should be unreachable"); + c->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; + break; + case MHD_CONNECTION_CLOSED: + mhd_assert (0 && "Should be unreachable"); + c->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; + return false; /* do nothing, not even reading */ #if 0 // def UPGRADE_SUPPORT // TODO: Upgrade support - case MHD_CONNECTION_UPGRADE: - mhd_assert (0); - break; + case MHD_CONNECTION_UPGRADE: + mhd_assert (0); + break; #endif /* UPGRADE_SUPPORT */ - default: - mhd_assert (0 && "Impossible value"); - MHD_UNREACHABLE_; - } - - if (0 != (MHD_EVENT_LOOP_INFO_READ & c->event_loop_info)) - { - /* Check whether the space is available to receive data */ - if (! mhd_stream_check_and_grow_read_buffer_space (c)) - { - mhd_assert (c->discard_request); - continue; - } - } - - /* Current MHD design assumes that data must be always processes when - * available. If it is not possible, connection must be suspended. */ - mhd_assert (MHD_EVENT_LOOP_INFO_PROCESS != c->event_loop_info); - - /* Sockets errors must be already handled */ - mhd_assert (0 == (c->sk_ready & mhd_SOCKET_NET_STATE_ERROR_READY)); - - if (0 != - (((unsigned int) c->sk_ready) & ((unsigned int) c->event_loop_info) - & (MHD_EVENT_LOOP_INFO_READ | MHD_EVENT_LOOP_INFO_WRITE))) - mhd_conn_mark_ready (c, c->daemon); - else - mhd_conn_mark_unready (c, c->daemon); - - break; /* Everything was processed. */ + default: + mhd_assert (0 && "Impossible value"); + MHD_UNREACHABLE_; } + + if (0 != (MHD_EVENT_LOOP_INFO_RECV & c->event_loop_info)) + { + /* Check whether the space is available to receive data */ + if (! mhd_stream_check_and_grow_read_buffer_space (c)) + { + mhd_assert (c->discard_request); + return false; + } + } + + /* Current MHD design assumes that data must be always processes when + * available. If it is not possible, connection must be suspended. */ + mhd_assert (MHD_EVENT_LOOP_INFO_PROCESS != c->event_loop_info); + + /* Sockets errors must be already handled */ + mhd_assert (0 == (c->sk_ready & mhd_SOCKET_NET_STATE_ERROR_READY)); + + if (0 != + (((unsigned int) c->sk_ready) & ((unsigned int) c->event_loop_info) + & (MHD_EVENT_LOOP_INFO_RECV | MHD_EVENT_LOOP_INFO_SEND))) + mhd_conn_mark_ready (c, c->daemon); + else + mhd_conn_mark_unready (c, c->daemon); + return true; } @@ -214,11 +215,11 @@ mhd_conn_process_data (struct MHD_Connection *restrict c) { if (0 == c->read_buffer_offset) { /* Read buffer is empty, connection state is actual */ - mhd_conn_pre_close (c, - (MHD_CONNECTION_INIT == c->state) ? - mhd_CONN_CLOSE_HTTP_COMPLETED : - mhd_CONN_CLOSE_CLIENT_SHUTDOWN_EARLY, - NULL); + mhd_conn_start_closing (c, + (MHD_CONNECTION_INIT == c->state) ? + mhd_CONN_CLOSE_HTTP_COMPLETED : + mhd_CONN_CLOSE_CLIENT_SHUTDOWN_EARLY, + NULL); return false; } } @@ -459,14 +460,15 @@ mhd_conn_process_data (struct MHD_Connection *restrict c) && ! c->sk_rmt_shut_wr); continue; case MHD_CONNECTION_PRE_CLOSING: - mhd_conn_pre_clean (c); - break; - case MHD_CONNECTION_CLOSED: - break; + return false; #if 0 // def UPGRADE_SUPPORT case MHD_CONNECTION_UPGRADE: return MHD_YES; /* keep open */ #endif /* UPGRADE_SUPPORT */ + case MHD_CONNECTION_CLOSED: + mhd_assert (0 && "Should be unreachable"); + MHD_UNREACHABLE_; + break; default: mhd_assert (0 && "Impossible value"); MHD_UNREACHABLE_; @@ -475,10 +477,13 @@ mhd_conn_process_data (struct MHD_Connection *restrict c) break; } - mhd_assert (MHD_CONNECTION_PRE_CLOSING != c->state); + mhd_assert (MHD_CONNECTION_CLOSED != c->state); - if (MHD_CONNECTION_CLOSED == c->state) + if (MHD_CONNECTION_PRE_CLOSING == c->state) + { + mhd_assert (0 && "Pre-closing should be already caught in the loop"); return false; + } if (c->suspended) { @@ -489,28 +494,22 @@ mhd_conn_process_data (struct MHD_Connection *restrict c) if ((c->sk_rmt_shut_wr) && (MHD_CONNECTION_START_REPLY > c->state)) { - mhd_conn_pre_close (c, - (MHD_CONNECTION_INIT == c->state) ? - mhd_CONN_CLOSE_HTTP_COMPLETED : - mhd_CONN_CLOSE_CLIENT_SHUTDOWN_EARLY, - NULL); - mhd_conn_pre_clean (c); + mhd_conn_start_closing (c, + (MHD_CONNECTION_INIT == c->state) ? + mhd_CONN_CLOSE_HTTP_COMPLETED : + mhd_CONN_CLOSE_CLIENT_SHUTDOWN_EARLY, + NULL); return false; } - if (mhd_stream_check_timedout (c)) // TODO: centralise timeout checks + if (mhd_stream_is_timeout_expired (c)) // TODO: centralise timeout checks { mhd_conn_pre_close_timedout (c); - mhd_conn_pre_clean (c); return false; } if (! update_active_state (c)) - { - mhd_conn_pre_clean (c); return false; - } - /* MHD_connection_update_event_loop_info (c);*/ return true; }