HTTP server: host=@ listens on IPV6 and IPV4 if possible
authorAdam Dickmeiss <adam@indexdata.dk>
Thu, 16 May 2013 14:00:27 +0000 (16:00 +0200)
committerAdam Dickmeiss <adam@indexdata.dk>
Thu, 16 May 2013 14:01:56 +0000 (16:01 +0200)
Also, allow ports to be given as names (not just integers).
Fix @-notation on systems that don't support IPV6 sockets.

src/http.c
src/http.h
src/pazpar2_config.c
src/pazpar2_config.h

index 74fdf66..6748bbe 100644 (file)
@@ -758,7 +758,6 @@ static int http_proxy(struct http_request *rq)
     struct http_proxy *p = c->proxy;
     struct http_header *hp;
     struct http_buf *requestbuf;
-    char server_port[16] = "";
     struct conf_server *ser = c->server;
 
     if (!p) // This is a new connection. Create a proxy channel
@@ -818,13 +817,12 @@ static int http_proxy(struct http_request *rq)
                                 "X-Pazpar2-Version", PACKAGE_VERSION);
         hp = http_header_append(c, hp,
                                 "X-Pazpar2-Server-Host", ser->host);
-        sprintf(server_port, "%d",  ser->port);
         hp = http_header_append(c, hp,
-                                "X-Pazpar2-Server-Port", server_port);
+                                "X-Pazpar2-Server-Port", ser->port);
         yaz_snprintf(server_via, sizeof(server_via),
                      "1.1 %s:%s (%s/%s)",
-                     ser->host ? ser->host : "@",
-                     server_port, PACKAGE_NAME, PACKAGE_VERSION);
+                     ser->host, ser->port,
+                     PACKAGE_NAME, PACKAGE_VERSION);
         hp = http_header_append(c, hp, "Via" , server_via);
         hp = http_header_append(c, hp, "X-Forwarded-For", c->addr);
     }
@@ -1212,19 +1210,17 @@ static void http_accept(IOCHAN i, int event)
 }
 
 /* Create a http-channel listener, syntax [host:]port */
