Sfoglia il codice sorgente

Implemented susped/resume of the connections

Evgeny Grin (Karlson2k) 10 mesi fa
parent
commit
23946f4de8

+ 3 - 9
src/include/microhttpd2.h

@@ -5690,17 +5690,11 @@ MHD_FN_CONST_;
 
 
 /**
- * Resume handling of network data for suspended request.  It is
- * safe to resume a suspended request at any time.  Calling this
- * function on a request that was not previously suspended will
+ * Resume handling of network data for suspended request.
+ * It is safe to resume a suspended request at any time.
+ * Calling this function on a request that was not previously suspended will
  * result in undefined behaviour.
  *
- * If you are using this function in ``external'' select mode, you must make
- * sure to run #MHD_daemon_process_blocking() afterwards (as otherwise the
- * change may not be reflected in the set returned to your
- * MHD_SocketRegistrationUpdateCallback and you may end up with a request
- * that is stuck until the next network activity.
- *
  * @param[in,out] request the request to resume
  */
 MHD_EXTERN_ void

+ 3 - 9
src/include/microhttpd2_main.h.in

@@ -1004,17 +1004,11 @@ MHD_FN_CONST_;
 
 
 /**
- * Resume handling of network data for suspended request.  It is
- * safe to resume a suspended request at any time.  Calling this
- * function on a request that was not previously suspended will
+ * Resume handling of network data for suspended request.
+ * It is safe to resume a suspended request at any time.
+ * Calling this function on a request that was not previously suspended will
  * result in undefined behaviour.
  *
- * If you are using this function in ``external'' select mode, you must make
- * sure to run #MHD_daemon_process_blocking() afterwards (as otherwise the
- * change may not be reflected in the set returned to your
- * MHD_SocketRegistrationUpdateCallback and you may end up with a request
- * that is stuck until the next network activity.
- *
  * @param[in,out] request the request to resume
  */
 MHD_EXTERN_ void

+ 1 - 0
src/mhd2/Makefile.am

@@ -85,6 +85,7 @@ libmicrohttpd2_la_SOURCES = \
   conn_get_info.c \
   request_funcs.c           request_funcs.h \
   request_get_value.c       request_get_value.h \
+  request_resume.c \
   respond_with_error.c      respond_with_error.h \
   request_get_info.c \
   response_from.c           response_from.h \

+ 12 - 1
src/mhd2/conn_data_process.c

@@ -58,6 +58,18 @@ mhd_conn_process_recv_send_data (struct MHD_Connection *restrict c)
   bool has_sock_err;
   bool data_processed;
 
+  data_processed = false;
+
+  if (c->resuming)
+  {
+    mhd_assert (! c->suspended);
+    /* Fully resume the connection + call app callbacks for the data */
+    if (! mhd_conn_process_data (c))
+      return false;
+
+    data_processed = true;
+  }
+
 #ifdef MHD_SUPPORT_HTTPS
   if (mhd_C_HAS_TLS (c))
   {
@@ -86,7 +98,6 @@ mhd_conn_process_recv_send_data (struct MHD_Connection *restrict c)
      (0 != (MHD_EVENT_LOOP_INFO_SEND & c->event_loop_info)));
   has_sock_err =
     (0 != (mhd_SOCKET_NET_STATE_ERROR_READY & c->sk.ready));
