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