tFirst version of multi listen. - geomyidae - A small C-based gopherd. (gopher://bitreich.org/1/scm/geomyidae)
git clone git://r-36.net/geomyidae
Log
Files
Refs
README
LICENSE
---
commit 60f33bbe3b6c58d451dad69933c1eb8b36cf3997
parent 3c940036398f0c5cb4b3822cb6f8ea1a76e2c968
Author: Christoph Lohmann <20h@r-36.net>
Date:   Sun, 11 Nov 2018 13:02:32 +0100

First version of multi listen.

Diffstat:
  main.c                              |     212 +++++++++++++++++++++++--------

1 file changed, 156 insertions(+), 56 deletions(-)
---
diff --git a/main.c b/main.c
t@@ -24,6 +24,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 #include "ind.h"
 #include "handlr.h"
t@@ -40,7 +42,8 @@ enum {
 
 int glfd = -1;
 int loglvl = 15;
-int listfd = -1;
+int *listfds = NULL;
+int nlistfds = 0;
 int revlookup = 1;
 char *logfile = NULL;
 
t@@ -253,6 +256,8 @@ handlerequest(int sock, char *base, char *ohost, char *port, char *clienth,
 void
 sighandler(int sig)
 {
+        int i;
+
         switch (sig) {
         case SIGCHLD:
                 while (waitpid(-1, NULL, WNOHANG) > 0);
t@@ -266,9 +271,13 @@ sighandler(int sig)
                         close(glfd);
                         glfd = -1;
                 }
-                if (listfd >= 0) {
-                        shutdown(listfd, SHUT_RDWR);
-                        close(listfd);
+                if (listfds != NULL) {
+                        for (i = 0; i < nlistfds; i++) {
+                                if (listfds[i] >= 0) {
+                                        shutdown(listfds[i], SHUT_RDWR);
+                                        close(listfds[i]);
+                                }
+                        }
                 }
                 exit(0);
                 break;
t@@ -295,60 +304,89 @@ initsignals(void)
  * TODO: Move Linux and BSD to Plan 9 socket and bind handling, so we do not
  *       need the inconsistent return and exit on getaddrinfo.
  */
-int
-getlistenfd(struct addrinfo *hints, char *bindip, char *port)
+int *
+getlistenfd(struct addrinfo *hints, char *bindip, char *port, int *rlfdnum)
 {
         char addstr[INET6_ADDRSTRLEN];
         struct addrinfo *ai, *rp;
         void *sinaddr;
-        int on, listenfd, aierr, errno_save;
+        int on, *listenfds, *listenfd, aierr, errno_save;
 
         if ((aierr = getaddrinfo(bindip, port, hints, &ai)) || ai == NULL) {
                 fprintf(stderr, "getaddrinfo (%s:%s): %s\n", bindip, port,
-                                gai_strerror(aierr));
+                        gai_strerror(aierr));
                 exit(1);
         }
 
-        listenfd = -1;
+        *rlfdnum = 0;
+        listenfds = NULL;
         on = 1;
         for (rp = ai; rp != NULL; rp = rp->ai_next) {
-                listenfd = socket(rp->ai_family, rp->ai_socktype,
+                printf("getaddrinfo result: %s:%d\n", rp->ai_canonname,
+                                rp->ai_protocol);
+                listenfds = xrealloc(listenfds,
+                                sizeof(*listenfds) * (++*rlfdnum));
+                listenfd = &listenfds[*rlfdnum-1];
+
+                *listenfd = socket(rp->ai_family, rp->ai_socktype,
                                 rp->ai_protocol);
-                if (listenfd < 0)
+                printf("*listenfd = %d\n", *listenfd);
+                if (*listenfd < 0)
+                        continue;
+                if (setsockopt(*listenfd, SOL_SOCKET, SO_REUSEADDR, &on,
+                                sizeof(on)) < 0) {
+                        printf("setsockopt failed\n");
+                        close(*listenfd);
+                        (*rlfdnum)--;
+                        continue;
+                }
+
+                if (rp->ai_family == AF_INET6 && (setsockopt(*listenfd,
+                                IPPROTO_IPV6, IPV6_V6ONLY, &on,
+                                sizeof(on)) < 0)) {
+                        printf("ipv6 only failed\n");
+                        close(*listenfd);
+                        (*rlfdnum)--;
                         continue;
-                if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on,
-                                        sizeof(on)) < 0) {
-                        close(listenfd);
-                        listenfd = -1;
-                        break;
                 }
 
                 sinaddr = (rp->ai_family == AF_INET) ?
                           (void *)&((struct sockaddr_in *)rp->ai_addr)->sin_addr :
                           (void *)&((struct sockaddr_in6 *)rp->ai_addr)->sin6_addr;
 
-                if (bind(listenfd, rp->ai_addr, rp->ai_addrlen) == 0) {
+                if (bind(*listenfd, rp->ai_addr, rp->ai_addrlen) == 0) {
                         if (loglvl & CONN && inet_ntop(rp->ai_family, sinaddr,
-                            addstr, sizeof(addstr))) {
+                                        addstr, sizeof(addstr))) {
+                                /* Do not revlookup here. */
+                                on = revlookup;
+                                revlookup = 0;
                                 logentry(addstr, port, "-", "listening");
+                                revlookup = on;
                         }
-                        break;
+                        continue;
                 }
 
                 /* Save errno, because fprintf in logentry overwrites it. */
                 errno_save = errno;
-                close(listenfd);
+                close(*listenfd);
+                (*rlfdnum)--;
                 if (loglvl & CONN && inet_ntop(rp->ai_family, sinaddr,
-                    addstr, sizeof(addstr))) {
+                                addstr, sizeof(addstr))) {
+                        /* Do not revlookup here. */
+                        on = revlookup;
+                        revlookup = 0;
                         logentry(addstr, port, "-", "could not bind");
+                        revlookup = on;
                 }
                 errno = errno_save;
         }
         freeaddrinfo(ai);
-        if (rp == NULL)
-                return -1;
+        if (*rlfdnum < 1) {
+                free(listenfds);
+                return NULL;
+        }
 
-        return listenfd;
+        return listenfds;
 }
 
 void
t@@ -367,11 +405,13 @@ main(int argc, char *argv[])
         struct addrinfo hints;
         struct sockaddr_storage clt;
         socklen_t cltlen;
-        int sock, dofork, inetf, usechroot, nocgi, errno_save;
+        int sock, dofork, inetf, usechroot, nocgi, errno_save, nbindips, i, j,
+            nlfdret, *lfdret, listfd, maxlfd;
         char *port, *base, clienth[NI_MAXHOST], clientp[NI_MAXSERV];
-        char *user, *group, *bindip, *ohost, *sport, *p;
+        char *user, *group, **bindips, *ohost, *sport, *p;
         struct passwd *us;
         struct group *gr;
+        fd_set rfd;
 
         base = stdbase;
         port = stdport;
t@@ -380,7 +420,8 @@ main(int argc, char *argv[])
         group = NULL;
         us = NULL;
         gr = NULL;
-        bindip = NULL;
+        bindips = NULL;
+        nbindips = 0;
         ohost = NULL;
         sport = NULL;
         inetf = AF_UNSPEC;
t@@ -424,7 +465,8 @@ main(int argc, char *argv[])
                 group = EARGF(usage());
                 break;
         case 'i':
-                bindip = EARGF(usage());
+                bindips = xrealloc(bindips, sizeof(*bindips) * (++nbindips));
+                bindips[nbindips-1] = EARGF(usage());
                 break;
         case 'h':
                 ohost = EARGF(usage());
t@@ -502,34 +544,50 @@ main(int argc, char *argv[])
                 glfd = 1;
         }
 
-        memset(&hints, 0, sizeof(hints));
-        hints.ai_family = inetf;
-        hints.ai_flags = AI_PASSIVE;
-        hints.ai_socktype = SOCK_STREAM;
-        if (bindip)
-                hints.ai_flags |= AI_CANONNAME;
-
-        if ((listfd = getlistenfd(&hints, bindip, port)) < 0) {
-                if (inetf == AF_UNSPEC) {
-                        hints.ai_family = AF_INET;
-                        listfd = getlistenfd(&hints, bindip, port);
-                }
-                /* Save errno because of fprintf to stderr. */
-                errno_save = errno;
-        }
-        if (listfd < 0) {
-                fprintf(stderr, "Unable to get a binding socket. "
-                                "Look at bindip and the tcp port.\n");
-                errno = errno_save;
-                perror("getlistenfd");
-                return 1;
+        if (bindips == NULL) {
+                bindips = xrealloc(bindips, sizeof(*bindips) * (++nbindips));
+                bindips[nbindips-1] = "0.0.0.0";
+                bindips = xrealloc(bindips, sizeof(*bindips) * (++nbindips));
+                bindips[nbindips-1] = "::";
         }
 
-        if (listen(listfd, 255)) {
-                perror("listen");
-                close(listfd);
-                return 1;
+        for (i = 0; i < nbindips; i++) {
+                printf("binding %s:%s\n", bindips[i], port);
+
+                memset(&hints, 0, sizeof(hints));
+                hints.ai_family = inetf;
+                hints.ai_flags = AI_PASSIVE;
+                hints.ai_socktype = SOCK_STREAM;
+                if (bindips[i])
+                        hints.ai_flags |= AI_CANONNAME;
+
+                nlfdret = 0;
+                lfdret = getlistenfd(&hints, bindips[i], port, &nlfdret);
+                if (nlfdret < 1) {
+                        errno_save = errno;
+                        fprintf(stderr, "Unable to get a binding socket for "
+                                        "%s:%s\n", bindips[i], port);
+                        errno = errno_save;
+                        perror("getlistenfd");
+                }
+
+                printf("nlfdret = %d\n", nlfdret);
+                for (j = 0; j < nlfdret; j++) {
+                        printf("lfdret[%d] = %d\n", j, lfdret[j]);
+                        if (listen(lfdret[j], 255) < 0) {
+                                perror("listen");
+                                close(lfdret[j]);
+                                continue;
+                        }
+                        listfds = xrealloc(listfds,
+                                        sizeof(*listfds) * ++nlistfds);
+                        listfds[nlistfds-1] = lfdret[j];
+                }
+                if (lfdret != NULL)
+                        free(lfdret);
         }
+        if (nlistfds < 1)
+                return 1;
 
         if (usechroot) {
                 if (chdir(base) < 0) {
t@@ -552,7 +610,15 @@ main(int argc, char *argv[])
 
         if (dropprivileges(gr, us) < 0) {
                 perror("dropprivileges");
-                close(listfd);
+                if (listfds != NULL) {
+                        for (i = 0; i < nlistfds; i++) {
+                                if (listfds[i] >= 0) {
+                                        shutdown(listfds[i], SHUT_RDWR);
+                                        close(listfds[i]);
+                                }
+                        }
+                        free(listfds);
+                }
                 return 1;
         }
 
t@@ -569,7 +635,34 @@ main(int argc, char *argv[])
 #endif /* __OpenBSD__ */
 
         while (1) {
+                FD_ZERO(&rfd);
+                maxlfd = 0;
+                for (i = 0; i < nlistfds; i++) {
+                        FD_SET(listfds[i], &rfd);
+                        if (listfds[i] > maxlfd)
+                                maxlfd = listfds[i];
+                }
+
+                printf("pselect\n");
+                if (pselect(maxlfd+1, &rfd, NULL, NULL, NULL, NULL) < 0) {
+                        if (errno == EINTR)
+                                continue;
+                        perror("pselect");
+                        break;
+                }
+
+                listfd = -1;
+                for (i = 0; i < nlistfds; i++) {
+                        if (FD_ISSET(listfds[i], &rfd)) {
+                                listfd = listfds[i];
+                                break;
+                        }
+                }
+                if (listfd < 0)
+                        continue;
+
                 cltlen = sizeof(clt);
+                printf("accept on %d\n", listfd);
                 sock = accept(listfd, (struct sockaddr *)&clt, &cltlen);
                 if (sock < 0) {
                         switch (errno) {
t@@ -638,8 +731,15 @@ main(int argc, char *argv[])
                 close(sock);
         }
 
-        shutdown(listfd, SHUT_RDWR);
-        close(listfd);
+        if (listfds != NULL) {
+                for (i = 0; i < nlistfds; i++) {
+                        if (listfds[i] >= 0) {
+                                shutdown(listfds[i], SHUT_RDWR);
+                                close(listfds[i]);
+                        }
+                }
+                free(listfds);
+        }
         if (logfile != NULL && glfd != -1) {
                 close(glfd);
                 glfd = -1;