View Issue Details

IDProjectCategoryView StatusLast Update
0001491libmicrohttpdexternal APIpublic2009-08-29 00:37
Reporterdreiss Assigned ToChristian Grothoff  
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 20: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 06: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 Modified Username Field Change
2009-08-23 20:23 dreiss New Issue
2009-08-23 20:23 dreiss File Added: libmicrohttpd-get_listen_sock.patch
2009-08-24 20:37 dreiss Note Added: 0003871
2009-08-25 06:08 Christian Grothoff Note Added: 0003873
2009-08-25 06:08 Christian Grothoff Status new => assigned
2009-08-25 06:08 Christian Grothoff Assigned To => Christian Grothoff
2009-08-28 11:04 Christian Grothoff Status assigned => resolved
2009-08-28 11:04 Christian Grothoff Resolution open => fixed
2009-08-29 00:37 Christian Grothoff Status resolved => closed
2009-08-29 00:37 Christian Grothoff Fixed in Version => 0.4.3
2013-05-06 12:52 Christian Grothoff Category API => libmicrohttpd API
2024-01-21 13:24 Christian Grothoff Category libmicrohttpd API => external API