add initial ipv6 support

Wed, 12 Oct 2022 23:34:20 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Wed, 12 Oct 2022 23:34:20 +0200
changeset 396
77d81f2bb9f7
parent 395
224c4e858125
child 397
f202a655f4c2

add initial ipv6 support

src/server/daemon/httplistener.c file | annotate | diff | comparison | revisions
src/server/daemon/httplistener.h file | annotate | diff | comparison | revisions
src/server/daemon/httprequest.c file | annotate | diff | comparison | revisions
src/server/daemon/sessionhandler.h file | annotate | diff | comparison | revisions
src/server/webdav/webdav.c file | annotate | diff | comparison | revisions
--- a/src/server/daemon/httplistener.c	Sun Sep 25 15:40:27 2022 +0200
+++ b/src/server/daemon/httplistener.c	Wed Oct 12 23:34:20 2022 +0200
@@ -36,6 +36,7 @@
 #include <sys/ipc.h>
 #include <sys/socket.h>
 #include <sys/file.h>
+#include <arpa/inet.h>
 #include <netinet/in.h>
 #include <netdb.h>
 #include <stdio.h>
@@ -46,6 +47,13 @@
 #include <stdbool.h>
 #include <pthread.h>
 
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
 #include <ucx/map.h>
 
 #include "../util/atomic.h"
@@ -91,6 +99,7 @@
     newls->default_vs.vs_name = conf->vs.ptr;  
     newls->port = fl->port;
     newls->server_socket = fl->server_socket;
+    newls->server_socket6 = fl->server_socket6;
     newls->running = 1;
     newls->threadpool = NULL;
     newls->ref = 2; // 1 reference is fl->next
@@ -111,6 +120,12 @@
         newls->acceptors[i] = acceptor_new(newls);
     }
     
+    newls->acceptors6 = calloc(newls->nacceptors, sizeof(void*));
+    for (int i=0;i<newls->nacceptors;i++) {
+        newls->acceptors6[i] = acceptor_new(newls);
+        newls->acceptors6[i]->ipv6 = TRUE;
+    }
+    
     // fl hold one reference of newls
     fl->next = newls;
     
@@ -118,7 +133,8 @@
     ucx_map_sstr_put(listener_map, newls->name, newls);
     
     for (int i=0;i<newls->nacceptors;i++) {
-        acceptor_start(newls->acceptors[i]);
+        //acceptor_start(newls->acceptors[i]);
+        acceptor_start(newls->acceptors6[i]);
     }
     
     // check if a restart is required to apply all changes
@@ -271,18 +287,29 @@
     ucx_map_sstr_put(listener_map, listener->name, listener);
 
     struct sockaddr_in servaddr;   /* server address */
+    struct sockaddr_in6 servaddr6;
 
     /* init address structure */
     memset(&servaddr, 0, sizeof(servaddr));
     servaddr.sin_family = AF_INET;
     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
     servaddr.sin_port = htons(conf->port);
+    
+    memset(&servaddr6, 0, sizeof(servaddr6));
+    servaddr6.sin6_family = AF_INET6;
+    servaddr6.sin6_addr = in6addr_any;
+    servaddr6.sin6_port = htons(conf->port);
 
     /* create socket */
     if((listener->server_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
         perror("Error: http_listener_new: socket");
         return NULL;
     }
+    
+    if((listener->server_socket6 = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)) == -1) {
+        perror("Error: http_listener_new: socket v6");
+        return NULL;
+    }
 
     int o = 1;
     setsockopt(
@@ -290,17 +317,31 @@
             SOL_SOCKET, SO_REUSEADDR,
             &o,
             sizeof(int));
+    o = 1;
+    setsockopt(
+            listener->server_socket6,
+            SOL_SOCKET, SO_REUSEADDR,
+            &o,
+            sizeof(int));
 
     /* bind server socket to address */
     if(bind(listener->server_socket, (struct sockaddr*)&servaddr, sizeof(servaddr))){
         log_ereport(LOG_FAILURE, "http_listener_new: bind failed. Port: %d", conf->port);
         return NULL;
     }
