Handle systems without IPv6 support correctly
[umurmur.git] / src / server.c
1 /* Copyright (C) 2009-2014, Martin Johansson <martin@fatbob.nu>
2    Copyright (C) 2005-2014, Thorvald Natvig <thorvald@natvig.com>
3
4    All rights reserved.
5
6    Redistribution and use in source and binary forms, with or without
7    modification, are permitted provided that the following conditions
8    are met:
9
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.
18
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.
30 */
31 #include <stdio.h>
32 #include <sys/time.h>
33 #include <sys/poll.h>
34 #include <netinet/tcp.h>
35 #include <sys/socket.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <limits.h>
39 #include <unistd.h>
40 #include <fcntl.h>
41 #include <errno.h>
42 #include <stdlib.h>
43
44 #include "client.h"
45 #include "conf.h"
46 #include "log.h"
47 #include "timer.h"
48 #include "version.h"
49 #include "util.h"
50
51 /* globals */
52 bool_t shutdown_server;
53 extern char *bindaddr;
54 extern char *bindaddr6;
55 extern int bindport;
56 extern int bindport6;
57 int* udpsocks;
58 bool hasv4 = true, hasv6 = true;
59
60 const int on = 1;
61 int nofServerSocks = 4;
62
63 /* Initialize the address structures for IPv4 and IPv6 */
64 struct sockaddr_storage** Server_setupAddressesAndPorts()
65 {
66         struct sockaddr_storage** addresses = calloc(2, sizeof(void*));
67
68         struct sockaddr_storage* v4address = calloc(1, sizeof(struct sockaddr_storage));
69         v4address->ss_family = AF_INET;
70         struct sockaddr_storage* v6address = calloc(1, sizeof(struct sockaddr_storage));
71         v6address->ss_family = AF_INET6;
72
73 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
74         v4address->ss_len = sizeof(struct sockaddr_storage);
75         v6address->ss_len = sizeof(struct sockaddr_storage);
76 #endif
77
78         int error = 0;
79
80         error = inet_pton(AF_INET, (!bindaddr) ? ((getStrConf(BINDADDR)) ? getStrConf(BINDADDR) : "0.0.0.0")
81                 : bindaddr, &(((struct sockaddr_in*)v4address)->sin_addr));
82         if (error == 0)
83                 Log_fatal("Invalid IPv4 address supplied!");
84         else if (error == -1) {
85                 Log_warn("Could not allocate IPv4 address");
86                 hasv4 = false;
87                 nofServerSocks -= 2;
88         }
89
90         error = inet_pton(AF_INET6, (!bindaddr6) ? ((getStrConf(BINDADDR6)) ? getStrConf(BINDADDR6) : "::")
91                 : bindaddr6, &(((struct sockaddr_in6*)v6address)->sin6_addr));
92         if (error == 0)
93                 Log_fatal("Invalid IPv6 address supplied!");
94         else if (error == -1) {
95                 Log_warn("Could not allocate IPv6 address");
96                 hasv6 = false;
97                 nofServerSocks -= 2;
98         }
99
100         if (!hasv4 && !hasv6)
101                 Log_fatal("Could not allocate IPv4 nor IPv6 address!");
102
103         ((struct sockaddr_in*)v4address)->sin_port = htons((bindport) ? bindport : getIntConf(BINDPORT));
104         ((struct sockaddr_in6*)v6address)->sin6_port = htons((bindport6) ? bindport6 : getIntConf(BINDPORT6));
105
106         addresses[0] = v4address;
107         addresses[1] = v6address;
108
109         return addresses;
110 }
111
112 void Server_runLoop(struct pollfd* pollfds)
113 {
114         int timeout, rc, clientcount;
115
116         etimer_t janitorTimer;
117         Timer_init(&janitorTimer);
118
119         while (!shutdown_server) {
120                 struct sockaddr_storage remote;
121                 int i;
122
123                 if (nofServerSocks == 4) {
124                         pollfds[0].revents = 0;
125                         pollfds[1].revents = 0;
126                         pollfds[2].revents = 0;
127                         pollfds[3].revents = 0;
128                 } else {
129                         pollfds[0].revents = 0;
130                         pollfds[1].revents = 0;
131                 }
132
133                 clientcount = Client_getfds(&pollfds[nofServerSocks]);
134
135                 timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
136                 if (timeout <= 0) {
137                         Client_janitor();
138                         Timer_restart(&janitorTimer);
139                         timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
140                 }
141                 rc = poll(pollfds, clientcount + nofServerSocks, timeout);
142                 if (rc == 0) {
143                         /* Poll timed out, do maintenance */
144                         Timer_restart(&janitorTimer);
145                         Client_janitor();
146                         continue;
147                 }
148                 if (rc < 0) {
149                         if (errno == EINTR) /* signal */
150                                 continue;
151                         else
152                                 Log_fatal("poll: error %d (%s)", errno, strerror(errno));
153                 }
154
155                 /* Check for new connection */
156                 for (i = 0; i < nofServerSocks / 2; i++) {
157                         if (pollfds[i].revents) {
158                                 static int tcpfd;
159                                 static uint32_t addrlen = sizeof(struct sockaddr_storage);
160                                 tcpfd = accept(pollfds[i].fd, (struct sockaddr *)&remote, &addrlen);
161                                 fcntl(tcpfd, F_SETFL, O_NONBLOCK);
162                                 setsockopt(tcpfd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(int));
163                                 Log_debug("Connection from %s port %d\n", Util_addressToString(&remote), Util_addressToPort(&remote));
164                                 if (Client_add(tcpfd, &remote) < 0)
165                                         close(tcpfd);
166                         }
167                 }
168
169                 for (i = nofServerSocks / 2; i < nofServerSocks; i++) {
170                         if (pollfds[i].revents)
171                                 Client_read_udp(udpsocks[i - nofServerSocks / 2]);
172                 }
173
174                 for (i = 0; i < clientcount; i++) {
175                         if (pollfds[nofServerSocks + i].revents & POLLIN)
176                                 Client_read_fd(pollfds[nofServerSocks + i].fd);
177
178                         if (pollfds[nofServerSocks + i].revents & POLLOUT)
179                                 Client_write_fd(pollfds[nofServerSocks + i].fd);
180                 }
181         }
182 }
183
184 void Server_setupTCPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds)
185 {
186         uint8_t yes = 1;
187         int sockets[2];
188
189         if (hasv4) {
190                 /* IPv4 socket setup */
191                 sockets[0] = socket(PF_INET, SOCK_STREAM, 0);
192                 if (sockets[0] < 0)
193                         Log_fatal("socket IPv4");
194                 if (setsockopt(sockets[0], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0)
195                         Log_fatal("setsockopt IPv4: %s", strerror(errno));
196                 if (bind(sockets[0], (struct sockaddr *)addresses[0], sizeof (struct sockaddr_in)) < 0)
197                         Log_fatal("bind %s %d: %s", Util_addressToString(addresses[0]), Util_addressToPort(addresses[0]), strerror(errno));
198                 if (listen(sockets[0], 3) < 0)
199                         Log_fatal("listen IPv4");
200                 fcntl(sockets[0], F_SETFL, O_NONBLOCK);
201
202                 pollfds[0].fd = sockets[0];
203                 pollfds[0].events = POLLIN;
204         }
205
206         if (hasv6) {
207                 /* IPv6 socket setup */
208                 sockets[1] = socket(PF_INET6, SOCK_STREAM, 0);
209                 if (sockets[1] < 0)
210                         Log_fatal("socket IPv6");
211                 if (setsockopt(sockets[1], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0)
212                         Log_fatal("setsockopt IPv6: %s", strerror(errno));
213                 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(int)) != 0)
214                         Log_fatal("setsockopt IPv6: %s", strerror(errno));
215                 if (bind(sockets[1], (struct sockaddr *)addresses[1], sizeof (struct sockaddr_in6)) < 0)
216                         Log_fatal("bind %s %d: %s", Util_addressToString(addresses[1]), Util_addressToPort(addresses[1]), strerror(errno));
217                 if (listen(sockets[1], 3) < 0)
218                         Log_fatal("listen IPv6");
219                 fcntl(sockets[1], F_SETFL, O_NONBLOCK);
220
221
222                 /* If  there is an IPv4 address, then IPv6 will use the second socket, otherwise it uses the first */
223                 pollfds[(hasv4) ? 1 : 0].fd = sockets[1];
224                 pollfds[(hasv4) ? 1 : 0].events = POLLIN;
225         }
226 }
227
228 void Server_setupUDPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds)
229 {
230         int val = 0;
231         int sockets[2] = {-1, -1};
232
233         if((udpsocks = calloc(nofServerSocks / 2, sizeof(int))) == NULL)
234                 Log_fatal("Out of memory (%s:%s)", __FILE__, __LINE__);
235
236         if (hasv4) {
237                 sockets[0] = socket(PF_INET, SOCK_DGRAM, 0);
238                 if (bind(sockets[0], (struct sockaddr *) addresses[0], sizeof (struct sockaddr_in)) < 0)
239                         Log_fatal("bind %s %d: %s", Util_addressToString(addresses[0]), Util_addressToPort(addresses[0]), strerror(errno));
240                 val = 0xe0;
241                 if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0)
242                         Log_warn("Server: Failed to set TOS for UDP Socket");
243                 val = 0x80;
244                 if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0)
245                         Log_warn("Server: Failed to set TOS for UDP Socket");
246
247                 fcntl(sockets[0], F_SETFL, O_NONBLOCK);
248                 pollfds[(hasv6) ? 2 : 1].fd = sockets[0];
249                 pollfds[(hasv6) ? 2 : 1].events = POLLIN | POLLHUP | POLLERR;
250                 udpsocks[0] = sockets[0];
251         }
252
253         if (hasv6) {
254                 sockets[1] = socket(PF_INET6, SOCK_DGRAM, 0);
255                 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(int)) != 0)
256                         Log_fatal("setsockopt IPv6: %s", strerror(errno));
257                 if (bind(sockets[1], (struct sockaddr *) addresses[1], sizeof (struct sockaddr_in6)) < 0)
258                         Log_fatal("bind %s %d: %s", Util_addressToString(addresses[1]), Util_addressToPort(addresses[1]), strerror(errno));
259                 val = 0xe0;
260                 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0)
261                         Log_warn("Server: Failed to set TOS for UDP Socket");
262                 val = 0x80;
263                 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0)
264                         Log_warn("Server: Failed to set TOS for UDP Socket");
265
266                 fcntl(sockets[1], F_SETFL, O_NONBLOCK);
267                 pollfds[(hasv4) ? 3 : 1].fd = sockets[1];
268                 pollfds[(hasv4) ? 3 : 1].events = POLLIN | POLLHUP | POLLERR;
269                 udpsocks[(hasv4) ? 1 : 0] = sockets[1];
270         }
271
272 }
273
274 void Server_run()
275 {
276         struct pollfd *pollfds;
277
278         /* max clients + listen sock + udp sock + client connecting that will be disconnected */
279         if ((pollfds = calloc((getIntConf(MAX_CLIENTS) + 5) , sizeof(struct pollfd))) == NULL)
280                 Log_fatal("out of memory");
281
282         /* Figure out bind address and port */
283         struct sockaddr_storage** addresses = Server_setupAddressesAndPorts();
284
285         /* Prepare TCP sockets */
286         Server_setupTCPSockets(addresses, pollfds);
287
288         /* Prepare UDP sockets */
289         Server_setupUDPSockets(addresses, pollfds);
290
291         Log_info("uMurmur version %s ('%s') protocol version %d.%d.%d",
292                 UMURMUR_VERSION, UMURMUR_CODENAME, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH);
293         Log_info("Visit http://code.google.com/p/umurmur/");
294
295         /* Main server loop */
296         Server_runLoop(pollfds);
297
298         /* Disconnect clients and cleanup memory */
299         Client_disconnect_all();
300         free(pollfds);
301         free(addresses[0]);
302         free(addresses[1]);
303         free(addresses);
304         free(udpsocks);
305 }
306
307 void Server_shutdown()
308 {
309         shutdown_server = true;
310 }