View Issue Details

IDProjectCategoryView StatusLast Update
0001661libmicrohttpdotherpublic2011-03-04 10:57
Reporterbplant Assigned ToChristian Grothoff  
PrioritynormalSeverityfeatureReproducibilityN/A
Status closedResolutionfixed 
Product Version0.9.5 
Summary0001661: Allow externally created connections (reverse http?)
DescriptionConsider 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);
TagsNo 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 ***************** */
 
 /**
mhd_ext_connections.patch (2,717 bytes)   

Activities

root

2011-02-24 14:55

administrator   ~0004265

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.

bplant

2011-02-24 15:15

reporter   ~0004266

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.

Christian Grothoff

2011-02-28 13:51

manager   ~0004272

Oh, but you don't need to use loopback, you could use a UNIX domain socket as well. Would that be acceptable?

bplant

2011-02-28 14:09

reporter   ~0004273

I wish I could, but there are no unix domain sockets on this tiny micro-controller OS.

Christian Grothoff

2011-03-02 17:00

manager   ~0004276

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?

bplant

2011-03-02 17:43

reporter   ~0004278

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.

Christian Grothoff

2011-03-04 10:33

manager   ~0004288

Added API to do this (MHD_add_connection) in SVN 14585.

Issue History

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