Fixed errors in address generation
[umurmur.git] / src / server.c
index d41aab10e231bb64133ec15b6399c7f34ebac924..5394b09dd545e05ad795c59fbf43f3f19684c303 100644 (file)
@@ -1,5 +1,5 @@
-/* Copyright (C) 2009-2010, Martin Johansson <martin@fatbob.nu>
-   Copyright (C) 2005-2010, Thorvald Natvig <thorvald@natvig.com>
+/* Copyright (C) 2009-2014, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2014, Thorvald Natvig <thorvald@natvig.com>
 
    All rights reserved.
 
 #define TCP_SOCK 0
 #define UDP_SOCK 1
 
+#define TCP6_SOCK 2
+#define UDP6_SOCK 3
+
 /* globals */
-int udpsock; 
+int udpsock;
 bool_t shutdown_server;
 extern char *bindaddr;
+extern char *bindaddr6;
 extern int bindport;
+extern int bindport6;
+
+struct sockaddr_storage** Server_setupAddressesAndPorts()
+{
+  struct sockaddr_storage** addresses = malloc(2 * sizeof(void*));
+
+  struct sockaddr_storage* v4address = calloc(1, sizeof(struct sockaddr_storage));
+  v4address->ss_family = AF_INET;
+  v4address->ss_len = sizeof(struct sockaddr_storage);
+  struct sockaddr_storage* v6address = calloc(1, sizeof(struct sockaddr_storage));
+  v6address->ss_family = AF_INET;
+  v6address->ss_len = sizeof(struct sockaddr_storage);
+
+  int error = 0;
+
+  error = inet_pton(AF_INET, (!bindaddr) ? ((getStrConf(BINDADDR)) ? getStrConf(BINDADDR) : "0.0.0.0")
+                                         : bindaddr, &(((struct sockaddr_in*)v4address)->sin_addr));
+  if (error == 0) Log_fatal("Invalid IPv4 address supplied!");
+
+  error = inet_pton(AF_INET6, (!bindaddr6) ? ((getStrConf(BINDADDR6)) ? getStrConf(BINDADDR6) : "::")
+                                         : bindaddr6, &(((struct sockaddr_in6*)v6address)->sin6_addr));
+  if (error == 0) Log_fatal("Invalid IPv6 address supplied!");
+
+  ((struct sockaddr_in*)v4address)->sin_port = htons((bindport) ? bindport : getIntConf(BINDPORT));
+  ((struct sockaddr_in6*)v6address)->sin6_port = htons((bindport) ? bindport : getIntConf(BINDPORT));
+
+  addresses[0] = v4address;
+  addresses[1] = v6address;
+
+  return addresses;
+}
+
+void Server_runLoop(struct pollfd* pollfds)
+  {
+  int timeout = 1000, rc, clientcount;
+       etimer_t janitorTimer;
+
+       Timer_init(&janitorTimer);
+
+       while (!shutdown_server) {
+               struct sockaddr_in remote;
+               int i;
+
+               pollfds[UDP_SOCK].revents = 0;
+               pollfds[TCP_SOCK].revents = 0;
+               clientcount = Client_getfds(&pollfds[2]);
+
+               timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
+               if (timeout <= 0) {
+                       Client_janitor();
+                       Timer_restart(&janitorTimer);
+                       timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
+               }
+               rc = poll(pollfds, clientcount + 2, timeout);
+               if (rc == 0) { /* Timeout */
+                       /* Do maintenance */
+                       Timer_restart(&janitorTimer);
+                       Client_janitor();
+                       continue;
+               }
+               if (rc < 0) {
+                       if (errno == EINTR) /* signal */
+                               continue;
+                       else
+                               Log_fatal("poll: error %d", errno);
+               }
+               if (pollfds[LISTEN_SOCK].revents) { /* New tcp connection */
+                       int tcpfd, flag = 1;
+                       uint32_t addrlen;
+                       addrlen = sizeof(struct sockaddr_in);
+                       tcpfd = accept(pollfds[LISTEN_SOCK].fd, (struct sockaddr*)&remote, &addrlen);
+                       fcntl(tcpfd, F_SETFL, O_NONBLOCK);
+                       setsockopt(tcpfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
+                       Log_debug("Connection from %s port %d\n", inet_ntoa(remote.sin_addr),
+                                         ntohs(remote.sin_port));
+                       if (Client_add(tcpfd, &remote) < 0)
+                               close(tcpfd);
+               }
+
+               if (pollfds[UDP_SOCK].revents) {
+                       Client_read_udp();
+               }
+               for (i = 0; i < clientcount; i++) {
+                       if (pollfds[i + 2].revents & POLLIN) {
+                               Client_read_fd(pollfds[i + 2].fd);
+                       }
+                       if (pollfds[i + 2].revents & POLLOUT) {
+                               Client_write_fd(pollfds[i + 2].fd);
+                       }
+               }
+       }
+  }
 
 void Server_run()
 {
-       int timeout = 1000, rc;
+       int rc;
        struct pollfd *pollfds;
        int tcpsock, sockopt = 1;
        struct sockaddr_in sin;
-       int val, clientcount;
-       etimer_t janitorTimer;
+       int val;
        unsigned short port;
        in_addr_t inet_address;
-       
+
        /* max clients + listen sock + udp sock + client connecting that will be disconnected */
        pollfds = malloc((getIntConf(MAX_CLIENTS) + 3) * sizeof(struct pollfd));
        if (pollfds == NULL)
                Log_fatal("out of memory");
 
        /* Figure out bind address and port */
-       if (bindport != 0)
-               port = htons(bindport);
-       else
-               port = htons(getIntConf(BINDPORT));
-       
-       if (bindaddr != NULL && inet_addr(bindaddr) != -1)
-               inet_address = inet_addr(bindaddr);
-       else if (inet_addr(getStrConf(BINDADDR)) !=  -1)
-               inet_address = inet_addr(getStrConf(BINDADDR));
-       else
-               inet_address = inet_addr("0.0.0.0");
-       Log_info("Bind to %s:%hu", inet_address == 0 ? "*" : inet_ntoa(*((struct in_addr *)&inet_address)), ntohs(port));
-       
+  struct sockaddr_storage** addresses = Server_setupAddressesAndPorts();
+
        /* Prepare TCP socket */
        memset(&sin, 0, sizeof(sin));
        tcpsock = socket(PF_INET, SOCK_STREAM, 0);
@@ -95,15 +179,15 @@ void Server_run()
        if (setsockopt(tcpsock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int)) != 0)
                Log_fatal("setsockopt: %s", strerror(errno));
        sin.sin_family = AF_INET;
-       sin.sin_port = port;    
+       sin.sin_port = port;
        sin.sin_addr.s_addr = inet_address;
-       
+
        rc = bind(tcpsock, (struct sockaddr *) &sin, sizeof (struct sockaddr_in));
        if (rc < 0) Log_fatal("bind: %s", strerror(errno));
        rc = listen(tcpsock, 3);
        if (rc < 0) Log_fatal("listen");
        fcntl(tcpsock, F_SETFL, O_NONBLOCK);
-       
+
        pollfds[LISTEN_SOCK].fd = tcpsock;
        pollfds[LISTEN_SOCK].events = POLLIN;
 
@@ -113,7 +197,7 @@ void Server_run()
        sin.sin_family = AF_INET;
        sin.sin_port = port;
        sin.sin_addr.s_addr = inet_address;
-       
+
        rc = bind(udpsock, (struct sockaddr *) &sin, sizeof (struct sockaddr_in));
        if (rc < 0)
                Log_fatal("bind %d %s: %s", getIntConf(BINDPORT), getStrConf(BINDADDR), strerror(errno));
@@ -125,69 +209,17 @@ void Server_run()
        rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val));
        if (rc < 0)
                Log_warn("Server: Failed to set TOS for UDP Socket");
