Sfoglia il codice sorgente

Fixed very rare data races when closing upgraded connection

Evgeny Grin (Karlson2k) 3 anni fa
parent
commit
a59760c5db
3 ha cambiato i file con 57 aggiunte e 3 eliminazioni
  1. 38 0
      src/microhttpd/daemon.c
  2. 15 0
      src/microhttpd/internal.h
  3. 4 3
      src/microhttpd/response.c

+ 38 - 0
src/microhttpd/daemon.c

@@ -3269,6 +3269,44 @@ MHD_resume_connection (struct MHD_Connection *connection)
 }
 
 
+#ifdef UPGRADE_SUPPORT
+/**
+ * Mark upgraded connection as closed by application.
+ *
+ * The @a connection pointer must not be used after call of this function
+ * as it may be freed in other thread immediately.
+ * @param connection the upgraded connection to mark as closed by application
+ */
+void
+MHD_upgraded_connection_mark_app_closed_ (struct MHD_Connection *connection)
+{
+  /* Cache 'daemon' here to avoid data races */
+  struct MHD_Daemon *const daemon = connection->daemon;
+#if defined(MHD_USE_THREADS)
+  mhd_assert (NULL == daemon->worker_pool);
+#endif /* MHD_USE_THREADS */
+  mhd_assert (NULL != connection->urh);
+  mhd_assert (0 != (daemon->options & MHD_TEST_ALLOW_SUSPEND_RESUME));
+
+  MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
+  connection->urh->was_closed = true;
+  connection->resuming = true;
+  daemon->resuming = true;
+  MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
+  if ( (MHD_ITC_IS_VALID_ (daemon->itc)) &&
+       (! MHD_itc_activate_ (daemon->itc, "r")) )
+  {
+#ifdef HAVE_MESSAGES
+    MHD_DLOG (daemon,
+              _ ("Failed to signal resume via " \
+                 "inter-thread communication channel.\n"));
+#endif
+  }
+}
+
+
+#endif /* UPGRADE_SUPPORT */
+
 /**
  * Run through the suspended connections and move any that are no
  * longer suspended back to the active state.

+ 15 - 0
src/microhttpd/internal.h

@@ -2408,4 +2408,19 @@ MHD_check_response_header_token_ci (const struct MHD_Response *response,
 void
 internal_suspend_connection_ (struct MHD_Connection *connection);
 
+
+#ifdef UPGRADE_SUPPORT
+/**
+ * Mark upgraded connection as closed by application.
+ *
+ * The @a connection pointer must not be used after call of this function
+ * as it may be freed in other thread immediately.
+ * @param connection the upgraded connection to mark as closed by application
+ */
+void
+MHD_upgraded_connection_mark_app_closed_ (struct MHD_Connection *connection);
+
+#endif /* UPGRADE_SUPPORT */
+
+
 #endif

+ 4 - 3
src/microhttpd/response.c

@@ -1587,11 +1587,12 @@ MHD_upgrade_action (struct MHD_UpgradeResponseHandle *urh,
     }
 #endif /* HTTPS_SUPPORT */
     mhd_assert (MHD_CONNECTION_UPGRADE == connection->state);
-    urh->was_closed = true;
-    /* As soon as connection will be marked with BOTH
+    /* The next function will mark the connection as closed by application
+     * by setting 'urh->was_closed'.
+     * As soon as connection will be marked with BOTH
      * 'urh->was_closed' AND 'urh->clean_ready', it will
      * be moved to cleanup list by MHD_resume_connection(). */
-    MHD_resume_connection (connection);
+    MHD_upgraded_connection_mark_app_closed_ (connection);
     return MHD_YES;
   case MHD_UPGRADE_ACTION_CORK_ON:
     /* Unportable API. TODO: replace with portable action. */