gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r37871 - libmicrohttpd/src/microhttpd


From: gnunet
Subject: [GNUnet-SVN] r37871 - libmicrohttpd/src/microhttpd
Date: Sun, 4 Sep 2016 17:05:41 +0200

Author: grothoff
Date: 2016-09-04 17:05:41 +0200 (Sun, 04 Sep 2016)
New Revision: 37871

Added:
   libmicrohttpd/src/microhttpd/test_upgrade_common.c
Modified:
   libmicrohttpd/src/microhttpd/Makefile.am
   libmicrohttpd/src/microhttpd/test_upgrade.c
   libmicrohttpd/src/microhttpd/test_upgrade_ssl.c
Log:
factor out shared test logic, test with external select as well

Modified: libmicrohttpd/src/microhttpd/Makefile.am
===================================================================
--- libmicrohttpd/src/microhttpd/Makefile.am    2016-09-04 14:47:20 UTC (rev 
37870)
+++ libmicrohttpd/src/microhttpd/Makefile.am    2016-09-04 15:05:41 UTC (rev 
37871)
@@ -8,6 +8,8 @@
 lib_LTLIBRARIES = \
   libmicrohttpd.la
 
+EXTRA_DIST = test_upgrade_common.c
+
 noinst_DATA =
 MOSTLYCLEANFILES =
 

Modified: libmicrohttpd/src/microhttpd/test_upgrade.c
===================================================================
--- libmicrohttpd/src/microhttpd/test_upgrade.c 2016-09-04 14:47:20 UTC (rev 
37870)
+++ libmicrohttpd/src/microhttpd/test_upgrade.c 2016-09-04 15:05:41 UTC (rev 
37871)
@@ -4,7 +4,7 @@
 
      libmicrohttpd is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      libmicrohttpd is distributed in the hope that it will be useful, but
@@ -39,338 +39,19 @@
 #include <netinet/in.h>
 #include <netinet/ip.h>
 #include "mhd_sockets.h"
+#include "test_upgrade_common.c"
 
 
 /**
- * Thread we use to run the interaction with the upgraded socket.
- */
-static pthread_t pt;
-
-/**
- * Will be set to the upgraded socket.
- */
-static MHD_socket usock;
-
-/**
- * Thread we use to run the interaction with the upgraded socket.
- */
-static pthread_t pt_client;
-
-
-/**
- * Change itc FD options to be non-blocking.
+ * Test upgrading a connection.
  *
- * @param fd the FD to manipulate
- * @return non-zero if succeeded, zero otherwise
+ * @param flags which event loop style should be tested
+ * @param pool size of the thread pool, 0 to disable
  */
