| First version of multi listen. - geomyidae - A small C-based gopherd. | |
| git clone git://bitreich.org/geomyidae/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfri… | |
| Log | |
| Files | |
| Refs | |
| Tags | |
| README | |
| LICENSE | |
| --- | |
| commit 60f33bbe3b6c58d451dad69933c1eb8b36cf3997 | |
| parent 3c940036398f0c5cb4b3822cb6f8ea1a76e2c968 | |
| Author: Christoph Lohmann <[email protected]> | |
| Date: Sun, 11 Nov 2018 13:02:32 +0100 | |
| First version of multi listen. | |
| Diffstat: | |
| M main.c | 212 +++++++++++++++++++++++------… | |
| 1 file changed, 156 insertions(+), 56 deletions(-) | |
| --- | |
| diff --git a/main.c b/main.c | |
| @@ -24,6 +24,8 @@ | |
| #include <errno.h> | |
| #include <arpa/inet.h> | |
| #include <limits.h> | |
| +#include <sys/select.h> | |
| +#include <sys/time.h> | |
| #include "ind.h" | |
| #include "handlr.h" | |
| @@ -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; | |
| @@ -253,6 +256,8 @@ handlerequest(int sock, char *base, char *ohost, char *port… | |
| void | |
| sighandler(int sig) | |
| { | |
| + int i; | |
| + | |
| switch (sig) { | |
| case SIGCHLD: | |
| while (waitpid(-1, NULL, WNOHANG) > 0); | |
| @@ -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; | |
| @@ -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_ad… | |
| (void *)&((struct sockaddr_in6 *)rp->ai_addr)->sin6_… | |
| - 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 | |
| @@ -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; | |
| @@ -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; | |
| @@ -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()); | |
| @@ -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) { | |
| @@ -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; | |
| } | |
| @@ -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) { | |
| @@ -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; |