conn_data_process.c (6940B)
1 /* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */ 2 /* 3 This file is part of GNU libmicrohttpd. 4 Copyright (C) 2015-2024 Evgeny Grin (Karlson2k) 5 Copyright (C) 2007-2020 Daniel Pittman and Christian Grothoff 6 7 GNU libmicrohttpd is free software; you can redistribute it and/or 8 modify it under the terms of the GNU Lesser General Public 9 License as published by the Free Software Foundation; either 10 version 2.1 of the License, or (at your option) any later version. 11 12 GNU libmicrohttpd is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 Lesser General Public License for more details. 16 17 Alternatively, you can redistribute GNU libmicrohttpd and/or 18 modify it under the terms of the GNU General Public License as 19 published by the Free Software Foundation; either version 2 of 20 the License, or (at your option) any later version, together 21 with the eCos exception, as follows: 22 23 As a special exception, if other files instantiate templates or 24 use macros or inline functions from this file, or you compile this 25 file and link it with other works to produce a work based on this 26 file, this file does not by itself cause the resulting work to be 27 covered by the GNU General Public License. However the source code 28 for this file must still be made available in accordance with 29 section (3) of the GNU General Public License v2. 30 31 This exception does not invalidate any other reasons why a work 32 based on this file might be covered by the GNU General Public 33 License. 34 35 You should have received copies of the GNU Lesser General Public 36 License and the GNU General Public License along with this library; 37 if not, see <https://www.gnu.org/licenses/>. 38 */ 39 40 /** 41 * @file src/mhd2/data_process.c 42 * @brief The implementation of data receiving, sending and processing 43 * functions for connection 44 * @author Karlson2k (Evgeny Grin) 45 * 46 * Based on the MHD v0.x code by Daniel Pittman, Christian Grothoff and other 47 * contributors. 48 */ 49 50 #include "mhd_sys_options.h" 51 52 #include "conn_data_process.h" 53 #include "sys_bool_type.h" 54 #include "sys_base_types.h" 55 56 #include "mhd_assert.h" 57 #include "mhd_assume.h" 58 #include "mhd_unreachable.h" 59 #include "mhd_constexpr.h" 60 61 #include <string.h> 62 63 #include "mhd_daemon.h" 64 #include "mhd_connection.h" 65 66 #include "mhd_socket_error_funcs.h" 67 68 #include "daemon_logger.h" 69 70 #include "mhd_comm_layer_state.h" 71 #ifdef MHD_SUPPORT_HTTPS 72 # include "conn_tls_check.h" 73 #endif /* MHD_SUPPORT_HTTPS */ 74 75 #include "conn_data_recv.h" 76 #include "conn_data_send.h" 77 #include "stream_process_states.h" 78 #include "mhd_comm_layer_state.h" 79 80 81 mhd_static_inline enum mhd_CommLayerState 82 process_conn_layer (struct MHD_Connection *restrict c) 83 { 84 #ifdef MHD_SUPPORT_HTTPS 85 if (mhd_C_HAS_TLS (c)) 86 return mhd_conn_tls_check (c); 87 #endif /* MHD_SUPPORT_HTTPS */ 88 89 return mhd_COMM_LAYER_OK; 90 } 91 92 93 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool 94 mhd_conn_process_recv_send_data (struct MHD_Connection *restrict c) 95 { 96 bool send_ready_state_known; 97 bool has_sock_err; 98 bool data_processed; 99 100 data_processed = false; 101 102 mhd_assert (! c->suspended); 103 if (c->resuming) 104 { 105 /* Fully resume the connection + call app callbacks for the data */ 106 if (! mhd_conn_process_data (c)) 107 return false; 108 109 data_processed = true; 110 } 111 112 switch (process_conn_layer (c)) 113 { 114 case mhd_COMM_LAYER_OK: 115 break; /* Connected, the data */ 116 case mhd_COMM_LAYER_PROCESSING: 117 return true; /* Not yet fully connected, too early for the data */ 118 case mhd_COMM_LAYER_BROKEN: 119 return false; /* Connection is broken */ 120 default: 121 mhd_UNREACHABLE (); 122 return false; 123 } 124 125 /* The "send-ready" state is known if system polling call is edge-triggered 126 (it always checks for both send- and recv-ready) or if connection needs 127 sending (therefore "send-ready" was explicitly checked by sockets polling 128 call). */ 129 send_ready_state_known = 130 ((mhd_D_IS_USING_EDGE_TRIG (c->daemon)) || 131 (0 != (MHD_EVENT_LOOP_INFO_SEND & c->event_loop_info))); 132 has_sock_err = 133 (0 != (mhd_SOCKET_NET_STATE_ERROR_READY & c->sk.ready)); 134 mhd_assert (mhd_SOCKET_ERR_NO_ERROR == c->sk.state.discnt_err); 135 136 if (0 != (MHD_EVENT_LOOP_INFO_RECV & c->event_loop_info)) 137 { 138 bool use_recv; 139 use_recv = (0 != (mhd_SOCKET_NET_STATE_RECV_READY 140 & (c->sk.ready | mhd_C_HAS_TLS_DATA_IN (c)))); 141 use_recv = use_recv || 142 (has_sock_err && c->sk.props.is_nonblck); 143 144 if (use_recv) 145 { 146 mhd_conn_data_recv (c, has_sock_err); 147 mhd_assert (! has_sock_err || 148 (mhd_SOCKET_ERR_NO_ERROR != c->sk.state.discnt_err)); 149 if (! mhd_C_IS_HTTP2 (c)) 150 { 151 if (! mhd_conn_process_data (c)) 152 return false; 153 data_processed = true; 154 mhd_ASSUME (mhd_SOCKET_ERR_NO_ERROR == c->sk.state.discnt_err); 155 } 156 } 157 } 158 159 if (0 != (MHD_EVENT_LOOP_INFO_SEND & c->event_loop_info)) 160 { 161 bool use_send; 162 /* Perform sending if: 163 * + connection is ready for sending or 164 * + just formed send data, connection send ready status is not known and 165 * connection socket is non-blocking 166 * + detected network error on the connection, to check for the error */ 167 /* Assuming that after finishing receiving phase, connection send system 168 buffers should have some space as sending was performed before receiving 169 or has not been performed yet. */ 170 use_send = (0 != (mhd_SOCKET_NET_STATE_SEND_READY & c->sk.ready)); 171 172 /* Do not try to send if connection is broken when receiving */ 173 use_send = use_send && (mhd_SOCKET_ERR_NO_ERROR == c->sk.state.discnt_err); 174 175 if (! mhd_C_IS_HTTP2 (c)) 176 { 177 use_send = use_send || 178 (data_processed && (! send_ready_state_known) 179 && c->sk.props.is_nonblck); 180 use_send = use_send || 181 (has_sock_err && c->sk.props.is_nonblck); 182 } 183 184 if (use_send) 185 { 186 mhd_conn_data_send (c); 187 mhd_assert (! has_sock_err || 188 (mhd_SOCKET_ERR_NO_ERROR != c->sk.state.discnt_err)); 189 if (! mhd_C_IS_HTTP2 (c)) 190 { 191 if (! mhd_conn_process_data (c)) 192 return false; 193 data_processed = true; 194 mhd_ASSUME (mhd_SOCKET_ERR_NO_ERROR == c->sk.state.discnt_err); 195 } 196 } 197 } 198 199 if (mhd_SCKT_NET_ST_HAS_FLAG (c->sk.ready, 200 mhd_SOCKET_NET_STATE_ERROR_READY) && 201 (mhd_SOCKET_ERR_NO_ERROR == c->sk.state.discnt_err)) 202 { 203 c->sk.state.discnt_err = mhd_socket_error_get_from_socket (c->sk.fd); 204 mhd_ASSUME (mhd_SOCKET_ERR_NO_ERROR != c->sk.state.discnt_err); 205 } 206 207 if (! data_processed || 208 mhd_C_IS_HTTP2 (c) || 209 (mhd_SOCKET_ERR_NO_ERROR != c->sk.state.discnt_err)) 210 return mhd_conn_process_data (c); 211 212 return true; 213 }