diff --git a/fanout.c b/fanout.c index 53ca424760589a4cd2908729568be74ae39bf5aa..1d7c9bea6df42e97bd2e35f83f16ba854df3ea7f 100644 --- a/fanout.c +++ b/fanout.c @@ -14,6 +14,10 @@ #include <grp.h> #include <sys/socket.h> #include <netinet/in.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> #include <arpa/inet.h> #include <sys/stat.h> #include <netinet/in.h> @@ -141,7 +145,13 @@ struct rlimit s_rlimit; int main (int argc, char *argv[]) { - int srvsock, epollfd, nfds, efd, n, res; + struct addrinfo *ai; + struct addrinfo hints; + memset (&hints, '\0', sizeof (hints)); + hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + hints.ai_socktype = SOCK_STREAM; + int e; + int epollfd, nevents, efd, n, res; int portno = 1986; int optval; socklen_t optlen = sizeof(optval); @@ -165,7 +175,7 @@ int main (int argc, char *argv[]) struct client *client_tmp = NULL; socklen_t clilen; - struct sockaddr_in6 serv_addr, cli_addr; + struct sockaddr_storage cli_addr; static struct option long_options[] = { {"port", 1, 0, 0}, @@ -309,32 +319,64 @@ xit\n"); exit (EXIT_FAILURE); } - srvsock = socket (AF_INET6, SOCK_STREAM, 0); - if (srvsock < 0) - fanout_error ("ERROR opening socket"); + char buf[5]; + snprintf(buf, sizeof buf, "%d", portno); - bzero((char *) &serv_addr, sizeof (serv_addr)); - serv_addr.sin6_family = AF_INET6; - serv_addr.sin6_addr = in6addr_any; - serv_addr.sin6_port = htons (portno); + e = getaddrinfo (NULL, buf, &hints, &ai); + if (e != 0) { + fanout_error ("getaddrinfo"); + exit (EXIT_FAILURE); + } - if ((setsockopt (srvsock, SOL_SOCKET, SO_REUSEADDR, &optval, optlen)) == -1) - fanout_error ("failed setting reuseaddr"); + int nfds = 0; + struct addrinfo *runp = ai; + while (runp != NULL) { + ++nfds; + runp = runp->ai_next; + } + struct epoll_event fds[nfds]; - if (bind (srvsock, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) - fanout_error ("ERROR on binding"); + for (nfds = 0, runp = ai; runp != NULL; runp = runp->ai_next) { + fds[nfds].data.fd = socket (runp->ai_family, runp->ai_socktype, runp->ai_protocol); + if (fds[nfds].data.fd == -1) { + fanout_error ("ERROR opening socket"); + exit (EXIT_FAILURE); + } + fds[nfds].events = EPOLLIN; - if (listen (srvsock, listen_backlog) == -1) - fanout_error ("ERROR listening on server socket"); + optval = 1; + if (runp->ai_family==AF_INET6 && setsockopt (fds[nfds].data.fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, optlen) == -1) { + fanout_error ("failed setting IPV6_V6ONLY"); + exit (EXIT_FAILURE); + } - if((epollfd = epoll_create (10)) < 0) - fanout_error ("ERROR creating epoll instance"); + optval = 1; + if (setsockopt (fds[nfds].data.fd, SOL_SOCKET, SO_REUSEADDR, &optval, optlen) == -1) { + fanout_error ("failed setting REUSEADDR"); + exit (EXIT_FAILURE); + } - ev.events = EPOLLIN; - ev.data.fd = srvsock; + if (bind (fds[nfds].data.fd, runp->ai_addr, runp->ai_addrlen ) != 0) { + fanout_error ("ERROR on binding"); + exit (EXIT_FAILURE); + } else { + if (listen (fds[nfds].data.fd, listen_backlog) != 0) { + fanout_error ("ERROR listening on server socket"); + exit (EXIT_FAILURE); + } + ++nfds; + } + } + freeaddrinfo(ai); - if (epoll_ctl (epollfd, EPOLL_CTL_ADD, srvsock, &ev) == -1) { - fanout_error ("epoll_ctl: srvsock"); + if((epollfd = epoll_create (nfds)) < 0) + fanout_error ("ERROR creating epoll instance"); + + for (n=0; n < nfds; n++) { + if (epoll_ctl (epollfd, EPOLL_CTL_ADD, fds[n].data.fd, &fds[n]) == -1) { + fanout_error ("epoll_ctl: srvsock"); + exit (EXIT_FAILURE); + } } @@ -450,25 +492,32 @@ xit\n"); while (1) { fanout_debug (3, "server waiting for new activity\n"); - if ((nfds = epoll_wait (epollfd, events, max_events, -1)) == -1) + if ((nevents = epoll_wait (epollfd, events, max_events, -1)) == -1) fanout_error ("epoll_wait"); - if (nfds == 0) { + if (nevents == 0) { continue; } - for (n = 0; n < nfds; n++) { + for (n = 0; n < nevents; n++) { // new connection efd = events[n].data.fd; - if (efd == srvsock) { + int newconnection = 0; + for (n=0; n < nfds; n++) { + if (efd == fds[n].data.fd) { + newconnection = 1; + break; + } + } + if (newconnection) { if ((client_i = calloc (1, sizeof (struct client))) == NULL) { fanout_debug (0, "memory error\n"); continue; } clilen = sizeof (cli_addr); - if ((client_i->fd = accept (srvsock, + if ((client_i->fd = accept (efd, (struct sockaddr *)&cli_addr, &clilen)) == -1) { fanout_debug (0, "%s\n", strerror (errno)); @@ -572,7 +621,9 @@ resetting counter\n"); }//end for }//end while (1) - close (srvsock); + for (n=0; n < nfds; n++) { + close (fds[n].data.fd); + } return 0; } @@ -695,12 +746,12 @@ void fanout_debug (int level, const char *format, ...) char *getsocketpeername (int fd) { - struct sockaddr_in6 m_addr; + struct sockaddr_storage m_addr; socklen_t len; len = sizeof m_addr; getpeername(fd, (struct sockaddr*)&m_addr, &len); - inet_ntop(AF_INET6, &m_addr.sin6_addr, ipstr, sizeof ipstr); + getnameinfo((struct sockaddr*)&m_addr, len, ipstr, sizeof ipstr, NULL, 0, NI_NUMERICHOST); return ipstr; }