-int http_init(const char *addr, struct conf_server *server,
-              const char *record_fname)
+int http_init(struct conf_server *server, const char *record_fname)
 {
     IOCHAN c;
-    int l;
+    int s = -1;
     int one = 1;
-    const char *pp;
     FILE *record_file = 0;
-    struct addrinfo hints, *ai = 0;
+    struct addrinfo hints, *af = 0, *ai;
     int error;
     int ipv6_only = -1;
 
-    yaz_log(YLOG_LOG, "HTTP listener %s", addr);
+    yaz_log(YLOG_LOG, "HTTP listener %s:%s", server->host, server->port);
 
     hints.ai_flags = 0;
     hints.ai_family = AF_UNSPEC;
@@ -1235,70 +1231,76 @@ int http_init(const char *addr, struct conf_server *server,
     hints.ai_canonname      = NULL;
     hints.ai_next           = NULL;
 
-    pp = strchr(addr, ':');
-    if (pp)
+    if (!strcmp(server->host, "@"))
     {
-        WRBUF w = wrbuf_alloc();
-        wrbuf_write(w, addr, pp - addr);
-        if (!strcmp(wrbuf_cstr(w), "@"))
-        {   /* IPV4 + IPV6 .. same as YAZ */
-            ipv6_only = 0;
-            hints.ai_flags = AI_PASSIVE;
-            hints.ai_family = AF_INET6;
-            error = getaddrinfo(0, pp + 1, &hints, &ai);
-        }
-        else
-            error = getaddrinfo(wrbuf_cstr(w), pp + 1, &hints, &ai);
-        wrbuf_destroy(w);
-    }
-    else
-    {
-        /* default for no host given is IPV4 */
+        ipv6_only = 0;
         hints.ai_flags = AI_PASSIVE;
-        hints.ai_family = AF_INET;
-        error = getaddrinfo(0, addr, &hints, &ai);
+        error = getaddrinfo(0, server->port, &hints, &af);
     }
+    else
+        error = getaddrinfo(server->host, server->port, &hints, &af);
+
     if (error)
     {
-        yaz_log(YLOG_FATAL, "Failed to resolve %s: %s", addr,
+        yaz_log(YLOG_FATAL, "Failed to resolve %s: %s", server->host,
                 gai_strerror(error));
         return 1;
     }
-    l = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
-    if (l < 0)
+    for (ai = af; ai; ai = ai->ai_next)
+    {
+        if (ai->ai_family == AF_INET6)
+        {
+            s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+            if (s != -1)
+                break;
+        }
+    }
+    if (s == -1)
+    {
+        for (ai = af; ai; ai = ai->ai_next)
+        {
+            s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+            if (s != -1)
+                break;
+        }
+    }
+    if (s == -1)
     {
         yaz_log(YLOG_FATAL|YLOG_ERRNO, "socket");
         freeaddrinfo(ai);
         return 1;
     }
-    if (ipv6_only >= 0 &&
-        setsockopt(l, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6_only, sizeof(ipv6_only)))
+    if (ipv6_only >= 0 && ai->ai_family == AF_INET6 &&
+        setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6_only, sizeof(ipv6_only)))
     {
-        yaz_log(YLOG_FATAL|YLOG_ERRNO, "setsockopt IPV6_V6ONLY %s %d", addr,
-            ipv6_only);
+        yaz_log(YLOG_FATAL|YLOG_ERRNO, "setsockopt IPV6_V6ONLY %s:%s %d",
+                server->host, server->port, ipv6_only);
         freeaddrinfo(ai);
-        CLOSESOCKET(l);
+        CLOSESOCKET(s);
         return 1;
     }
-    if (setsockopt(l, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)))
+    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)))
     {
-        yaz_log(YLOG_FATAL|YLOG_ERRNO, "setsockopt SO_REUSEADDR %s", addr);
+        yaz_log(YLOG_FATAL|YLOG_ERRNO, "setsockopt SO_REUSEADDR %s:%s",
+                server->host, server->port);
         freeaddrinfo(ai);
-        CLOSESOCKET(l);
+        CLOSESOCKET(s);
         return 1;
     }
-    if (bind(l, ai->ai_addr, ai->ai_addrlen) < 0)
+    if (bind(s, ai->ai_addr, ai->ai_addrlen) < 0)
     {
-        yaz_log(YLOG_FATAL|YLOG_ERRNO, "bind %s", addr);
+        yaz_log(YLOG_FATAL|YLOG_ERRNO, "bind %s:%s",
+                server->host, server->port);
         freeaddrinfo(ai);
-        CLOSESOCKET(l);
+        CLOSESOCKET(s);
         return 1;
     }
     freeaddrinfo(ai);
-    if (listen(l, SOMAXCONN) < 0)
+    if (listen(s, SOMAXCONN) < 0)
     {
-        yaz_log(YLOG_FATAL|YLOG_ERRNO, "listen %s", addr);
-        CLOSESOCKET(l);
+        yaz_log(YLOG_FATAL|YLOG_ERRNO, "listen %s:%s",
+                server->host, server->port);
+        CLOSESOCKET(s);
         return 1;
     }
 
@@ -1308,16 +1310,16 @@ int http_init(const char *addr, struct conf_server *server,
         if (!record_file)
         {
             yaz_log(YLOG_FATAL|YLOG_ERRNO, "fopen %s", record_fname);
-            CLOSESOCKET(l);
+            CLOSESOCKET(s);
             return 1;
         }
     }
     server->http_server = http_server_create();
 
     server->http_server->record_file = record_file;
-    server->http_server->listener_socket = l;
+    server->http_server->listener_socket = s;
 
