View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0001661 | libmicrohttpd | other | public | 2011-02-23 15:47 | 2011-03-04 10:57 |
Reporter | bplant | Assigned To | Christian Grothoff | ||
Priority | normal | Severity | feature | Reproducibility | N/A |
Status | closed | Resolution | fixed | ||
Product Version | 0.9.5 | ||||
Summary | 0001661: Allow externally created connections (reverse http?) | ||||
Description | Consider the following: 1. An outbound connection is made from the server to a remote host using socket s 2. A http client connects to the same remote host using socket t 3. The remote host joins the socket s and socket t together 4. The server creates a new MHD_Connection struct and socket s is assigned to it 5. MHD_handle_connection is called 6. Cleanup This might sound a bit crazy, but it's very useful for accessing a http interface for a device that is behind nat and/or a firewall without requiring port forwarding etc. All the attached patch is provide the option to make 3 functions non-static. These functions being: - MHD_handle_connection - recv_param_adapter - send_param_adapter | ||||
Additional Information | --- Code example --- // Connect to the remote host s = SOCKET(...); BIND(...); CONNECT(...); // Setup MHD_Connection struct connection = (struct MHD_Connection*)MALLOC(sizeof(struct MHD_Connection)); connection->daemon = mhd_daemon; memset(connection, 0, sizeof(struct MHD_Connection)); connection->pool = NULL; connection->addr = NULL; connection->addr_len = 0; connection->socket_fd = sock; connection->last_activity = time(NULL); MHD_set_http_callbacks_(connection); connection->recv_cls = &recv_param_adapter; connection->send_cls = &send_param_adapter; // Handle the connection MHD_handle_connection(arg); // Cleanup if(connection->pool != NULL) { MHD_pool_destroy(connection->pool); } if(connection->response != NULL) { MHD_destroy_response(connection->response); connection->response = NULL; } if(connection->addr != NULL) { FREE(connection->addr); connection->addr = NULL; } FREE(connection); | ||||
Tags | No tags attached. | ||||
Attached Files | mhd_ext_connections.patch (2,717 bytes)
Index: D:/svn/dspy/NEW/libmicrohttpd/tags/0.9.5-r1/src/daemon/daemon.c =================================================================== --- D:/svn/dspy/NEW/libmicrohttpd/tags/0.9.5-r1/src/daemon/daemon.c (revision 693) +++ D:/svn/dspy/NEW/libmicrohttpd/tags/0.9.5-r1/src/daemon/daemon.c (revision 694) @@ -553,7 +553,11 @@ * @param data the 'struct MHD_Connection' this thread will handle * @return always NULL */ +#ifdef MHD_ALLOW_EXTERNAL_CONNECTIONS +void * +#else static void * +#endif MHD_handle_connection (void *data) { struct MHD_Connection *con = data; @@ -676,7 +680,11 @@ * @param i maximum size of other (in bytes) * @return number of bytes actually received */ +#ifdef MHD_ALLOW_EXTERNAL_CONNECTIONS +ssize_t +#else static ssize_t +#endif recv_param_adapter (struct MHD_Connection *connection, void *other, size_t i) { if (connection->socket_fd == -1) @@ -694,7 +702,11 @@ * @param i number of bytes to write * @return actual number of bytes written */ +#ifdef MHD_ALLOW_EXTERNAL_CONNECTIONS +ssize_t +#else static ssize_t +#endif send_param_adapter (struct MHD_Connection *connection, const void *other, size_t i) { Index: D:/svn/dspy/NEW/libmicrohttpd/tags/0.9.5-r1/src/include/microhttpd.h =================================================================== --- D:/svn/dspy/NEW/libmicrohttpd/tags/0.9.5-r1/src/include/microhttpd.h (revision 693) +++ D:/svn/dspy/NEW/libmicrohttpd/tags/0.9.5-r1/src/include/microhttpd.h (revision 694) @@ -1078,7 +1078,39 @@ */ int MHD_run (struct MHD_Daemon *daemon); +#ifdef MHD_ALLOW_EXTERNAL_CONNECTIONS +/** + * Main function of the thread that handles an individual + * connection when MHD_USE_THREAD_PER_CONNECTION is set. + * + * @param data the 'struct MHD_Connection' this thread will handle + * @return always NULL + */ +void *MHD_handle_connection (void *data); +/** + * Callback for receiving data from the socket. + * + * @param conn the MHD connection structure + * @param other where to write received data to + * @param i maximum size of other (in bytes) + * @return number of bytes actually received + */ +ssize_t recv_param_adapter (struct MHD_Connection *connection, + void *other, size_t i); + +/** + * Callback for writing data to the socket. + * + * @param conn the MHD connection structure + * @param other data to write + * @param i number of bytes to write + * @return actual number of bytes written + */ +ssize_t send_param_adapter (struct MHD_Connection *connection, + const void *other, size_t i); +#endif + /* **************** Connection handling functions ***************** */ /** | ||||
|
That's an ugly solution. You can already do this with the existing API with a tiny trick. Here is what you do: main () { // start MHD as usual int s = connect_tcp () // socket, connect to 'reverse HTTP client' int d = connect_loopback () // socket, connect (loopback) to MHD on localhost bond (s, d); bond (d, s); close (s); close (d); // wait // eventually stop MHD } 'bond' here is a little function I wrote a long time ago which patches the two TCP streams together: int bond(int i, int o) { if (fork()) return 0; close(0); dup2(i, 0); close(1); dup2(o, 1); execlp("bond", "cat", "-", NULL); } The end. |
|
I agree that on a powerful PC with lots of memory, connecting via loopback would be a much more elegant solution. I had definitely considered that. Unfortunately, I'm running MHD on a tiny cortex M3 micro-controller (80MHz) that has very limited memory (96KB). Using the loopback interface would required extra memory (for tcp sockets & buffers) and use extra cpu cycles managing the connection and copying buffers etc. While my patch isn't the cleanest method of doing things, it is the least resource intensive. |
|
Oh, but you don't need to use loopback, you could use a UNIX domain socket as well. Would that be acceptable? |
|
I wish I could, but there are no unix domain sockets on this tiny micro-controller OS. |
|
Ok, I see. Well, I still don't like your API ;-). But maybe we can find a better one. What if we added a way to pass an existing TCP socket to 'MHD_start_daemon'? Would we need to be able to support disabling listening on a server socket as well? |
|
For my purposes, I wouldn't need to support disabling listening on a server socket. I would however like to be able to pass multiple different TCP sockets at any time during the lifetime of the server. I'm making multiple outbound connections at the moment that I'd like to pass to MHD. |
|
Added API to do this (MHD_add_connection) in SVN 14585. |
Date Modified | Username | Field | Change |
---|---|---|---|
2011-02-23 15:47 | bplant | New Issue | |
2011-02-23 15:47 | bplant | File Added: mhd_ext_connections.patch | |
2011-02-24 14:55 | root | Note Added: 0004265 | |
2011-02-24 14:57 | root | Assigned To | => Christian Grothoff |
2011-02-24 14:57 | root | Status | new => closed |
2011-02-24 14:57 | root | Resolution | open => no change required |
2011-02-24 15:15 | bplant | Note Added: 0004266 | |
2011-02-24 15:15 | bplant | Status | closed => feedback |
2011-02-24 15:15 | bplant | Resolution | no change required => reopened |
2011-02-28 13:51 | Christian Grothoff | Note Added: 0004272 | |
2011-02-28 14:09 | bplant | Note Added: 0004273 | |
2011-03-02 17:00 | Christian Grothoff | Note Added: 0004276 | |
2011-03-02 17:43 | bplant | Note Added: 0004278 | |
2011-03-04 10:33 | Christian Grothoff | Note Added: 0004288 | |
2011-03-04 10:33 | Christian Grothoff | Status | feedback => resolved |
2011-03-04 10:33 | Christian Grothoff | Resolution | reopened => fixed |
2011-03-04 10:57 | Christian Grothoff | Status | resolved => closed |