5d67e8f873a1927387c966805760ab33b31881f6
[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 #define TCP_SOCK  0
52 #define TCP_SOCK6 1
53 #define TCP_SOCKS 2
54 #define UDP_SOCK  2
55 #define UDP_SOCK6 3
56 #define UDP_SOCKS 2
57 #define SERVER_SOCKS UDP_SOCKS + TCP_SOCKS
58
59 /* globals */
60 bool_t shutdown_server;
61 extern char *bindaddr;
62 extern char *bindaddr6;
63 extern int bindport;
64 extern int bindport6;
65 int* udpsocks;
66
67 const int on = 1;
68
69 /* Initialize the address structures for IPv4 and IPv6 */
70 struct sockaddr_storage** Server_setupAddressesAndPorts()
71 {
72         struct sockaddr_storage** addresses = malloc(2 * sizeof(void*));
73
74         struct sockaddr_storage* v4address = calloc(1, sizeof(struct sockaddr_storage));
75         v4address->ss_family = AF_INET;
76         struct sockaddr_storage* v6address = calloc(1, sizeof(struct sockaddr_storage));
77         v6address->ss_family = AF_INET6;
78
79 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
80         v4address->ss_len = sizeof(struct sockaddr_storage);
81         v6address->ss_len = sizeof(struct sockaddr_storage);
82 #endif
83
84         int error = 0;
85
86         error = inet_pton(AF_INET, (!bindaddr) ? ((getStrConf(BINDADDR)) ? getStrConf(BINDADDR) : "0.0.0.0")
87                 : bindaddr, &(((struct sockaddr_in*)v4address)->sin_addr));
88         if (error == 0) Log_fatal("Invalid IPv4 address supplied!");
89
90         error = inet_pton(AF_INET6, (!bindaddr6) ? ((getStrConf(BINDADDR6)) ? getStrConf(BINDADDR6) : "::")
91                 : bindaddr6, &(((struct sockaddr_in6*)v6address)->sin6_addr));
92         if (error == 0) Log_fatal("Invalid IPv6 address supplied!");
93
94         ((struct sockaddr_in*)v4address)->sin_port = htons((bindport) ? bindport : getIntConf(BINDPORT));
95         ((struct sockaddr_in6*)v6address)->sin6_port = htons((bindport6) ? bindport6 : getIntConf(BINDPORT6));
96
97         addresses[0] = v4address;
98         addresses[1] = v6address;
99
100         return addresses;
101 }
102
103 void Server_runLoop(struct pollfd* pollfds)
104 {
105         int timeout, rc, clientcount;
106
107         etimer_t janitorTimer;
108         Timer_init(&janitorTimer);
109
110         while (!shutdown_server) {
111                 struct sockaddr_storage remote;
112                 int i;
113
114                 pollfds[UDP_SOCK].revents = 0;
115                 pollfds[UDP_SOCK6].revents = 0;
116                 pollfds[TCP_SOCK].revents = 0;
117                 pollfds[TCP_SOCK6].revents = 0;
118                 clientcount = Client_getfds(&pollfds[SERVER_SOCKS]);
119
120                 timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
121                 if (timeout <= 0) {
122                         Client_janitor();
123                         Timer_restart(&janitorTimer);
124                         timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
125                 }
126                 rc = poll(pollfds, clientcount + SERVER_SOCKS, timeout);
127                 if (rc == 0) {
128                         /* Poll timed out, do maintenance */
129                         Timer_restart(&janitorTimer);
130                         Client_janitor();
131                         continue;
132                 }
133                 if (rc < 0) {
134                         if (errno == EINTR) /* signal */
135                                 continue;
136                         else
137                                 Log_fatal("poll: error %d (%s)", errno, strerror(errno));
138                 }
139
140                 /* Check for new connection */
141                 for (i = 0; i < TCP_SOCKS; i++) {
142                         if (pollfds[i].revents) {
143                                 static int tcpfd;
144                                 static uint32_t addrlen = sizeof(struct sockaddr_storage);
145                                 tcpfd = accept(pollfds[i].fd, (struct sockaddr *)&remote, &addrlen);
146                                 fcntl(tcpfd, F_SETFL, O_NONBLOCK);
147                                 setsockopt(tcpfd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(int));
148                                 Log_debug("Connection from %s port %d\n", Util_addressToString(&remote), Util_addressToPort(&remote));
149                                 if (Client_add(tcpfd, &remote) < 0)
150                                         close(tcpfd);
151                         }
152                 }
153
154                 for (i = 2; i < SERVER_SOCKS; i++) {
155                         if (pollfds[i].revents) {
156                                 Client_read_udp(udpsocks[i - UDP_SOCKS]);
157                         }
158                 }
159
160                 for (i = 0; i < clientcount; i++) {
161                         if (pollfds[i + 4].revents & POLLIN) {
162                                 Client_read_fd(pollfds[i + 4].fd);
163                         }
164                         if (pollfds[i + 4].revents & POLLOUT) {
165                                 Client_write_fd(pollfds[i + 4].fd);
166                         }
167                 }
168         }
169 }
170
171 void Server_setupTCPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds)
172 {
173         uint8_t yes = 1;
174         int sockets[2];
175
176         /* IPv4 socket setup */
177         sockets[0] = socket(PF_INET, SOCK_STREAM, 0);
178         if (sockets[0] < 0)
179                 Log_fatal("socket IPv4");
180         if (setsockopt(sockets[0], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0)
181                 Log_fatal("setsockopt IPv4: %s", strerror(errno));
182         if (bind(sockets[0], (struct sockaddr *)addresses[0], sizeof (struct sockaddr_in)) < 0)
183                 Log_fatal("bind %s %d: %s", Util_addressToString(addresses[0]), Util_addressToPort(addresses[0]), strerror(errno));
184         if (listen(sockets[0], 3) < 0)
185                 Log_fatal("listen IPv4");
186         fcntl(sockets[0], F_SETFL, O_NONBLOCK);
187
188         pollfds[TCP_SOCK].fd = sockets[0];
189         pollfds[TCP_SOCK].events = POLLIN;
190
191         /* IPv6 socket setup */
192         sockets[1] = socket(PF_INET6, SOCK_STREAM, 0);
193         if (sockets[1] < 0)
194                 Log_fatal("socket IPv6");
195         if (setsockopt(sockets[1], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0)
196                 Log_fatal("setsockopt IPv6: %s", strerror(errno));
197         if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(int)) != 0)
198                 Log_fatal("setsockopt IPv6: %s", strerror(errno));
199         if (bind(sockets[1], (struct sockaddr *)addresses[1], sizeof (struct sockaddr_in6)) < 0)
200                 Log_fatal("bind %s %d: %s", Util_addressToString(addresses[1]), Util_addressToPort(addresses[1]), strerror(errno));
201         if (listen(sockets[1], 3) < 0)
202                 Log_fatal("listen IPv6");
203         fcntl(sockets[1], F_SETFL, O_NONBLOCK);
204
205         pollfds[TCP_SOCK6].fd = sockets[1];
206         pollfds[TCP_SOCK6].events = POLLIN;
207 }
208
209 void Server_setupUDPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds)
210 {
211         int val = 0;
212         int sockets[2];
213
214         if((udpsocks = malloc(2 * sizeof(int))) == NULL)
215                 Log_fatal("Out of memory (%s:%s)", __FILE__, __LINE__);
216
217         sockets[0] = socket(PF_INET, SOCK_DGRAM, 0);
218         if (bind(sockets[0], (struct sockaddr *) addresses[0], sizeof (struct sockaddr_in)) < 0)
219                 Log_fatal("bind %s %d: %s", Util_addressToString(addresses[0]), Util_addressToPort(addresses[0]), strerror(errno));
220         val = 0xe0;
221         if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0)
222                 Log_warn("Server: Failed to set TOS for UDP Socket");
223         val = 0x80;
224         if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0)
225                 Log_warn("Server: Failed to set TOS for UDP Socket");
226
227         fcntl(sockets[0], F_SETFL, O_NONBLOCK);
228         pollfds[UDP_SOCK].fd = sockets[0];
229         pollfds[UDP_SOCK].events = POLLIN | POLLHUP | POLLERR;
230
231         sockets[1] = socket(PF_INET6, SOCK_DGRAM, 0);
232         if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_V6ONLY, &on, 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         val = 0xe0;
237         if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0)
238                 Log_warn("Server: Failed to set TOS for UDP Socket");
239         val = 0x80;
240         if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0)
241                 Log_warn("Server: Failed to set TOS for UDP Socket");
242
243         fcntl(sockets[1], F_SETFL, O_NONBLOCK);
244         pollfds[UDP_SOCK6].fd = sockets[1];
245         pollfds[UDP_SOCK6].events = POLLIN | POLLHUP | POLLERR;
246         udpsocks[UDP_SOCK - UDP_SOCKS] = sockets[0];
247         udpsocks[UDP_SOCK6 - UDP_SOCKS] = sockets[1];
248 }
249
250 void Server_run()
251 {
252         struct pollfd *pollfds;
253
254         /* max clients + listen sock + udp sock + client connecting that will be disconnected */
255         if ((pollfds = calloc((getIntConf(MAX_CLIENTS) + 5) , sizeof(struct pollfd))) == NULL)
256                 Log_fatal("out of memory");
257
258         /* Figure out bind address and port */
259         struct sockaddr_storage** addresses = Server_setupAddressesAndPorts();
260
261         /* Prepare TCP sockets */
262         Server_setupTCPSockets(addresses, pollfds);
263
264         /* Prepare UDP sockets */
265         Server_setupUDPSockets(addresses, pollfds);
266
267         Log_info("uMurmur version %s ('%s') protocol version %d.%d.%d",
268                 UMURMUR_VERSION, UMURMUR_CODENAME, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH);
269         Log_info("Visit http://code.google.com/p/umurmur/");
270
271         /* Main server loop */
272         Server_runLoop(pollfds);
273
274         /* Disconnect clients and cleanup memory */
275         Client_disconnect_all();
276         free(pollfds);
277         free(addresses[0]);
278         free(addresses[1]);
279         free(addresses);
280         free(udpsocks);
281 }
282
283 void Server_shutdown()
284 {
285         shutdown_server = true;
286 }