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 for(i = 0; i < nofServerSocks; i++) {
146 pollfds[i].revents = 0;
149 clientcount = Client_getfds(&pollfds[nofServerSocks]);
151 timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
154 Timer_restart(&janitorTimer);
155 timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
157 rc = poll(pollfds, clientcount + nofServerSocks, timeout);
159 /* Poll timed out, do maintenance */
160 Timer_restart(&janitorTimer);
165 if (errno == EINTR) /* signal */
168 Log_fatal("poll: error %d (%s)", errno, strerror(errno));
171 /* Check for new connection */
172 for (i = 0; i < nofServerSocks / 2; i++) {
173 if (pollfds[i].revents) {
175 static uint32_t addrlen = sizeof(struct sockaddr_storage);
176 tcpfd = accept(pollfds[i].fd, (struct sockaddr *)&remote, &addrlen);
177 fcntl(tcpfd, F_SETFL, O_NONBLOCK);
178 setsockopt(tcpfd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(int));
179 Log_debug("Connection from %s port %d\n", Util_addressToString(&remote), Util_addressToPort(&remote));
180 if (Client_add(tcpfd, &remote) < 0)
185 for (i = nofServerSocks / 2; i < nofServerSocks; i++) {
186 if (pollfds[i].revents)
187 Client_read_udp(udpsocks[i - nofServerSocks / 2]);
190 for (i = 0; i < clientcount; i++) {
191 if (pollfds[nofServerSocks + i].revents & POLLIN)
192 Client_read_fd(pollfds[nofServerSocks + i].fd);
194 if (pollfds[nofServerSocks + i].revents & POLLOUT)
195 Client_write_fd(pollfds[nofServerSocks + i].fd);
197 #ifdef USE_SHAREDMEMORY_API
198 Sharedmemory_update();
203 void Server_setupTCPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds)
209 /* IPv4 socket setup */
210 sockets[0] = socket(PF_INET, SOCK_STREAM, 0);
212 Log_fatal("socket IPv4");
213 if (setsockopt(sockets[0], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0)
214 Log_fatal("setsockopt IPv4: %s", strerror(errno));
215 if (bind(sockets[0], (struct sockaddr *)addresses[0], sizeof (struct sockaddr_in)) < 0)
216 Log_fatal("bind %s %d: %s", Util_addressToString(addresses[0]), Util_addressToPort(addresses[0]), strerror(errno));
217 if (listen(sockets[0], 3) < 0)
218 Log_fatal("listen IPv4");
219 fcntl(sockets[0], F_SETFL, O_NONBLOCK);
221 pollfds[0].fd = sockets[0];
222 pollfds[0].events = POLLIN;
226 /* IPv6 socket setup */
227 sockets[1] = socket(PF_INET6, SOCK_STREAM, 0);
229 Log_fatal("socket IPv6: %s", strerror(errno));
230 if (setsockopt(sockets[1], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0)
231 Log_fatal("setsockopt IPv6: %s", strerror(errno));
232 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(int)) != 0)
233 Log_fatal("setsockopt IPv6: %s", strerror(errno));
234 if (bind(sockets[1], (struct sockaddr *)addresses[1], sizeof (struct sockaddr_in6)) < 0)
235 Log_fatal("bind %s %d: %s", Util_addressToString(addresses[1]), Util_addressToPort(addresses[1]), strerror(errno));
236 if (listen(sockets[1], 3) < 0)
237 Log_fatal("listen IPv6");
238 fcntl(sockets[1], F_SETFL, O_NONBLOCK);
241 /* If there is an IPv4 address, then IPv6 will use the second socket, otherwise it uses the first */
242 pollfds[(hasv4) ? 1 : 0].fd = sockets[1];
243 pollfds[(hasv4) ? 1 : 0].events = POLLIN;
247 void Server_setupUDPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds)
250 int sockets[2] = {-1, -1};
252 if((udpsocks = calloc(nofServerSocks / 2, sizeof(int))) == NULL)
253 Log_fatal("Out of memory (%s:%s)", __FILE__, __LINE__);
256 sockets[0] = socket(PF_INET, SOCK_DGRAM, 0);
257 if (bind(sockets[0], (struct sockaddr *) addresses[0], sizeof (struct sockaddr_in)) < 0)
258 Log_fatal("bind %s %d: %s", Util_addressToString(addresses[0]), Util_addressToPort(addresses[0]), strerror(errno));
260 if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0)
261 Log_warn("Server: Failed to set TOS for UDP Socket");
263 if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0)
264 Log_warn("Server: Failed to set TOS for UDP Socket");
266 fcntl(sockets[0], F_SETFL, O_NONBLOCK);
267 pollfds[(hasv6) ? 2 : 1].fd = sockets[0];
268 pollfds[(hasv6) ? 2 : 1].events = POLLIN | POLLHUP | POLLERR;
269 udpsocks[0] = sockets[0];
273 sockets[1] = socket(PF_INET6, SOCK_DGRAM, 0);
274 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(int)) != 0)
275 Log_fatal("setsockopt IPv6: %s", strerror(errno));
276 if (bind(sockets[1], (struct sockaddr *) addresses[1], sizeof (struct sockaddr_in6)) < 0)
277 Log_fatal("bind %s %d: %s", Util_addressToString(addresses[1]), Util_addressToPort(addresses[1]), strerror(errno));
279 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0)
280 Log_warn("Server: Failed to set TOS for UDP Socket");
282 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0)
283 Log_warn("Server: Failed to set TOS for UDP Socket");
285 fcntl(sockets[1], F_SETFL, O_NONBLOCK);
286 pollfds[(hasv4) ? 3 : 1].fd = sockets[1];
287 pollfds[(hasv4) ? 3 : 1].events = POLLIN | POLLHUP | POLLERR;
288 udpsocks[(hasv4) ? 1 : 0] = sockets[1];
295 struct pollfd *pollfds;
299 /* max clients + server sokets + client connecting that will be disconnected */
300 if ((pollfds = calloc((getIntConf(MAX_CLIENTS) + nofServerSocks + 1) , sizeof(struct pollfd))) == NULL)
301 Log_fatal("out of memory");
303 /* Figure out bind address and port */
304 struct sockaddr_storage** addresses = Server_setupAddressesAndPorts();
306 /* Prepare TCP sockets */
307 Server_setupTCPSockets(addresses, pollfds);
309 /* Prepare UDP sockets */
310 Server_setupUDPSockets(addresses, pollfds);
312 Log_info("uMurmur version %s ('%s') protocol version %d.%d.%d",
313 UMURMUR_VERSION, UMURMUR_CODENAME, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH);
314 Log_info("Visit http://code.google.com/p/umurmur/");
316 /* Main server loop */
317 Server_runLoop(pollfds);
319 /* Disconnect clients and cleanup memory */
320 Client_disconnect_all();
328 void Server_shutdown()
330 shutdown_server = true;