X-Git-Url: http://git.code-monkey.de/?a=blobdiff_plain;f=src%2Fserver.c;h=827b99b4f3b47050f4b0c068fcadb88f006fecb1;hb=6b301bd735bbbe384057a463ede871616efb5861;hp=d41aab10e231bb64133ec15b6399c7f34ebac924;hpb=a76733ea91c6a1d42dfbb50631fa214cc284c3bf;p=umurmur.git diff --git a/src/server.c b/src/server.c index d41aab1..827b99b 100644 --- a/src/server.c +++ b/src/server.c @@ -1,5 +1,5 @@ -/* Copyright (C) 2009-2010, Martin Johansson - Copyright (C) 2005-2010, Thorvald Natvig +/* Copyright (C) 2009-2014, Martin Johansson + Copyright (C) 2005-2014, Thorvald Natvig All rights reserved. @@ -51,42 +51,126 @@ #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; + + 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_INET, (!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();