-    c = iochan_create(l, http_accept, EVENT_INPUT | EVENT_EXCEPT, "http_server");
+    c = iochan_create(s, http_accept, EVENT_INPUT | EVENT_EXCEPT, "http_server");
     iochan_setdata(c, server);
 
     iochan_add(server->iochan_man, c);
index dfe7446..1b1ae10 100644 (file)
@@ -104,8 +104,7 @@ void http_mutex_init(struct conf_server *server);
 void http_server_destroy(http_server_t hs);
 
 void http_set_proxyaddr(const char *url, struct conf_server *ser);
-int http_init(const char *addr, struct conf_server *ser,
-              const char *record_fname);
+int http_init(struct conf_server *ser, const char *record_fname);
 void http_close_server(struct conf_server *ser);
 void http_addheader(struct http_response *r,
                     const char *name, const char *value);
index 22e047d..d6053ae 100644 (file)
@@ -782,7 +782,7 @@ static struct conf_server *server_create(struct conf_config *config,
     struct conf_server *server = nmem_malloc(nmem, sizeof(struct conf_server));
     xmlChar *server_id = xmlGetProp(node, (xmlChar *) "id");
 
-    server->host = 0;
+    server->host = "@";
     server->port = 0;
     server->proxy_host = 0;
     server->proxy_port = 0;
@@ -811,10 +811,12 @@ static struct conf_server *server_create(struct conf_config *config,
         {
             xmlChar *port = xmlGetProp(n, (xmlChar *) "port");
             xmlChar *host = xmlGetProp(n, (xmlChar *) "host");
+
             if (port)
-                server->port = atoi((const char *) port);
+                server->port = nmem_strdup(nmem, (const char *) port);
             if (host)
                 server->host = nmem_strdup(nmem, (const char *) host);
+
             xmlFree(port);
             xmlFree(host);
         }
@@ -918,6 +920,11 @@ static struct conf_server *server_create(struct conf_config *config,
             return 0;
         }
     }
+    if (!server->port)
+    {
+        yaz_log(YLOG_FATAL, "No listening port given");
+        return 0;
+    }
     if (server->service)
     {
         struct conf_service *s;
@@ -1139,28 +1146,27 @@ int config_start_listeners(struct conf_config *conf,
     conf->iochan_man = iochan_man_create(conf->no_threads);
     for (ser = conf->servers; ser; ser = ser->next)
     {
-        WRBUF w = wrbuf_alloc();
+        WRBUF w;
         int r;
 
         ser->iochan_man = conf->iochan_man;
         if (listener_override)
         {
-            wrbuf_puts(w, listener_override);
-            listener_override = 0; /* only first server is overriden */
-        }
-        else
-        {
-            if (ser->host)
-                wrbuf_puts(w, ser->host);
-            if (ser->port)
+            const char *cp = strrchr(listener_override, ':');
+            if (cp)
             {
-                if (wrbuf_len(w))
-                    wrbuf_puts(w, ":");
-                wrbuf_printf(w, "%d", ser->port);
+                ser->host = nmem_strdupn(conf->nmem, listener_override,
+                                         cp - listener_override);
+                ser->port = nmem_strdup(conf->nmem, cp + 1);
+            }
+            else
+            {
+                ser->host = "@";
+                ser->port = nmem_strdup(conf->nmem, listener_override);
             }
+            listener_override = 0; /* only first server is overriden */
         }
-        r = http_init(wrbuf_cstr(w), ser, record_fname);
-        wrbuf_destroy(w);
+        r = http_init(ser, record_fname);
         if (r)
             return -1;
 
index c20bae6..deacda7 100644 (file)
@@ -143,7 +143,7 @@ int conf_service_sortkey_field_id(struct conf_service *service, const char * nam
 struct conf_server
 {
     char *host;
-    int port;
+    char *port;
     char *proxy_host;
     int proxy_port;
     char *myurl;