[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] [libmicrohttpd] GNU libmicrohttpd branch master updated. ca
From: |
gitolite |
Subject: |
[GNUnet-SVN] [libmicrohttpd] GNU libmicrohttpd branch master updated. ca582a0633be1d06210ad5eefca753f8e87d6211 |
Date: |
Fri, 4 Nov 2016 17:01:27 +0100 (CET) |
The branch, master has been updated
via ca582a0633be1d06210ad5eefca753f8e87d6211 (commit)
from f8e3016ce00c974c27657b18d843ebf775415c62 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit ca582a0633be1d06210ad5eefca753f8e87d6211
Author: Christian Grothoff <address@hidden>
Date: Fri Nov 4 17:01:25 2016 +0100
add example for MHD upgrade use
-----------------------------------------------------------------------
Summary of changes:
src/examples/Makefile.am | 6 +
src/examples/upgrade_example.c | 289 +++++++++++++++++++++++++++++++++++
src/microhttpd/test_upgrade_common.c | 2 +-
3 files changed, 296 insertions(+), 1 deletion(-)
create mode 100644 src/examples/upgrade_example.c
diff --git a/src/examples/Makefile.am b/src/examples/Makefile.am
index 495ab52..ee8918b 100644
--- a/src/examples/Makefile.am
+++ b/src/examples/Makefile.am
@@ -20,6 +20,7 @@ noinst_PROGRAMS = \
benchmark_https \
chunked_example \
minimal_example \
+ upgrade_example \
dual_stack_example \
minimal_example_comet \
querystring_example \
@@ -62,6 +63,11 @@ minimal_example_SOURCES = \
minimal_example_LDADD = \
$(top_builddir)/src/microhttpd/libmicrohttpd.la
+upgrade_example_SOURCES = \
+ upgrade_example.c
+upgrade_example_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+
timeout_SOURCES = \
timeout.c
timeout_LDADD = \
diff --git a/src/examples/upgrade_example.c b/src/examples/upgrade_example.c
new file mode 100644
index 0000000..a917b72
--- /dev/null
+++ b/src/examples/upgrade_example.c
@@ -0,0 +1,289 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2016 Christian Grothoff (and other contributing authors)
+
+ This library 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.
+
+ This library 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 upgrade_example.c
+ * @brief example for how to use libmicrohttpd upgrade
+ * @author Christian Grothoff
+ *
+ * Telnet to the HTTP server, use this in the request:
+ * GET / http/1.1
+ * Connection: Upgrade
+ *
+ * After this, whatever you type will be echo'ed back to you.
+ */
+
+#include "platform.h"
+#include <microhttpd.h>
+#include <pthread.h>
+
+#define PAGE "<html><head><title>libmicrohttpd
demo</title></head><body>libmicrohttpd demo</body></html>"
+
+
+/**
+ * Change socket to blocking.
+ *
+ * @param fd the socket to manipulate
+ * @return non-zero if succeeded, zero otherwise
+ */
+static void
+make_blocking (MHD_socket fd)
+{
+#if defined(MHD_POSIX_SOCKETS)
+ int flags;
+
+ flags = fcntl (fd, F_GETFL);
+ if (-1 == flags)
+ return;
+ if ((flags & ~O_NONBLOCK) != flags)
+ if (-1 == fcntl (fd, F_SETFL, flags & ~O_NONBLOCK))
+ abort ();
+#elif defined(MHD_WINSOCK_SOCKETS)
+ unsigned long flags = 1;
+
+ ioctlsocket (fd, FIONBIO, &flags);
+#endif /* MHD_WINSOCK_SOCKETS */
+
+}
+
+
+static void
+send_all (MHD_socket sock,
+ const char *buf,
+ size_t len)
+{
+ ssize_t ret;
+
+ make_blocking (sock);
+ for (size_t off = 0; off < len; off += ret)
+ {
+ ret = send (sock,
+ &buf[off],
+ len - off,
+ 0);
+ if (0 > ret)
+ {
+ if (EAGAIN == errno)
+ {
+ ret = 0;
+ continue;
+ }
+ break;
+ }
+ if (0 == ret)
+ break;
+ }
+}
+
+
+struct MyData
+{
+ struct MHD_UpgradeResponseHandle *urh;
+ char *extra_in;
+ size_t extra_in_size;
+ MHD_socket sock;
+};
+
+
+/**
+ * Main function for the thread that runs the interaction with
+ * the upgraded socket. Writes what it reads.
+ *
+ * @param cls the `struct MyData`
+ */
+static void *
+run_usock (void *cls)
+{
+ struct MyData *md = cls;
+ struct MHD_UpgradeResponseHandle *urh = md->urh;
+ char buf[128];
+ ssize_t got;
+
+ make_blocking (md->sock);
+ /* start by sending extra data MHD may have already read, if any */
+ if (0 != md->extra_in_size)
+ {
+ send_all (md->sock,
+ md->extra_in,
+ md->extra_in_size);
+ free (md->extra_in);
+ }
+ /* now echo in a loop */
+ while (1)
+ {
+ got = recv (md->sock,
+ buf,
+ sizeof (buf),
+ 0);
+ if (0 >= got)
+ break;
+ send_all (md->sock,
+ buf,
+ got);
+ }
+ free (md);
+ MHD_upgrade_action (urh,
+ MHD_UPGRADE_ACTION_CLOSE);
+ 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 already received on the socket will be made available in
+ * @e extra_in. This can happen if the application sent extra data
+ * before MHD send the upgrade response. The application should
+ * treat data from @a extra_in as if it had read it from the socket.
+ *
+ * Note that the application must not close() @a sock directly,
+ * but instead use #MHD_upgrade_action() for special operations
+ * on @a sock.
+ *
+ * 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` of 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). The application is expected
+ * to perform read()/recv() and write()/send() calls on the socket.
+ * The application may also call shutdown(), but must not call
+ * close() directly.
+ * @param urh argument for #MHD_upgrade_action()s on this @a connection.
+ * Applications must eventually use this callback to (indirectly)
+ * perform the close() action on the @a sock.
+ */
+static void
+uh_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)
+{
+ struct MyData *md;
+ pthread_t pt;
+
+ md = malloc (sizeof (struct MyData));
+ if (NULL == md)
+ abort ();
+ memset (md, 0, sizeof (struct MyData));
+ if (0 != extra_in_size)
+ {
+ md->extra_in = malloc (extra_in_size);
+ if (NULL == md->extra_in)
+ abort ();
+ memcpy (md->extra_in,
+ extra_in,
+ extra_in_size);
+ }
+ md->extra_in_size = extra_in_size;
+ md->sock = sock;
+ md->urh = urh;
+ if (0 != pthread_create (&pt,
+ NULL,
+ &run_usock,
+ md))
+ abort ();
+ /* Note that by detaching like this we make it impossible to ensure
+ a clean shutdown, as the we stop the daemon even if a worker thread
+ is still running. Alas, this is a simple example... */
+ pthread_detach (pt);
+}
+
+
+static int
+ahc_echo (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 **ptr)
+{
+ static int aptr;
+ struct MHD_Response *response;
+ int ret;
+
+ if (0 != strcmp (method, "GET"))
+ return MHD_NO; /* unexpected method */
+ if (&aptr != *ptr)
+ {
+ /* do never respond on first call */
+ *ptr = &aptr;
+ return MHD_YES;
+ }
+ *ptr = NULL; /* reset when done */
+ response = MHD_create_response_for_upgrade (&uh_cb,
+ NULL);
+
+ MHD_add_response_header (response,
+ MHD_HTTP_HEADER_UPGRADE,
+ "Echo Server");
+ ret = MHD_queue_response (connection,
+ MHD_HTTP_SWITCHING_PROTOCOLS,
+ response);
+ MHD_destroy_response (response);
+ return ret;
+}
+
+
+int
+main (int argc,
+ char *const *argv)
+{
+ struct MHD_Daemon *d;
+
+ if (argc != 2)
+ {
+ printf ("%s PORT\n", argv[0]);
+ return 1;
+ }
+ d = MHD_start_daemon (MHD_ALLOW_UPGRADE | MHD_USE_SELECT_INTERNALLY |
MHD_USE_DEBUG,
+ atoi (argv[1]),
+ NULL, NULL,
+ &ahc_echo, NULL,
+ MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 120,
+ MHD_OPTION_END);
+ if (d == NULL)
+ return 1;
+ (void) getc (stdin);
+ MHD_stop_daemon (d);
+ return 0;
+}
diff --git a/src/microhttpd/test_upgrade_common.c
b/src/microhttpd/test_upgrade_common.c
index f04288d..a96ffcd 100644
--- a/src/microhttpd/test_upgrade_common.c
+++ b/src/microhttpd/test_upgrade_common.c
@@ -131,7 +131,7 @@ notify_connection_cb (void *cls,
/**
- * Change socket to non-blocking.
+ * Change socket to blocking.
*
* @param fd the socket to manipulate
* @return non-zero if succeeded, zero otherwise
hooks/post-receive
--
GNU libmicrohttpd
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] [libmicrohttpd] GNU libmicrohttpd branch master updated. ca582a0633be1d06210ad5eefca753f8e87d6211,
gitolite <=