-static void
-make_blocking (MHD_socket fd)
-{
-  int flags;
-
-  flags = fcntl (fd, F_GETFL);
-  if (-1 == flags)
-    return;
-  if ((flags & ~O_NONBLOCK) != flags)
-    fcntl (fd, F_SETFL, flags & ~O_NONBLOCK);
-}
-
-
-static void
-send_all (MHD_socket sock,
-          const char *text)
-{
-  size_t len = strlen (text);
-  ssize_t ret;
-
-  make_blocking (sock);
-  for (size_t off = 0; off < len; off += ret)
-    {
-      ret = write (sock,
-                   &text[off],
-                   len - off);
-      if (-1 == ret)
-        {
-          if (EAGAIN == errno)
-            {
-              ret = 0;
-              continue;
-            }
-          abort ();
-        }
-    }
-}
-
-
-/**
- * Read character-by-character until we
- * get '\r\n\r\n'.
- */
-static void
-recv_hdr (MHD_socket sock)
-{
-  unsigned int i;
-  char next;
-  char c;
-  ssize_t ret;
-
-  make_blocking (sock);
-  next = '\r';
-  i = 0;
-  while (i < 4)
-    {
-      ret = read (sock,
-                  &c,
-                  1);
-      if (-1 == ret)
-        {
-          if (EAGAIN == errno)
-            {
-              ret = 0;
-              continue;
-            }
-          abort ();
-        }
-      if (0 == ret)
-        continue;
-      if (c == next)
-        {
-          i++;
-          if (next == '\r')
-            next = '\n';
-          else
-            next = '\r';
-          continue;
-        }
-      if (c == '\r')
-        {
-          i = 1;
-          next = '\n';
-          continue;
-        }
-      i = 0;
-      next = '\r';
-    }
-}
-
-
-static void
-recv_all (MHD_socket sock,
-          const char *text)
-{
-  size_t len = strlen (text);
-  char buf[len];
-  ssize_t ret;
-
-  make_blocking (sock);
-  for (size_t off = 0; off < len; off += ret)
-    {
-      ret = read (sock,
-                  &buf[off],
-                  len - off);
-      if (-1 == ret)
-        {
-          if (EAGAIN == errno)
-            {
-              ret = 0;
-              continue;
-            }
-          abort ();
-        }
-    }
-  if (0 != strncmp (text, buf, len))
-    abort();
-}
-
-
-/**
- * Main function for the thread that runs the interaction with
- * the upgraded socket.
- *
- * @param cls the handle for the upgrade
- */
-static void *
-run_usock (void *cls)
-{
-  struct MHD_UpgradeResponseHandle *urh = cls;
-
-  send_all (usock,
-            "Hello");
-  recv_all (usock,
-            "World");
-  send_all (usock,
-            "Finished");
-  MHD_upgrade_action (urh,
-                      MHD_UPGRADE_ACTION_CLOSE);
-  return NULL;
-}
-
-
-/**
- * Main function for the thread that runs the client-side of the
- * interaction with the upgraded socket.
- *
- * @param cls the client socket
- */
-static void *
-run_usock_client (void *cls)
-{
-  MHD_socket *sock = cls;
-
-  send_all (*sock,
-            "GET / HTTP/1.1\r\nConnection: Upgrade\r\n\r\n");
-  recv_hdr (*sock);
-  recv_all (*sock,
-            "Hello");
-  send_all (*sock,
-            "World");
-  recv_all (*sock,
-            "Finished");
-  MHD_socket_close_ (*sock);
-  return NULL;
-}
-
-
-/**
- * Function called after a protocol "upgrade" response was sent
- * successfully and the socket should now be controlled by some
- * protocol other than HTTP.
- *
- * Any data received on the socket will be made available in
- * 'data_in'.  The function should update 'data_in_size' to
- * reflect the number of bytes consumed from 'data_in' (the remaining
- * bytes will be made available in the next call to the handler).
- *
- * Any data that should be transmitted on the socket should be
- * stored in 'data_out'.  '*data_out_size' is initially set to
- * the available buffer space in 'data_out'.  It should be set to
- * the number of bytes stored in 'data_out' (which can be zero).
- *
- * The return value is a BITMASK that indicates how the function
- * intends to interact with the event loop.  It can request to be
- * notified for reading, writing, request to UNCORK the send buffer
- * (which MHD is allowed to ignore, if it is not possible to uncork on
- * the local platform), to wait for the 'external' select loop to
- * trigger another round.  It is also possible to specify "no events"
- * to terminate the connection; in this case, the
- * #MHD_RequestCompletedCallback will be called and all resources of
- * the connection will be released.
- *
- * Except when in 'thread-per-connection' mode, implementations
- * of this function should never block (as it will still be called
- * from within the main event loop).
- *
- * @param cls closure, whatever was given to 
#MHD_create_response_for_upgrade().
- * @param connection original HTTP connection handle,
- *                   giving the function a last chance
- *                   to inspect the original HTTP request
- * @param con_cls last value left in `*con_cls` in the 
`MHD_AccessHandlerCallback`
- * @param extra_in if we happened to have read bytes after the
- *                 HTTP header already (because the client sent
- *                 more than the HTTP header of the request before
- *                 we sent the upgrade response),
- *                 these are the extra bytes already read from @a sock
- *                 by MHD.  The application should treat these as if
- *                 it had read them from @a sock.
- * @param extra_in_size number of bytes in @a extra_in
- * @param sock socket to use for bi-directional communication
- *        with the client.  For HTTPS, this may not be a socket
- *        that is directly connected to the client and thus certain
- *        operations (TCP-specific setsockopt(), getsockopt(), etc.)
- *        may not work as expected (as the socket could be from a
- *        socketpair() or a TCP-loopback)
- * @param urh argument for #MHD_upgrade_action()s on this @a connection.
- *        Applications must eventually use this function to perform the
- *        close() action on the @a sock.
- */
-static void
-upgrade_cb (void *cls,
-            struct MHD_Connection *connection,
-            void *con_cls,
-            const char *extra_in,
-            size_t extra_in_size,
-            MHD_socket sock,
-            struct MHD_UpgradeResponseHandle *urh)
-{
-  usock = sock;
-  if (0 != extra_in_size)
-    abort ();
-  pthread_create (&pt,
-                  NULL,
-                  &run_usock,
-                  urh);
-}
-
-
-/**
- * A client has requested the given url using the given method
- * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT,
- * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc).  The callback
- * must call MHD callbacks to provide content to give back to the
- * client and return an HTTP status code (i.e. #MHD_HTTP_OK,
- * #MHD_HTTP_NOT_FOUND, etc.).
- *
- * @param cls argument given together with the function
- *        pointer when the handler was registered with MHD
- * @param url the requested url
- * @param method the HTTP method used (#MHD_HTTP_METHOD_GET,
- *        #MHD_HTTP_METHOD_PUT, etc.)
- * @param version the HTTP version string (i.e.
- *        #MHD_HTTP_VERSION_1_1)
- * @param upload_data the data being uploaded (excluding HEADERS,
- *        for a POST that fits into memory and that is encoded
- *        with a supported encoding, the POST data will NOT be
- *        given in upload_data and is instead available as
- *        part of #MHD_get_connection_values; very large POST
- *        data *will* be made available incrementally in
- *        @a upload_data)
- * @param upload_data_size set initially to the size of the
- *        @a upload_data provided; the method must update this
- *        value to the number of bytes NOT processed;
- * @param con_cls pointer that the callback can set to some
- *        address and that will be preserved by MHD for future
- *        calls for this request; since the access handler may
- *        be called many times (i.e., for a PUT/POST operation
- *        with plenty of upload data) this allows the application
- *        to easily associate some request-specific state.
- *        If necessary, this state can be cleaned up in the
- *        global #MHD_RequestCompletedCallback (which
- *        can be set with the #MHD_OPTION_NOTIFY_COMPLETED).
- *        Initially, `*con_cls` will be NULL.
- * @return #MHD_YES if the connection was handled successfully,
- *         #MHD_NO if the socket must be closed due to a serios
- *         error while handling the request
- */
 static int
