Make sharedmemory api a compile time option
[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_t hasv4 = true, hasv6 = true;
59
60 const int on = 1;
61 int nofServerSocks = 4;
62
63 /* Check which IP versions are supported by the system. */
64 void checkIPversions()
65 {
66         int testsocket = -1;
67
68         testsocket = socket(PF_INET, SOCK_STREAM, 0);
69         hasv4 = (errno == EAFNOSUPPORT) ? false : true;
70         if (!(testsocket < 0)) close(testsocket);
71
72         testsocket = socket(PF_INET6, SOCK_STREAM, 0);
73         hasv6 = (errno == EAFNOSUPPORT) ? false : true;
74         if (!(testsocket < 0)) close(testsocket);
75
76         if(!hasv4)
77         {
78                 Log_info("IPv4 is not supported by this system");
79                 nofServerSocks -= 2;
80         }
81
82         if(!hasv6)
83         {
84                 Log_info("IPv6 is not supported by this system");
85                 nofServerSocks -= 2;
86         }
87
88         if(nofServerSocks == 0)
89         {
90                 Log_fatal("Neither IPv4 nor IPv6 are supported by this system");
91         }
92 }
93
94 /* Initialize the address structures for IPv4 and IPv6 */
95 struct sockaddr_storage** Server_setupAddressesAndPorts()
96 {
97         struct sockaddr_storage** addresses = calloc(2, sizeof(void*));
98
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;
103
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);
107 #endif
108
109         int error = 0;
110
111         error = inet_pton(AF_INET, (!bindaddr) ? ((getStrConf(BINDADDR)) ? getStrConf(BINDADDR) : "0.0.0.0")
112                 : bindaddr, &(((struct sockaddr_in*)v4address)->sin_addr));
113         if (error == 0)
114                 Log_fatal("Invalid IPv4 address supplied!");
115         else if (error == -1)
116                 Log_warn("Could not allocate IPv4 address");
117
118         error = inet_pton(AF_INET6, (!bindaddr6) ? ((getStrConf(BINDADDR6)) ? getStrConf(BINDADDR6) : "::")
119                 : bindaddr6, &(((struct sockaddr_in6*)v6address)->sin6_addr));
120         if (error == 0)
121                 Log_fatal("Invalid IPv6 address supplied!");
122         else if (error == -1)
123                 Log_warn("Could not allocate IPv6 address");
124
125         ((struct sockaddr_in*)v4address)->sin_port = htons((bindport) ? bindport : getIntConf(BINDPORT));
126         ((struct sockaddr_in6*)v6address)->sin6_port = htons((bindport6) ? bindport6 : getIntConf(BINDPORT6));
127
128         addresses[0] = v4address;
129         addresses[1] = v6address;
130
131         return addresses;
132 }
133
134 void Server_runLoop(struct pollfd* pollfds)
135 {
136         int timeout, rc, clientcount;
137
138         etimer_t janitorTimer;
139         Timer_init(&janitorTimer);
140
141         while (!shutdown_server) {
142                 struct sockaddr_storage remote;
143                 int i;
144
145                 for(i = 0; i < nofServerSocks; i++) {
146                         pollfds[i].revents = 0;
147                 }
148
149                 clientcount = Client_getfds(&pollfds[nofServerSocks]);
150
151                 timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
152                 if (timeout <= 0) {
153                         Client_janitor();
154                         Timer_restart(&janitorTimer);
155                         timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
156                 }
157                 rc = poll(pollfds, clientcount + nofServerSocks, timeout);
158                 if (rc == 0) {
159                         /* Poll timed out, do maintenance */
160                         Timer_restart(&janitorTimer);
161                         Client_janitor();
162                         continue;
163                 }
164                 if (rc < 0) {
165                         if (errno == EINTR) /* signal */
166                                 continue;
167                         else
168                                 Log_fatal("poll: error %d (%s)", errno, strerror(errno));
169                 }
170
171                 /* Check for new connection */
172                 for (i = 0; i < nofServerSocks / 2; i++) {
173                         if (pollfds[i].revents) {
174                                 static int tcpfd;
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)
181                                         close(tcpfd);
182                         }
183                 }
184
185                 for (i = nofServerSocks / 2; i < nofServerSocks; i++) {
186                         if (pollfds[i].revents)
187                                 Client_read_udp(udpsocks[i - nofServerSocks / 2]);
188                 }
189
190                 for (i = 0; i < clientcount; i++) {
191                         if (pollfds[nofServerSocks + i].revents & POLLIN)
192                                 Client_read_fd(pollfds[nofServerSocks + i].fd);
193
194                         if (pollfds[nofServerSocks + i].revents & POLLOUT)
195                                 Client_write_fd(pollfds[nofServerSocks + i].fd);
196                 }
197 #ifdef USE_SHAREDMEMORY_API    
198     Sharedmemory_update();
199 #endif    
200         }
201 }
202
203 void Server_setupTCPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds)
204 {
205         uint8_t yes = 1;
206         int sockets[2];
207
208         if (hasv4) {
209                 /* IPv4 socket setup */
210                 sockets[0] = socket(PF_INET, SOCK_STREAM, 0);
211                 if (sockets[0] < 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);
220
221                 pollfds[0].fd = sockets[0];
222                 pollfds[0].events = POLLIN;
223         }
224
225         if (hasv6) {
226                 /* IPv6 socket setup */
227                 sockets[1] = socket(PF_INET6, SOCK_STREAM, 0);
228                 if (sockets[1] < 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);
239
240
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;
244         }
245 }
246
247 void Server_setupUDPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds)
248 {
249         int val = 0;
250         int sockets[2] = {-1, -1};
251
252         if((udpsocks = calloc(nofServerSocks / 2, sizeof(int))) == NULL)
253                 Log_fatal("Out of memory (%s:%s)", __FILE__, __LINE__);
254
255         if (hasv4) {
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));
259                 val = 0xe0;
260                 if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0)
261                         Log_warn("Server: Failed to set TOS for UDP Socket");
262                 val = 0x80;
263                 if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0)
264                         Log_warn("Server: Failed to set TOS for UDP Socket");
265
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];
270         }
271
272         if (hasv6) {
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));
278                 val = 0xe0;
279                 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0)
280                         Log_warn("Server: Failed to set TOS for UDP Socket");
281                 val = 0x80;
282                 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0)
283                         Log_warn("Server: Failed to set TOS for UDP Socket");
284
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];
289         }
290
291 }
292
293 void Server_run()
294 {
295         struct pollfd *pollfds;
296
297         checkIPversions();
298
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");
302
303         /* Figure out bind address and port */
304         struct sockaddr_storage** addresses = Server_setupAddressesAndPorts();
305
306         /* Prepare TCP sockets */
307         Server_setupTCPSockets(addresses, pollfds);
308
309         /* Prepare UDP sockets */
310         Server_setupUDPSockets(addresses, pollfds);
311
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/");
315
316         /* Main server loop */
317         Server_runLoop(pollfds);
318
319         /* Disconnect clients and cleanup memory */
320         Client_disconnect_all();
321         free(pollfds);
322         free(addresses[0]);
323         free(addresses[1]);
324         free(addresses);
325         free(udpsocks);
326 }
327
328 void Server_shutdown()
329 {
330         shutdown_server = true;
331 }