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>
50 #include "sharedmemory.h"
53 bool_t shutdown_server;
54 extern char *bindaddr;
55 extern char *bindaddr6;
59 bool_t hasv4 = true, hasv6 = true;
62 int nofServerSocks = 4;
64 /* Check which IP versions are supported by the system. */
65 void checkIPversions()
69 testsocket = socket(PF_INET, SOCK_STREAM, 0);
70 hasv4 = (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) ? false : true;
71 if (!(testsocket < 0)) close(testsocket);
73 testsocket = socket(PF_INET6, SOCK_STREAM, 0);
74 hasv6 = (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) ? false : true;
75 if (!(testsocket < 0)) close(testsocket);
79 Log_info("IPv4 is not supported by this system");
85 Log_info("IPv6 is not supported by this system");
88 if(nofServerSocks == 0)
90 Log_fatal("Neither IPv4 nor IPv6 are supported by this system");
94 /* Initialize the address structures for IPv4 and IPv6 */
95 struct sockaddr_storage** Server_setupAddressesAndPorts()
97 struct sockaddr_storage** addresses = calloc(2, sizeof(void*));
99 Log_fatal("Not enough memory to allocate addresses");
101 struct sockaddr_storage* v4address = calloc(1, sizeof(struct sockaddr_storage));
102 v4address->ss_family = AF_INET;
104 Log_fatal("Not enough memory to allocate IPv4 address");
106 struct sockaddr_storage* v6address = calloc(1, sizeof(struct sockaddr_storage));
107 v6address->ss_family = AF_INET6;
109 Log_fatal("Not enough memory to allocate IPv6 address");
111 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
112 v4address->ss_len = sizeof(struct sockaddr_storage);
113 v6address->ss_len = sizeof(struct sockaddr_storage);
118 error = inet_pton(AF_INET, (!bindaddr) ? ((getStrConf(BINDADDR)) ? getStrConf(BINDADDR) : "0.0.0.0")
119 : bindaddr, &(((struct sockaddr_in*)v4address)->sin_addr));
121 Log_fatal("Invalid IPv4 address supplied!");
122 else if (error == -1)
123 Log_warn("Could not allocate IPv4 address");
125 error = inet_pton(AF_INET6, (!bindaddr6) ? ((getStrConf(BINDADDR6)) ? getStrConf(BINDADDR6) : "::")
126 : bindaddr6, &(((struct sockaddr_in6*)v6address)->sin6_addr));
128 Log_fatal("Invalid IPv6 address supplied!");
129 else if (error == -1)
130 Log_warn("Could not allocate IPv6 address");
132 ((struct sockaddr_in*)v4address)->sin_port = htons((bindport) ? bindport : getIntConf(BINDPORT));
133 ((struct sockaddr_in6*)v6address)->sin6_port = htons((bindport6) ? bindport6 : getIntConf(BINDPORT6));
135 addresses[0] = v4address;
136 addresses[1] = v6address;
141 void Server_runLoop(struct pollfd* pollfds)
143 int timeout, rc, clientcount;
145 etimer_t janitorTimer;
146 Timer_init(&janitorTimer);
148 while (!shutdown_server) {
149 struct sockaddr_storage remote;
152 #ifdef USE_SHAREDMEMORY_API
153 Sharedmemory_alivetick();
156 for(i = 0; i < nofServerSocks; i++) {
157 pollfds[i].revents = 0;
160 clientcount = Client_getfds(&pollfds[nofServerSocks]);
162 timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
165 Timer_restart(&janitorTimer);
166 timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
168 rc = poll(pollfds, clientcount + nofServerSocks, timeout);
170 /* Poll timed out, do maintenance */
171 Timer_restart(&janitorTimer);
176 if (errno == EINTR) /* signal */
179 Log_fatal("poll: error %d (%s)", errno, strerror(errno));
182 /* Check for new connection */
183 for (i = 0; i < nofServerSocks / 2; i++) {
184 if (pollfds[i].revents) {
186 uint32_t addrlen = sizeof(struct sockaddr_storage);
187 tcpfd = accept(pollfds[i].fd, (struct sockaddr *)&remote, &addrlen);
188 fcntl(tcpfd, F_SETFL, O_NONBLOCK);
189 setsockopt(tcpfd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(int));
190 char *addressString = Util_addressToString(&remote);
191 Log_debug("Connection from %s port %d\n", addressString, Util_addressToPort(&remote));
193 if (Client_add(tcpfd, &remote) < 0)
198 for (i = nofServerSocks / 2; i < nofServerSocks; i++) {
199 if (pollfds[i].revents)
200 Client_read_udp(udpsocks[i - nofServerSocks / 2]);
203 for (i = 0; i < clientcount; i++) {
204 if (pollfds[nofServerSocks + i].revents & POLLIN)
205 Client_read_fd(pollfds[nofServerSocks + i].fd);
207 if (pollfds[nofServerSocks + i].revents & POLLOUT)
208 Client_write_fd(pollfds[nofServerSocks + i].fd);
210 #ifdef USE_SHAREDMEMORY_API
211 Sharedmemory_update();
216 void Server_setupTCPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds)
222 /* IPv4 socket setup */
223 sockets[0] = socket(PF_INET, SOCK_STREAM, 0);
225 Log_fatal("socket IPv4");
226 if (setsockopt(sockets[0], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0)
227 Log_fatal("setsockopt IPv4: %s", strerror(errno));
228 if (bind(sockets[0], (struct sockaddr *)addresses[0], sizeof (struct sockaddr_in)) < 0) {
229 char *addressString = Util_addressToString(addresses[0]);
230 Log_fatal("bind %s %d: %s", addressString, Util_addressToPort(addresses[0]), strerror(errno));
233 if (listen(sockets[0], 3) < 0)
234 Log_fatal("listen IPv4");
235 fcntl(sockets[0], F_SETFL, O_NONBLOCK);
237 pollfds[0].fd = sockets[0];
238 pollfds[0].events = POLLIN;
242 /* IPv6 socket setup */
243 sockets[1] = socket(PF_INET6, SOCK_STREAM, 0);
245 Log_fatal("socket IPv6: %s", strerror(errno));
246 if (setsockopt(sockets[1], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0)
247 Log_fatal("setsockopt IPv6: %s", strerror(errno));
248 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(int)) != 0)
249 Log_fatal("setsockopt IPv6: %s", strerror(errno));
250 if (bind(sockets[1], (struct sockaddr *)addresses[1], sizeof (struct sockaddr_in6)) < 0) {
251 char *addressString = Util_addressToString(addresses[1]);
252 Log_fatal("bind %s %d: %s", addressString, Util_addressToPort(addresses[1]), strerror(errno));
255 if (listen(sockets[1], 3) < 0)
256 Log_fatal("listen IPv6");
257 fcntl(sockets[1], F_SETFL, O_NONBLOCK);
260 /* If there is an IPv4 address, then IPv6 will use the second socket, otherwise it uses the first */
261 pollfds[(hasv4) ? 1 : 0].fd = sockets[1];
262 pollfds[(hasv4) ? 1 : 0].events = POLLIN;
266 void Server_setupUDPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds)
269 int sockets[2] = {-1, -1};
271 if((udpsocks = calloc(nofServerSocks / 2, sizeof(int))) == NULL)
272 Log_fatal("Out of memory (%s:%s)", __FILE__, __LINE__);
275 sockets[0] = socket(PF_INET, SOCK_DGRAM, 0);
276 if (bind(sockets[0], (struct sockaddr *) addresses[0], sizeof (struct sockaddr_in)) < 0) {
277 char *addressString = Util_addressToString(addresses[0]);
278 Log_fatal("bind %s %d: %s", addressString, Util_addressToPort(addresses[0]), strerror(errno));
282 if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0)
283 Log_warn("Server: Failed to set TOS for UDP Socket");
285 if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0)
286 Log_warn("Server: Failed to set TOS for UDP Socket");
288 fcntl(sockets[0], F_SETFL, O_NONBLOCK);
289 pollfds[(hasv6) ? 2 : 1].fd = sockets[0];
290 pollfds[(hasv6) ? 2 : 1].events = POLLIN | POLLHUP | POLLERR;
291 udpsocks[0] = sockets[0];
295 sockets[1] = socket(PF_INET6, SOCK_DGRAM, 0);
296 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(int)) != 0)
297 Log_fatal("setsockopt IPv6: %s", strerror(errno));
298 if (bind(sockets[1], (struct sockaddr *) addresses[1], sizeof (struct sockaddr_in6)) < 0) {
299 char *addressString = Util_addressToString(addresses[1]);
300 Log_fatal("bind %s %d: %s", addressString, Util_addressToPort(addresses[1]), strerror(errno));
304 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0)
305 Log_warn("Server: Failed to set TOS for UDP Socket");
307 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0)
308 Log_warn("Server: Failed to set TOS for UDP Socket");
310 fcntl(sockets[1], F_SETFL, O_NONBLOCK);
311 pollfds[(hasv4) ? 3 : 1].fd = sockets[1];
312 pollfds[(hasv4) ? 3 : 1].events = POLLIN | POLLHUP | POLLERR;
313 udpsocks[(hasv4) ? 1 : 0] = sockets[1];
320 struct pollfd *pollfds;
324 /* max clients + server sokets + client connecting that will be disconnected */
325 if ((pollfds = calloc((getIntConf(MAX_CLIENTS) + nofServerSocks + 1) , sizeof(struct pollfd))) == NULL)
326 Log_fatal("out of memory");
328 /* Figure out bind address and port */
329 struct sockaddr_storage** addresses = Server_setupAddressesAndPorts();
331 /* Prepare TCP sockets */
332 Server_setupTCPSockets(addresses, pollfds);
334 /* Prepare UDP sockets */
335 Server_setupUDPSockets(addresses, pollfds);
337 Log_info("uMurmur version %s ('%s') protocol version %d.%d.%d",
338 UMURMUR_VERSION, UMURMUR_CODENAME, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH);
339 Log_info("Visit http://code.google.com/p/umurmur/");
341 /* Main server loop */
342 Server_runLoop(pollfds);
344 /* Disconnect clients and cleanup memory */
345 Client_disconnect_all();
353 void Server_shutdown()
355 shutdown_server = true;