From 8ae0400b0d5804a03452ad39bf3a881f69026813 Mon Sep 17 00:00:00 2001
From: Sergey Lyubka <valenok@gmail.com>
Date: Sat, 25 Jan 2014 13:50:57 +0000
Subject: [PATCH] Added ability to set "0" as listening port. Exported local_ip
 and local_port to the client.

---
 mongoose.c  | 18 +++++++++++++++++-
 mongoose.h  |  2 ++
 unit_test.c | 12 +++++++++++-
 3 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/mongoose.c b/mongoose.c
index ed7be4814..e3bf97081 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -275,6 +275,7 @@ struct mg_server {
   mg_handler_t error_handler;
   mg_handler_t auth_handler;
   char *config_options[NUM_OPTIONS];
+  char local_ip[48];
   void *server_data;
 #ifdef MONGOOSE_USE_SSL
   SSL_CTX *ssl_ctx;            // Server SSL context
@@ -1214,6 +1215,7 @@ static void forward_post_data(struct connection *conn) {
 
 // 'sa' must be an initialized address to bind to
 static sock_t open_listening_socket(union socket_address *sa) {
+  socklen_t len = sizeof(*sa);
   sock_t on = 1, sock = INVALID_SOCKET;
 
   if ((sock = socket(sa->sa.sa_family, SOCK_STREAM, 6)) != INVALID_SOCKET &&
@@ -1222,6 +1224,8 @@ static sock_t open_listening_socket(union socket_address *sa) {
             sizeof(sa->sin) : sizeof(sa->sa)) &&
       !listen(sock, SOMAXCONN)) {
     set_non_blocking_mode(sock);
+    // In case port was set to 0, get the real port number
+    (void) getsockname(sock, &sa->sa, &len);
   } else if (sock != INVALID_SOCKET) {
     closesocket(sock);
     sock = INVALID_SOCKET;
@@ -1329,6 +1333,8 @@ static struct connection *accept_new_connection(struct mg_server *server) {
                        sizeof(conn->mg_conn.remote_ip), &sa);
     conn->mg_conn.remote_port = ntohs(sa.sin.sin_port);
     conn->mg_conn.server_param = server->server_data;
+    conn->mg_conn.local_ip = server->local_ip;
+    conn->mg_conn.local_port = ntohs(server->lsa.sin.sin_port);
     LINKED_LIST_ADD_TO_FRONT(&server->active_connections, &conn->link);
     DBG(("added conn %p", conn));
   }
@@ -4067,7 +4073,7 @@ static int parse_port_string(const char *str, union socket_address *sa) {
     port = 0;   // Parsing failure. Make port invalid.
   }
 
-  return port > 0 && port < 0xffff && str[len] == '\0';
+  return port <= 0xffff && str[len] == '\0';
 }
 
 const char *mg_set_option(struct mg_server *server, const char *name,
@@ -4092,6 +4098,16 @@ const char *mg_set_option(struct mg_server *server, const char *name,
       server->listening_sock = open_listening_socket(&server->lsa);
       if (server->listening_sock == INVALID_SOCKET) {
         error_msg = "Cannot bind to port";
+      } else {
+        sockaddr_to_string(server->local_ip, sizeof(server->local_ip),
+                           &server->lsa);
+        if (!strcmp(value, "0")) {
+          char buf[10];
+          mg_snprintf(buf, sizeof(buf), "%d",
+                      (int) ntohs(server->lsa.sin.sin_port));
+          free(server->config_options[ind]);
+          server->config_options[ind] = mg_strdup(buf);
+        }
       }
 #ifndef _WIN32
     } else if (ind == RUN_AS_USER) {
diff --git a/mongoose.h b/mongoose.h
index 459bf73bd..f15543269 100644
--- a/mongoose.h
+++ b/mongoose.h
@@ -38,6 +38,8 @@ struct mg_connection {
 
   char remote_ip[48];         // Max IPv6 string length is 45 characters
   int remote_port;            // Client's port
+  const char *local_ip;       // Local IP address
+  int local_port;             // Local port number
 
   int num_headers;            // Number of HTTP headers
   struct mg_header {
diff --git a/unit_test.c b/unit_test.c
index 171265f8e..53ff20851 100644
--- a/unit_test.c
+++ b/unit_test.c
@@ -289,7 +289,7 @@ static const char *test_parse_port_string(void) {
     NULL
   };
   static const char *invalid[] = {
-    "0", "99999", "1k", "1.2.3", "1.2.3.4:", "1.2.3.4:2p", NULL
+    "99999", "1k", "1.2.3", "1.2.3.4:", "1.2.3.4:2p", NULL
   };
   union socket_address sa;
   int i;
@@ -301,6 +301,7 @@ static const char *test_parse_port_string(void) {
   for (i = 0; invalid[i] != NULL; i++) {
     ASSERT(parse_port_string(invalid[i], &sa) == 0);
   }
+  ASSERT(parse_port_string("0", &sa) != 0);
 
   return NULL;
 }
@@ -577,6 +578,14 @@ static const char *test_ssl(void) {
 }
 #endif
 
+static const char *test_mg_set_option(void) {
+  struct mg_server *server = mg_create_server(NULL);
+  ASSERT(mg_set_option(server, "listening_port", "0") == NULL);
+  ASSERT(mg_get_option(server, "listening_port")[0] != '\0');
+  mg_destroy_server(&server);
+  return NULL;
+}
+
 static const char *run_all_tests(void) {
   RUN_TEST(test_should_keep_alive);
   RUN_TEST(test_match_prefix);
@@ -592,6 +601,7 @@ static const char *run_all_tests(void) {
   RUN_TEST(test_parse_multipart);
   RUN_TEST(test_server);
   RUN_TEST(test_mg_connect);
+  RUN_TEST(test_mg_set_option);
 #ifdef MONGOOSE_USE_SSL
   RUN_TEST(test_ssl);
 #endif
-- 
GitLab