[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 */
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r37871 - libmicrohttpd/src/microhttpd,
gnunet <=