1 /* Copyright (C) 2009-2014, Martin Johansson <martin@fatbob.nu>
2 Copyright (C) 2005-2014, Thorvald Natvig <thorvald@natvig.com>
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
10 - Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12 - Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
15 - Neither the name of the Developers nor the names of its contributors may
16 be used to endorse or promote products derived from this software without
17 specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
23 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include <netinet/tcp.h>
35 #include <sys/socket.h>
51 #include "sharedmemory.h"
54 bool_t shutdown_server;
55 extern char *bindaddr;
56 extern char *bindaddr6;
60 bool_t hasv4 = true, hasv6 = true;
63 int nofServerSocks = 4;
65 /* Check which IP versions are supported by the system. */
66 void checkIPversions()
70 testsocket = socket(PF_INET, SOCK_STREAM, 0);
71 hasv4 = (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) ? false : true;
72 if (!(testsocket < 0)) close(testsocket);
74 testsocket = socket(PF_INET6, SOCK_STREAM, 0);
75 hasv6 = (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) ? false : true;
76 if (!(testsocket < 0)) close(testsocket);
80 Log_info("IPv4 is not supported by this system");
86 Log_info("IPv6 is not supported by this system");
89 if(nofServerSocks == 0)
91 Log_fatal("Neither IPv4 nor IPv6 are supported by this system");
95 /* Initialize the address structures for IPv4 and IPv6 */
96 struct sockaddr_storage** Server_setupAddressesAndPorts()
98 struct sockaddr_storage** addresses = Memory_safeCalloc(2, sizeof(void*));
100 struct sockaddr_storage* v4address = Memory_safeCalloc(1, sizeof(struct sockaddr_storage));
101 v4address->ss_family = AF_INET;
102 struct sockaddr_storage* v6address = Memory_safeCalloc(1, sizeof(struct sockaddr_storage));
103 v6address->ss_family = AF_INET6;
105 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
106 v4address->ss_len = sizeof(struct sockaddr_storage);
107 v6address->ss_len = sizeof(struct sockaddr_storage);
112 error = inet_pton(AF_INET, (!bindaddr) ? ((getStrConf(BINDADDR)) ? getStrConf(BINDADDR) : "0.0.0.0")
113 : bindaddr, &(((struct sockaddr_in*)v4address)->sin_addr));
115 Log_fatal("Invalid IPv4 address supplied!");
116 else if (error == -1)
117 Log_warn("Could not allocate IPv4 address");
119 error = inet_pton(AF_INET6, (!bindaddr6) ? ((getStrConf(BINDADDR6)) ? getStrConf(BINDADDR6) : "::")
120 : bindaddr6, &(((struct sockaddr_in6*)v6address)->sin6_addr));
122 Log_fatal("Invalid IPv6 address supplied!");
123 else if (error == -1)
124 Log_warn("Could not allocate IPv6 address");
126 ((struct sockaddr_in*)v4address)->sin_port = htons((bindport) ? bindport : getIntConf(BINDPORT));
127 ((struct sockaddr_in6*)v6address)->sin6_port = htons((bindport6) ? bindport6 : getIntConf(BINDPORT6));
129 addresses[0] = v4address;
130 addresses[1] = v6address;
135 void Server_runLoop(struct pollfd* pollfds)
137 int timeout, rc, clientcount;
139 etimer_t janitorTimer;
140 Timer_init(&janitorTimer);
142 while (!shutdown_server) {
143 struct sockaddr_storage remote;
146 #ifdef USE_SHAREDMEMORY_API
147 Sharedmemory_alivetick();
150 for(i = 0; i < nofServerSocks; i++) {
151 pollfds[i].revents = 0;
154 clientcount = Client_getfds(&pollfds[nofServerSocks]);
156 timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
159 Timer_restart(&janitorTimer);
160 timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
162 rc = poll(pollfds, clientcount + nofServerSocks, timeout);
164 /* Poll timed out, do maintenance */
165 Timer_restart(&janitorTimer);
170 if (errno == EINTR) /* signal */
173 Log_fatal("poll: error %d (%s)", errno, strerror(errno));
176 /* Check for new connection */
177 for (i = 0; i < nofServerSocks / 2; i++) {
178 if (pollfds[i].revents) {
180 uint32_t addrlen = sizeof(struct sockaddr_storage);
181 tcpfd = accept(pollfds[i].fd, (struct sockaddr *)&remote, &addrlen);
182 fcntl(tcpfd, F_SETFL, O_NONBLOCK);
183 setsockopt(tcpfd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(int));
184 char *addressString = Util_addressToString(&remote);
185 Log_debug("Connection from %s port %d\n", addressString, Util_addressToPort(&remote));
187 if (Client_add(tcpfd, &remote) < 0)
192 for (i = nofServerSocks / 2; i < nofServerSocks; i++) {
193 if (pollfds[i].revents)
194 Client_read_udp(udpsocks[i - nofServerSocks / 2]);
197 for (i = 0; i < clientcount; i++) {
198 if (pollfds[nofServerSocks + i].revents & POLLIN)
199 Client_read_fd(pollfds[nofServerSocks + i].fd);
201 if (pollfds[nofServerSocks + i].revents & POLLOUT)
202 Client_write_fd(pollfds[nofServerSocks + i].fd);
204 #ifdef USE_SHAREDMEMORY_API
205 Sharedmemory_update();
210 void Server_setupTCPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds)
216 /* IPv4 socket setup */
217 sockets[0] = socket(PF_INET, SOCK_STREAM, 0);
219 Log_fatal("socket IPv4");
220 if (setsockopt(sockets[0], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0)
221 Log_fatal("setsockopt IPv4: %s", strerror(errno));
222 if (bind(sockets[0], (struct sockaddr *)addresses[0], sizeof (struct sockaddr_in)) < 0) {
223 char *addressString = Util_addressToString(addresses[0]);
224 Log_fatal("bind %s %d: %s", addressString, Util_addressToPort(addresses[0]), strerror(errno));
227 if (listen(sockets[0], 3) < 0)
228 Log_fatal("listen IPv4");
229 fcntl(sockets[0], F_SETFL, O_NONBLOCK);
231 pollfds[0].fd = sockets[0];
232 pollfds[0].events = POLLIN;
236 /* IPv6 socket setup */
237 sockets[1] = socket(PF_INET6, SOCK_STREAM, 0);
239 Log_fatal("socket IPv6: %s", strerror(errno));
240 if (setsockopt(sockets[1], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0)
241 Log_fatal("setsockopt IPv6: %s", strerror(errno));
242 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(int)) != 0)
243 Log_fatal("setsockopt IPv6: %s", strerror(errno));
244 if (bind(sockets[1], (struct sockaddr *)addresses[1], sizeof (struct sockaddr_in6)) < 0) {
245 char *addressString = Util_addressToString(addresses[1]);
246 Log_fatal("bind %s %d: %s", addressString, Util_addressToPort(addresses[1]), strerror(errno));
249 if (listen(sockets[1], 3) < 0)
250 Log_fatal("listen IPv6");
251 fcntl(sockets[1], F_SETFL, O_NONBLOCK);
254 /* If there is an IPv4 address, then IPv6 will use the second socket, otherwise it uses the first */
255 pollfds[(hasv4) ? 1 : 0].fd = sockets[1];
256 pollfds[(hasv4) ? 1 : 0].events = POLLIN;
260 void Server_setupUDPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds)
263 int sockets[2] = {-1, -1};
265 udpsocks = Memory_safeCalloc(nofServerSocks / 2, sizeof(int));
268 sockets[0] = socket(PF_INET, SOCK_DGRAM, 0);
269 if (bind(sockets[0], (struct sockaddr *) addresses[0], sizeof (struct sockaddr_in)) < 0) {
270 char *addressString = Util_addressToString(addresses[0]);
271 Log_fatal("bind %s %d: %s", addressString, Util_addressToPort(addresses[0]), strerror(errno));
275 if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0)
276 Log_warn("Server: Failed to set TOS for UDP Socket");
278 if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0)
279 Log_warn("Server: Failed to set TOS for UDP Socket");
281 fcntl(sockets[0], F_SETFL, O_NONBLOCK);
282 pollfds[(hasv6) ? 2 : 1].fd = sockets[0];
283 pollfds[(hasv6) ? 2 : 1].events = POLLIN | POLLHUP | POLLERR;
284 udpsocks[0] = sockets[0];
288 sockets[1] = socket(PF_INET6, SOCK_DGRAM, 0);
289 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(int)) != 0)
290 Log_fatal("setsockopt IPv6: %s", strerror(errno));
291 if (bind(sockets[1], (struct sockaddr *) addresses[1], sizeof (struct sockaddr_in6)) < 0) {
292 char *addressString = Util_addressToString(addresses[1]);
293 Log_fatal("bind %s %d: %s", addressString, Util_addressToPort(addresses[1]), strerror(errno));
297 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0)
298 Log_warn("Server: Failed to set TOS for UDP Socket");
300 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0)
301 Log_warn("Server: Failed to set TOS for UDP Socket");
303 fcntl(sockets[1], F_SETFL, O_NONBLOCK);
304 pollfds[(hasv4) ? 3 : 1].fd = sockets[1];
305 pollfds[(hasv4) ? 3 : 1].events = POLLIN | POLLHUP | POLLERR;
306 udpsocks[(hasv4) ? 1 : 0] = sockets[1];
313 struct pollfd *pollfds;
317 /* max clients + server sokets + client connecting that will be disconnected */
318 pollfds = Memory_safeCalloc((getIntConf(MAX_CLIENTS) + nofServerSocks + 1) , sizeof(struct pollfd));
320 /* Figure out bind address and port */
321 struct sockaddr_storage** addresses = Server_setupAddressesAndPorts();
323 /* Prepare TCP sockets */
324 Server_setupTCPSockets(addresses, pollfds);
326 /* Prepare UDP sockets */
327 Server_setupUDPSockets(addresses, pollfds);
329 Log_info("uMurmur version %s ('%s') protocol version %d.%d.%d",
330 UMURMUR_VERSION, UMURMUR_CODENAME, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH);
331 Log_info("Visit http://code.google.com/p/umurmur/");
333 /* Main server loop */
334 Server_runLoop(pollfds);
336 /* Disconnect clients and cleanup memory */
337 Client_disconnect_all();
345 void Server_shutdown()
347 shutdown_server = true;