commit f9578650704c2260173f5e4aac9c956a9e5a9d6a
parent a73a6be16f6fe1da7b3043cf5c77afd19c312737
Author: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Date: Mon, 30 Sep 2024 02:46:33 +0100
Finished implementation of HTTP Upgrade + some fixes
Diffstat:
14 files changed, 809 insertions(+), 731 deletions(-)
diff --git a/src/include/microhttpd2.h b/src/include/microhttpd2.h
@@ -1439,7 +1439,7 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
MHD_SC_DAEMON_DESTROYED_WITH_UNCLOSED_UPGRADED = 60160
,
/**
- * The provided pointer to 'struct MHD_UpgradeHandle' is invalid
+ * The provided pointer to 'struct MHD_UpgradedHandle' is invalid
*/
MHD_SC_UPGRADED_HANDLE_INVALID = 60161
,
@@ -6628,7 +6628,7 @@ MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_OUT_SIZE_ (3,2);
* actions relating to MHD responses that "upgrade"
* the HTTP protocol (i.e. to WebSockets).
*/
-struct MHD_UpgradeHandle;
+struct MHD_UpgradedHandle;
#ifndef MHD_UPGRADEHANDLER_DEFINED
@@ -6657,9 +6657,10 @@ struct MHD_UpgradeHandle;
* perform the close() action on the @a sock.
*/
typedef void
-(*MHD_UpgradeHandler)(void *cls,
+(MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_NONNULL_ (3)
+ *MHD_UpgradeHandler)(void *cls,
struct MHD_Request *MHD_RESTRICT request,
- struct MHD_UpgradeHandle *MHD_RESTRICT urh);
+ struct MHD_UpgradedHandle *MHD_RESTRICT urh);
#define MHD_UPGRADEHANDLER_DEFINED 1
#endif /* ! MHD_UPGRADEHANDLER_DEFINED */
@@ -6772,7 +6773,7 @@ MHD_FN_PAR_IN_SIZE_ (6,5);
* by this MHD build or platform
*/
MHD_EXTERN_ enum MHD_StatusCode
-MHD_upgraded_recv (struct MHD_UpgradeHandle *MHD_RESTRICT urh,
+MHD_upgraded_recv (struct MHD_UpgradedHandle *MHD_RESTRICT urh,
size_t recv_buf_size,
void *MHD_RESTRICT recv_buf,
size_t *MHD_RESTRICT received_size,
@@ -6801,9 +6802,7 @@ MHD_FN_PAR_OUT_ (4);
* @param max_wait_millisec the maximum wait time for the data,
* non-blocking operation if set to zero,
* wait indefinitely if larger or equal to
- * #MHD_WAIT_INDEFINITELY,
- * the function may return earlier if waiting is
- * interrupted or by other reasons
+ * #MHD_WAIT_INDEFINITELY
* @param more_data_to_come set to #MHD_YES if the provided data in
* the @a send_buf is part of a larger data package,
* like an incomplete message or streamed
@@ -6828,7 +6827,7 @@ MHD_FN_PAR_OUT_ (4);
* by this MHD build or platform
*/
MHD_EXTERN_ enum MHD_StatusCode
-MHD_upgraded_send (struct MHD_UpgradeHandle *MHD_RESTRICT urh,
+MHD_upgraded_send (struct MHD_UpgradedHandle *MHD_RESTRICT urh,
size_t send_buf_size,
const void *MHD_RESTRICT send_buf,
size_t *MHD_RESTRICT sent_size,
@@ -6851,7 +6850,7 @@ MHD_FN_PAR_OUT_ (4);
* error code otherwise
*/
MHD_EXTERN_ enum MHD_StatusCode
-MHD_upgraded_close (struct MHD_UpgradeHandle *urh)
+MHD_upgraded_close (struct MHD_UpgradedHandle *urh)
MHD_FN_PAR_NONNULL_ (1);
diff --git a/src/include/microhttpd2_main.h.in b/src/include/microhttpd2_main.h.in
@@ -2204,7 +2204,7 @@ MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_OUT_SIZE_ (3,2);
* actions relating to MHD responses that "upgrade"
* the HTTP protocol (i.e. to WebSockets).
*/
-struct MHD_UpgradeHandle;
+struct MHD_UpgradedHandle;
#ifndef MHD_UPGRADEHANDLER_DEFINED
@@ -2233,9 +2233,10 @@ struct MHD_UpgradeHandle;
* perform the close() action on the @a sock.
*/
typedef void
-(*MHD_UpgradeHandler)(void *cls,
+(MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_NONNULL_ (3)
+ *MHD_UpgradeHandler)(void *cls,
struct MHD_Request *MHD_RESTRICT request,
- struct MHD_UpgradeHandle *MHD_RESTRICT urh);
+ struct MHD_UpgradedHandle *MHD_RESTRICT urh);
#define MHD_UPGRADEHANDLER_DEFINED 1
#endif /* ! MHD_UPGRADEHANDLER_DEFINED */
@@ -2348,7 +2349,7 @@ MHD_FN_PAR_IN_SIZE_ (6,5);
* by this MHD build or platform
*/
MHD_EXTERN_ enum MHD_StatusCode
-MHD_upgraded_recv (struct MHD_UpgradeHandle *MHD_RESTRICT urh,
+MHD_upgraded_recv (struct MHD_UpgradedHandle *MHD_RESTRICT urh,
size_t recv_buf_size,
void *MHD_RESTRICT recv_buf,
size_t *MHD_RESTRICT received_size,
@@ -2377,9 +2378,7 @@ MHD_FN_PAR_OUT_ (4);
* @param max_wait_millisec the maximum wait time for the data,
* non-blocking operation if set to zero,
* wait indefinitely if larger or equal to
- * #MHD_WAIT_INDEFINITELY,
- * the function may return earlier if waiting is
- * interrupted or by other reasons
+ * #MHD_WAIT_INDEFINITELY
* @param more_data_to_come set to #MHD_YES if the provided data in
* the @a send_buf is part of a larger data package,
* like an incomplete message or streamed
@@ -2404,7 +2403,7 @@ MHD_FN_PAR_OUT_ (4);
* by this MHD build or platform
*/
MHD_EXTERN_ enum MHD_StatusCode
-MHD_upgraded_send (struct MHD_UpgradeHandle *MHD_RESTRICT urh,
+MHD_upgraded_send (struct MHD_UpgradedHandle *MHD_RESTRICT urh,
size_t send_buf_size,
const void *MHD_RESTRICT send_buf,
size_t *MHD_RESTRICT sent_size,
@@ -2427,7 +2426,7 @@ MHD_FN_PAR_OUT_ (4);
* error code otherwise
*/
MHD_EXTERN_ enum MHD_StatusCode
-MHD_upgraded_close (struct MHD_UpgradeHandle *urh)
+MHD_upgraded_close (struct MHD_UpgradedHandle *urh)
MHD_FN_PAR_NONNULL_ (1);
diff --git a/src/include/microhttpd2_preamble.h.in b/src/include/microhttpd2_preamble.h.in
@@ -1439,7 +1439,7 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
MHD_SC_DAEMON_DESTROYED_WITH_UNCLOSED_UPGRADED = 60160
,
/**
- * The provided pointer to 'struct MHD_UpgradeHandle' is invalid
+ * The provided pointer to 'struct MHD_UpgradedHandle' is invalid
*/
MHD_SC_UPGRADED_HANDLE_INVALID = 60161
,
diff --git a/src/mhd2/Makefile.am b/src/mhd2/Makefile.am
@@ -102,7 +102,7 @@ upgrade_files = \
mhd_upgrade.h \
upgrade_prep.c upgrade_prep.h \
upgrade_proc.c upgrade_proc.h \
- upgrade_net.c
+ upgraded_net.c
if HAVE_POST_PARSER
libmicrohttpd2_la_SOURCES += $(post_parser_files)
diff --git a/src/mhd2/conn_data_send.c b/src/mhd2/conn_data_send.c
@@ -91,8 +91,9 @@ mhd_conn_data_send (struct MHD_Connection *restrict c)
res = mhd_SOCKET_ERR_INTERNAL;
- if (MHD_CONNECTION_CONTINUE_SENDING == c->state)
+ switch (c->state)
{
+ case MHD_CONNECTION_CONTINUE_SENDING:
res = mhd_send_data (c,
http_100_continue_msg_len
- c->continue_message_write_offset,
@@ -102,177 +103,176 @@ mhd_conn_data_send (struct MHD_Connection *restrict c)
&sent);
if (mhd_SOCKET_ERR_NO_ERROR == res)
c->continue_message_write_offset += sent;
- }
- else if (MHD_CONNECTION_HEADERS_SENDING == c->state)
- {
- struct MHD_Response *const restrict resp = c->rp.response;
- const size_t wb_ready = c->write_buffer_append_offset
- - c->write_buffer_send_offset;
- mhd_assert (c->write_buffer_append_offset >= \
- c->write_buffer_send_offset);
- mhd_assert (NULL != resp);
- mhd_assert ((mhd_CONN_MUST_UPGRADE != c->conn_reuse) || \
- (! c->rp.props.send_reply_body));
-
- // TODO: support body generating alongside with header sending
-
- if ((c->rp.props.send_reply_body) &&
- (mhd_REPLY_CNTN_LOC_RESP_BUF == c->rp.cntn_loc))
+ break;
+ case MHD_CONNECTION_HEADERS_SENDING:
+ if (1)
{
- /* Send response headers alongside the response body, if the body
- * data is available. */
- mhd_assert (mhd_RESPONSE_CONTENT_DATA_BUFFER == resp->cntn_dtype);
- mhd_assert (! c->rp.props.chunked);
+ struct MHD_Response *const restrict resp = c->rp.response;
+ const size_t wb_ready = c->write_buffer_append_offset
+ - c->write_buffer_send_offset;
+ mhd_assert (c->write_buffer_append_offset >= \
+ c->write_buffer_send_offset);
+ mhd_assert (NULL != resp);
+ mhd_assert ((mhd_CONN_MUST_UPGRADE != c->conn_reuse) || \
+ (! c->rp.props.send_reply_body));
- res = mhd_send_hdr_and_body (c,
- wb_ready,
- c->write_buffer
- + c->write_buffer_send_offset,
- false,
- resp->cntn_size,
- (const char *) resp->cntn.buf,
- true,
- &sent);
- }
- else
- {
- /* This is response for HEAD request or reply body is not allowed
- * for any other reason or reply body is dynamically generated. */
- /* Do not send the body data even if it's available. */
- res = mhd_send_hdr_and_body (c,
- wb_ready,
- c->write_buffer
- + c->write_buffer_send_offset,
- false,
- 0,
- NULL,
- ((0 == resp->cntn_size) ||
- (! c->rp.props.send_reply_body)),
- &sent);
- }
- if (mhd_SOCKET_ERR_NO_ERROR == res)
- {
- mhd_assert (MHD_CONNECTION_HEADERS_SENDING == c->state);
+ // TODO: support body generating alongside with header sending
- if (sent > wb_ready)
+ if ((c->rp.props.send_reply_body) &&
+ (mhd_REPLY_CNTN_LOC_RESP_BUF == c->rp.cntn_loc))
{
- /* The complete header and some response data have been sent,
- * update both offsets. */
- mhd_assert (0 == c->rp.rsp_cntn_read_pos);
+ /* Send response headers alongside the response body, if the body
+ * data is available. */
+ mhd_assert (mhd_RESPONSE_CONTENT_DATA_BUFFER == resp->cntn_dtype);
mhd_assert (! c->rp.props.chunked);
- mhd_assert (c->rp.props.send_reply_body);
- c->state = MHD_CONNECTION_UNCHUNKED_BODY_READY;
- c->write_buffer_send_offset += wb_ready;
- c->rp.rsp_cntn_read_pos = sent - wb_ready;
- if (c->rp.rsp_cntn_read_pos == c->rp.response->cntn_size)
- c->state = MHD_CONNECTION_FULL_REPLY_SENT;
+
+ res = mhd_send_hdr_and_body (c,
+ wb_ready,
+ c->write_buffer
+ + c->write_buffer_send_offset,
+ false,
+ resp->cntn_size,
+ (const char *) resp->cntn.buf,
+ true,
+ &sent);
}
else
{
- c->write_buffer_send_offset += sent;
- // TODO: move it to data processing
- check_write_done (c,
- MHD_CONNECTION_HEADERS_SENT);
+ /* This is response for HEAD request or reply body is not allowed
+ * for any other reason or reply body is dynamically generated. */
+ /* Do not send the body data even if it's available. */
+ res = mhd_send_hdr_and_body (c,
+ wb_ready,
+ c->write_buffer
+ + c->write_buffer_send_offset,
+ false,
+ 0,
+ NULL,
+ ((0 == resp->cntn_size) ||
+ (! c->rp.props.send_reply_body)),
+ &sent);
}
-
-
- }
-
- }
- else if ((MHD_CONNECTION_UNCHUNKED_BODY_READY == c->state) ||
- (MHD_CONNECTION_CHUNKED_BODY_READY == c->state))
- {
- struct MHD_Response *const restrict resp = c->rp.response;
- mhd_assert (c->rp.props.send_reply_body);
- mhd_assert (c->rp.rsp_cntn_read_pos < resp->cntn_size);
- mhd_assert ((MHD_CONNECTION_CHUNKED_BODY_READY != c->state) || \
- (mhd_REPLY_CNTN_LOC_CONN_BUF == c->rp.cntn_loc));
- if (mhd_REPLY_CNTN_LOC_RESP_BUF == c->rp.cntn_loc)
- {
- mhd_assert (mhd_RESPONSE_CONTENT_DATA_BUFFER == resp->cntn_dtype);
-
- res = mhd_send_data (c,
- c->rp.rsp_cntn_read_pos - resp->cntn_size,
- (const char *) resp->cntn.buf
- + c->rp.rsp_cntn_read_pos,
- true,
- &sent);
- }
- else if (mhd_REPLY_CNTN_LOC_CONN_BUF == c->rp.cntn_loc)
- {
- mhd_assert (c->write_buffer_append_offset > \
- c->write_buffer_send_offset);
-
- res = mhd_send_data (c,
- c->write_buffer_append_offset
- - c->write_buffer_send_offset,
- c->write_buffer + c->write_buffer_send_offset,
- true,
- &sent);
- }
- else if (mhd_REPLY_CNTN_LOC_IOV == c->rp.cntn_loc)
- {
- mhd_assert (mhd_RESPONSE_CONTENT_DATA_IOVEC == resp->cntn_dtype);
-
- res = mhd_send_iovec (c,
- &c->rp.resp_iov,
- true,
- &sent);
- }
-#if defined(MHD_USE_SENDFILE)
- else if (mhd_REPLY_CNTN_LOC_FILE == c->rp.cntn_loc)
- {
- mhd_assert (mhd_RESPONSE_CONTENT_DATA_FILE == resp->cntn_dtype);
-
- res = mhd_send_sendfile (c, &sent);
- if (mhd_SOCKET_ERR_INTR == res)
+ if (mhd_SOCKET_ERR_NO_ERROR == res)
{
- if (! c->rp.response->cntn.file.use_sf)
- { /* Switch to filereader */
+ mhd_assert (MHD_CONNECTION_HEADERS_SENDING == c->state);
+
+ if (sent > wb_ready)
+ {
+ /* The complete header and some response data have been sent,
+ * update both offsets. */
+ mhd_assert (0 == c->rp.rsp_cntn_read_pos);
mhd_assert (! c->rp.props.chunked);
- c->rp.cntn_loc = mhd_REPLY_CNTN_LOC_CONN_BUF;
- c->state = MHD_CONNECTION_UNCHUNKED_BODY_UNREADY;
+ mhd_assert (c->rp.props.send_reply_body);
+ c->state = MHD_CONNECTION_UNCHUNKED_BODY_READY;
+ c->write_buffer_send_offset += wb_ready;
+ c->rp.rsp_cntn_read_pos = sent - wb_ready;
+ if (c->rp.rsp_cntn_read_pos == c->rp.response->cntn_size)
+ c->state = MHD_CONNECTION_FULL_REPLY_SENT;
+ }
+ else
+ {
+ c->write_buffer_send_offset += sent;
+ // TODO: move it to data processing
+ check_write_done (c,
+ MHD_CONNECTION_HEADERS_SENT);
}
}
}
-#endif /* MHD_USE_SENDFILE */
- else
+ break;
+ case MHD_CONNECTION_UNCHUNKED_BODY_READY:
+ case MHD_CONNECTION_CHUNKED_BODY_READY:
+ if (1)
{
- mhd_assert (0 && "Should be unreachable");
- res = mhd_SOCKET_ERR_INTERNAL;
- }
+ struct MHD_Response *const restrict resp = c->rp.response;
+ mhd_assert (c->rp.props.send_reply_body);
+ mhd_assert (c->rp.rsp_cntn_read_pos < resp->cntn_size);
+ mhd_assert ((MHD_CONNECTION_CHUNKED_BODY_READY != c->state) || \
+ (mhd_REPLY_CNTN_LOC_CONN_BUF == c->rp.cntn_loc));
+ if (mhd_REPLY_CNTN_LOC_RESP_BUF == c->rp.cntn_loc)
+ {
+ mhd_assert (mhd_RESPONSE_CONTENT_DATA_BUFFER == resp->cntn_dtype);
+
+ res = mhd_send_data (c,
+ c->rp.rsp_cntn_read_pos - resp->cntn_size,
+ (const char *) resp->cntn.buf
+ + c->rp.rsp_cntn_read_pos,
+ true,
+ &sent);
+ }
+ else if (mhd_REPLY_CNTN_LOC_CONN_BUF == c->rp.cntn_loc)
+ {
+ mhd_assert (c->write_buffer_append_offset > \
+ c->write_buffer_send_offset);
+
+ res = mhd_send_data (c,
+ c->write_buffer_append_offset
+ - c->write_buffer_send_offset,
+ c->write_buffer + c->write_buffer_send_offset,
+ true,
+ &sent);
+ }
+ else if (mhd_REPLY_CNTN_LOC_IOV == c->rp.cntn_loc)
+ {
+ mhd_assert (mhd_RESPONSE_CONTENT_DATA_IOVEC == resp->cntn_dtype);
- if (mhd_SOCKET_ERR_NO_ERROR == res)
- {
- if (mhd_REPLY_CNTN_LOC_CONN_BUF == c->rp.cntn_loc)
+ res = mhd_send_iovec (c,
+ &c->rp.resp_iov,
+ true,
+ &sent);
+ }
+ #if defined(MHD_USE_SENDFILE)
+ else if (mhd_REPLY_CNTN_LOC_FILE == c->rp.cntn_loc)
{
- enum MHD_CONNECTION_STATE next_state;
- c->write_buffer_send_offset += sent;
- // TODO: move it to data processing
- if (MHD_CONNECTION_CHUNKED_BODY_READY == c->state)
- next_state =
- (c->rp.response->cntn_size == c->rp.rsp_cntn_read_pos) ?
- MHD_CONNECTION_CHUNKED_BODY_SENT :
- MHD_CONNECTION_CHUNKED_BODY_UNREADY;
- else
- next_state =
- (c->rp.rsp_cntn_read_pos == resp->cntn_size) ?
- MHD_CONNECTION_FULL_REPLY_SENT :
- MHD_CONNECTION_UNCHUNKED_BODY_UNREADY;
- check_write_done (c,
- next_state);
+ mhd_assert (mhd_RESPONSE_CONTENT_DATA_FILE == resp->cntn_dtype);
+
+ res = mhd_send_sendfile (c, &sent);
+ if (mhd_SOCKET_ERR_INTR == res)
+ {
+ if (! c->rp.response->cntn.file.use_sf)
+ { /* Switch to filereader */
+ mhd_assert (! c->rp.props.chunked);
+ c->rp.cntn_loc = mhd_REPLY_CNTN_LOC_CONN_BUF;
+ c->state = MHD_CONNECTION_UNCHUNKED_BODY_UNREADY;
+ }
+ }
}
+ #endif /* MHD_USE_SENDFILE */
else
{
- c->rp.rsp_cntn_read_pos += sent;
- if (c->rp.rsp_cntn_read_pos == resp->cntn_size)
- c->state = MHD_CONNECTION_FULL_REPLY_SENT;
+ mhd_assert (0 && "Should be unreachable");
+ res = mhd_SOCKET_ERR_INTERNAL;
}
- }
- }
- else if (MHD_CONNECTION_FOOTERS_SENDING == c->state)
- {
+ if (mhd_SOCKET_ERR_NO_ERROR == res)
+ {
+ if (mhd_REPLY_CNTN_LOC_CONN_BUF == c->rp.cntn_loc)
+ {
+ enum MHD_CONNECTION_STATE next_state;
+ c->write_buffer_send_offset += sent;
+ // TODO: move it to data processing
+ if (MHD_CONNECTION_CHUNKED_BODY_READY == c->state)
+ next_state =
+ (c->rp.response->cntn_size == c->rp.rsp_cntn_read_pos) ?
+ MHD_CONNECTION_CHUNKED_BODY_SENT :
+ MHD_CONNECTION_CHUNKED_BODY_UNREADY;
+ else
+ next_state =
+ (c->rp.rsp_cntn_read_pos == resp->cntn_size) ?
+ MHD_CONNECTION_FULL_REPLY_SENT :
+ MHD_CONNECTION_UNCHUNKED_BODY_UNREADY;
+ check_write_done (c,
+ next_state);
+ }
+ else
+ {
+ c->rp.rsp_cntn_read_pos += sent;
+ if (c->rp.rsp_cntn_read_pos == resp->cntn_size)
+ c->state = MHD_CONNECTION_FULL_REPLY_SENT;
+ }
+ }
+ }
+ break;
+ case MHD_CONNECTION_FOOTERS_SENDING:
res = mhd_send_data (c,
c->write_buffer_append_offset
- c->write_buffer_send_offset,
@@ -287,11 +287,54 @@ mhd_conn_data_send (struct MHD_Connection *restrict c)
check_write_done (c,
MHD_CONNECTION_FULL_REPLY_SENT);
}
- }
- else
- {
+ break;
+#ifdef MHD_UPGRADE_SUPPORT
+ case MHD_CONNECTION_UPGRADE_HEADERS_SENDING:
+ res = mhd_send_data (c,
+ c->write_buffer_append_offset
+ - c->write_buffer_send_offset,
+ c->write_buffer
+ + c->write_buffer_send_offset,
+ true,
+ &sent);
+ if (mhd_SOCKET_ERR_NO_ERROR == res)
+ c->write_buffer_send_offset += sent;
+ break;
+#endif /* MHD_UPGRADE_SUPPORT */
+ case MHD_CONNECTION_INIT:
+ case MHD_CONNECTION_REQ_LINE_RECEIVING:
+ case MHD_CONNECTION_REQ_LINE_RECEIVED:
+ case MHD_CONNECTION_REQ_HEADERS_RECEIVING:
+ case MHD_CONNECTION_HEADERS_RECEIVED:
+ case MHD_CONNECTION_HEADERS_PROCESSED:
+ case MHD_CONNECTION_BODY_RECEIVING:
+ case MHD_CONNECTION_BODY_RECEIVED:
+ case MHD_CONNECTION_FOOTERS_RECEIVING:
+ case MHD_CONNECTION_FOOTERS_RECEIVED:
+ case MHD_CONNECTION_FULL_REQ_RECEIVED:
+ case MHD_CONNECTION_REQ_RECV_FINISHED:
+ case MHD_CONNECTION_START_REPLY:
+ case MHD_CONNECTION_HEADERS_SENT:
+ case MHD_CONNECTION_UNCHUNKED_BODY_UNREADY:
+ case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
+ case MHD_CONNECTION_CHUNKED_BODY_SENT:
+ case MHD_CONNECTION_FULL_REPLY_SENT:
+ case MHD_CONNECTION_PRE_CLOSING:
+ case MHD_CONNECTION_CLOSED:
+#ifdef MHD_UPGRADE_SUPPORT
+ case MHD_CONNECTION_UPGRADING:
+ case MHD_CONNECTION_UPGRADED:
+ case MHD_CONNECTION_UPGRADED_CLEANING:
+#endif /* MHD_UPGRADE_SUPPORT */
mhd_assert (0 && "Should be unreachable");
+ MHD_UNREACHABLE_;
+ res = mhd_SOCKET_ERR_INTERNAL;
+ break;
+ default:
+ mhd_assert (0 && "Impossible value");
+ MHD_UNREACHABLE_;
res = mhd_SOCKET_ERR_INTERNAL;
+ break;
}
if (mhd_SOCKET_ERR_NO_ERROR == res)
diff --git a/src/mhd2/events_process.c b/src/mhd2/events_process.c
@@ -694,6 +694,10 @@ poll_update_fds (struct MHD_Daemon *restrict d,
unsigned int i_s;
unsigned int i_c;
struct MHD_Connection *restrict c;
+#ifndef NDEBUG
+ unsigned int num_skipped = 0;
+#endif /* ! NDEBUG */
+
mhd_assert (mhd_POLL_TYPE_POLL == d->events.poll_type);
i_s = 0;
@@ -722,7 +726,12 @@ poll_update_fds (struct MHD_Daemon *restrict d,
unsigned short events; /* 'unsigned' for correct bits manipulations */
if (is_conn_excluded_from_http_comm (c))
+ {
+#ifndef NDEBUG
+ ++num_skipped;
+#endif /* ! NDEBUG */
continue;
+ }
mhd_assert ((i_c - i_s) < d->conns.cfg.count_limit);
mhd_assert (i_c < d->dbg.num_events_elements);
@@ -739,7 +748,7 @@ poll_update_fds (struct MHD_Daemon *restrict d,
d->events.data.poll.fds[i_c].events = (short) events;
++i_c;
}
- mhd_assert (d->conns.count == (i_c - i_s));
+ mhd_assert ((d->conns.count - num_skipped) == (i_c - i_s));
mhd_assert (i_c <= d->dbg.num_events_elements);
return i_c;
}
diff --git a/src/mhd2/mhd_action.h b/src/mhd2/mhd_action.h
@@ -213,14 +213,14 @@ struct mhd_PostParseActionData
#ifdef MHD_UPGRADE_SUPPORT
-struct MHD_UpgradeHandle; /* forward declaration */
+struct MHD_UpgradedHandle; /* forward declaration */
#ifndef MHD_UPGRADEHANDLER_DEFINED
typedef void
(*MHD_UpgradeHandler)(void *cls,
struct MHD_Request *MHD_RESTRICT request,
- struct MHD_UpgradeHandle *MHD_RESTRICT urh);
+ struct MHD_UpgradedHandle *MHD_RESTRICT urh);
#define MHD_UPGRADEHANDLER_DEFINED 1
#endif /* ! MHD_UPGRADEHANDLER_DEFINED */
diff --git a/src/mhd2/mhd_connection.h b/src/mhd2/mhd_connection.h
@@ -458,7 +458,7 @@ struct MHD_Connection
/**
* The data for handling HTTP-Upgraded connection
*/
- struct MHD_UpgradeHandle upgr;
+ struct MHD_UpgradedHandle upgr;
/**
* Double-linke list of HTTP-Upgraded connections waiting for clean-up
diff --git a/src/mhd2/mhd_sockets_macros.h b/src/mhd2/mhd_sockets_macros.h
@@ -97,6 +97,15 @@
# define mhd_SCKT_GET_LERR() (WSAGetLastError ())
#endif
+/**
+ * Set last socket error
+ */
+#if defined(MHD_POSIX_SOCKETS)
+# define mhd_SCKT_SET_LERR(err) do { errno = (err); } while (0)
+#elif defined(MHD_WINSOCK_SOCKETS)
+# define mhd_SCKT_SET_LERR(err) WSASetLastError ((err))
+#endif
+
#if defined(MHD_POSIX_SOCKETS)
# if defined(EAGAIN) && defined(EWOULDBLOCK) && \
((EWOULDBLOCK + 0) != (EAGAIN + 0))
@@ -217,6 +226,16 @@
# define mhd_SCKT_ERR_IS_PIPE(err) (WSAESHUTDOWN == (err))
#endif
+#if defined(MHD_POSIX_SOCKETS)
+# ifdef EINPROGRESS
+# define mhd_SCKT_ERR_IS_INPROGRESS(err) (EINPROGRESS == (err))
+# else
+# define mhd_SCKT_ERR_IS_INPROGRESS(err) ((void) (err), ! ! 0)
+# endif
+#elif defined(MHD_WINSOCK_SOCKETS)
+# define mhd_SCKT_ERR_IS_INPROGRESS(err) (WSAEINPROGRESS == (err))
+#endif
+
/**
* Check whether is given socket error is type of "incoming connection
* was disconnected before 'accept()' is called".
diff --git a/src/mhd2/mhd_upgrade.h b/src/mhd2/mhd_upgrade.h
@@ -37,7 +37,7 @@ struct MHD_Connection; /* forward declaration */
/**
* The data for "HTTP-upgraded" connection
*/
-struct MHD_UpgradeHandle
+struct MHD_UpgradedHandle
{
/**
* The pointer to the "connection" object
diff --git a/src/mhd2/stream_funcs.c b/src/mhd2/stream_funcs.c
@@ -806,7 +806,7 @@ mhd_conn_start_closing (struct MHD_Connection *restrict c,
#ifdef MHD_UPGRADE_SUPPORT
if (mhd_CONN_CLOSE_UPGRADE == reason)
{
- c->state = MHD_CONNECTION_UPGRADING;
+ mhd_assert (MHD_CONNECTION_UPGRADING == c->state);
c->event_loop_info = MHD_EVENT_LOOP_INFO_UPGRADED;
}
else
@@ -883,6 +883,24 @@ mhd_conn_pre_clean_part1 (struct MHD_Connection *restrict c)
mhd_stream_call_dcc_cleanup_if_needed (c);
if (NULL != c->rq.cntn.lbuf.data)
mhd_daemon_free_lbuf (c->daemon, &(c->rq.cntn.lbuf));
+
+#ifdef MHD_USE_EPOLL
+ if (mhd_POLL_TYPE_EPOLL == c->daemon->events.poll_type)
+ {
+ struct epoll_event event;
+
+ event.events = 0;
+ event.data.ptr = NULL;
+ if (0 != epoll_ctl (c->daemon->events.data.epoll.e_fd,
+ EPOLL_CTL_DEL,
+ c->socket_fd,
+ &event))
+ {
+ mhd_LOG_MSG (c->daemon, MHD_SC_EPOLL_CTL_REMOVE_FAILED,
+ "Failed to remove connection socket from epoll.");
+ }
+ }
+#endif /* MHD_USE_EPOLL */
}
@@ -895,6 +913,9 @@ mhd_conn_pre_clean (struct MHD_Connection *restrict c)
mhd_assert (c->dbg.closing_started);
mhd_assert (! c->dbg.pre_cleaned);
+#ifdef MHD_UPGRADE_SUPPORT
+ if (NULL == c->upgr.c)
+#endif
mhd_conn_pre_clean_part1 (c);
if (NULL != c->rp.resp_iov.iov)
@@ -918,24 +939,6 @@ mhd_conn_pre_clean (struct MHD_Connection *restrict c)
mhd_pool_destroy (c->pool);
c->pool = NULL;
-#ifdef MHD_USE_EPOLL
- if (mhd_POLL_TYPE_EPOLL == c->daemon->events.poll_type)
- {
- struct epoll_event event;
-
- event.events = 0;
- event.data.ptr = NULL;
- if (0 != epoll_ctl (c->daemon->events.data.epoll.e_fd,
- EPOLL_CTL_DEL,
- c->socket_fd,
- &event))
- {
- mhd_LOG_MSG (c->daemon, MHD_SC_EPOLL_CTL_REMOVE_FAILED,
- "Failed to remove connection socket from epoll.");
- }
- }
-#endif /* MHD_USE_EPOLL */
-
c->state = MHD_CONNECTION_CLOSED;
#ifndef NDEBUG
c->dbg.pre_cleaned = true;
diff --git a/src/mhd2/upgrade_net.c b/src/mhd2/upgrade_net.c
@@ -1,531 +0,0 @@
-/*
- This file is part of GNU libmicrohttpd
- Copyright (C) 2024 Evgeny Grin (Karlson2k) & Christian Grothoff
-
- GNU libmicrohttpd 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.
-
- GNU libmicrohttpd 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 src/mhd2/upgrade_net.c
- * @brief The implementation of functions for network data exchange
- * for HTTP Upgraded connections
- * @author Karlson2k (Evgeny Grin)
- * @author Christian Grothoff
- */
-
-#include "mhd_sys_options.h"
-
-#include "sys_bool_type.h"
-#include "sys_base_types.h"
-
-#include "sys_poll.h"
-#ifndef MHD_USE_POLL
-# include "sys_select.h"
-#endif
-#include "mhd_limits.h"
-
-#include "mhd_sockets_macros.h"
-
-#include "mhd_upgrade.h"
-#include "mhd_connection.h"
-#include "mhd_locks.h"
-
-#include "mhd_recv.h"
-#include "mhd_send.h"
-#include "mhd_mono_clock.h"
-
-#include "mhd_public_api.h"
-
-
-#if ! defined (MHD_USE_POLL) && \
- (defined(MHD_POSIX_SOCKETS) || ! defined(MHD_USE_SELECT))
-# if defined(_WIN32) || defined(HAVE_NANOSLEEP) || defined(HAVE_USLEEP)
-# define mhd_HAVE_MHD_SLEEP 1
-
-/**
- * Pause execution for specified number of milliseconds.
- *
- * @param millisec the number of milliseconds to sleep
- */
-static void
-mhd_sleep (uint_fast32_t millisec)
-{
-#if defined(_WIN32)
- Sleep (millisec);
-#elif defined(HAVE_NANOSLEEP)
- struct timespec slp = {millisec / 1000, (millisec % 1000) * 1000000};
- struct timespec rmn;
- int num_retries = 0;
- while (0 != nanosleep (&slp, &rmn))
- {
- if (EINTR != errno)
- externalErrorExit ();
- if (num_retries++ > 8)
- break;
- slp = rmn;
- }
-#elif defined(HAVE_USLEEP)
- uint64_t us = millisec * 1000;
- do
- {
- uint64_t this_sleep;
- if (999999 < us)
- this_sleep = 999999;
- else
- this_sleep = us;
- /* Ignore return value as it could be void */
- usleep (this_sleep);
- us -= this_sleep;
- } while (us > 0);
-#endif
-}
-
-
-#endif /* _WIN32 || HAVE_NANOSLEEP || HAVE_USLEEP */
-#endif /* ! MHD_USE_POLL) && (MHD_POSIX_SOCKETS || ! MHD_USE_SELECT) */
-
-
-MHD_EXTERN_
-MHD_FN_PAR_NONNULL_ALL_
-MHD_FN_PAR_OUT_SIZE_ (3,2)
-MHD_FN_PAR_OUT_ (4) enum MHD_StatusCode
-MHD_upgraded_recv (struct MHD_UpgradeHandle *MHD_RESTRICT urh,
- size_t recv_buf_size,
- void *MHD_RESTRICT recv_buf,
- size_t *MHD_RESTRICT received_size,
- uint_fast64_t max_wait_millisec)
-{
- struct MHD_Connection *restrict c = urh->c;
-#if defined(MHD_USE_POLL) || defined(MHD_USE_SELECT)
- const MHD_Socket socket_fd = c->socket_fd;
-#endif /* MHD_USE_POLL || MHD_USE_SELECT */
- char *restrict buf_char = (char *) recv_buf;
- size_t last_block_size;
- enum mhd_SocketError res;
-
- *received_size = 0;
-
- if (&(c->upgr) != urh)
- return MHD_SC_UPGRADED_HANDLE_INVALID;
- if (MHD_CONNECTION_UPGRADED != c->state)
- return MHD_SC_UPGRADED_HANDLE_INVALID;
-
- if (0 == recv_buf_size)
- return MHD_SC_OK;
-
- if (NULL != c->read_buffer)
- {
- mhd_mutex_lock_chk (&(urh->lock));
- if (0 != c->read_buffer_offset) /* Re-check under the lock */
- {
- if (recv_buf_size < c->read_buffer_offset)
- {
- memcpy (buf_char, c->read_buffer, recv_buf_size);
- last_block_size = recv_buf_size;
- c->read_buffer += recv_buf_size;
- c->read_buffer_offset -= recv_buf_size;
- c->read_buffer_size -= recv_buf_size;
- }
- else
- {
- /* recv_buf_size >= c->read_buffer_offset */
- memcpy (buf_char, c->read_buffer, c->read_buffer_offset);
- last_block_size = c->read_buffer_offset;
- c->read_buffer_offset = 0;
- c->read_buffer_size = 0;
- /* Do not deallocate the read buffer to save the time under the lock.
- The connection memory pool will not be used anyway. */
- c->read_buffer = NULL;
- }
- }
- mhd_mutex_unlock_chk (&(urh->lock));
- *received_size = last_block_size;
- if (recv_buf_size == last_block_size)
- return MHD_SC_OK;
- }
-
- last_block_size = 0;
- res = mhd_recv (c,
- recv_buf_size - *received_size,
- buf_char + *received_size,
- &last_block_size);
- if (mhd_SOCKET_ERR_NO_ERROR == res)
- {
- if (0 == last_block_size)
- c->sk_rmt_shut_wr = true;
- *received_size += last_block_size;
- return MHD_SC_OK;
- }
- else if (0 != *received_size)
- return MHD_SC_OK;
-
- if (! mhd_SOCKET_ERR_IS_HARD (res))
- {
- while (0 != max_wait_millisec)
- {
-#if defined(MHD_USE_POLL)
- if (1)
- {
- struct pollfd fds[1];
- int poll_wait;
- int poll_res;
- int wait_err;
-
- if (MHD_WAIT_INDEFINITELY <= max_wait_millisec)
- poll_wait = -1;
- else
- {
- poll_wait = (int) max_wait_millisec;
- if ((max_wait_millisec != (uint_fast64_t) poll_wait) ||
- (0 > poll_wait))
- poll_wait = INT_MAX;
- }
- fds[0].fd = socket_fd;
- fds[0].events = POLLIN;
-
- poll_res = mhd_poll (fds,
- 1,
- poll_wait);
- if ((0 >= poll_res) &&
- (0 != *received_size))
- return MHD_SC_OK;
- if (0 == poll_res)
- return MHD_SC_UPGRADED_NET_TIMEOUT;
-
- wait_err = mhd_SCKT_GET_LERR ();
- if (! mhd_SCKT_ERR_IS_EAGAIN (wait_err) &&
- ! mhd_SCKT_ERR_IS_EINTR (wait_err) &&
- ! mhd_SCKT_ERR_IS_LOW_RESOURCES (wait_err))
- return MHD_SC_UPGRADED_NET_HARD_ERROR;
- max_wait_millisec = 0; /* Re-try only one time */
- }
-#else /* ! MHD_USE_POLL */
- bool use_select;
-# if defined(MHD_USE_SELECT)
-# ifdef MHD_POSIX_SOCKETS
- use_select = socket_fd < FD_SETSIZE;
-# else /* MHD_WINSOCK_SOCKETS */
- use_select = true;
-# endif /* MHD_WINSOCK_SOCKETS */
- if (use_select)
- {
- fd_set rfds;
- int sel_res;
- int wait_err;
- struct timeval tmvl;
-
-# ifdef MHD_POSIX_SOCKETS
- tmvl.tv_sec = (long) (max_wait_millisec / 1000);
-# else /* MHD_WINSOCK_SOCKETS */
- tmvl.tv_sec = (long) (max_wait_millisec / 1000);
-# endif /* MHD_WINSOCK_SOCKETS */
- if ((max_wait_millisec / 1000 != (uint_fast64_t) tmvl.tv_sec) ||
- (0 > tmvl.tv_sec))
- {
- tmvl.tv_sec = mhd_TIMEVAL_TV_SEC_MAX;
- tmvl.tv_usec = 0;
- }
- else
- tmvl.tv_usec = (int) (max_wait_millisec % 1000);
- FD_ZERO (&rfds);
- FD_SET (socket_fd, &rfds);
-
- sel_res = select (c->socket_fd + 1,
- &rfds,
- NULL,
- NULL,
- (MHD_WAIT_INDEFINITELY <= max_wait_millisec) ?
- NULL : &tmvl);
-
- if ((0 >= sel_res) &&
- (0 != *received_size))
- return MHD_SC_OK;
- if (0 == sel_res)
- return MHD_SC_UPGRADED_NET_TIMEOUT;
-
- wait_err = mhd_SCKT_GET_LERR ();
- if (! mhd_SCKT_ERR_IS_EAGAIN (wait_err) &&
- ! mhd_SCKT_ERR_IS_EINTR (wait_err) &&
- ! mhd_SCKT_ERR_IS_LOW_RESOURCES (wait_err))
- return MHD_SC_UPGRADED_NET_HARD_ERROR;
- max_wait_millisec = 0; /* Re-try only one time */
- }
-# else /* ! MHD_USE_SELECT */
- use_select = false;
-# endif /* ! MHD_USE_SELECT */
-# if ! defined(MHD_WINSOCK_SOCKETS) || ! defined(MHD_USE_SELECT)
- if (! use_select)
- {
-# ifndef mhd_HAVE_MHD_SLEEP
- return MHD_SC_UPGRADED_WAITING_NOT_SUPPORTED;
-# else /* mhd_HAVE_MHD_SLEEP */
- uint_fast32_t wait_millisec = max_wait_millisec;
-
- if (wait_millisec > 100)
- wait_millisec = 100;
- mhd_sleep (wait_millisec);
- if (MHD_WAIT_INDEFINITELY > max_wait_millisec)
- max_wait_millisec -= wait_millisec;
-# endif /* mhd_HAVE_MHD_SLEEP */
- }
-# endif /* ! MHD_WINSOCK_SOCKETS) || ! MHD_USE_SELECT */
-#endif /* ! MHD_USE_POLL */
- last_block_size = 0;
- res = mhd_recv (c,
- recv_buf_size - *received_size,
- buf_char + *received_size,
- &last_block_size);
- if (mhd_SOCKET_ERR_NO_ERROR == res)
- {
- if (0 == last_block_size)
- c->sk_rmt_shut_wr = true;
- *received_size += last_block_size;
- return MHD_SC_OK;
- }
- }
- }
- if (! mhd_SOCKET_ERR_IS_HARD (res))
- return MHD_SC_UPGRADED_NET_TIMEOUT;
- if (mhd_SOCKET_ERR_REMT_DISCONN == res)
- return MHD_SC_UPGRADED_NET_CONN_CLOSED;
- if (mhd_SOCKET_ERR_TLS == res)
- return MHD_SC_UPGRADED_TLS_ERROR;
- if (! mhd_SOCKET_ERR_IS_BAD (res))
- return MHD_SC_UPGRADED_NET_CONN_BROKEN;
-
- return MHD_SC_UPGRADED_NET_HARD_ERROR;
-}
-
-
-MHD_EXTERN_
-MHD_FN_PAR_NONNULL_ALL_
-MHD_FN_PAR_IN_SIZE_ (3,2)
-MHD_FN_PAR_OUT_ (4) enum MHD_StatusCode
-MHD_upgraded_send (struct MHD_UpgradeHandle *MHD_RESTRICT urh,
- size_t send_buf_size,
- const void *MHD_RESTRICT send_buf,
- size_t *MHD_RESTRICT sent_size,
- uint_fast64_t max_wait_millisec,
- enum MHD_Bool more_data_to_come)
-{
- struct MHD_Connection *restrict c = urh->c;
-#if defined(MHD_USE_POLL) || defined(MHD_USE_SELECT)
- const MHD_Socket socket_fd = c->socket_fd;
-#endif /* MHD_USE_POLL || MHD_USE_SELECT */
- const char *restrict buf_char = (const char *) send_buf;
- const bool push_data = (MHD_NO == more_data_to_come);
- bool finish_time_set;
- bool wait_indefinitely;
- uint_fast64_t finish_time = 0;
-
- *sent_size = 0;
-
- if (&(c->upgr) != urh)
- return MHD_SC_UPGRADED_HANDLE_INVALID;
- if (MHD_CONNECTION_UPGRADED != c->state)
- return MHD_SC_UPGRADED_HANDLE_INVALID;
-
- finish_time_set = false;
- wait_indefinitely = (MHD_WAIT_INDEFINITELY <= max_wait_millisec);
-
- while (*sent_size != send_buf_size)
- {
- enum mhd_SocketError res;
- size_t last_block_size;
- uint_fast64_t wait_left;
-#if ! defined(MHD_USE_POLL)
- bool use_select;
-#endif /* ! MHD_USE_POLL */
-
- last_block_size = 0;
- res = mhd_send_data (c,
- send_buf_size - *sent_size,
- buf_char + *sent_size,
- push_data,
- &last_block_size);
- if (mhd_SOCKET_ERR_NO_ERROR == res)
- *sent_size += last_block_size;
- else if (mhd_SOCKET_ERR_IS_HARD (res))
- {
- if (0 != *sent_size)
- return MHD_SC_OK;
-
- if (mhd_SOCKET_ERR_REMT_DISCONN == res)
- return MHD_SC_UPGRADED_NET_CONN_CLOSED;
- if (mhd_SOCKET_ERR_TLS == res)
- return MHD_SC_UPGRADED_TLS_ERROR;
- if (! mhd_SOCKET_ERR_IS_BAD (res))
- return MHD_SC_UPGRADED_NET_CONN_BROKEN;
-
- return MHD_SC_UPGRADED_NET_HARD_ERROR;
- }
-
- if (0 == max_wait_millisec)
- {
- if (0 != *sent_size)
- return MHD_SC_OK;
-
- return MHD_SC_UPGRADED_NET_TIMEOUT;
- }
-
- if (! wait_indefinitely)
- {
- uint_fast64_t cur_time;
- cur_time = MHD_monotonic_msec_counter ();
-
- if (! finish_time_set)
- {
- finish_time = cur_time + max_wait_millisec;
- wait_left = max_wait_millisec;
- }
- else
- {
- wait_left = finish_time - cur_time;
- if (wait_left > cur_time - finish_time)
- return MHD_SC_UPGRADED_NET_TIMEOUT;
- }
- }
-
-#if defined(MHD_USE_POLL)
- if (1)
- {
- struct pollfd fds[1];
- int poll_wait;
- int poll_res;
- int wait_err;
-
- if (wait_indefinitely)
- poll_wait = -1;
- else
- {
- poll_wait = (int) wait_left;
- if ((wait_left != (uint_fast64_t) poll_wait) ||
- (0 > poll_wait))
- poll_wait = INT_MAX;
- }
- fds[0].fd = socket_fd;
- fds[0].events = POLLOUT;
-
- poll_res = mhd_poll (fds,
- 1,
- poll_wait);
- if (0 < poll_res)
- continue;
- if (0 == poll_res)
- {
- if (wait_indefinitely ||
- (INT_MAX == poll_wait))
- continue;
- if (0 != *sent_size)
- return MHD_SC_OK;
- return MHD_SC_UPGRADED_NET_TIMEOUT;
- }
-
- wait_err = mhd_SCKT_GET_LERR ();
- if (! mhd_SCKT_ERR_IS_EAGAIN (wait_err) &&
- ! mhd_SCKT_ERR_IS_EINTR (wait_err) &&
- ! mhd_SCKT_ERR_IS_LOW_RESOURCES (wait_err))
- return MHD_SC_UPGRADED_NET_HARD_ERROR;
- }
-#else /* ! MHD_USE_POLL */
-# if defined(MHD_USE_SELECT)
-# ifdef MHD_POSIX_SOCKETS
- use_select = socket_fd < FD_SETSIZE;
-# else /* MHD_WINSOCK_SOCKETS */
- use_select = true;
-# endif /* MHD_WINSOCK_SOCKETS */
- if (use_select)
- {
- fd_set wfds;
- int sel_res;
- int wait_err;
- struct timeval tmvl;
- bool max_wait;
-
- max_wait = false;
- if (wait_indefinitely)
- {
- tmvl.tv_sec = 0;
- tmvl.tv_usec = 0;
- }
- else
- {
-# ifdef MHD_POSIX_SOCKETS
- tmvl.tv_sec = (long) (max_wait_millisec / 1000);
-# else /* MHD_WINSOCK_SOCKETS */
- tmvl.tv_sec = (long) (max_wait_millisec / 1000);
-# endif /* MHD_WINSOCK_SOCKETS */
- if ((max_wait_millisec / 1000 != (uint_fast64_t) tmvl.tv_sec) ||
- (0 > tmvl.tv_sec))
- {
- tmvl.tv_sec = mhd_TIMEVAL_TV_SEC_MAX;
- tmvl.tv_usec = 0;
- max_wait = true;
- }
- else
- tmvl.tv_usec = (int) (max_wait_millisec % 1000);
- }
- FD_ZERO (&wfds);
- FD_SET (socket_fd, &wfds);
-
- sel_res = select (c->socket_fd + 1,
- NULL,
- &wfds,
- NULL,
- wait_indefinitely ? NULL : &tmvl);
-
- if (0 < sel_res)
- continue;
- if (0 == sel_res)
- {
- if (wait_indefinitely ||
- max_wait)
- continue;
- if (0 != *sent_size)
- return MHD_SC_OK;
- return MHD_SC_UPGRADED_NET_TIMEOUT;
- }
-
- wait_err = mhd_SCKT_GET_LERR ();
- if (! mhd_SCKT_ERR_IS_EAGAIN (wait_err) &&
- ! mhd_SCKT_ERR_IS_EINTR (wait_err) &&
- ! mhd_SCKT_ERR_IS_LOW_RESOURCES (wait_err))
- return MHD_SC_UPGRADED_NET_HARD_ERROR;
- }
-# else /* ! MHD_USE_SELECT */
- use_select = false;
-# endif /* ! MHD_USE_SELECT */
-# if ! defined(MHD_WINSOCK_SOCKETS) || ! defined(MHD_USE_SELECT)
- if (! use_select)
- {
-# ifndef mhd_HAVE_MHD_SLEEP
- return MHD_SC_UPGRADED_WAITING_NOT_SUPPORTED;
-# else /* mhd_HAVE_MHD_SLEEP */
- uint_fast32_t wait_millisec = max_wait_millisec;
-
- if (wait_millisec > 100)
- wait_millisec = 100;
- mhd_sleep (wait_millisec);
- if (MHD_WAIT_INDEFINITELY > max_wait_millisec)
- max_wait_millisec -= wait_millisec;
-# endif /* mhd_HAVE_MHD_SLEEP */
- }
-# endif /* ! MHD_WINSOCK_SOCKETS) || ! MHD_USE_SELECT */
-#endif /* ! MHD_USE_POLL */
- }
-
- return MHD_SC_OK;
-}
diff --git a/src/mhd2/upgrade_proc.c b/src/mhd2/upgrade_proc.c
@@ -73,7 +73,7 @@ mhd_upgrade_finish_switch_to_upgraded (struct MHD_Connection *restrict c)
mhd_assert (MHD_CONNECTION_UPGRADING == c->state);
mhd_assert (NULL != c->write_buffer);
mhd_assert ((0 != c->read_buffer_offset) || (NULL == c->read_buffer));
- mhd_assert (c == c->upgr.c);
+ mhd_assert (NULL == c->upgr.c);
pupgr_data = (mhd_ACTION_UPGRADE == c->rq.app_act.head_act.act) ?
&(c->rq.app_act.head_act.data.upgrd) :
@@ -116,7 +116,7 @@ mhd_upgrade_finish_switch_to_upgraded (struct MHD_Connection *restrict c)
MHD_EXTERN_
MHD_FN_PAR_NONNULL_ (1) enum MHD_StatusCode
-MHD_upgraded_close (struct MHD_UpgradeHandle *urh)
+MHD_upgraded_close (struct MHD_UpgradedHandle *urh)
{
struct MHD_Connection *const restrict c = urh->c;
struct MHD_Daemon *const restrict d = c->daemon;
diff --git a/src/mhd2/upgraded_net.c b/src/mhd2/upgraded_net.c
@@ -0,0 +1,537 @@
+/*
+ This file is part of GNU libmicrohttpd
+ Copyright (C) 2024 Evgeny Grin (Karlson2k) & Christian Grothoff
+
+ GNU libmicrohttpd 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.
+
+ GNU libmicrohttpd 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 src/mhd2/upgraded_net.c
+ * @brief The implementation of functions for network data exchange
+ * for HTTP Upgraded connections
+ * @author Karlson2k (Evgeny Grin)
+ * @author Christian Grothoff
+ */
+
+#include "mhd_sys_options.h"
+
+#include "sys_bool_type.h"
+#include "sys_base_types.h"
+
+#include "sys_poll.h"
+#ifndef MHD_USE_POLL
+# include "sys_select.h"
+#endif
+#include "mhd_limits.h"
+
+#include "mhd_sockets_macros.h"
+
+#include "mhd_upgrade.h"
+#include "mhd_connection.h"
+#include "mhd_locks.h"
+
+#include "mhd_recv.h"
+#include "mhd_send.h"
+#include "mhd_mono_clock.h"
+
+#include "mhd_public_api.h"
+
+
+#if ! defined (MHD_USE_POLL) && \
+ (defined(MHD_POSIX_SOCKETS) || ! defined(MHD_USE_SELECT))
+# if defined(_WIN32) || defined(HAVE_NANOSLEEP) || defined(HAVE_USLEEP)
+# define mhd_HAVE_MHD_SLEEP 1
+
+/**
+ * Pause execution for specified number of milliseconds.
+ *
+ * @param millisec the number of milliseconds to sleep
+ */
+static void
+mhd_sleep (uint_fast32_t millisec)
+{
+#if defined(_WIN32)
+ Sleep (millisec);
+#elif defined(HAVE_NANOSLEEP)
+ struct timespec slp = {millisec / 1000, (millisec % 1000) * 1000000};
+ struct timespec rmn;
+ int num_retries = 0;
+ while (0 != nanosleep (&slp, &rmn))
+ {
+ if (EINTR != errno)
+ externalErrorExit ();
+ if (num_retries++ > 8)
+ break;
+ slp = rmn;
+ }
+#elif defined(HAVE_USLEEP)
+ uint64_t us = millisec * 1000;
+ do
+ {
+ uint64_t this_sleep;
+ if (999999 < us)
+ this_sleep = 999999;
+ else
+ this_sleep = us;
+ /* Ignore return value as it could be void */
+ usleep (this_sleep);
+ us -= this_sleep;
+ } while (us > 0);
+#endif
+}
+
+
+#endif /* _WIN32 || HAVE_NANOSLEEP || HAVE_USLEEP */
+#endif /* ! MHD_USE_POLL) && (MHD_POSIX_SOCKETS || ! MHD_USE_SELECT) */
+
+
+MHD_EXTERN_
+MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_OUT_SIZE_ (3,2)
+MHD_FN_PAR_OUT_ (4) enum MHD_StatusCode
+MHD_upgraded_recv (struct MHD_UpgradedHandle *MHD_RESTRICT urh,
+ size_t recv_buf_size,
+ void *MHD_RESTRICT recv_buf,
+ size_t *MHD_RESTRICT received_size,
+ uint_fast64_t max_wait_millisec)
+{
+ struct MHD_Connection *restrict c = urh->c;
+#if defined(MHD_USE_POLL) || defined(MHD_USE_SELECT)
+ const MHD_Socket socket_fd = c->socket_fd;
+#endif /* MHD_USE_POLL || MHD_USE_SELECT */
+ char *restrict buf_char = (char *) recv_buf;
+ size_t last_block_size;
+ enum mhd_SocketError res;
+
+ *received_size = 0;
+
+ if (&(c->upgr) != urh)
+ return MHD_SC_UPGRADED_HANDLE_INVALID;
+ if (MHD_CONNECTION_UPGRADED != c->state)
+ return MHD_SC_UPGRADED_HANDLE_INVALID;
+
+ if (0 == recv_buf_size)
+ return MHD_SC_OK;
+
+ if (NULL != c->read_buffer)
+ {
+ mhd_mutex_lock_chk (&(urh->lock));
+ if (0 != c->read_buffer_offset) /* Re-check under the lock */
+ {
+ if (recv_buf_size < c->read_buffer_offset)
+ {
+ memcpy (buf_char, c->read_buffer, recv_buf_size);
+ last_block_size = recv_buf_size;
+ c->read_buffer += recv_buf_size;
+ c->read_buffer_offset -= recv_buf_size;
+ c->read_buffer_size -= recv_buf_size;
+ }
+ else
+ {
+ /* recv_buf_size >= c->read_buffer_offset */
+ memcpy (buf_char, c->read_buffer, c->read_buffer_offset);
+ last_block_size = c->read_buffer_offset;
+ c->read_buffer_offset = 0;
+ c->read_buffer_size = 0;
+ /* Do not deallocate the read buffer to save the time under the lock.
+ The connection memory pool will not be used anyway. */
+ c->read_buffer = NULL;
+ }
+ }
+ else
+ last_block_size = 0;
+ mhd_mutex_unlock_chk (&(urh->lock));
+ *received_size = last_block_size;
+ if (recv_buf_size == last_block_size)
+ return MHD_SC_OK;
+ }
+
+ last_block_size = 0;
+ res = mhd_recv (c,
+ recv_buf_size - *received_size,
+ buf_char + *received_size,
+ &last_block_size);
+ if (mhd_SOCKET_ERR_NO_ERROR == res)
+ {
+ if (0 == last_block_size)
+ c->sk_rmt_shut_wr = true;
+ *received_size += last_block_size;
+ return MHD_SC_OK;
+ }
+ else if (0 != *received_size)
+ return MHD_SC_OK;
+
+ if (! mhd_SOCKET_ERR_IS_HARD (res))
+ {
+ while (0 != max_wait_millisec)
+ {
+#if defined(MHD_USE_POLL)
+ if (1)
+ {
+ struct pollfd fds[1];
+ int poll_wait;
+ int poll_res;
+ int wait_err;
+
+ if (MHD_WAIT_INDEFINITELY <= max_wait_millisec)
+ poll_wait = -1;
+ else
+ {
+ poll_wait = (int) max_wait_millisec;
+ if ((max_wait_millisec != (uint_fast64_t) poll_wait) ||
+ (0 > poll_wait))
+ poll_wait = INT_MAX;
+ }
+ fds[0].fd = socket_fd;
+ fds[0].events = POLLIN;
+
+ poll_res = mhd_poll (fds,
+ 1,
+ poll_wait);
+ if ((0 >= poll_res) &&
+ (0 != *received_size))
+ return MHD_SC_OK;
+ else if (0 == poll_res)
+ return MHD_SC_UPGRADED_NET_TIMEOUT;
+ else if (0 > poll_res)
+ {
+ wait_err = mhd_SCKT_GET_LERR ();
+ if (! mhd_SCKT_ERR_IS_EAGAIN (wait_err) &&
+ ! mhd_SCKT_ERR_IS_EINTR (wait_err) &&
+ ! mhd_SCKT_ERR_IS_LOW_RESOURCES (wait_err))
+ return MHD_SC_UPGRADED_NET_HARD_ERROR;
+ }
+ max_wait_millisec = 0; /* Re-try only one time */
+ }
+#else /* ! MHD_USE_POLL */
+# if defined(MHD_USE_SELECT)
+ bool use_select;
+# ifdef MHD_POSIX_SOCKETS
+ use_select = (socket_fd < FD_SETSIZE);
+# else /* MHD_WINSOCK_SOCKETS */
+ use_select = true;
+# endif /* MHD_WINSOCK_SOCKETS */
+ if (use_select)
+ {
+ fd_set rfds;
+ int sel_res;
+ int wait_err;
+ struct timeval tmvl;
+
+# ifdef MHD_POSIX_SOCKETS
+ tmvl.tv_sec = (time_t) (max_wait_millisec / 1000);
+# else /* MHD_WINSOCK_SOCKETS */
+ tmvl.tv_sec = (long) (max_wait_millisec / 1000);
+# endif /* MHD_WINSOCK_SOCKETS */
+ if ((max_wait_millisec / 1000 != (uint_fast64_t) tmvl.tv_sec) ||
+ (0 > tmvl.tv_sec))
+ {
+ tmvl.tv_sec = mhd_TIMEVAL_TV_SEC_MAX;
+ tmvl.tv_usec = 0;
+ }
+ else
+ tmvl.tv_usec = (int) (max_wait_millisec % 1000);
+ FD_ZERO (&rfds);
+ FD_SET (socket_fd, &rfds);
+
+ sel_res = select (c->socket_fd + 1,
+ &rfds,
+ NULL,
+ NULL,
+ (MHD_WAIT_INDEFINITELY <= max_wait_millisec) ?
+ NULL : &tmvl);
+
+ if ((0 >= sel_res) &&
+ (0 != *received_size))
+ return MHD_SC_OK;
+ else if (0 == sel_res)
+ return MHD_SC_UPGRADED_NET_TIMEOUT;
+ else if (0 > sel_res)
+ {
+ wait_err = mhd_SCKT_GET_LERR ();
+ if (! mhd_SCKT_ERR_IS_EAGAIN (wait_err) &&
+ ! mhd_SCKT_ERR_IS_EINTR (wait_err) &&
+ ! mhd_SCKT_ERR_IS_LOW_RESOURCES (wait_err))
+ return MHD_SC_UPGRADED_NET_HARD_ERROR;
+ }
+ max_wait_millisec = 0; /* Re-try only one time */
+ }
+ else /* combined with the next 'if()' */
+# endif /* MHD_USE_SELECT */
+ if (1)
+ {
+# ifndef mhd_HAVE_MHD_SLEEP
+ return MHD_SC_UPGRADED_WAITING_NOT_SUPPORTED;
+# else /* mhd_HAVE_MHD_SLEEP */
+ uint_fast32_t wait_millisec = (uint_fast32_t) max_wait_millisec;
+
+ if ((wait_millisec != max_wait_millisec) ||
+ (wait_millisec > 100))
+ wait_millisec = 100;
+ mhd_sleep (wait_millisec);
+ if (MHD_WAIT_INDEFINITELY > max_wait_millisec)
+ max_wait_millisec -= wait_millisec;
+# endif /* mhd_HAVE_MHD_SLEEP */
+ }
+#endif /* ! MHD_USE_POLL */
+ last_block_size = 0;
+ res = mhd_recv (c,
+ recv_buf_size - *received_size,
+ buf_char + *received_size,
+ &last_block_size);
+ if (mhd_SOCKET_ERR_NO_ERROR == res)
+ {
+ if (0 == last_block_size)
+ c->sk_rmt_shut_wr = true;
+ *received_size += last_block_size;
+ return MHD_SC_OK;
+ }
+ }
+ }
+ if (! mhd_SOCKET_ERR_IS_HARD (res))
+ return MHD_SC_UPGRADED_NET_TIMEOUT;
+ if (mhd_SOCKET_ERR_REMT_DISCONN == res)
+ return MHD_SC_UPGRADED_NET_CONN_CLOSED;
+ if (mhd_SOCKET_ERR_TLS == res)
+ return MHD_SC_UPGRADED_TLS_ERROR;
+ if (! mhd_SOCKET_ERR_IS_BAD (res))
+ return MHD_SC_UPGRADED_NET_CONN_BROKEN;
+
+ return MHD_SC_UPGRADED_NET_HARD_ERROR;
+}
+
+
+MHD_EXTERN_
+MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_IN_SIZE_ (3,2)
+MHD_FN_PAR_OUT_ (4) enum MHD_StatusCode
+MHD_upgraded_send (struct MHD_UpgradedHandle *MHD_RESTRICT urh,
+ size_t send_buf_size,
+ const void *MHD_RESTRICT send_buf,
+ size_t *MHD_RESTRICT sent_size,
+ uint_fast64_t max_wait_millisec,
+ enum MHD_Bool more_data_to_come)
+{
+ struct MHD_Connection *restrict c = urh->c;
+#if defined(MHD_USE_POLL) || defined(MHD_USE_SELECT)
+ const MHD_Socket socket_fd = c->socket_fd;
+#endif /* MHD_USE_POLL || MHD_USE_SELECT */
+ const char *restrict buf_char = (const char *) send_buf;
+ const bool push_data = (MHD_NO == more_data_to_come);
+ bool finish_time_set;
+ bool wait_indefinitely;
+ uint_fast64_t finish_time = 0;
+
+ *sent_size = 0;
+
+ if (&(c->upgr) != urh)
+ return MHD_SC_UPGRADED_HANDLE_INVALID;
+ if (MHD_CONNECTION_UPGRADED != c->state)
+ return MHD_SC_UPGRADED_HANDLE_INVALID;
+
+ finish_time_set = false;
+ wait_indefinitely = (MHD_WAIT_INDEFINITELY <= max_wait_millisec);
+
+ while (1)
+ {
+ enum mhd_SocketError res;
+ size_t last_block_size;
+ uint_fast64_t wait_left;
+#if ! defined(MHD_USE_POLL) && defined(MHD_USE_SELECT)
+ bool use_select;
+#endif /* ! MHD_USE_POLL */
+
+ last_block_size = 0;
+ res = mhd_send_data (c,
+ send_buf_size - *sent_size,
+ buf_char + *sent_size,
+ push_data,
+ &last_block_size);
+ if (mhd_SOCKET_ERR_NO_ERROR == res)
+ {
+ *sent_size += last_block_size;
+ if (send_buf_size == *sent_size)
+ break;
+ }
+ else if (mhd_SOCKET_ERR_IS_HARD (res))
+ {
+ if (0 != *sent_size)
+ break;
+
+ if (mhd_SOCKET_ERR_REMT_DISCONN == res)
+ return MHD_SC_UPGRADED_NET_CONN_CLOSED;
+ if (mhd_SOCKET_ERR_TLS == res)
+ return MHD_SC_UPGRADED_TLS_ERROR;
+ if (! mhd_SOCKET_ERR_IS_BAD (res))
+ return MHD_SC_UPGRADED_NET_CONN_BROKEN;
+
+ return MHD_SC_UPGRADED_NET_HARD_ERROR;
+ }
+
+ if (0 == max_wait_millisec)
+ {
+ mhd_assert (0 == *sent_size);
+
+ return MHD_SC_UPGRADED_NET_TIMEOUT;
+ }
+
+ if (! wait_indefinitely)
+ {
+ uint_fast64_t cur_time;
+ cur_time = MHD_monotonic_msec_counter ();
+
+ if (! finish_time_set)
+ {
+ finish_time = cur_time + max_wait_millisec;
+ wait_left = max_wait_millisec;
+ }
+ else
+ {
+ wait_left = finish_time - cur_time;
+ if ((wait_left > cur_time - finish_time) ||
+ (0 == wait_left))
+ return MHD_SC_UPGRADED_NET_TIMEOUT;
+ }
+ }
+
+#if defined(MHD_USE_POLL)
+ if (1)
+ {
+ struct pollfd fds[1];
+ int poll_wait;
+ int poll_res;
+ int wait_err;
+
+ if (wait_indefinitely)
+ poll_wait = -1;
+ else
+ {
+ poll_wait = (int) wait_left;
+ if ((wait_left != (uint_fast64_t) poll_wait) ||
+ (0 > poll_wait))
+ poll_wait = INT_MAX;
+ }
+ fds[0].fd = socket_fd;
+ fds[0].events = POLLOUT;
+
+ poll_res = mhd_poll (fds,
+ 1,
+ poll_wait);
+ if (0 < poll_res)
+ continue;
+ if (0 == poll_res)
+ {
+ if (wait_indefinitely ||
+ (INT_MAX == poll_wait))
+ continue;
+ if (0 != *sent_size)
+ return MHD_SC_OK;
+ return MHD_SC_UPGRADED_NET_TIMEOUT;
+ }
+
+ mhd_assert (0 > poll_res);
+ wait_err = mhd_SCKT_GET_LERR ();
+ if (! mhd_SCKT_ERR_IS_EAGAIN (wait_err) &&
+ ! mhd_SCKT_ERR_IS_EINTR (wait_err) &&
+ ! mhd_SCKT_ERR_IS_LOW_RESOURCES (wait_err))
+ return MHD_SC_UPGRADED_NET_HARD_ERROR;
+ }
+#else /* ! MHD_USE_POLL */
+# if defined(MHD_USE_SELECT)
+# ifdef MHD_POSIX_SOCKETS
+ use_select = (socket_fd < FD_SETSIZE);
+# else /* MHD_WINSOCK_SOCKETS */
+ use_select = true;
+# endif /* MHD_WINSOCK_SOCKETS */
+ if (use_select)
+ {
+ fd_set wfds;
+ int sel_res;
+ int wait_err;
+ struct timeval tmvl;
+ bool max_wait;
+
+ max_wait = false;
+ if (wait_indefinitely)
+ {
+ tmvl.tv_sec = 0;
+ tmvl.tv_usec = 0;
+ }
+ else
+ {
+# ifdef MHD_POSIX_SOCKETS
+ tmvl.tv_sec = (time_t) (wait_left / 1000);
+# else /* MHD_WINSOCK_SOCKETS */
+ tmvl.tv_sec = (long) (wait_left / 1000);
+# endif /* MHD_WINSOCK_SOCKETS */
+ if ((max_wait_millisec / 1000 != (uint_fast64_t) tmvl.tv_sec) ||
+ (0 > tmvl.tv_sec))
+ {
+ tmvl.tv_sec = mhd_TIMEVAL_TV_SEC_MAX;
+ tmvl.tv_usec = 0;
+ max_wait = true;
+ }
+ else
+ tmvl.tv_usec = (int) (max_wait_millisec % 1000);
+ }
+ FD_ZERO (&wfds);
+ FD_SET (socket_fd, &wfds);
+
+ sel_res = select (c->socket_fd + 1,
+ NULL,
+ &wfds,
+ NULL,
+ wait_indefinitely ? NULL : &tmvl);
+
+ if (0 < sel_res)
+ continue;
+ if (0 == sel_res)
+ {
+ if (wait_indefinitely ||
+ max_wait)
+ continue;
+ if (0 != *sent_size)
+ return MHD_SC_OK;
+ return MHD_SC_UPGRADED_NET_TIMEOUT;
+ }
+
+ mhd_assert (0 > sel_res);
+ wait_err = mhd_SCKT_GET_LERR ();
+ if (! mhd_SCKT_ERR_IS_EAGAIN (wait_err) &&
+ ! mhd_SCKT_ERR_IS_EINTR (wait_err) &&
+ ! mhd_SCKT_ERR_IS_LOW_RESOURCES (wait_err))
+ return MHD_SC_UPGRADED_NET_HARD_ERROR;
+ }
+ else /* combined with the next 'if()' */
+# endif /* MHD_USE_SELECT */
+ if (1)
+ {
+# ifndef mhd_HAVE_MHD_SLEEP
+ return MHD_SC_UPGRADED_WAITING_NOT_SUPPORTED;
+# else /* mhd_HAVE_MHD_SLEEP */
+ uint_fast32_t wait_millisec = (uint_fast32_t) wait_left;
+
+ if ((wait_millisec != wait_left) ||
+ (wait_millisec > 100))
+ wait_millisec = 100;
+ mhd_sleep (wait_millisec);
+# endif /* mhd_HAVE_MHD_SLEEP */
+ }
+#endif /* ! MHD_USE_POLL */
+ }
+
+ return MHD_SC_OK;
+}