View Issue Details

IDProjectCategoryView StatusLast Update
0001491libmicrohttpdexternal APIpublic2009-08-28 22:37
Reporterdreiss Assigned ToChristian Grothoff Due Date
PrioritynormalSeverityfeatureReproducibilityalways
Status closedResolutionfixed 
Product VersionGit master 
Fixed in Version0.4.3 
Summary0001491: Allow MHD_get_daemon_info to return the daemon's listen socket
DescriptionIncludes a test case that uses this functionality to bind a server to an OS-assigned port, look the port up with getsockname, and curl it.

This is useful if you don't care what port the server starts on and you don't want to worry about port conflicts.
Additional InformationPatch released as public domain, or same license as libmicrohttpd, or copyright assigned to you, or whatever.
TagsNo tags attached.
Attached Files
libmicrohttpd-get_listen_sock.patch (4,477 bytes)   
commit 55bafbb567a97fe7ab852b46cefc5703ff90f3ca
Author: David Reiss <dreiss@facebook.com>
Date:   Sun Aug 23 16:21:35 2009 -0700

    Allow MHD_get_daemon_info to return the daemon's listen socket
    
    Includes a test case that uses this functionality to bind a server to
    an OS-assigned port, look the port up with getsockname, and curl it.

diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c
index cc6c036..ef292cb 100644
--- a/src/daemon/daemon.c
+++ b/src/daemon/daemon.c
@@ -1496,7 +1496,13 @@ const union MHD_DaemonInfo *
 MHD_get_daemon_info (struct MHD_Daemon *daemon,
                      enum MHD_DaemonInfoType infoType, ...)
 {
-  return NULL;
+  switch (infoType)
+    {
+    case MHD_DAEMON_INFO_LISTEN_FD:
+      return (const union MHD_DaemonInfo *) &daemon->socket_fd;
+    default:
+      return NULL;
+    };
 }
 
 /**
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index 6f358fe..256c8fc 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -595,7 +595,13 @@ enum MHD_DaemonInfoType
    * algorithm should be passed as an extra
    * argument (of type 'enum MHD_GNUTLS_HashAlgorithm').
    */
-  MHD_DAEMON_INFO_MAC_KEY_SIZE
+  MHD_DAEMON_INFO_MAC_KEY_SIZE,
+
+  /**
+   * Request the file descriptor for the listening socket.
+   * No extra arguments should be passed.
+   */
+  MHD_DAEMON_INFO_LISTEN_FD
 };
 
 
@@ -1176,6 +1182,11 @@ union MHD_DaemonInfo
    * Size of the mac key (unit??)
    */
   size_t mac_key_size;
+
+  /**
+   * Listen socket file descriptor
+   */
+  int listen_fd;
 };
 
 /**
diff --git a/src/testcurl/daemontest_get.c b/src/testcurl/daemontest_get.c
index acf2bcc..26feee9 100644
--- a/src/testcurl/daemontest_get.c
+++ b/src/testcurl/daemontest_get.c
@@ -32,6 +32,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include <sys/socket.h>
 
 #ifndef WINDOWS
 #include <unistd.h>
@@ -360,6 +361,79 @@ testExternalGet ()
   return 0;
 }
 
+static int
+testUnknownPortGet ()
+{
+  struct MHD_Daemon *d;
+  const union MHD_DaemonInfo *di;
+  CURL *c;
+  char buf[2048];
+  struct CBC cbc;
+  CURLcode errornum;
+
+  struct sockaddr_in addr;
+  socklen_t addr_len = sizeof(addr);
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_port = 0;
+  addr.sin_addr.s_addr = INADDR_ANY;
+
+  cbc.buf = buf;
+  cbc.size = 2048;
+  cbc.pos = 0;
+  d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+                        1, NULL, NULL, &ahc_echo, "GET",
+                        MHD_OPTION_SOCK_ADDR, &addr,
+                        MHD_OPTION_END);
+  if (d == NULL)
+    return 32768;
+
+  di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_LISTEN_FD);
+  if (di == NULL)
+    return 65536;
+
+  if (0 != getsockname(di->listen_fd, &addr, &addr_len))
+    return 131072;
+
+  if (addr.sin_family != AF_INET)
+    return 26214;
+
+  snprintf(buf, sizeof(buf), "http://localhost:%hu/hello_world",
+           ntohs(addr.sin_port));
+
+  c = curl_easy_init ();
+  curl_easy_setopt (c, CURLOPT_URL, buf);
+  curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
+  curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+  curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+  curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+  curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
+  if (oneone)
+    curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+  else
+    curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+  // NOTE: use of CONNECTTIMEOUT without also
+  //   setting NOSIGNAL results in really weird
+  //   crashes on my system!
+  curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+  if (CURLE_OK != (errornum = curl_easy_perform (c)))
+    {
+      fprintf (stderr,
+               "curl_easy_perform failed: `%s'\n",
+               curl_easy_strerror (errornum));
+      curl_easy_cleanup (c);
+      MHD_stop_daemon (d);
+      return 524288;
+    }
+  curl_easy_cleanup (c);
+  MHD_stop_daemon (d);
+  if (cbc.pos != strlen ("/hello_world"))
+    return 1048576;
+  if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+    return 2097152;
+  return 0;
+}
+
 
 
 int
@@ -374,6 +448,7 @@ main (int argc, char *const *argv)
   errorCount += testMultithreadedGet ();
   errorCount += testMultithreadedPoolGet ();
   errorCount += testExternalGet ();
+  errorCount += testUnknownPortGet ();
   if (errorCount != 0)
     fprintf (stderr, "Error (code: %u)\n", errorCount);
   curl_global_cleanup ();

Activities

dreiss

2009-08-24 18:37

reporter   ~0003871

I forgot to mention that I have no idea whether the test works on Windows. I am only able to test on Linux. The actual code is so simple that I am fairly sure it will work on all platforms, though.

Christian Grothoff

2009-08-25 04:08

manager   ~0003873

Interesting. Looks fine to me, I'll need to check & document it. Expect it to show in SVN HEAD in a few days...

Issue History

Date ModifiedUsernameFieldChange
2009-08-23 18:23dreissNew Issue
2009-08-23 18:23dreissFile Added: libmicrohttpd-get_listen_sock.patch
2009-08-24 18:37dreissNote Added: 0003871
2009-08-25 04:08Christian GrothoffNote Added: 0003873
2009-08-25 04:08Christian GrothoffStatusnew => assigned
2009-08-25 04:08Christian GrothoffAssigned To => Christian Grothoff
2009-08-28 09:04Christian GrothoffStatusassigned => resolved
2009-08-28 09:04Christian GrothoffResolutionopen => fixed
2009-08-28 22:37Christian GrothoffStatusresolved => closed
2009-08-28 22:37Christian GrothoffFixed in Version => 0.4.3
2013-05-06 10:52Christian GrothoffCategoryAPI => libmicrohttpd API
2024-01-21 12:24Christian GrothoffCategorylibmicrohttpd API => external API