-       
+
        fcntl(udpsock, F_SETFL, O_NONBLOCK);
        pollfds[UDP_SOCK].fd = udpsock;
        pollfds[UDP_SOCK].events = POLLIN | POLLHUP | POLLERR;
-       
-       Timer_init(&janitorTimer);
-       
-       Log_info("uMurmur version %s protocol version %d.%d.%d",
-                        UMURMUR_VERSION, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH);
+
+       Log_info("uMurmur version %s ('%s') protocol version %d.%d.%d",
+                UMURMUR_VERSION, UMURMUR_CODENAME, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH);
        Log_info("Visit http://code.google.com/p/umurmur/");
-       
-       /* Main server loop */
-       while (!shutdown_server) {
-               struct sockaddr_in remote;
-               int i;
-               
-               pollfds[UDP_SOCK].revents = 0;
-               pollfds[TCP_SOCK].revents = 0;
-               clientcount = Client_getfds(&pollfds[2]);
-               
-               timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
-               if (timeout <= 0) {
-                       Client_janitor();
-                       Timer_restart(&janitorTimer);
-                       timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
-               }
-               rc = poll(pollfds, clientcount + 2, timeout);
-               if (rc == 0) { /* Timeout */
-                       /* Do maintenance */
-                       Timer_restart(&janitorTimer);
-                       Client_janitor();
-                       continue;
-               }
-               if (rc < 0) {
-                       if (errno == EINTR) /* signal */
-                               continue;
-                       else
-                               Log_fatal("poll: error %d", errno);
-               }
-               if (pollfds[LISTEN_SOCK].revents) { /* New tcp connection */
-                       int tcpfd, flag = 1;
-                       uint32_t addrlen;
-                       addrlen = sizeof(struct sockaddr_in);
-                       tcpfd = accept(pollfds[LISTEN_SOCK].fd, (struct sockaddr*)&remote, &addrlen);
-                       fcntl(tcpfd, F_SETFL, O_NONBLOCK);
-                       setsockopt(tcpfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
-                       Log_debug("Connection from %s port %d\n", inet_ntoa(remote.sin_addr),
-                                         ntohs(remote.sin_port));
-                       Client_add(tcpfd, &remote);
-               }
 
-               if (pollfds[UDP_SOCK].revents) {
-                       Client_read_udp();
-               }
-               for (i = 0; i < clientcount; i++) {
-                       if (pollfds[i + 2].revents & POLLIN) {
-                               Client_read_fd(pollfds[i + 2].fd);
-                       }
-                       if (pollfds[i + 2].revents & POLLOUT) {
-                               Client_write_fd(pollfds[i + 2].fd);
-                       }
-               }
-       }       
+       /* Main server loop */
+  Server_runLoop(pollfds);
 
        /* Disconnect clients */
        Client_disconnect_all();