-ahc_upgrade (void *cls,
-             struct MHD_Connection *connection,
-             const char *url,
-             const char *method,
-             const char *version,
-             const char *upload_data,
-             size_t *upload_data_size,
-             void **con_cls)
+test_upgrade (int flags,
+              unsigned int pool)
 {
-  struct MHD_Response *resp;
-  int ret;
-
-  resp = MHD_create_response_for_upgrade (&upgrade_cb,
-                                          NULL);
-  MHD_add_response_header (resp,
-                           MHD_HTTP_HEADER_UPGRADE,
-                           "Hello World Protocol");
-  ret = MHD_queue_response (connection,
-                            MHD_HTTP_SWITCHING_PROTOCOLS,
-                            resp);
-  MHD_destroy_response (resp);
-  return ret;
-}
-
-
-static int
-test_upgrade_internal (int flags,
-                       unsigned int pool)
-{
   struct MHD_Daemon *d;
   MHD_socket sock;
   struct sockaddr_in sa;
@@ -399,7 +80,9 @@
                   NULL,
                   &run_usock_client,
                   &sock);
-
+  if (0 == (flags & (MHD_USE_SELECT_INTERNALLY |
+                     MHD_USE_THREAD_PER_CONNECTION)) )
+    run_mhd_loop (d, flags);
   pthread_join (pt_client,
                 NULL);
   pthread_join (pt,
@@ -415,27 +98,36 @@
 {
   int error_count = 0;
 
-  error_count += test_upgrade_internal (MHD_USE_THREAD_PER_CONNECTION,
-                                        0);
-  error_count += test_upgrade_internal (MHD_USE_THREAD_PER_CONNECTION | 
MHD_USE_POLL,
-                                        0);
-  error_count += test_upgrade_internal (MHD_USE_SELECT_INTERNALLY,
-                                        0);
-  error_count += test_upgrade_internal (MHD_USE_SELECT_INTERNALLY,
-                                        2);
+  /* try external select */
+  error_count += test_upgrade (0,
+                               0);
+
+  /* Test thread-per-connection */
+  error_count += test_upgrade (MHD_USE_THREAD_PER_CONNECTION,
+                               0);
+  error_count += test_upgrade (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_POLL,
+                               0);
+
+  /* Test different event loops, with and without thread pool */
+  error_count += test_upgrade (MHD_USE_SELECT_INTERNALLY,
+                               0);
+  error_count += test_upgrade (MHD_USE_SELECT_INTERNALLY,
+                               2);
 #ifdef HAVE_POLL
-  error_count += test_upgrade_internal (MHD_USE_POLL_INTERNALLY,
-                                        0);
-  error_count += test_upgrade_internal (MHD_USE_POLL_INTERNALLY,
-                                        2);
+  error_count += test_upgrade (MHD_USE_POLL_INTERNALLY,
+                               0);
+  error_count += test_upgrade (MHD_USE_POLL_INTERNALLY,
+                               2);
 #endif
 #ifdef EPOLL_SUPPORT
-  error_count += test_upgrade_internal (MHD_USE_EPOLL_INTERNALLY,
-                                        0);
-  error_count += test_upgrade_internal (MHD_USE_EPOLL_INTERNALLY,
-                                        2);
+  error_count += test_upgrade (MHD_USE_EPOLL_INTERNALLY,
+                               0);
+  error_count += test_upgrade (MHD_USE_EPOLL_INTERNALLY,
+                               2);
 #endif
-  if (error_count != 0)
+
+  /* report result */
+  if (0 != error_count)
     fprintf (stderr,
              "Error (code: %u)\n",
              error_count);

Added: libmicrohttpd/src/microhttpd/test_upgrade_common.c
===================================================================
--- libmicrohttpd/src/microhttpd/test_upgrade_common.c                          
(rev 0)
+++ libmicrohttpd/src/microhttpd/test_upgrade_common.c  2016-09-04 15:05:41 UTC 
(rev 37871)
@@ -0,0 +1,451 @@
+/*
+     This file is part of libmicrohttpd
+     Copyright (C) 2016 Christian Grothoff
+
+     libmicrohttpd is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 2, or (at your
+     option) any later version.
+
+     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
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with libmicrohttpd; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file test_upgrade_common.c
+ * @brief Shared logic for testcases for libmicrohttpd upgrading a connection
+ * @author Christian Grothoff
+ */
+
+
+/**
+ * Thread we use to run the interaction with the upgraded socket.
+ */
+static pthread_t pt;
+
+/**
+ * Will be set to the upgraded socket.
+ */
+static MHD_socket usock;
+
+/**
+ * Thread we use to run the interaction with the upgraded socket.
+ */
+static pthread_t pt_client;
+
+/**
+ * Flag set to 1 once the test is finished.
+ */
+static int done;
+
+/**
+ * Change itc FD options to be non-blocking.
+ *
+ * @param fd the FD to manipulate
+ * @return non-zero if succeeded, zero otherwise
+ */
+static void
+make_blocking (MHD_socket fd)
+{
+  int flags;
+
+  flags = fcntl (fd, F_GETFL);
+  if (-1 == flags)
+    return;
+  if ((flags & ~O_NONBLOCK) != flags)
+    fcntl (fd, F_SETFL, flags & ~O_NONBLOCK);
+}
+
+
+static void
+send_all (MHD_socket sock,
+          const char *text)
+{
+  size_t len = strlen (text);
+  ssize_t ret;
+
+  make_blocking (sock);
+  for (size_t off = 0; off < len; off += ret)
+    {
+      ret = write (sock,
+                   &text[off],
+                   len - off);
+      if (-1 == ret)
+        {
+          if (EAGAIN == errno)
+            {
+              ret = 0;
+              continue;
+            }
+          abort ();
+        }
+    }
+}
+
+
+/**
+ * Read character-by-character until we
+ * get '\r\n\r\n'.
+ */
+static void
+recv_hdr (MHD_socket sock)
+{
+  unsigned int i;
+  char next;
+  char c;
+  ssize_t ret;
+
+  make_blocking (sock);
+  next = '\r';
+  i = 0;
+  while (i < 4)
+    {
+      ret = read (sock,
+                  &c,
+                  1);
+      if (-1 == ret)
+        {
+          if (EAGAIN == errno)
+            {
+              ret = 0;
+              continue;
+            }
+          abort ();
+        }
+      if (0 == ret)
+        continue;
+      if (c == next)
+        {
+          i++;
+          if (next == '\r')
+            next = '\n';
+          else
+            next = '\r';
+          continue;
+        }
+      if (c == '\r')
+        {
+          i = 1;
+          next = '\n';
+          continue;
+        }
+      i = 0;
+      next = '\r';
+    }
+}
+
+
+static void
+recv_all (MHD_socket sock,
+          const char *text)
+{
+  size_t len = strlen (text);
+  char buf[len];
+  ssize_t ret;
+
+  make_blocking (sock);
+  for (size_t off = 0; off < len; off += ret)
+    {
+      ret = read (sock,
+                  &buf[off],
+                  len - off);
+      if (-1 == ret)
+        {
+          if (EAGAIN == errno)
+            {
+              ret = 0;
+              continue;
+            }
+          abort ();
+        }
+    }
+  if (0 != strncmp (text, buf, len))
+    abort();
+}
+
+
+/**
+ * Main function for the thread that runs the interaction with
+ * the upgraded socket.
+ *
+ * @param cls the handle for the upgrade
+ */
+static void *
+run_usock (void *cls)
+{
+  struct MHD_UpgradeResponseHandle *urh = cls;
+
+  send_all (usock,
+            "Hello");
+  recv_all (usock,
+            "World");
+  send_all (usock,
+            "Finished");
+  MHD_upgrade_action (urh,
+                      MHD_UPGRADE_ACTION_CLOSE);
+  return NULL;
+}
+
+
+/**
+ * Main function for the thread that runs the client-side of the
+ * interaction with the upgraded socket.
+ *
+ * @param cls the client socket
+ */
+static void *
+run_usock_client (void *cls)
+{
+  MHD_socket *sock = cls;
+
+  send_all (*sock,
+            "GET / HTTP/1.1\r\nConnection: Upgrade\r\n\r\n");
+  recv_hdr (*sock);
+  recv_all (*sock,
+            "Hello");
+  send_all (*sock,
+            "World");
+  recv_all (*sock,
+            "Finished");
+  MHD_socket_close_ (*sock);
+  done = 1;
+  return NULL;
+}
+
+
+/**
+ * Function called after a protocol "upgrade" response was sent
+ * successfully and the socket should now be controlled by some
+ * protocol other than HTTP.
+ *
+ * Any data received on the socket will be made available in
+ * 'data_in'.  The function should update 'data_in_size' to
+ * reflect the number of bytes consumed from 'data_in' (the remaining
+ * bytes will be made available in the next call to the handler).
+ *
+ * Any data that should be transmitted on the socket should be
+ * stored in 'data_out'.  '*data_out_size' is initially set to
+ * the available buffer space in 'data_out'.  It should be set to
+ * the number of bytes stored in 'data_out' (which can be zero).
+ *
+ * The return value is a BITMASK that indicates how the function
+ * intends to interact with the event loop.  It can request to be
+ * notified for reading, writing, request to UNCORK the send buffer
+ * (which MHD is allowed to ignore, if it is not possible to uncork on
+ * the local platform), to wait for the 'external' select loop to
+ * trigger another round.  It is also possible to specify "no events"
+ * to terminate the connection; in this case, the
+ * #MHD_RequestCompletedCallback will be called and all resources of
+ * the connection will be released.
+ *
+ * Except when in 'thread-per-connection' mode, implementations
+ * of this function should never block (as it will still be called
+ * from within the main event loop).
+ *
+ * @param cls closure, whatever was given to 
#MHD_create_response_for_upgrade().
+ * @param connection original HTTP connection handle,
+ *                   giving the function a last chance
+ *                   to inspect the original HTTP request
+ * @param con_cls last value left in `*con_cls` in the 
`MHD_AccessHandlerCallback`
+ * @param extra_in if we happened to have read bytes after the
+ *                 HTTP header already (because the client sent
+ *                 more than the HTTP header of the request before
+ *                 we sent the upgrade response),
+ *                 these are the extra bytes already read from @a sock
+ *                 by MHD.  The application should treat these as if
+ *                 it had read them from @a sock.
+ * @param extra_in_size number of bytes in @a extra_in
+ * @param sock socket to use for bi-directional communication
+ *        with the client.  For HTTPS, this may not be a socket
+ *        that is directly connected to the client and thus certain
+ *        operations (TCP-specific setsockopt(), getsockopt(), etc.)
+ *        may not work as expected (as the socket could be from a
+ *        socketpair() or a TCP-loopback)
+ * @param urh argument for #MHD_upgrade_action()s on this @a connection.
+ *        Applications must eventually use this function to perform the
+ *        close() action on the @a sock.
+ */
+static void
+upgrade_cb (void *cls,
+            struct MHD_Connection *connection,
+            void *con_cls,
+            const char *extra_in,
+            size_t extra_in_size,
+            MHD_socket sock,
+            struct MHD_UpgradeResponseHandle *urh)
+{
+  usock = sock;
+  if (0 != extra_in_size)
+    abort ();
+  pthread_create (&pt,
+                  NULL,
+                  &run_usock,
+                  urh);
+}
+
+
+/**
+ * A client has requested the given url using the given method
+ * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT,
+ * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc).  The callback
+ * must call MHD callbacks to provide content to give back to the
+ * client and return an HTTP status code (i.e. #MHD_HTTP_OK,
+ * #MHD_HTTP_NOT_FOUND, etc.).
+ *
+ * @param cls argument given together with the function
+ *        pointer when the handler was registered with MHD
+ * @param url the requested url
+ * @param method the HTTP method used (#MHD_HTTP_METHOD_GET,
+ *        #MHD_HTTP_METHOD_PUT, etc.)
+ * @param version the HTTP version string (i.e.
+ *        #MHD_HTTP_VERSION_1_1)
+ * @param upload_data the data being uploaded (excluding HEADERS,
+ *        for a POST that fits into memory and that is encoded
+ *        with a supported encoding, the POST data will NOT be
+ *        given in upload_data and is instead available as
+ *        part of #MHD_get_connection_values; very large POST
+ *        data *will* be made available incrementally in
+ *        @a upload_data)
+ * @param upload_data_size set initially to the size of the
+ *        @a upload_data provided; the method must update this
+ *        value to the number of bytes NOT processed;
+ * @param con_cls pointer that the callback can set to some
+ *        address and that will be preserved by MHD for future
+ *        calls for this request; since the access handler may
+ *        be called many times (i.e., for a PUT/POST operation
+ *        with plenty of upload data) this allows the application
+ *        to easily associate some request-specific state.
+ *        If necessary, this state can be cleaned up in the
+ *        global #MHD_RequestCompletedCallback (which
+ *        can be set with the #MHD_OPTION_NOTIFY_COMPLETED).
+ *        Initially, `*con_cls` will be NULL.
+ * @return #MHD_YES if the connection was handled successfully,
+ *         #MHD_NO if the socket must be closed due to a serios
+ *         error while handling the request
+ */
+static int
+ahc_upgrade (void *cls,
+             struct MHD_Connection *connection,
+             const char *url,
+             const char *method,
+             const char *version,
+             const char *upload_data,
+             size_t *upload_data_size,
+             void **con_cls)
+{
+  struct MHD_Response *resp;
+  int ret;
+
+  resp = MHD_create_response_for_upgrade (&upgrade_cb,
+                                          NULL);
+  MHD_add_response_header (resp,
+                           MHD_HTTP_HEADER_UPGRADE,
+                           "Hello World Protocol");
+  ret = MHD_queue_response (connection,
+                            MHD_HTTP_SWITCHING_PROTOCOLS,
+                            resp);
+  MHD_destroy_response (resp);
+  return ret;
+}
+
+
+/**
+ * Run the MHD external event loop using select.
+ *
+ * @param daemon daemon to run it for
+ * @param flags the flags the daemon was started with
+ */
+static void
+run_mhd_select_loop (struct MHD_Daemon *daemon)
+{
+  fd_set rs;
+  fd_set ws;
+  fd_set es;
+  MHD_socket max_fd;
+  MHD_UNSIGNED_LONG_LONG to;
+  struct timeval tv;
+
+  while (! done)
+    {
+      FD_ZERO (&rs);
+      FD_ZERO (&ws);
+      FD_ZERO (&es);
+      max_fd = -1;
+      to = 1000;
+
+      if (MHD_YES !=
+          MHD_get_fdset (daemon,
+                         &rs,
+                         &ws,
+                         &es,
+                         &max_fd))
+        abort ();
+      MHD_get_timeout (daemon,
+                       &to);
+      tv.tv_sec = to / 1000;
+      tv.tv_usec = 1000 * (to % 1000);
+      select (max_fd + 1,
+              &rs,
+              &ws,
+              &es,
+              &tv);
+      MHD_run_from_select (daemon,
+                           &rs,
+                           &ws,
+                           &es);
+    }
+}
+
+
+/**
+ * Run the MHD external event loop using select.
+ *
+ * @param daemon daemon to run it for
+ * @param flags the flags the daemon was started with
+ */
+static void
+run_mhd_poll_loop (struct MHD_Daemon *daemon)
+{
+  abort (); // not implemented
+}
+
+
+/**
+ * Run the MHD external event loop using select.
+ *
+ * @param daemon daemon to run it for
+ * @param flags the flags the daemon was started with
+ */
+static void
+run_mhd_epoll_loop (struct MHD_Daemon *daemon)
+{
+  abort (); // not implemented
+}
+
+
+/**
+ * Run the MHD external event loop using select.
+ *
+ * @param daemon daemon to run it for
+ * @param flags the flags the daemon was started with
+ */
+static void
+run_mhd_loop (struct MHD_Daemon *daemon,
+              int flags)
+{
+  if (0 != (flags & MHD_USE_POLL))
+    run_mhd_poll_loop (daemon);
+#if EPOLL_SUPPORT
+  else if (0 != (flags & MHD_USE_EPOLL))
+    run_mhd_epoll_loop (daemon);
+#endif
+  else
+    run_mhd_select_loop (daemon);
+}

Modified: libmicrohttpd/src/microhttpd/test_upgrade_ssl.c
===================================================================
--- libmicrohttpd/src/microhttpd/test_upgrade_ssl.c     2016-09-04 14:47:20 UTC 
(rev 37870)
+++ libmicrohttpd/src/microhttpd/test_upgrade_ssl.c     2016-09-04 15:05:41 UTC 
(rev 37871)
@@ -4,7 +4,7 @@
 
      libmicrohttpd is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      libmicrohttpd is distributed in the hope that it will be useful, but
@@ -40,26 +40,12 @@
 #include <netinet/ip.h>
 #include <pthread.h>
 #include "mhd_sockets.h"
+#include "test_upgrade_common.c"
 
 #include "../testcurl/https/tls_test_keys.h"
 
 
 /**
- * Thread we use to run the interaction with the upgraded socket.
- */
-static pthread_t pt;
-
-/**
- * Will be set to the upgraded socket.
- */
-static MHD_socket usock;
-
-/**
- * Thread we use to run the interaction with the upgraded socket.
- */
-static pthread_t pt_client;
-
-/**
  * Fork child that connects via OpenSSL to our @a port.  Allows us to
  * talk to our port over a socket in @a sp without having to worry
  * about TLS.
@@ -109,323 +95,15 @@
 
 
 /**
- * Change itc FD options to be non-blocking.
+ * Test upgrading a connection.
  *
- * @param fd the FD to manipulate
- * @return non-zero if succeeded, zero otherwise
+ * @param flags which event loop style should be tested
+ * @param pool size of the thread pool, 0 to disable
  */
-static void
-make_blocking (MHD_socket fd)
-{
-  int flags;
-
-  flags = fcntl (fd, F_GETFL);
-  if (-1 == flags)
-    return;
-  if ((flags & ~O_NONBLOCK) != flags)
-    fcntl (fd, F_SETFL, flags & ~O_NONBLOCK);
-}
-
-
-static void
-send_all (MHD_socket sock,
-          const char *text)
-{
-  size_t len = strlen (text);
-  ssize_t ret;
-
-  make_blocking (sock);
-  for (size_t off = 0; off < len; off += ret)
-    {
-      ret = write (sock,
-                   &text[off],
-                   len - off);
-      if (-1 == ret)
-        {
-          if (EAGAIN == errno)
-            {
-              ret = 0;
-              continue;
-            }
-          abort ();
-        }
-    }
-}
-
-
-/**
- * Read character-by-character until we
- * get '\r\n\r\n'.
- */
-static void
-recv_hdr (MHD_socket sock)
-{
-  unsigned int i;
-  char next;
-  char c;
-  ssize_t ret;
-
-  make_blocking (sock);
-  next = '\r';
-  i = 0;
-  while (i < 4)
-    {
-      ret = read (sock,
-                  &c,
-                  1);
-      if (0 == ret)
-        abort (); /* this is fatal */
-      if (-1 == ret)
-        {
-          if (EAGAIN == errno)
-            {
-              ret = 0;
-              continue;
-            }
-          abort ();
-        }
-      if (0 == ret)
-        continue;
-      if (c == next)
-        {
-          i++;
-          if (next == '\r')
-            next = '\n';
-          else
-            next = '\r';
-          continue;
-        }
-      if (c == '\r')
-        {
-          i = 1;
-          next = '\n';
-          continue;
-        }
-      i = 0;
-      next = '\r';
-    }
-}
-
-
-static void
-recv_all (MHD_socket sock,
-          const char *text)
-{
-  size_t len = strlen (text);
-  char buf[len];
-  ssize_t ret;
-
-  make_blocking (sock);
-  for (size_t off = 0; off < len; off += ret)
-    {
-      ret = read (sock,
-                  &buf[off],
-                  len - off);
-      if (0 == ret)
-        abort (); /* this is fatal */
-      if (-1 == ret)
-        {
-          if (EAGAIN == errno)
-            {
-              ret = 0;
-              continue;
-            }
-          abort ();
-        }
-    }
-  if (0 != strncmp (text, buf, len))
-    abort();
-}
-
-
-/**
- * Main function for the thread that runs the interaction with
- * the upgraded socket.
- *
- * @param cls the handle for the upgrade
- */
-static void *
-run_usock (void *cls)
-{
-  struct MHD_UpgradeResponseHandle *urh = cls;
-
-  send_all (usock,
-            "Hello");
-  recv_all (usock,
-            "World");
-  send_all (usock,
-            "Finished");
-  MHD_upgrade_action (urh,
-                      MHD_UPGRADE_ACTION_CLOSE);
-  return NULL;
-}
-
-
-/**
- * Main function for the thread that runs the client-side of the
- * interaction with the upgraded socket.
- *
- * @param cls the client socket
- */
-static void *
-run_usock_client (void *cls)
-{
-  MHD_socket *sock = cls;
-
-  send_all (*sock,
-            "GET / HTTP/1.1\r\nConnection: Upgrade\r\n\r\n");
-  recv_hdr (*sock);
-  recv_all (*sock,
-            "Hello");
-  send_all (*sock,
-            "World");
-  recv_all (*sock,
-            "Finished");
-  MHD_socket_close_ (*sock);
-  return NULL;
-}
-
-
-/**
- * Function called after a protocol "upgrade" response was sent
- * successfully and the socket should now be controlled by some
- * protocol other than HTTP.
- *
- * Any data received on the socket will be made available in
- * 'data_in'.  The function should update 'data_in_size' to
- * reflect the number of bytes consumed from 'data_in' (the remaining
- * bytes will be made available in the next call to the handler).
- *
- * Any data that should be transmitted on the socket should be
- * stored in 'data_out'.  '*data_out_size' is initially set to
- * the available buffer space in 'data_out'.  It should be set to
- * the number of bytes stored in 'data_out' (which can be zero).
- *
- * The return value is a BITMASK that indicates how the function
- * intends to interact with the event loop.  It can request to be
- * notified for reading, writing, request to UNCORK the send buffer
- * (which MHD is allowed to ignore, if it is not possible to uncork on
- * the local platform), to wait for the 'external' select loop to
- * trigger another round.  It is also possible to specify "no events"
- * to terminate the connection; in this case, the
- * #MHD_RequestCompletedCallback will be called and all resources of
- * the connection will be released.
- *
- * Except when in 'thread-per-connection' mode, implementations
- * of this function should never block (as it will still be called
- * from within the main event loop).
- *
- * @param cls closure, whatever was given to 
#MHD_create_response_for_upgrade().
- * @param connection original HTTP connection handle,
- *                   giving the function a last chance
- *                   to inspect the original HTTP request
- * @param con_cls last value left in `*con_cls` in the 
`MHD_AccessHandlerCallback`
- * @param extra_in if we happened to have read bytes after the
- *                 HTTP header already (because the client sent
- *                 more than the HTTP header of the request before
- *                 we sent the upgrade response),
- *                 these are the extra bytes already read from @a sock
- *                 by MHD.  The application should treat these as if
- *                 it had read them from @a sock.
- * @param extra_in_size number of bytes in @a extra_in
- * @param sock socket to use for bi-directional communication
- *        with the client.  For HTTPS, this may not be a socket
- *        that is directly connected to the client and thus certain
- *        operations (TCP-specific setsockopt(), getsockopt(), etc.)
- *        may not work as expected (as the socket could be from a
- *        socketpair() or a TCP-loopback)
- * @param urh argument for #MHD_upgrade_action()s on this @a connection.
- *        Applications must eventually use this function to perform the
- *        close() action on the @a sock.
- */
-static void
-upgrade_cb (void *cls,
-            struct MHD_Connection *connection,
-            void *con_cls,
-            const char *extra_in,
-            size_t extra_in_size,
-            MHD_socket sock,
-            struct MHD_UpgradeResponseHandle *urh)
-{
-  usock = sock;
-  if (0 != extra_in_size)
-    abort ();
-  pthread_create (&pt,
-                  NULL,
-                  &run_usock,
-                  urh);
-}
-
-
-/**
- * A client has requested the given url using the given method
- * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT,
- * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc).  The callback
- * must call MHD callbacks to provide content to give back to the
- * client and return an HTTP status code (i.e. #MHD_HTTP_OK,
- * #MHD_HTTP_NOT_FOUND, etc.).
- *
- * @param cls argument given together with the function
- *        pointer when the handler was registered with MHD
- * @param url the requested url
- * @param method the HTTP method used (#MHD_HTTP_METHOD_GET,
- *        #MHD_HTTP_METHOD_PUT, etc.)
- * @param version the HTTP version string (i.e.
- *        #MHD_HTTP_VERSION_1_1)
- * @param upload_data the data being uploaded (excluding HEADERS,
- *        for a POST that fits into memory and that is encoded
- *        with a supported encoding, the POST data will NOT be
- *        given in upload_data and is instead available as
- *        part of #MHD_get_connection_values; very large POST
- *        data *will* be made available incrementally in
- *        @a upload_data)
- * @param upload_data_size set initially to the size of the
- *        @a upload_data provided; the method must update this
- *        value to the number of bytes NOT processed;
- * @param con_cls pointer that the callback can set to some
- *        address and that will be preserved by MHD for future
- *        calls for this request; since the access handler may
- *        be called many times (i.e., for a PUT/POST operation
- *        with plenty of upload data) this allows the application
- *        to easily associate some request-specific state.
- *        If necessary, this state can be cleaned up in the
- *        global #MHD_RequestCompletedCallback (which
- *        can be set with the #MHD_OPTION_NOTIFY_COMPLETED).
- *        Initially, `*con_cls` will be NULL.
- * @return #MHD_YES if the connection was handled successfully,
- *         #MHD_NO if the socket must be closed due to a serios
- *         error while handling the request
- */
 static int
-ahc_upgrade (void *cls,
-             struct MHD_Connection *connection,
-             const char *url,
-             const char *method,
-             const char *version,
-             const char *upload_data,
-             size_t *upload_data_size,
-             void **con_cls)
+test_upgrade (int flags,
+              unsigned int pool)
 {
-  struct MHD_Response *resp;
-  int ret;
-
-  resp = MHD_create_response_for_upgrade (&upgrade_cb,
-                                          NULL);
-  MHD_add_response_header (resp,
-                           MHD_HTTP_HEADER_UPGRADE,
-                           "Hello World Protocol");
-  ret = MHD_queue_response (connection,
-                            MHD_HTTP_SWITCHING_PROTOCOLS,
-                            resp);
-  MHD_destroy_response (resp);
-  return ret;
-}
-
-
-static int
-test_upgrade_internal (int flags,
-                       unsigned int pool)
-{
   struct MHD_Daemon *d;
   MHD_socket sock;
   pid_t pid;
@@ -452,9 +130,14 @@
                   NULL,
                   &run_usock_client,
                   &sock);
-
+  if (0 == (flags & (MHD_USE_SELECT_INTERNALLY |
+                     MHD_USE_THREAD_PER_CONNECTION)) )
+    run_mhd_loop (d, flags);
   pthread_join (pt_client,
                 NULL);
+  if (0 == (flags & (MHD_USE_SELECT_INTERNALLY |
+                     MHD_USE_THREAD_PER_CONNECTION)) )
+    run_mhd_loop (d, flags);
   pthread_join (pt,
                 NULL);
   waitpid (pid,
@@ -474,30 +157,34 @@
   if (0 != system ("openssl version 1> /dev/null"))
     return 77; /* openssl not available, can't run the test */
 
+  /* try external select */
+  error_count += test_upgrade (0,
+                               0);
+
   /* Test thread-per-connection */
-  error_count += test_upgrade_internal (MHD_USE_THREAD_PER_CONNECTION,
-                                        0);
-  error_count += test_upgrade_internal (MHD_USE_THREAD_PER_CONNECTION | 
MHD_USE_POLL,
-                                        0);
+  error_count += test_upgrade (MHD_USE_THREAD_PER_CONNECTION,
+                               0);
+  error_count += test_upgrade (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_POLL,
+                               0);
 
   /* Test different event loops, with and without thread pool */
-  error_count += test_upgrade_internal (MHD_USE_SELECT_INTERNALLY,
-                                        0);
-  error_count += test_upgrade_internal (MHD_USE_SELECT_INTERNALLY,
-                                        2);
+  error_count += test_upgrade (MHD_USE_SELECT_INTERNALLY,
+                               0);
+  error_count += test_upgrade (MHD_USE_SELECT_INTERNALLY,
+                               2);
 #ifdef HAVE_POLL
-  error_count += test_upgrade_internal (MHD_USE_POLL_INTERNALLY,
-                                        0);
-  error_count += test_upgrade_internal (MHD_USE_POLL_INTERNALLY,
-                                        2);
+  error_count += test_upgrade (MHD_USE_POLL_INTERNALLY,
+                               0);
+  error_count += test_upgrade (MHD_USE_POLL_INTERNALLY,
+                               2);
 #endif
 #ifdef EPOLL_SUPPORT
-  error_count += test_upgrade_internal (MHD_USE_EPOLL_INTERNALLY |
-                                        MHD_USE_TLS_EPOLL_UPGRADE,
-                                        0);
-  error_count += test_upgrade_internal (MHD_USE_EPOLL_INTERNALLY |
-                                        MHD_USE_TLS_EPOLL_UPGRADE,
-                                        2);
+  error_count += test_upgrade (MHD_USE_EPOLL_INTERNALLY |
+                               MHD_USE_TLS_EPOLL_UPGRADE,
+                               0);
+  error_count += test_upgrade (MHD_USE_EPOLL_INTERNALLY |
+                               MHD_USE_TLS_EPOLL_UPGRADE,
+                               2);
 #endif
 
   /* report result */




reply via email to

[Prev in Thread] Current Thread [Next in Thread]