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