X-Git-Url: http://git.code-monkey.de/?a=blobdiff_plain;f=src%2Fserver.c;h=27244a2b95c2950a3624183dcfab61297e5d878b;hb=77e7246bd3a4260da52f74f7fe014131c918d6e4;hp=36e2d47af50cd618e2aa069d87ac64bd07cf7382;hpb=c289fc55d1fce7f474127933063ba2008a188259;p=umurmur.git diff --git a/src/server.c b/src/server.c index 36e2d47..27244a2 100644 --- a/src/server.c +++ b/src/server.c @@ -46,12 +46,7 @@ #include "log.h" #include "timer.h" #include "version.h" - -#define TCP_SOCK 0 -#define TCP_SOCK6 1 - -#define UDP_SOCK 2 -#define UDP_SOCK6 3 +#include "util.h" /* globals */ bool_t shutdown_server; @@ -59,44 +54,64 @@ extern char *bindaddr; extern char *bindaddr6; extern int bindport; extern int bindport6; - int* udpsocks; +bool hasv4 = true, hasv6 = true; + +const int on = 1; +int nofServerSocks = 4; /* Initialize the address structures for IPv4 and IPv6 */ 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_INET6; - v6address->ss_len = sizeof(struct sockaddr_storage); - - int error = 0; + struct sockaddr_storage** addresses = calloc(2, sizeof(void*)); + + struct sockaddr_storage* v4address = calloc(1, sizeof(struct sockaddr_storage)); + v4address->ss_family = AF_INET; + struct sockaddr_storage* v6address = calloc(1, sizeof(struct sockaddr_storage)); + v6address->ss_family = AF_INET6; + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) + v4address->ss_len = sizeof(struct sockaddr_storage); + v6address->ss_len = sizeof(struct sockaddr_storage); +#endif + + 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!"); + else if (error == -1) { + Log_warn("Could not allocate IPv4 address"); + hasv4 = false; + nofServerSocks -= 2; + } - const char* confadd = getStrConf(BINDADDR); - 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!"); + else if (error == -1) { + Log_warn("Could not allocate IPv6 address"); + hasv6 = false; + nofServerSocks -= 2; + } - 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!"); + if (!hasv4 && !hasv6) + Log_fatal("Could not allocate IPv4 nor IPv6 address!"); - ((struct sockaddr_in*)v4address)->sin_port = htons((bindport) ? bindport : getIntConf(BINDPORT)); - ((struct sockaddr_in6*)v6address)->sin6_port = htons((bindport6) ? bindport6 : getIntConf(BINDPORT6)); + ((struct sockaddr_in*)v4address)->sin_port = htons((bindport) ? bindport : getIntConf(BINDPORT)); + ((struct sockaddr_in6*)v6address)->sin6_port = htons((bindport6) ? bindport6 : getIntConf(BINDPORT6)); - addresses[0] = v4address; - addresses[1] = v6address; + addresses[0] = v4address; + addresses[1] = v6address; - return addresses; + return addresses; } void Server_runLoop(struct pollfd* pollfds) - { - int timeout = 1000, rc, clientcount; +{ + int timeout, rc, clientcount; etimer_t janitorTimer; Timer_init(&janitorTimer); @@ -105,11 +120,17 @@ void Server_runLoop(struct pollfd* pollfds) struct sockaddr_storage remote; int i; - pollfds[UDP_SOCK].revents = 0; - pollfds[UDP_SOCK6].revents = 0; - pollfds[TCP_SOCK].revents = 0; - pollfds[TCP_SOCK6].revents = 0; - clientcount = Client_getfds(&pollfds[4]); + if (nofServerSocks == 4) { + pollfds[0].revents = 0; + pollfds[1].revents = 0; + pollfds[2].revents = 0; + pollfds[3].revents = 0; + } else { + pollfds[0].revents = 0; + pollfds[1].revents = 0; + } + + clientcount = Client_getfds(&pollfds[nofServerSocks]); timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL; if (timeout <= 0) { @@ -117,9 +138,9 @@ void Server_runLoop(struct pollfd* pollfds) Timer_restart(&janitorTimer); timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL; } - rc = poll(pollfds, clientcount + 4, timeout); - if (rc == 0) { /* Timeout */ - /* Do maintenance */ + rc = poll(pollfds, clientcount + nofServerSocks, timeout); + if (rc == 0) { + /* Poll timed out, do maintenance */ Timer_restart(&janitorTimer); Client_janitor(); continue; @@ -128,135 +149,127 @@ void Server_runLoop(struct pollfd* pollfds) if (errno == EINTR) /* signal */ continue; else - Log_fatal("poll: error %d", errno); - } - if (pollfds[TCP_SOCK].revents) { /* New tcp connection */ - int tcpfd, flag = 1; - uint32_t addrlen; - addrlen = sizeof(struct sockaddr_in); - tcpfd = accept(pollfds[TCP_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(((struct sockaddr_in*)&remote)->sin_addr), - ntohs(((struct sockaddr_in*)&remote)->sin_port)); - if (Client_add(tcpfd, &remote) < 0) - close(tcpfd); + Log_fatal("poll: error %d (%s)", errno, strerror(errno)); } - if (pollfds[TCP_SOCK6].revents) { /* New tcp connection */ - int tcpfd, flag = 1; - uint32_t addrlen; - addrlen = sizeof(struct sockaddr_in6); - tcpfd = accept(pollfds[TCP_SOCK6].fd, (struct sockaddr*)&remote, &addrlen); - fcntl(tcpfd, F_SETFL, O_NONBLOCK); - setsockopt(tcpfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); - if (Client_add(tcpfd, &remote) < 0) - close(tcpfd); + /* Check for new connection */ + for (i = 0; i < nofServerSocks / 2; i++) { + if (pollfds[i].revents) { + static int tcpfd; + static uint32_t addrlen = sizeof(struct sockaddr_storage); + tcpfd = accept(pollfds[i].fd, (struct sockaddr *)&remote, &addrlen); + fcntl(tcpfd, F_SETFL, O_NONBLOCK); + setsockopt(tcpfd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(int)); + Log_debug("Connection from %s port %d\n", Util_addressToString(&remote), Util_addressToPort(&remote)); + if (Client_add(tcpfd, &remote) < 0) + close(tcpfd); + } } - if (pollfds[UDP_SOCK].revents) { - Client_read_udp(udpsocks[0]); - } - if (pollfds[UDP_SOCK6].revents) { - Client_read_udp(udpsocks[1]); + for (i = nofServerSocks / 2; i < nofServerSocks; i++) { + if (pollfds[i].revents) + Client_read_udp(udpsocks[i - nofServerSocks / 2]); } + for (i = 0; i < clientcount; i++) { - if (pollfds[i + 4].revents & POLLIN) { - Client_read_fd(pollfds[i + 4].fd); - } - if (pollfds[i + 4].revents & POLLOUT) { - Client_write_fd(pollfds[i + 4].fd); - } + if (pollfds[nofServerSocks + i].revents & POLLIN) + Client_read_fd(pollfds[nofServerSocks + i].fd); + + if (pollfds[nofServerSocks + i].revents & POLLOUT) + Client_write_fd(pollfds[nofServerSocks + i].fd); } } - free(udpsocks); - } +} void Server_setupTCPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds) - { - uint8_t yes = 1; - int error = 0; - int sockets[2]; - - /* IPv4 socket setup */ - sockets[0] = socket(PF_INET, SOCK_STREAM, 0); - if (sockets[0] < 0) - Log_fatal("socket IPv4"); - if (setsockopt(sockets[0], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0) - Log_fatal("setsockopt IPv4: %s", strerror(errno)); - if (bind(sockets[0], (struct sockaddr *)addresses[0], sizeof (struct sockaddr_in)) < 0) - Log_fatal("bind IPv4: %s", strerror(errno)); - if (listen(sockets[0], 3) < 0) - Log_fatal("listen IPv4"); - fcntl(sockets[0], F_SETFL, O_NONBLOCK); - - pollfds[TCP_SOCK].fd = sockets[0]; - pollfds[TCP_SOCK].events = POLLIN; - - /* IPv6 socket setup */ - sockets[1] = socket(PF_INET6, SOCK_STREAM, 0); - if (sockets[1] < 0) - Log_fatal("socket IPv6"); - if (setsockopt(sockets[1], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0) - Log_fatal("setsockopt IPv6: %s", strerror(errno)); - if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(int)) != 0) - Log_fatal("setsockopt IPv6: %s", strerror(errno)); - if (bind(sockets[1], (struct sockaddr *)addresses[1], sizeof (struct sockaddr_in6)) < 0) - Log_fatal("bind IPv6: %s", strerror(errno)); - if (listen(sockets[1], 3) < 0) - Log_fatal("listen IPv6"); - fcntl(sockets[1], F_SETFL, O_NONBLOCK); - - pollfds[TCP_SOCK6].fd = sockets[1]; - pollfds[TCP_SOCK6].events = POLLIN; - } +{ + uint8_t yes = 1; + int sockets[2]; + + if (hasv4) { + /* IPv4 socket setup */ + sockets[0] = socket(PF_INET, SOCK_STREAM, 0); + if (sockets[0] < 0) + Log_fatal("socket IPv4"); + if (setsockopt(sockets[0], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0) + Log_fatal("setsockopt IPv4: %s", strerror(errno)); + if (bind(sockets[0], (struct sockaddr *)addresses[0], sizeof (struct sockaddr_in)) < 0) + Log_fatal("bind %s %d: %s", Util_addressToString(addresses[0]), Util_addressToPort(addresses[0]), strerror(errno)); + if (listen(sockets[0], 3) < 0) + Log_fatal("listen IPv4"); + fcntl(sockets[0], F_SETFL, O_NONBLOCK); + + pollfds[0].fd = sockets[0]; + pollfds[0].events = POLLIN; + } + + if (hasv6) { + /* IPv6 socket setup */ + sockets[1] = socket(PF_INET6, SOCK_STREAM, 0); + if (sockets[1] < 0) + Log_fatal("socket IPv6"); + if (setsockopt(sockets[1], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0) + Log_fatal("setsockopt IPv6: %s", strerror(errno)); + if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(int)) != 0) + Log_fatal("setsockopt IPv6: %s", strerror(errno)); + if (bind(sockets[1], (struct sockaddr *)addresses[1], sizeof (struct sockaddr_in6)) < 0) + Log_fatal("bind %s %d: %s", Util_addressToString(addresses[1]), Util_addressToPort(addresses[1]), strerror(errno)); + if (listen(sockets[1], 3) < 0) + Log_fatal("listen IPv6"); + fcntl(sockets[1], F_SETFL, O_NONBLOCK); + + + /* If there is an IPv4 address, then IPv6 will use the second socket, otherwise it uses the first */ + pollfds[(hasv4) ? 1 : 0].fd = sockets[1]; + pollfds[(hasv4) ? 1 : 0].events = POLLIN; + } +} void Server_setupUDPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds) - { - uint8_t yes = 1; - int val = 0; - int error = 0; - int sockets[2]; - char ipv6Representation[INET6_ADDRSTRLEN]; - - if((udpsocks = malloc(2 * sizeof(int))) == NULL) - Log_fatal("Out of memory (%s:%s)", __FILE__, __LINE__); - - inet_ntop(AF_INET6, &((struct sockaddr_in6*)addresses[1])->sin6_addr, ipv6Representation, sizeof(INET6_ADDRSTRLEN)); - - sockets[0] = socket(PF_INET, SOCK_DGRAM, 0); - if (bind(sockets[0], (struct sockaddr *) addresses[0], sizeof (struct sockaddr_in)) < 0) - Log_fatal("bind %d %s: %s", ((struct sockaddr_in*)addresses[0])->sin_port, - inet_ntoa(((struct sockaddr_in*)addresses[0])->sin_addr), strerror(errno)); - val = 0xe0; - if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0) - Log_warn("Server: Failed to set TOS for UDP Socket"); - val = 0x80; - if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0) - Log_warn("Server: Failed to set TOS for UDP Socket"); - - fcntl(sockets[0], F_SETFL, O_NONBLOCK); - pollfds[UDP_SOCK].fd = sockets[0]; - pollfds[UDP_SOCK].events = POLLIN | POLLHUP | POLLERR; - - sockets[1] = socket(PF_INET6, SOCK_DGRAM, 0); - if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(int)) != 0) - Log_fatal("setsockopt IPv6: %s", strerror(errno)); - if (bind(sockets[1], (struct sockaddr *) addresses[1], sizeof (struct sockaddr_in6)) < 0) - Log_fatal("bind %d %s: %s", ((struct sockaddr_in*)addresses[1])->sin_port, ipv6Representation, strerror(errno)); - val = 0xe0; - if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0) - Log_warn("Server: Failed to set TOS for UDP Socket"); - val = 0x80; - if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0) - Log_warn("Server: Failed to set TOS for UDP Socket"); - - fcntl(sockets[1], F_SETFL, O_NONBLOCK); - pollfds[UDP_SOCK6].fd = sockets[1]; - pollfds[UDP_SOCK6].events = POLLIN | POLLHUP | POLLERR; - udpsocks[0] = sockets[0]; - udpsocks[1] = sockets[1]; - } +{ + int val = 0; + int sockets[2] = {-1, -1}; + + if((udpsocks = calloc(nofServerSocks / 2, sizeof(int))) == NULL) + Log_fatal("Out of memory (%s:%s)", __FILE__, __LINE__); + + if (hasv4) { + sockets[0] = socket(PF_INET, SOCK_DGRAM, 0); + if (bind(sockets[0], (struct sockaddr *) addresses[0], sizeof (struct sockaddr_in)) < 0) + Log_fatal("bind %s %d: %s", Util_addressToString(addresses[0]), Util_addressToPort(addresses[0]), strerror(errno)); + val = 0xe0; + if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0) + Log_warn("Server: Failed to set TOS for UDP Socket"); + val = 0x80; + if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0) + Log_warn("Server: Failed to set TOS for UDP Socket"); + + fcntl(sockets[0], F_SETFL, O_NONBLOCK); + pollfds[(hasv6) ? 2 : 1].fd = sockets[0]; + pollfds[(hasv6) ? 2 : 1].events = POLLIN | POLLHUP | POLLERR; + udpsocks[0] = sockets[0]; + } + + if (hasv6) { + sockets[1] = socket(PF_INET6, SOCK_DGRAM, 0); + if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(int)) != 0) + Log_fatal("setsockopt IPv6: %s", strerror(errno)); + if (bind(sockets[1], (struct sockaddr *) addresses[1], sizeof (struct sockaddr_in6)) < 0) + Log_fatal("bind %s %d: %s", Util_addressToString(addresses[1]), Util_addressToPort(addresses[1]), strerror(errno)); + val = 0xe0; + if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0) + Log_warn("Server: Failed to set TOS for UDP Socket"); + val = 0x80; + if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0) + Log_warn("Server: Failed to set TOS for UDP Socket"); + + fcntl(sockets[1], F_SETFL, O_NONBLOCK); + pollfds[(hasv4) ? 3 : 1].fd = sockets[1]; + pollfds[(hasv4) ? 3 : 1].events = POLLIN | POLLHUP | POLLERR; + udpsocks[(hasv4) ? 1 : 0] = sockets[1]; + } + +} void Server_run() { @@ -267,27 +280,28 @@ void Server_run() Log_fatal("out of memory"); /* Figure out bind address and port */ - struct sockaddr_storage** addresses = Server_setupAddressesAndPorts(); + struct sockaddr_storage** addresses = Server_setupAddressesAndPorts(); /* Prepare TCP sockets */ - Server_setupTCPSockets(addresses, pollfds); + Server_setupTCPSockets(addresses, pollfds); /* Prepare UDP sockets */ - Server_setupUDPSockets(addresses, pollfds); + Server_setupUDPSockets(addresses, pollfds); Log_info("uMurmur version %s ('%s') protocol version %d.%d.%d", - UMURMUR_VERSION, UMURMUR_CODENAME, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH); + UMURMUR_VERSION, UMURMUR_CODENAME, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH); Log_info("Visit http://code.google.com/p/umurmur/"); /* Main server loop */ - Server_runLoop(pollfds); + Server_runLoop(pollfds); /* Disconnect clients and cleanup memory */ Client_disconnect_all(); free(pollfds); - free(addresses[0]); - free(addresses[1]); - free(addresses); + free(addresses[0]); + free(addresses[1]); + free(addresses); + free(udpsocks); } void Server_shutdown()