Final part of external events

This commit is contained in:
Evgeny Grin (Karlson2k)
2025-04-01 06:25:10 +03:00
parent 6b3d439cea
commit d2792c5e11
13 changed files with 728 additions and 68 deletions
+25
View File
@@ -1296,6 +1296,14 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
*/
MHD_SC_DAEMON_THREAD_STOP_UNEXPECTED = 50351
,
/**
* Daemon system data is broken (like listen socket was unexpectedly closed).
* The daemon needs to be closed.
* A new daemon can be started as a replacement after closing the current
* daemon.
*/
MHD_SC_DAEMON_SYS_DATA_BROKEN = 50370
,
/**
* Failed to acquire response mutex lock
*/
@@ -1666,6 +1674,16 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
* The Digest Auth is not supported due to configuration
*/
MHD_SC_AUTH_DIGEST_UNSUPPORTED = 60242
,
/**
* The application failed to register FD for the external events monitoring
*/
MHD_SC_EXTR_EVENT_REG_FAILED = 60243
,
/**
* The application failed to de-register FD for the external events monitoring
*/
MHD_SC_EXTR_EVENT_DEREG_FAILED = 60244
};
/**
@@ -3923,6 +3941,13 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_RequestEndedCode
*/
MHD_REQUEST_ENDED_BY_APP_ERROR = 41
,
/**
* The request was aborted due to the application failed to register external
* event monitoring for the connection.
* @ingroup request
*/
MHD_REQUEST_ENDED_BY_EXT_EVENT_ERROR = 42
,
/**
* Error handling the connection due to resources exhausted.
* @ingroup request
+25
View File
@@ -1296,6 +1296,14 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
*/
MHD_SC_DAEMON_THREAD_STOP_UNEXPECTED = 50351
,
/**
* Daemon system data is broken (like listen socket was unexpectedly closed).
* The daemon needs to be closed.
* A new daemon can be started as a replacement after closing the current
* daemon.
*/
MHD_SC_DAEMON_SYS_DATA_BROKEN = 50370
,
/**
* Failed to acquire response mutex lock
*/
@@ -1666,6 +1674,16 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
* The Digest Auth is not supported due to configuration
*/
MHD_SC_AUTH_DIGEST_UNSUPPORTED = 60242
,
/**
* The application failed to register FD for the external events monitoring
*/
MHD_SC_EXTR_EVENT_REG_FAILED = 60243
,
/**
* The application failed to de-register FD for the external events monitoring
*/
MHD_SC_EXTR_EVENT_DEREG_FAILED = 60244
};
/**
@@ -3923,6 +3941,13 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_RequestEndedCode
*/
MHD_REQUEST_ENDED_BY_APP_ERROR = 41
,
/**
* The request was aborted due to the application failed to register external
* event monitoring for the connection.
* @ingroup request
*/
MHD_REQUEST_ENDED_BY_EXT_EVENT_ERROR = 42
,
/**
* Error handling the connection due to resources exhausted.
* @ingroup request
+1
View File
@@ -77,6 +77,7 @@ libmicrohttpd2_la_SOURCES = \
daemon_get_info.c \
daemon_add_conn.c daemon_add_conn.h \
daemon_funcs.c daemon_funcs.h \
daemon_event_update.c extr_events_funcs.c extr_events_funcs.h \
conn_data_process.c conn_data_process.h \
conn_data_recv.c conn_data_recv.h \
conn_data_send.c conn_data_send.h \
+126
View File
@@ -0,0 +1,126 @@
/*
This file is part of GNU libmicrohttpd
Copyright (C) 2025 Evgeny Grin (Karlson2k)
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/daemon_event_update.c
* @brief The implementation of MHD_daemon_event_update() function for external
* events updates
* @author Karlson2k (Evgeny Grin)
*/
#include "mhd_sys_options.h"
#include "sys_bool_type.h"
#include "mhd_assert.h"
#include "mhd_daemon.h"
#include "mhd_connection.h"
#include "daemon_logger.h"
#include "mhd_public_api.h"
MHD_EXTERN_
MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) void
MHD_daemon_event_update (
struct MHD_Daemon *MHD_RESTRICT daemon,
struct MHD_EventUpdateContext *MHD_RESTRICT ecb_cntx,
enum MHD_FdState fd_current_state)
{
bool broken_app_data;
bool unneeded_event;
if (mhd_DAEMON_STATE_STARTED > daemon->state)
return;
if (! mhd_WM_INT_HAS_EXT_EVENTS (daemon->wmode_int))
return; /* FIXME: log error? */
if (mhd_DAEMON_STATE_STARTED < daemon->state)
return;
broken_app_data = false;
switch ((mhd_SockRelMarker) ecb_cntx)
{
case mhd_SOCKET_REL_MARKER_EMPTY:
broken_app_data = true;
break;
case mhd_SOCKET_REL_MARKER_ITC:
#ifdef MHD_SUPPORT_THREADS
if (MHD_FD_STATE_IS_SET_EXCEPT (fd_current_state))
daemon->events.data.extr.itc_data.is_broken = true;
else
{
daemon->events.data.extr.itc_data.is_active =
MHD_FD_STATE_IS_SET_RECV (fd_current_state);
unneeded_event = MHD_FD_STATE_IS_SET_SEND (fd_current_state);
}
#else /* ! MHD_SUPPORT_THREADS */
broken_app_data = true;
#endif /* ! MHD_SUPPORT_THREADS */
break;
case mhd_SOCKET_REL_MARKER_LISTEN:
if (MHD_INVALID_SOCKET == daemon->net.listen.fd)
broken_app_data = true;
else if (MHD_FD_STATE_IS_SET_EXCEPT (fd_current_state))
daemon->net.listen.is_broken = true;
else
{
daemon->events.accept_pending =
MHD_FD_STATE_IS_SET_RECV (fd_current_state);
unneeded_event = MHD_FD_STATE_IS_SET_SEND (fd_current_state);
}
break;
default:
if (((struct MHD_Connection *) ecb_cntx)->daemon != daemon)
broken_app_data = true;
else
{
struct MHD_Connection *const c = ((struct MHD_Connection *) ecb_cntx);
unsigned int err_flag;
mhd_assert (MHD_FD_STATE_NONE != c->extr_event.reg_for);
unneeded_event = (0 != ((~((unsigned int) c->extr_event.reg_for))
& ((unsigned int) fd_current_state)));
/* Preserve connection's "error flag" */
err_flag = (((unsigned int) c->sk.ready)
& (unsigned int) mhd_SOCKET_NET_STATE_ERROR_READY);
c->sk.ready =
(enum mhd_SocketNetState)
(err_flag | (((unsigned int) fd_current_state)
& ((unsigned int) c->extr_event.reg_for)));
}
break;
}
if (broken_app_data)
{
// TODO: log error
(void) 0;
}
else if (unneeded_event)
{
// TODO: log error
(void) 0;
}
}
+79 -51
View File
@@ -79,10 +79,11 @@
# include "mhd_tls_funcs.h"
#endif
#include "events_process.h"
#ifdef MHD_SUPPORT_THREADS
# include "mhd_itc.h"
# include "mhd_threads.h"
# include "events_process.h"
# include "daemon_funcs.h"
#endif
@@ -1339,11 +1340,15 @@ daemon_choose_and_preinit_events (struct MHD_Daemon *restrict d,
(MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE == s->work_mode.mode));
mhd_assert (mhd_WM_INT_HAS_EXT_EVENTS (d->wmode_int));
d->events.poll_type = mhd_POLL_TYPE_EXT;
d->events.data.ext.cb_data.cb =
d->events.data.extr.cb_data.cb =
s->work_mode.params.v_external_event_loop_cb.reg_cb;
d->events.data.ext.cb_data.cls =
d->events.data.extr.cb_data.cls =
s->work_mode.params.v_external_event_loop_cb.reg_cb_cls;
d->events.data.ext.reg_all = (MHD_NO != s->reregister_all);
d->events.data.extr.reg_all = (MHD_NO != s->reregister_all);
#ifdef MHD_SUPPORT_THREADS
d->events.data.extr.itc_data.app_cntx = NULL;
#endif /* MHD_SUPPORT_THREADS */
d->events.data.extr.listen_data.app_cntx = NULL;
break;
#ifdef MHD_SUPPORT_SELECT
case mhd_POLL_TYPE_SELECT:
@@ -1795,7 +1800,8 @@ allocate_events (struct MHD_Daemon *restrict d)
switch (d->events.poll_type)
{
case mhd_POLL_TYPE_EXT:
mhd_assert (NULL != d->events.data.ext.cb_data.cb);
mhd_assert (NULL != d->events.data.extr.cb_data.cb);
/* Nothing to do: allocation is not needed */
#ifndef NDEBUG
d->dbg.events_allocated = true;
#endif
@@ -2064,21 +2070,25 @@ init_daemon_fds_monitoring (struct MHD_Daemon *restrict d)
switch (d->events.poll_type)
{
case mhd_POLL_TYPE_EXT:
mhd_assert (NULL != d->events.data.ext.cb_data.cb);
if (! d->events.data.ext.reg_all)
mhd_assert (NULL != d->events.data.extr.cb_data.cb);
#ifdef MHD_SUPPORT_THREADS
d->events.data.extr.itc_data.is_active = false;
d->events.data.extr.itc_data.is_broken = false;
#endif /* MHD_SUPPORT_THREADS */
if (! d->events.data.extr.reg_all)
{
bool itc_reg_succeed;
/* Register daemon's FDs now */
#ifdef MHD_SUPPORT_THREADS
d->events.data.ext.app_cntx.itc =
d->events.data.ext.cb_data.cb (d->events.data.ext.cb_data.cls,
mhd_itc_r_fd (d->threading.itc),
MHD_FD_STATE_RECV,
NULL,
(struct MHD_EventUpdateContext *)
mhd_SOCKET_REL_MARKER_ITC);
itc_reg_succeed = (NULL != d->events.data.ext.app_cntx.itc);
d->events.data.extr.itc_data.app_cntx =
d->events.data.extr.cb_data.cb (d->events.data.extr.cb_data.cls,
mhd_itc_r_fd (d->threading.itc),
MHD_FD_STATE_RECV_EXCEPT,
NULL,
(struct MHD_EventUpdateContext *)
mhd_SOCKET_REL_MARKER_ITC);
itc_reg_succeed = (NULL != d->events.data.extr.itc_data.app_cntx);
#else /* ! MHD_SUPPORT_THREADS */
itc_reg_succeed = true;
#endif /* ! MHD_SUPPORT_THREADS */
@@ -2086,31 +2096,31 @@ init_daemon_fds_monitoring (struct MHD_Daemon *restrict d)
{
if (MHD_INVALID_SOCKET == d->net.listen.fd)
{
d->events.data.ext.app_cntx.listen = NULL;
d->events.data.extr.listen_data.app_cntx = NULL;
return MHD_SC_OK; /* Success exit point */
}
/* Need to register the listen FD */
d->events.data.ext.app_cntx.listen =
d->events.data.ext.cb_data.cb (d->events.data.ext.cb_data.cls,
d->net.listen.fd,
MHD_FD_STATE_RECV,
NULL,
(struct MHD_EventUpdateContext *)
mhd_SOCKET_REL_MARKER_LISTEN);
if (NULL != d->events.data.ext.app_cntx.listen)
d->events.data.extr.listen_data.app_cntx =
d->events.data.extr.cb_data.cb (d->events.data.extr.cb_data.cls,
d->net.listen.fd,
MHD_FD_STATE_RECV_EXCEPT,
NULL,
(struct MHD_EventUpdateContext *)
mhd_SOCKET_REL_MARKER_LISTEN);
if (NULL != d->events.data.extr.listen_data.app_cntx)
return MHD_SC_OK; /* Success exit point */
/* Below is a clean-up path for 'case mhd_POLL_TYPE_EXT:' */
#ifdef MHD_SUPPORT_THREADS
/* De-register ITC FD */
(void) d->events.data.ext.cb_data.cb (d->events.data.ext.cb_data.cls,
mhd_itc_r_fd (d->threading.itc),
MHD_FD_STATE_NONE,
d->events.data.ext.app_cntx.itc,
(struct MHD_EventUpdateContext *)
mhd_SOCKET_REL_MARKER_ITC);
d->events.data.ext.app_cntx.itc = NULL;
(void) d->events.data.extr.cb_data.cb (
d->events.data.extr.cb_data.cls,
mhd_itc_r_fd (d->threading.itc),
MHD_FD_STATE_NONE,
d->events.data.extr.itc_data.app_cntx,
(struct MHD_EventUpdateContext *) mhd_SOCKET_REL_MARKER_ITC);
d->events.data.extr.itc_data.app_cntx = NULL;
#endif /* MHD_SUPPORT_THREADS */
}
@@ -2123,9 +2133,9 @@ init_daemon_fds_monitoring (struct MHD_Daemon *restrict d)
{
/* Daemons FDs are repeatedly registered every processing cycle */
#ifdef MHD_SUPPORT_THREADS
d->events.data.ext.app_cntx.itc = NULL;
d->events.data.extr.itc_data.app_cntx = NULL;
#endif /* MHD_SUPPORT_THREADS */
d->events.data.ext.app_cntx.listen = NULL;
d->events.data.extr.listen_data.app_cntx = NULL;
return MHD_SC_OK;
}
break;
@@ -2229,21 +2239,21 @@ deinit_daemon_fds_monitoring (struct MHD_Daemon *restrict d)
switch (d->events.poll_type)
{
case mhd_POLL_TYPE_EXT:
if (NULL != d->events.data.ext.app_cntx.listen)
(void) d->events.data.ext.cb_data.cb (d->events.data.ext.cb_data.cls,
d->net.listen.fd,
MHD_FD_STATE_NONE,
d->events.data.ext.app_cntx.listen,
(struct MHD_EventUpdateContext *)
mhd_SOCKET_REL_MARKER_LISTEN);
if (NULL != d->events.data.extr.listen_data.app_cntx)
(void) d->events.data.extr.cb_data.cb (
d->events.data.extr.cb_data.cls,
d->net.listen.fd,
MHD_FD_STATE_NONE,
d->events.data.extr.listen_data.app_cntx,
(struct MHD_EventUpdateContext *) mhd_SOCKET_REL_MARKER_LISTEN);
#ifdef MHD_SUPPORT_THREADS
if (NULL != d->events.data.ext.app_cntx.itc)
(void) d->events.data.ext.cb_data.cb (d->events.data.ext.cb_data.cls,
mhd_itc_r_fd (d->threading.itc),
MHD_FD_STATE_NONE,
d->events.data.ext.app_cntx.itc,
(struct MHD_EventUpdateContext *)
mhd_SOCKET_REL_MARKER_ITC);
if (NULL != d->events.data.extr.itc_data.app_cntx)
(void) d->events.data.extr.cb_data.cb (
d->events.data.extr.cb_data.cls,
mhd_itc_r_fd (d->threading.itc),
MHD_FD_STATE_NONE,
d->events.data.extr.itc_data.app_cntx,
(struct MHD_EventUpdateContext *) mhd_SOCKET_REL_MARKER_ITC);
#endif /* MHD_SUPPORT_THREADS */
return;
#ifdef MHD_SUPPORT_SELECT
@@ -2624,7 +2634,7 @@ set_d_threading_type (struct MHD_Daemon *restrict d)
case mhd_WM_INT_EXTERNAL_EVENTS_LEVEL:
mhd_assert (! mhd_WM_INT_HAS_THREADS (d->wmode_int));
mhd_assert (mhd_POLL_TYPE_EXT == d->events.poll_type);
mhd_assert (NULL != d->events.data.ext.cb_data.cb);
mhd_assert (NULL != d->events.data.extr.cb_data.cb);
#ifdef MHD_SUPPORT_THREADS
d->threading.d_type = mhd_DAEMON_TYPE_SINGLE;
#endif /* MHD_SUPPORT_THREADS */
@@ -3183,9 +3193,7 @@ daemon_start_threads (struct MHD_Daemon *restrict d)
/**
* Stop the daemon internal threads, if the daemon configured to use them.
* @param d the daemon object, the threads (if any) must be started
* @return #MHD_SC_OK on success,
* the error code otherwise
* @param d the daemon object to stop threads
*/
static MHD_FN_PAR_NONNULL_ (1) void
daemon_stop_threads (struct MHD_Daemon *restrict d)
@@ -3219,6 +3227,24 @@ daemon_stop_threads (struct MHD_Daemon *restrict d)
}
/**
* Close all daemon connections for modes without internal threads
* @param d the daemon object
*/
static MHD_FN_PAR_NONNULL_ (1) void
daemon_close_connections (struct MHD_Daemon *restrict d)
{
if (mhd_WM_INT_HAS_THREADS (d->wmode_int))
{
/* In these modes connections must be closed in the daemon thread */
mhd_assert (NULL == mhd_DLINKEDL_GET_LAST (&(d->conns),all_conn));
return;
}
mhd_daemon_close_all_conns (d);
}
/**
* Internal daemon initialisation function.
* This function calls all required initialisation stages one-by-one.
@@ -3333,6 +3359,8 @@ MHD_daemon_destroy (struct MHD_Daemon *daemon)
daemon_stop_threads (daemon);
daemon_close_connections (daemon);
daemon_deinit_threading_and_conn (daemon);
daemon_deinit_large_buf (daemon);
+257 -4
View File
@@ -57,6 +57,7 @@
#include "daemon_funcs.h"
#include "conn_data_process.h"
#include "stream_funcs.h"
#include "extr_events_funcs.h"
#ifdef MHD_SUPPORT_UPGRADE
# include "upgrade_proc.h"
@@ -373,8 +374,8 @@ daemon_cleanup_upgraded_conns (struct MHD_Daemon *d)
#define daemon_cleanup_upgraded_conns(d) ((void) d)
#endif /* ! MHD_SUPPORT_UPGRADE */
static void
close_all_daemon_conns (struct MHD_Daemon *d)
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
mhd_daemon_close_all_conns (struct MHD_Daemon *d)
{
struct MHD_Connection *c;
bool has_upgraded_unclosed;
@@ -415,6 +416,198 @@ close_all_daemon_conns (struct MHD_Daemon *d)
}
/**
* Process all external events updated of existing connections, information
* about new connections pending to be accept()'ed, presence of the events on
* the daemon's ITC.
* @return 'true' if processed successfully,
* 'false' is unrecoverable error occurs and the daemon must be
* closed
*/
static MHD_FN_PAR_NONNULL_ (1) bool
ext_events_process_net_updates (struct MHD_Daemon *restrict d)
{
struct MHD_Connection *restrict c;
mhd_assert (mhd_WM_INT_HAS_EXT_EVENTS (d->wmode_int));
mhd_assert (mhd_POLL_TYPE_EXT == d->events.poll_type);
#ifdef MHD_SUPPORT_THREADS
if (d->events.data.extr.itc_data.is_active)
{
d->events.data.extr.itc_data.is_active = false;
/* Clear ITC here, before other data processing.
* Any external events will activate ITC again if additional data to
* process is added externally. Clearing ITC early ensures that new data
* (with additional ITC activation) will not be missed. */
mhd_itc_clear (d->threading.itc);
}
#endif /* MHD_SUPPORT_THREADS */
for (c = mhd_DLINKEDL_GET_FIRST (&(d->conns),all_conn);
NULL != c;
c = mhd_DLINKEDL_GET_NEXT (c,all_conn))
{
bool has_err_state;
if (is_conn_excluded_from_http_comm (c))
continue;
has_err_state =
(0 != (((unsigned int) c->sk.ready) & mhd_SOCKET_NET_STATE_ERROR_READY));
mhd_conn_mark_ready_update3 (c,
has_err_state,
d);
}
return true;
}
/**
* Update all registrations of FDs for external monitoring.
* @return #MHD_SC_OK on success,
* error code otherwise
*/
static MHD_FN_PAR_NONNULL_ (1) enum MHD_StatusCode
ext_events_update_registrations (struct MHD_Daemon *restrict d)
{
const bool rereg_all = d->events.data.extr.reg_all;
const bool edge_trigg = (mhd_WM_INT_EXTERNAL_EVENTS_EDGE == d->wmode_int);
bool daemon_fds_succeed;
struct MHD_Connection *c;
struct MHD_Connection *c_next;
mhd_assert (mhd_WM_INT_HAS_EXT_EVENTS (d->wmode_int));
mhd_assert (mhd_POLL_TYPE_EXT == d->events.poll_type);
/* (Re-)register daemon's FDs */
#ifdef MHD_SUPPORT_THREADS
if (rereg_all ||
(NULL == d->events.data.extr.itc_data.app_cntx))
{
/* (Re-)register ITC FD */
d->events.data.extr.itc_data.app_cntx =
d->events.data.extr.cb_data.cb (d->events.data.extr.cb_data.cls,
mhd_itc_r_fd (d->threading.itc),
MHD_FD_STATE_RECV_EXCEPT,
d->events.data.extr.itc_data.app_cntx,
(struct MHD_EventUpdateContext *)
mhd_SOCKET_REL_MARKER_ITC);
if (NULL != d->events.data.extr.itc_data.app_cntx)
mhd_log_extr_event_dereg_failed (d);
}
daemon_fds_succeed = (NULL != d->events.data.extr.itc_data.app_cntx);
#else /* ! MHD_SUPPORT_THREADS */
daemon_fds_succeed = true;
#endif /* ! MHD_SUPPORT_THREADS */
if (daemon_fds_succeed)
{
if ((MHD_INVALID_SOCKET == d->net.listen.fd) &&
(NULL != d->events.data.extr.listen_data.app_cntx))
{
/* De-register the listen FD */
d->events.data.extr.listen_data.app_cntx =
d->events.data.extr.cb_data.cb (d->events.data.extr.cb_data.cls,
d->net.listen.fd,
MHD_FD_STATE_NONE,
d->events.data.extr.listen_data.app_cntx
,
(struct MHD_EventUpdateContext *)
mhd_SOCKET_REL_MARKER_LISTEN);
if (NULL != d->events.data.extr.listen_data.app_cntx)
mhd_log_extr_event_dereg_failed (d);
}
else if ((MHD_INVALID_SOCKET != d->net.listen.fd) &&
(rereg_all || (NULL == d->events.data.extr.listen_data.app_cntx)))
{
/* (Re-)register listen FD */
d->events.data.extr.listen_data.app_cntx =
d->events.data.extr.cb_data.cb (d->events.data.extr.cb_data.cls,
d->net.listen.fd,
MHD_FD_STATE_RECV_EXCEPT,
d->events.data.extr.listen_data.app_cntx
,
(struct MHD_EventUpdateContext *)
mhd_SOCKET_REL_MARKER_LISTEN);
daemon_fds_succeed = (NULL != d->events.data.extr.listen_data.app_cntx);
}
}
if (! daemon_fds_succeed)
{
mhd_LOG_MSG (d, MHD_SC_EXT_EVENT_REG_DAEMON_FDS_FAILURE, \
"Failed to register daemon FDs in the application "
"(external events) monitoring.");
return MHD_SC_EXT_EVENT_REG_DAEMON_FDS_FAILURE;
}
for (c = mhd_DLINKEDL_GET_FIRST (&(d->conns),all_conn);
NULL != c;
c = c_next)
{
enum MHD_FdState watch_for;
/* Get the next connection now, as the current connection could be removed
from the daemon. */
c_next = mhd_DLINKEDL_GET_NEXT (c,all_conn);
if (is_conn_excluded_from_http_comm (c))
{
if (NULL != c->extr_event.app_cntx)
{
c->extr_event.app_cntx =
d->events.data.extr.cb_data.cb (d->events.data.extr.cb_data.cls,
c->sk.fd,
MHD_FD_STATE_NONE,
c->extr_event.app_cntx,
(struct MHD_EventUpdateContext *) c);
if (NULL != c->extr_event.app_cntx)
mhd_log_extr_event_dereg_failed (d);
}
continue;
}
watch_for =
edge_trigg ?
MHD_FD_STATE_RECV_SEND_EXCEPT :
(enum MHD_FdState) (MHD_FD_STATE_EXCEPT
| (((unsigned int) c->event_loop_info)
& (MHD_EVENT_LOOP_INFO_RECV
| MHD_EVENT_LOOP_INFO_SEND)));
mhd_assert ((! edge_trigg) || \
(MHD_FD_STATE_RECV_SEND_EXCEPT == c->extr_event.reg_for) || \
(NULL == c->extr_event.app_cntx));
if ((NULL == c->extr_event.app_cntx) ||
rereg_all ||
(! edge_trigg && (watch_for != c->extr_event.reg_for)))
{
c->extr_event.app_cntx =
d->events.data.extr.cb_data.cb (d->events.data.extr.cb_data.cls,
c->sk.fd,
watch_for,
c->extr_event.app_cntx,
(struct MHD_EventUpdateContext *) c);
if (NULL == c->extr_event.app_cntx)
{
mhd_conn_start_closing_ext_event_failed (c);
mhd_conn_pre_clean (c);
mhd_conn_remove_from_daemon (c);
mhd_conn_close_final (c);
}
c->extr_event.reg_for = watch_for;
}
}
return MHD_SC_OK;
}
#ifdef MHD_SUPPORT_SELECT
/**
@@ -1147,7 +1340,9 @@ process_all_events_and_data (struct MHD_Daemon *restrict d)
switch (d->events.poll_type)
{
case mhd_POLL_TYPE_EXT:
return false; // TODO: implement
mhd_assert (mhd_WM_INT_HAS_EXT_EVENTS (d->wmode_int));
if (! ext_events_process_net_updates (d))
return false;
break;
#ifdef MHD_SUPPORT_SELECT
case mhd_POLL_TYPE_SELECT:
@@ -1192,6 +1387,64 @@ process_all_events_and_data (struct MHD_Daemon *restrict d)
}
MHD_EXTERN_
MHD_FN_PAR_NONNULL_ (1) enum MHD_StatusCode
MHD_daemon_process_reg_events (struct MHD_Daemon *MHD_RESTRICT daemon,
uint_fast64_t *MHD_RESTRICT next_max_wait)
{
enum MHD_StatusCode res;
if (mhd_DAEMON_STATE_STARTED > daemon->state)
return MHD_SC_TOO_EARLY;
if (! mhd_WM_INT_HAS_EXT_EVENTS (daemon->wmode_int))
return MHD_SC_EXTERNAL_EVENT_ONLY;
if (mhd_DAEMON_STATE_STARTED < daemon->state)
return MHD_SC_TOO_LATE;
#ifdef MHD_SUPPORT_THREADS
if (daemon->events.data.extr.itc_data.is_broken)
return MHD_SC_DAEMON_SYS_DATA_BROKEN;
#endif /* MHD_SUPPORT_THREADS */
if (daemon->net.listen.is_broken)
return MHD_SC_DAEMON_SYS_DATA_BROKEN;
#ifdef MHD_SUPPORT_THREADS
if (daemon->threading.resume_requested)
mhd_daemon_resume_conns (daemon);
#endif /* MHD_SUPPORT_THREADS */
/* Ignore returned value */
(void) process_all_events_and_data (daemon);
if (NULL != next_max_wait)
*next_max_wait = MHD_WAIT_INDEFINITELY;
res = ext_events_update_registrations (daemon);
if (MHD_SC_OK != res)
return res;
#ifdef MHD_SUPPORT_THREADS
if (daemon->events.data.extr.itc_data.is_broken)
{
log_itc_broken (daemon);
return MHD_SC_DAEMON_SYS_DATA_BROKEN;
}
#endif /* MHD_SUPPORT_THREADS */
if (daemon->net.listen.is_broken)
{
log_listen_broken (daemon);
return MHD_SC_DAEMON_SYS_DATA_BROKEN;
}
if (NULL != next_max_wait)
*next_max_wait = mhd_daemon_get_wait_max ();
return MHD_SC_OK;
}
/**
* The entry point for the daemon worker thread
* @param cls the closure
@@ -1230,7 +1483,7 @@ mhd_worker_all_events (void *cls)
"The daemon thread is stopping, but termination has not " \
"been requested for the daemon.");
}
close_all_daemon_conns (d);
mhd_daemon_close_all_conns (d);
return (mhd_THRD_RTRN_TYPE) 0;
}
+9
View File
@@ -66,4 +66,13 @@ MHD_INTERNAL uint_fast64_t
mhd_daemon_get_wait_max (struct MHD_Daemon *restrict d)
MHD_FN_PAR_NONNULL_ALL_;
/**
* Close all daemon connections.
* Must not be called when any other connections processing function is running
* @param d the daemon to use
*/
MHD_INTERNAL void
mhd_daemon_close_all_conns (struct MHD_Daemon *d)
MHD_FN_PAR_NONNULL_ALL_;
#endif /* ! MHD_EVENTS_PROCESS_H */
+44
View File
@@ -0,0 +1,44 @@
/*
This file is part of GNU libmicrohttpd
Copyright (C) 2025 Evgeny Grin (Karlson2k)
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/extr_events_funcs.c
* @brief The implementation of the external events internal helper functions
* @author Karlson2k (Evgeny Grin)
*/
#include "mhd_sys_options.h"
#include "extr_events_funcs.h"
#ifdef MHD_SUPPORT_LOG_FUNCTIONALITY
#include "daemon_logger.h"
MHD_INTERNAL void
mhd_log_extr_event_dereg_failed (struct MHD_Daemon *restrict d)
{
mhd_LOG_MSG (d, \
MHD_SC_EXTR_EVENT_DEREG_FAILED, \
"Application failed to de-register FD: registration callback " \
"returned non-NULL value");
}
#endif /* MHD_SUPPORT_LOG_FUNCTIONALITY */
+51
View File
@@ -0,0 +1,51 @@
/*
This file is part of GNU libmicrohttpd
Copyright (C) 2025 Evgeny Grin (Karlson2k)
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/extr_events_funcs.h
* @brief The definition of the external events internal helper functions
* @author Karlson2k (Evgeny Grin)
*/
#ifndef MHD_EXTR_EVENTS_FUNCS_H
#define MHD_EXTR_EVENTS_FUNCS_H 1
#include "mhd_sys_options.h"
#ifdef MHD_SUPPORT_LOG_FUNCTIONALITY
struct MHD_Daemon; /* forward declaration */
/**
* Log message about failed de-registration of FDs
*/
MHD_INTERNAL void
mhd_log_extr_event_dereg_failed (struct MHD_Daemon *restrict d);
#else /* ! MHD_SUPPORT_LOG_FUNCTIONALITY */
/**
* Log message about failed de-registration of FDs (no-op implementation)
*/
#define mhd_log_extr_event_dereg_failed(d) ((void) 0)
#endif /* ! MHD_SUPPORT_LOG_FUNCTIONALITY */
#endif /* ! MHD_EXTR_EVENTS_FUNCS_H */
+23
View File
@@ -456,6 +456,24 @@ enum MHD_FIXED_ENUM_ mhd_HttpStage
};
/**
* The connection's external event data
*/
struct mhd_ConnExtrEvents
{
/**
* Connection's application context for the external events monitoring
*/
void *app_cntx;
/**
* The last targets for which the connection FD has been registration for
*/
enum MHD_FdState reg_for;
};
struct mhd_ConnDebugData
{
bool closing_started;
@@ -506,6 +524,11 @@ struct MHD_Connection
*/
struct mhd_ConnSocket sk;
/**
* The connection's external event data
*/
struct mhd_ConnExtrEvents extr_event;
#ifdef MHD_SUPPORT_HTTPS
/**
* Connection-specific TLS data.
+38 -12
View File
@@ -332,22 +332,41 @@ struct mhd_DaemonEventsExternalCallback
};
/**
* Application context for external events for daemon's FDs
*/
struct mhd_DaemonEventsExternalScktAppCntx
{
#ifdef MHD_SUPPORT_THREADS
/**
* External events data for ITC FD
*/
struct mhd_DaemonEventsExternalDaemonItcData
{
/**
* Application context for ITC FD
*/
void *itc;
#endif /* MHD_SUPPORT_THREADS */
void *app_cntx;
/**
* Application context for listen socket
* Set to 'true' when active state was detected on ITC by
* external polling
*/
void *listen;
bool is_active;
/**
* Set to 'true' when error state was detected on ITC by
* external polling.
* The daemon may become non-functional.
*/
bool is_broken;
};
#endif /* MHD_SUPPORT_THREADS */
/**
* External events data for the listen socket
*/
struct mhd_DaemonEventsExternalDaemonListenData
{
/**
* Application context for ITC FD
*/
void *app_cntx;
};
/**
@@ -361,10 +380,17 @@ struct mhd_DaemonEventsExternal
*/
struct mhd_DaemonEventsExternalCallback cb_data;
#ifdef MHD_SUPPORT_THREADS
/**
* Application context for external events for daemon's FDs
* External events data for ITC FD
*/
struct mhd_DaemonEventsExternalScktAppCntx app_cntx;
struct mhd_DaemonEventsExternalDaemonItcData itc_data;
#endif /* MHD_SUPPORT_THREADS */
/**
* External events data for the listen socket
*/
struct mhd_DaemonEventsExternalDaemonListenData listen_data;
/**
* If set to 'true' then all FDs must be registered each round.
@@ -405,7 +431,7 @@ union mhd_DaemonEventMonitoringTypeSpecificData
/**
* Daemon's data for external events for sockets monitoring.
*/
struct mhd_DaemonEventsExternal ext;
struct mhd_DaemonEventsExternal extr;
};
+22 -1
View File
@@ -53,6 +53,7 @@
#include "daemon_funcs.h"
#include "conn_mark_ready.h"
#include "stream_process_reply.h"
#include "extr_events_funcs.h"
#ifdef MHD_SUPPORT_HTTPS
# include "mhd_tls_funcs.h"
@@ -750,6 +751,11 @@ mhd_conn_start_closing (struct MHD_Connection *restrict c,
close_hard = true;
end_code = MHD_REQUEST_ENDED_NO_RESOURCES;
break;
case mhd_CONN_CLOSE_EXTR_EVENT_REG_FAILED:
close_hard = true;
end_code = MHD_REQUEST_ENDED_BY_EXT_EVENT_ERROR;
sc = MHD_SC_EXTR_EVENT_REG_FAILED;
break;
case mhd_CONN_CLOSE_NO_SYS_RESOURCES:
close_hard = true;
end_code = MHD_REQUEST_ENDED_NO_RESOURCES;
@@ -941,8 +947,23 @@ mhd_conn_pre_clean_part1 (struct MHD_Connection *restrict c)
if (NULL != c->rq.cntn.lbuf.data)
mhd_daemon_free_lbuf (c->daemon, &(c->rq.cntn.lbuf));
if (mhd_WM_INT_HAS_EXT_EVENTS (c->daemon->wmode_int))
{
struct MHD_Daemon *const d = c->daemon;
if (NULL != c->extr_event.app_cntx)
{
c->extr_event.app_cntx =
d->events.data.extr.cb_data.cb (d->events.data.extr.cb_data.cls,
c->sk.fd,
MHD_FD_STATE_NONE,
c->extr_event.app_cntx,
(struct MHD_EventUpdateContext *) c);
if (NULL != c->extr_event.app_cntx)
mhd_log_extr_event_dereg_failed (d);
}
}
#ifdef MHD_SUPPORT_EPOLL
if (mhd_POLL_TYPE_EPOLL == c->daemon->events.poll_type)
else if (mhd_POLL_TYPE_EPOLL == c->daemon->events.poll_type)
{
struct epoll_event event;
+28
View File
@@ -228,6 +228,11 @@ enum mhd_ConnCloseReason
*/
mhd_CONN_CLOSE_INT_ERROR
,
/**
* Failed to register the connection for the external event monitoring
*/
mhd_CONN_CLOSE_EXTR_EVENT_REG_FAILED
,
/**
* No system resources available to handle connection
*/
@@ -321,6 +326,29 @@ MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_CSTR_ (3);
#define mhd_conn_start_closing_app_abort(c) \
mhd_conn_start_closing ((c), mhd_CONN_CLOSE_APP_ABORTED, NULL)
#ifdef MHD_SUPPORT_LOG_FUNCTIONALITY
/**
* Perform initial clean-up and mark for closing.
* Set the reason to "socket error"
* @param c the connection for pre-closing
*/
#define mhd_conn_start_closing_ext_event_failed(c) \
mhd_conn_start_closing ((c), \
mhd_CONN_CLOSE_EXTR_EVENT_REG_FAILED, \
"The application failed to register FD for " \
"the external events monitoring.")
#else /* ! MHD_SUPPORT_LOG_FUNCTIONALITY */
/**
* Perform initial clean-up and mark for closing.
* Set the reason to "socket error"
* @param c the connection for pre-closing
*/
#define mhd_conn_start_closing_ext_event_failed(c) \
mhd_conn_start_closing ((c), \
mhd_CONN_CLOSE_EXTR_EVENT_REG_FAILED, NULL)
#endif /* ! MHD_SUPPORT_LOG_FUNCTIONALITY */
/**
* Perform initial clean-up and mark for closing.
* Set the reason to "socket error"