Some optimizations
[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 /* 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                 for(i = 0; i < nofServerSocks; i++) {
124                         pollfds[i].revents = 0;
125                 }
126
127                 clientcount = Client_getfds(&pollfds[nofServerSocks]);
128
129                 timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
130                 if (timeout <= 0) {
131                         Client_janitor();
132                         Timer_restart(&janitorTimer);
133                         timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
134                 }
135                 rc = poll(pollfds, clientcount + nofServerSocks, timeout);
136                 if (rc == 0) {
137                         /* Poll timed out, do maintenance */
138                         Timer_restart(&janitorTimer);
139                         Client_janitor();
140                         continue;
141                 }
142                 if (rc < 0) {
143                         if (errno == EINTR) /* signal */
144                                 continue;
145                         else
146                                 Log_fatal("poll: error %d (%s)", errno, strerror(errno));
147                 }
148
149                 /* Check for new connection */
150                 for (i = 0; i < nofServerSocks / 2; i++) {
151                         if (pollfds[i].revents) {
152                                 static int tcpfd;
153                                 static uint32_t addrlen = sizeof(struct sockaddr_storage);
154                                 tcpfd = accept(pollfds[i].fd, (struct sockaddr *)&remote, &addrlen);
155                                 fcntl(tcpfd, F_SETFL, O_NONBLOCK);
156                                 setsockopt(tcpfd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(int));
157                                 Log_debug("Connection from %s port %d\n", Util_addressToString(&remote), Util_addressToPort(&remote));
158                                 if (Client_add(tcpfd, &remote) < 0)
159                                         close(tcpfd);
160                         }
161                 }
162
163                 for (i = nofServerSocks / 2; i < nofServerSocks; i++) {
164                         if (pollfds[i].revents)
165                                 Client_read_udp(udpsocks[i - nofServerSocks / 2]);
166                 }
167
168                 for (i = 0; i < clientcount; i++) {
169                         if (pollfds[nofServerSocks + i].revents & POLLIN)
170                                 Client_read_fd(pollfds[nofServerSocks + i].fd);
171
172                         if (pollfds[nofServerSocks + i].revents & POLLOUT)
173                                 Client_write_fd(pollfds[nofServerSocks + i].fd);
174                 }
175         }
176 }
177
178 void Server_setupTCPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds)
179 {
180         uint8_t yes = 1;
181         int sockets[2];
182
183         if (hasv4) {
184                 /* IPv4 socket setup */
185                 sockets[0] = socket(PF_INET, SOCK_STREAM, 0);
186                 if (sockets[0] < 0)
187                         Log_fatal("socket IPv4");
188                 if (setsockopt(sockets[0], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0)
189                         Log_fatal("setsockopt IPv4: %s", strerror(errno));
190                 if (bind(sockets[0], (struct sockaddr *)addresses[0], sizeof (struct sockaddr_in)) < 0)
191                         Log_fatal("bind %s %d: %s", Util_addressToString(addresses[0]), Util_addressToPort(addresses[0]), strerror(errno));
192                 if (listen(sockets[0], 3) < 0)
193                         Log_fatal("listen IPv4");
194                 fcntl(sockets[0], F_SETFL, O_NONBLOCK);
195
196                 pollfds[0].fd = sockets[0];
197                 pollfds[0].events = POLLIN;
198         }
199
200         if (hasv6) {
201                 /* IPv6 socket setup */
202                 sockets[1] = socket(PF_INET6, SOCK_STREAM, 0);
203                 if (sockets[1] < 0)
204                         Log_fatal("socket IPv6");
205                 if (setsockopt(sockets[1], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0)
206                         Log_fatal("setsockopt IPv6: %s", strerror(errno));
207                 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(int)) != 0)
208                         Log_fatal("setsockopt IPv6: %s", strerror(errno));
209                 if (bind(sockets[1], (struct sockaddr *)addresses[1], sizeof (struct sockaddr_in6)) < 0)
210                         Log_fatal("bind %s %d: %s", Util_addressToString(addresses[1]), Util_addressToPort(addresses[1]), strerror(errno));
211                 if (listen(sockets[1], 3) < 0)
212                         Log_fatal("listen IPv6");
213                 fcntl(sockets[1], F_SETFL, O_NONBLOCK);
214
215
216                 /* If  there is an IPv4 address, then IPv6 will use the second socket, otherwise it uses the first */
217                 pollfds[(hasv4) ? 1 : 0].fd = sockets[1];
218                 pollfds[(hasv4) ? 1 : 0].events = POLLIN;
219         }
220 }
221
222 void Server_setupUDPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds)
223 {
224         int val = 0;
225         int sockets[2] = {-1, -1};
226
227         if((udpsocks = calloc(nofServerSocks / 2, sizeof(int))) == NULL)
228                 Log_fatal("Out of memory (%s:%s)", __FILE__, __LINE__);
229
230         if (hasv4) {
231                 sockets[0] = socket(PF_INET, SOCK_DGRAM, 0);
232                 if (bind(sockets[0], (struct sockaddr *) addresses[0], sizeof (struct sockaddr_in)) < 0)
233                         Log_fatal("bind %s %d: %s", Util_addressToString(addresses[0]), Util_addressToPort(addresses[0]), strerror(errno));
234                 val = 0xe0;
235                 if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0)
236                         Log_warn("Server: Failed to set TOS for UDP Socket");
237                 val = 0x80;
238                 if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0)
239                         Log_warn("Server: Failed to set TOS for UDP Socket");
240
241                 fcntl(sockets[0], F_SETFL, O_NONBLOCK);
242                 pollfds[(hasv6) ? 2 : 1].fd = sockets[0];
243                 pollfds[(hasv6) ? 2 : 1].events = POLLIN | POLLHUP | POLLERR;
244                 udpsocks[0] = sockets[0];
245         }
246
247         if (hasv6) {
248                 sockets[1] = socket(PF_INET6, SOCK_DGRAM, 0);
249                 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(int)) != 0)
250                         Log_fatal("setsockopt IPv6: %s", strerror(errno));
251                 if (bind(sockets[1], (struct sockaddr *) addresses[1], sizeof (struct sockaddr_in6)) < 0)
252                         Log_fatal("bind %s %d: %s", Util_addressToString(addresses[1]), Util_addressToPort(addresses[1]), strerror(errno));
253                 val = 0xe0;
254                 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0)
255                         Log_warn("Server: Failed to set TOS for UDP Socket");
256                 val = 0x80;
257                 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0)
258                         Log_warn("Server: Failed to set TOS for UDP Socket");
259
260                 fcntl(sockets[1], F_SETFL, O_NONBLOCK);
261                 pollfds[(hasv4) ? 3 : 1].fd = sockets[1];
262                 pollfds[(hasv4) ? 3 : 1].events = POLLIN | POLLHUP | POLLERR;
263                 udpsocks[(hasv4) ? 1 : 0] = sockets[1];
264         }
265
266 }
267
268 void Server_run()
269 {
270         struct pollfd *pollfds;
271
272         /* Figure out bind address and port */
273         struct sockaddr_storage** addresses = Server_setupAddressesAndPorts();
274
275         /* max clients + server sokets + client connecting that will be disconnected */
276         if ((pollfds = calloc((getIntConf(MAX_CLIENTS) + nofServerSocks + 1) , sizeof(struct pollfd))) == NULL)
277                 Log_fatal("out of memory");
278
279         /* Prepare TCP sockets */
280         Server_setupTCPSockets(addresses, pollfds);
281
282         /* Prepare UDP sockets */
283         Server_setupUDPSockets(addresses, pollfds);
284
285         Log_info("uMurmur version %s ('%s') protocol version %d.%d.%d",
286                 UMURMUR_VERSION, UMURMUR_CODENAME, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH);
287         Log_info("Visit http://code.google.com/p/umurmur/");
288
289         /* Main server loop */
290         Server_runLoop(pollfds);
291
292         /* Disconnect clients and cleanup memory */
293         Client_disconnect_all();
294         free(pollfds);
295         free(addresses[0]);
296         free(addresses[1]);
297         free(addresses);
298         free(udpsocks);
299 }
300
301 void Server_shutdown()
302 {
303         shutdown_server = true;
304 }