-  data_processed = false;
 
   if (0 != (MHD_EVENT_LOOP_INFO_RECV & c->event_loop_info))
   {

+ 0 - 10
src/mhd2/daemon_funcs.c

@@ -68,16 +68,6 @@ mhd_daemon_trigger_itc (struct MHD_Daemon *restrict d)
 #endif /* MHD_SUPPORT_THREADS */
 
 
-MHD_NORETURN_ // TODO: implement
-MHD_INTERNAL
-MHD_FN_PAR_NONNULL_ALL_ void
-mhd_daemon_resume_conns (struct MHD_Daemon *restrict d)
-{
-  (void) d;
-  mhd_assert (0 && "Not implemented yet");
-}
-
-
 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
 MHD_FN_MUST_CHECK_RESULT_ bool
 mhd_daemon_claim_lbuf (struct MHD_Daemon *d,

+ 0 - 10
src/mhd2/daemon_funcs.h

@@ -63,16 +63,6 @@ mhd_daemon_trigger_itc (struct MHD_Daemon *restrict d);
 #endif /* ! MHD_SUPPORT_THREADS */
 
 
-/**
- * Check whether any resuming connections are pending and resume them
- * @param d the daemon to use
- */
-MHD_NORETURN_ // TODO: implement
-MHD_INTERNAL void
-mhd_daemon_resume_conns (struct MHD_Daemon *restrict d)
-MHD_FN_PAR_NONNULL_ALL_;
-
-
 /**
  * Request allocation of the large buffer
  * @param d the daemon to use

+ 25 - 3
src/mhd2/events_process.c

@@ -109,6 +109,28 @@ mhd_daemon_get_wait_max (struct MHD_Daemon *restrict d)
 }
 
 
+/**
+ * Check whether any resuming connections are pending and resume them
+ * @param d the daemon to use
+ */
+static MHD_FN_PAR_NONNULL_ALL_ void
+daemon_resume_conns (struct MHD_Daemon *restrict d)
+{
+  struct MHD_Connection *c;
+  for (c = mhd_DLINKEDL_GET_FIRST (&(d->conns),all_conn);
+       NULL != c;
+       c = mhd_DLINKEDL_GET_NEXT (c,all_conn))
+  {
+    if (! c->resuming)
+      continue;
+
+    mhd_assert (c->suspended);
+    c->suspended = false;
+    mhd_conn_mark_ready (c, d); /* Force processing connection in this round */
+  }
+}
+
+
 mhd_DATA_TRUNCATION_RUNTIME_CHECK_DISABLE
 
 static MHD_FN_PAR_NONNULL_ALL_ int
@@ -1411,7 +1433,7 @@ MHD_daemon_process_reg_events (struct MHD_Daemon *MHD_RESTRICT daemon,
 
 #ifdef MHD_SUPPORT_THREADS
   if (daemon->threading.resume_requested)
-    mhd_daemon_resume_conns (daemon);
+    daemon_resume_conns (daemon);
 #endif /* MHD_SUPPORT_THREADS */
 
   /* Ignore returned value */
@@ -1439,7 +1461,7 @@ MHD_daemon_process_reg_events (struct MHD_Daemon *MHD_RESTRICT daemon,
   }
 
   if (NULL != next_max_wait)
-    *next_max_wait = mhd_daemon_get_wait_max ();
+    *next_max_wait = mhd_daemon_get_wait_max (daemon);
 
   return MHD_SC_OK;
 }
@@ -1472,7 +1494,7 @@ mhd_worker_all_events (void *cls)
   while (! d->threading.stop_requested)
   {
     if (d->threading.resume_requested)
-      mhd_daemon_resume_conns (d);
+      daemon_resume_conns (d);
 
     if (! process_all_events_and_data (d))
       break;

+ 2 - 2
src/mhd2/mhd_connection.h

@@ -591,12 +591,12 @@ struct MHD_Connection
   /**
    * True if connection is suspended
    */
-  bool suspended;
+  volatile bool suspended;
 
   /**
    * True if connection is resuming
    */
-  bool resuming;
+  volatile bool resuming;
 
   /**
    * Request-specific data

+ 49 - 0
src/mhd2/request_resume.c

@@ -0,0 +1,49 @@
+/*
+  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/request_resume.c
+ * @brief  The implementation of MHD_request_resume() function
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#include "mhd_sys_options.h"
+
+#include "mhd_cntnr_ptr.h"
+
+#include "mhd_daemon.h"
+#include "mhd_connection.h"
+
+#include "daemon_funcs.h"
+
+#include "mhd_public_api.h"
+
+MHD_EXTERN_ MHD_FN_PAR_NONNULL_ALL_ void
+MHD_request_resume (struct MHD_Request *request)
+{
+  struct MHD_Connection *c = mhd_CNTNR_PTR (request, \
+                                            struct MHD_Connection, \
+                                            rq);
+  struct MHD_Daemon *d = c->daemon;
+
+  c->resuming = true;
+  d->threading.resume_requested = true;
+  mhd_daemon_trigger_itc (d);
+}

+ 43 - 9
src/mhd2/stream_funcs.c

@@ -673,6 +673,48 @@ mhd_stream_update_activity_mark (struct MHD_Connection *restrict c)
 }
 
 
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
+mhd_stream_resumed_activity_mark (struct MHD_Connection *restrict c)
+{
+  struct MHD_Daemon *const restrict d = c->daemon;
+#if defined(MHD_SUPPORT_THREADS)
+  mhd_assert (! mhd_D_HAS_WORKERS (d));
+#endif /* MHD_SUPPORT_THREADS */
+
+  mhd_assert (! c->suspended);
+  mhd_assert (c->resuming);
+
+  /* Update of activity for connections without timeout timer unless
+   * no timeout is set */
+  if (0 != c->connection_timeout_ms)
+    c->last_activity = mhd_monotonic_msec_counter (); // TODO: Get and use time value one time per round
+
+  if (mhd_D_HAS_THR_PER_CONN (d))
+    return; /* each connection has personal timeout */
+
+  if (c->connection_timeout_ms == d->conns.cfg.timeout)
+    mhd_DLINKEDL_INS_FIRST_D (&(d->conns.def_timeout), c, by_timeout);
+  else
+    mhd_DLINKEDL_INS_FIRST_D (&(d->conns.cust_timeout), c, by_timeout);
+}
+
+
+MHD_INTERNAL
+MHD_FN_PAR_NONNULL_ALL_ void
+mhd_conn_remove_from_timeout_lists (struct MHD_Connection *restrict c)
+{
+  if (! mhd_D_HAS_THR_PER_CONN (c->daemon))
+  {
+    if (c->connection_timeout_ms == c->daemon->conns.cfg.timeout)
+      mhd_DLINKEDL_DEL_D (&(c->daemon->conns.def_timeout), \
+                          c, by_timeout);
+    else
+      mhd_DLINKEDL_DEL_D (&(c->daemon->conns.cust_timeout), \
+                          c, by_timeout);
+  }
+}
+
+
 MHD_INTERNAL
 MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_CSTR_ (3) void
 mhd_conn_start_closing (struct MHD_Connection *restrict c,
@@ -920,15 +962,7 @@ mhd_conn_start_closing (struct MHD_Connection *restrict c,
 #endif
   c->rq.app_aware = false;
 
-  if (! mhd_D_HAS_THR_PER_CONN (c->daemon))
-  {
-    if (c->connection_timeout_ms == c->daemon->conns.cfg.timeout)
-      mhd_DLINKEDL_DEL_D (&(c->daemon->conns.def_timeout), \
-                          c, by_timeout);
-    else
-      mhd_DLINKEDL_DEL_D (&(c->daemon->conns.cust_timeout), \
-                          c, by_timeout);
-  }
+  mhd_conn_remove_from_timeout_lists (c);
 
 #ifndef NDEBUG
   c->dbg.closing_started = true;

+ 18 - 0
src/mhd2/stream_funcs.h

@@ -142,6 +142,24 @@ MHD_INTERNAL void
 mhd_stream_update_activity_mark (struct MHD_Connection *restrict c)
 MHD_FN_PAR_NONNULL_ALL_;
 
+
+/**
+ * Update last activity mark on the resumed connection
+ * @param c the connection to update
+ */
+MHD_INTERNAL void
+mhd_stream_resumed_activity_mark (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
+
+
+/**
+ * Remove connection from time-out lists
+ * @param c the connection to process
+ */
+MHD_INTERNAL void
+mhd_conn_remove_from_timeout_lists (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
+
 /**
  * Check whether connection's timeout is expired.
  * @param c the connection to update

+ 23 - 8
src/mhd2/stream_process_states.c

@@ -179,6 +179,22 @@ mhd_conn_event_loop_state_update (struct MHD_Connection *restrict c)
 }
 
 
+/**
+ * Finalise resuming of the connection
+ * @param c the connection to resume
+ */
+static MHD_FN_PAR_NONNULL_ALL_ void
+finish_resume (struct MHD_Connection *restrict c)
+{
+  mhd_assert (! c->suspended);
+  mhd_assert (c->resuming);
+  mhd_assert (MHD_EVENT_LOOP_INFO_PROCESS == c->event_loop_info);
+  mhd_stream_resumed_activity_mark (c);
+
+  c->resuming = false;
+}
+
+
 /**
  * Update current processing state: need to receive, need to send.
  * Mark stream as ready or not ready for processing.
@@ -248,13 +264,9 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
     }
   }
 
-  mhd_assert (c->resuming || ! c->suspended);
+  mhd_assert (! c->suspended);
   if (c->resuming)
-  {
-    // TODO: finish resuming, update activity mark
-    // TODO: move to special function
-    (void) 0;
-  }
+    finish_resume (c);
 
   if ((mhd_SOCKET_ERR_NO_ERROR != c->sk.state.discnt_err) ||
       (0 != (c->sk.ready & mhd_SOCKET_NET_STATE_ERROR_READY)))
@@ -278,6 +290,8 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
     return false;
   }
 
+  mhd_assert (! c->suspended);
+
   while (! c->suspended)
   {
 #ifdef MHD_SUPPORT_HTTPS
@@ -509,8 +523,9 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
 
   if (c->suspended)
   {
-    // TODO: process
-    mhd_assert (0 && "Not implemented yet");
+    /* Do not perform any network activity while suspended */
+    c->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS;
+    mhd_conn_remove_from_timeout_lists (c);
     return true;
   }