+    
+    if(bind(listener->server_socket6, (struct sockaddr*)&servaddr6, sizeof(servaddr6))){
+        log_ereport(LOG_FAILURE, "http_listener_new: bind v6 failed. Port: %d: %s", conf->port, strerror(errno));
+        return NULL;
+    }
 
     /* create acceptors */
     listener->acceptors = calloc(listener->nacceptors, sizeof(void*));
+    listener->acceptors6 = calloc(listener->nacceptors, sizeof(void*));
     for (int i=0;i<listener->nacceptors;i++) {
         listener->acceptors[i] = acceptor_new(listener);
+        listener->acceptors6[i] = acceptor_new(listener);
+        listener->acceptors6[i]->ipv6 = TRUE;
     }
 
     return listener;
@@ -316,10 +357,15 @@
         log_ereport(LOG_FAILURE, "http_listener_start: listen failed");
         return -1;
     }
+    if (listen(listener->server_socket6, 256) == -1) {
+        log_ereport(LOG_FAILURE, "http_listener_start: listen failed");
+        return -1;
+    }
 
     /* start acceptor threads */
     for (int i=0;i<listener->nacceptors;i++) {
         acceptor_start(listener->acceptors[i]);
+        acceptor_start(listener->acceptors6[i]);
     }
 
     return 0;
@@ -344,6 +390,7 @@
 Acceptor* acceptor_new(HttpListener *listener) {
     Acceptor *acceptor = malloc(sizeof(Acceptor));
     acceptor->listener = listener;
+    acceptor->ipv6 = WS_FALSE;
     return acceptor;
 }
 
@@ -366,19 +413,37 @@
     
     HttpListener *listener = acceptor->listener;
 
