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>
52 bool_t shutdown_server;
53 extern char *bindaddr;
54 extern char *bindaddr6;
58 bool_t hasv4 = true, hasv6 = true;
61 int nofServerSocks = 4;
63 /* Check which IP versions are supported by the system. */
64 void checkIPversions()
68 testsocket = socket(PF_INET, SOCK_STREAM, 0);
69 hasv4 = (errno == EAFNOSUPPORT) ? false : true;
70 if (!(testsocket < 0)) close(testsocket);
72 testsocket = socket(PF_INET6, SOCK_STREAM, 0);
73 hasv6 = (errno == EAFNOSUPPORT) ? false : true;
74 if (!(testsocket < 0)) close(testsocket);
78 Log_info("IPv4 is not supported by this system");
84 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 struct sockaddr_storage* v4address = calloc(1, sizeof(struct sockaddr_storage));
100 v4address->ss_family = AF_INET;
101 struct sockaddr_storage* v6address = calloc(1, sizeof(struct sockaddr_storage));
102 v6address->ss_family = AF_INET6;
104 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
105 v4address->ss_len = sizeof(struct sockaddr_storage);
106 v6address->ss_len = sizeof(struct sockaddr_storage);
111 error = inet_pton(AF_INET, (!bindaddr) ? ((getStrConf(BINDADDR)) ? getStrConf(BINDADDR) : "0.0.0.0")
112 : bindaddr, &(((struct sockaddr_in*)v4address)->sin_addr));
114 Log_fatal("Invalid IPv4 address supplied!");
115 else if (error == -1)
116 Log_warn("Could not allocate IPv4 address");
118 error = inet_pton(AF_INET6, (!bindaddr6) ? ((getStrConf(BINDADDR6)) ? getStrConf(BINDADDR6) : "::")
119 : bindaddr6, &(((struct sockaddr_in6*)v6address)->sin6_addr));
121 Log_fatal("Invalid IPv6 address supplied!");
122 else if (error == -1)
123 Log_warn("Could not allocate IPv6 address");
125 ((struct sockaddr_in*)v4address)->sin_port = htons((bindport) ? bindport : getIntConf(BINDPORT));
126 ((struct sockaddr_in6*)v6address)->sin6_port = htons((bindport6) ? bindport6 : getIntConf(BINDPORT6));
128 addresses[0] = v4address;
129 addresses[1] = v6address;
134 void Server_runLoop(struct pollfd* pollfds)
136 int timeout, rc, clientcount;
138 etimer_t janitorTimer;
139 Timer_init(&janitorTimer);
141 while (!shutdown_server) {
142 struct sockaddr_storage remote;
145 #ifdef USE_SHAREDMEMORY_API
146 Sharedmemory_alivetick();
149 for(i = 0; i < nofServerSocks; i++) {
150 pollfds[i].revents = 0;
153 clientcount = Client_getfds(&pollfds[nofServerSocks]);
155 timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
158 Timer_restart(&janitorTimer);
159 timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
161 rc = poll(pollfds, clientcount + nofServerSocks, timeout);
163 /* Poll timed out, do maintenance */
164 Timer_restart(&janitorTimer);
169 if (errno == EINTR) /* signal */
172 Log_fatal("poll: error %d (%s)", errno, strerror(errno));
175 /* Check for new connection */
176 for (i = 0; i < nofServerSocks / 2; i++) {
177 if (pollfds[i].revents) {
179 uint32_t addrlen = sizeof(struct sockaddr_storage);
180 tcpfd = accept(pollfds[i].fd, (struct sockaddr *)&remote, &addrlen);
181 fcntl(tcpfd, F_SETFL, O_NONBLOCK);
182 setsockopt(tcpfd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(int));
183 Log_debug("Connection from %s port %d\n", Util_addressToString(&remote), Util_addressToPort(&remote));
184 if (Client_add(tcpfd, &remote) < 0)
189 for (i = nofServerSocks / 2; i < nofServerSocks; i++) {
190 if (pollfds[i].revents)
191 Client_read_udp(udpsocks[i - nofServerSocks / 2]);
194 for (i = 0; i < clientcount; i++) {
195 if (pollfds[nofServerSocks + i].revents & POLLIN)
196 Client_read_fd(pollfds[nofServerSocks + i].fd);
198 if (pollfds[nofServerSocks + i].revents & POLLOUT)
199 Client_write_fd(pollfds[nofServerSocks + i].fd);
201 #ifdef USE_SHAREDMEMORY_API
202 Sharedmemory_update();
207 void Server_setupTCPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds)
213 /* IPv4 socket setup */
214 sockets[0] = socket(PF_INET, SOCK_STREAM, 0);
216 Log_fatal("socket IPv4");
217 if (setsockopt(sockets[0], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0)
218 Log_fatal("setsockopt IPv4: %s", strerror(errno));
219 if (bind(sockets[0], (struct sockaddr *)addresses[0], sizeof (struct sockaddr_in)) < 0)
220 Log_fatal("bind %s %d: %s", Util_addressToString(addresses[0]), Util_addressToPort(addresses[0]), strerror(errno));
221 if (listen(sockets[0], 3) < 0)
222 Log_fatal("listen IPv4");
223 fcntl(sockets[0], F_SETFL, O_NONBLOCK);
225 pollfds[0].fd = sockets[0];
226 pollfds[0].events = POLLIN;
230 /* IPv6 socket setup */
231 sockets[1] = socket(PF_INET6, SOCK_STREAM, 0);
233 Log_fatal("socket IPv6: %s", strerror(errno));
234 if (setsockopt(sockets[1], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0)
235 Log_fatal("setsockopt IPv6: %s", strerror(errno));
236 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(int)) != 0)
237 Log_fatal("setsockopt IPv6: %s", strerror(errno));
238 if (bind(sockets[1], (struct sockaddr *)addresses[1], sizeof (struct sockaddr_in6)) < 0)
239 Log_fatal("bind %s %d: %s", Util_addressToString(addresses[1]), Util_addressToPort(addresses[1]), strerror(errno));
240 if (listen(sockets[1], 3) < 0)
241 Log_fatal("listen IPv6");
242 fcntl(sockets[1], F_SETFL, O_NONBLOCK);
245 /* If there is an IPv4 address, then IPv6 will use the second socket, otherwise it uses the first */
246 pollfds[(hasv4) ? 1 : 0].fd = sockets[1];
247 pollfds[(hasv4) ? 1 : 0].events = POLLIN;
251 void Server_setupUDPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds)
254 int sockets[2] = {-1, -1};
256 if((udpsocks = calloc(nofServerSocks / 2, sizeof(int))) == NULL)
257 Log_fatal("Out of memory (%s:%s)", __FILE__, __LINE__);
260 sockets[0] = socket(PF_INET, SOCK_DGRAM, 0);
261 if (bind(sockets[0], (struct sockaddr *) addresses[0], sizeof (struct sockaddr_in)) < 0)
262 Log_fatal("bind %s %d: %s", Util_addressToString(addresses[0]), Util_addressToPort(addresses[0]), strerror(errno));
264 if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0)
265 Log_warn("Server: Failed to set TOS for UDP Socket");
267 if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0)
268 Log_warn("Server: Failed to set TOS for UDP Socket");
270 fcntl(sockets[0], F_SETFL, O_NONBLOCK);
271 pollfds[(hasv6) ? 2 : 1].fd = sockets[0];
272 pollfds[(hasv6) ? 2 : 1].events = POLLIN | POLLHUP | POLLERR;
273 udpsocks[0] = sockets[0];
277 sockets[1] = socket(PF_INET6, SOCK_DGRAM, 0);
278 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(int)) != 0)
279 Log_fatal("setsockopt IPv6: %s", strerror(errno));
280 if (bind(sockets[1], (struct sockaddr *) addresses[1], sizeof (struct sockaddr_in6)) < 0)
281 Log_fatal("bind %s %d: %s", Util_addressToString(addresses[1]), Util_addressToPort(addresses[1]), strerror(errno));
283 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0)
284 Log_warn("Server: Failed to set TOS for UDP Socket");
286 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0)
287 Log_warn("Server: Failed to set TOS for UDP Socket");
289 fcntl(sockets[1], F_SETFL, O_NONBLOCK);
290 pollfds[(hasv4) ? 3 : 1].fd = sockets[1];
291 pollfds[(hasv4) ? 3 : 1].events = POLLIN | POLLHUP | POLLERR;
292 udpsocks[(hasv4) ? 1 : 0] = sockets[1];
299 struct pollfd *pollfds;
303 /* max clients + server sokets + client connecting that will be disconnected */
304 if ((pollfds = calloc((getIntConf(MAX_CLIENTS) + nofServerSocks + 1) , sizeof(struct pollfd))) == NULL)
305 Log_fatal("out of memory");
307 /* Figure out bind address and port */
308 struct sockaddr_storage** addresses = Server_setupAddressesAndPorts();
310 /* Prepare TCP sockets */
311 Server_setupTCPSockets(addresses, pollfds);
313 /* Prepare UDP sockets */
314 Server_setupUDPSockets(addresses, pollfds);
316 Log_info("uMurmur version %s ('%s') protocol version %d.%d.%d",
317 UMURMUR_VERSION, UMURMUR_CODENAME, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH);
318 Log_info("Visit http://code.google.com/p/umurmur/");
320 /* Main server loop */
321 Server_runLoop(pollfds);
323 /* Disconnect clients and cleanup memory */
324 Client_disconnect_all();
332 void Server_shutdown()
334 shutdown_server = true;