+    int server_socket;
+    
+    ConnectionAddr ca;
+    struct sockaddr *ca_ptr;
+    socklen_t ca_length;
+    ConnectionAddrType addr_type;
+    if(acceptor->ipv6) {
+        server_socket = listener->server_socket6;
+        ca_ptr = (struct sockaddr*)&ca.address_v6;
+        ca_length = sizeof(ca.address_v6);
+        addr_type = CONN_ADDR_IPV6;
+    } else {
+        server_socket = listener->server_socket;
+        ca_ptr = (struct sockaddr*)&ca.address_v4;
+        ca_length = sizeof(ca.address_v4);
+        addr_type = CONN_ADDR_IPV4;
+    }
+    
+    
     for (;;) {
         /* accept connections */
-        struct sockaddr_in ca;
-        socklen_t length = sizeof(ca);
         int clientfd;
+        socklen_t length = ca_length;
 
         /* accept a connection */
         clientfd = accept(
-                listener->server_socket,
-                (struct sockaddr*)&ca,
+                server_socket,
+                ca_ptr,
                 &length);
         if (clientfd == -1) {
-            perror("Error: acceptor_thread: accept");
+            log_ereport(LOG_FAILURE, "accept %s failed: %s", acceptor->ipv6 ? "ipv6" : "ipv4", strerror(errno));
             continue;
         }
                  
@@ -393,6 +458,7 @@
         /* create Connection object */
         Connection *conn = malloc(sizeof(Connection));
         conn->address = ca;
+        conn->addr_type = addr_type;
         conn->fd = clientfd;
         conn->listener = ls;
         conn->ssl_accepted = 0;
--- a/src/server/daemon/httplistener.h	Sun Sep 25 15:40:27 2022 +0200
+++ b/src/server/daemon/httplistener.h	Wed Oct 12 23:34:20 2022 +0200
@@ -73,6 +73,7 @@
 struct _acceptor {
     pthread_t      tid;
     HttpListener   *listener;
+    WSBool         ipv6;
 };
 
 struct _http_listener {
@@ -81,10 +82,12 @@
     union vs             default_vs;
     int                  port;
     int                  server_socket;
+    int                  server_socket6;
     SessionHandler       *session_handler;
     threadpool_t         *threadpool;
     HttpListener         *next;
     Acceptor             **acceptors;
+    Acceptor             **acceptors6;
     int                  nacceptors;
     int                  running;
     HttpSSL              *ssl;
--- a/src/server/daemon/httprequest.c	Sun Sep 25 15:40:27 2022 +0200
+++ b/src/server/daemon/httprequest.c	Wed Oct 12 23:34:20 2022 +0200
@@ -165,13 +165,16 @@
 
     // add ip to sn->client pblock
     char ip_str[INET_ADDRSTRLEN];
-    if(inet_ntop(
-            AF_INET,
-            &request->connection->address.sin_addr,
-            ip_str,
-            INET_ADDRSTRLEN) != NULL)
-    {
-        pblock_kvinsert(pb_key_ip, ip_str, INET_ADDRSTRLEN, sn->sn.client);
+    // TODO: ipv6
+    if(request->connection->addr_type == CONN_ADDR_IPV4) {
+        if(inet_ntop(
+                AF_INET,
+                &request->connection->address.address_v4.sin_addr,
+                ip_str,
+                INET_ADDRSTRLEN) != NULL)
+        {
+            pblock_kvinsert(pb_key_ip, ip_str, INET_ADDRSTRLEN, sn->sn.client);
+        }
     }
 
     // init NSAPI request structure
--- a/src/server/daemon/sessionhandler.h	Sun Sep 25 15:40:27 2022 +0200
+++ b/src/server/daemon/sessionhandler.h	Wed Oct 12 23:34:20 2022 +0200
@@ -45,9 +45,24 @@
 typedef struct _session_handler   SessionHandler;
 typedef struct _connection        Connection;
 
+typedef union ConnectionAddr      ConnectionAddr;
+
+union ConnectionAddr {
+    struct sockaddr_in   address_v4;
+    struct sockaddr_in6  address_v6;
+};
+
+enum ConnectionAddrType {
+    CONN_ADDR_IPV4 = 0,
+    CONN_ADDR_IPV6
+};
+
+typedef enum ConnectionAddrType ConnectionAddrType;
+
 struct _connection {
     int                  fd;
-    struct sockaddr_in   address;
+    ConnectionAddr       address;
+    ConnectionAddrType   addr_type;
     HttpListener         *listener;
     SessionHandler       *session_handler;
     SSL                  *ssl;
--- a/src/server/webdav/webdav.c	Sun Sep 25 15:40:27 2022 +0200
+++ b/src/server/webdav/webdav.c	Wed Oct 12 23:34:20 2022 +0200
@@ -539,21 +539,20 @@
         protocol_status(sn, rq, 201, NULL);
         protocol_start_response(sn, rq);
         ret = REQ_PROCEED;
-    } else {
-        if(rq->status_num <= 0) {
-            int status_code = 500;
-            if(op->vfs->vfs_errno == EEXIST) {
-                // 405 (Method Not Allowed) - MKCOL can only be executed on an unmapped URL.
-                status_code = 405;
-            } else if(op->vfs->vfs_errno == ENOENT) {
-                // 409 (Conflict) - A collection cannot be made at the Request-URI until
-                // one or more intermediate collections have been created.  The server
-                // MUST NOT create those intermediate collections automatically.
-                status_code = 409;
-            }
-            protocol_status(sn, rq, status_code, NULL);
+    } else if(rq->status_num <= 0) {
+        int status_code = 500;
+        if(op->vfs->vfs_errno == EEXIST) {
+            // 405 (Method Not Allowed) - MKCOL can only be executed on an unmapped URL.
+            status_code = 405;
+        } else if(op->vfs->vfs_errno == ENOENT) {
+            // 409 (Conflict) - A collection cannot be made at the Request-URI until
+            // one or more intermediate collections have been created.  The server
+            // MUST NOT create those intermediate collections automatically.
+            status_code = 409;
+        } else {
+            log_ereport(LOG_VERBOSE, "webdav_mkcol: errno: %d", op->vfs->vfs_errno);
         }
-        
+        protocol_status(sn, rq, status_code, NULL);
     }
     
     return ret;

mercurial