1 /* Copyright (C) 2009-2014, Martin Johansson <martin@fatbob.nu>
2 Copyright (C) 2005-2014, Thorvald Natvig <thorvald@natvig.com>
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
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.
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.
34 #include <netinet/tcp.h>
35 #include <sys/socket.h>
52 bool_t shutdown_server;
53 extern char *bindaddr;
54 extern char *bindaddr6;
58 bool_t hasv4 = true, hasv6 = true;
61 int nofServerSocks = 4;
63 /* Initialize the address structures for IPv4 and IPv6 */
64 struct sockaddr_storage** Server_setupAddressesAndPorts()
66 struct sockaddr_storage** addresses = calloc(2, sizeof(void*));
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;
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);
80 error = inet_pton(AF_INET, (!bindaddr) ? ((getStrConf(BINDADDR)) ? getStrConf(BINDADDR) : "0.0.0.0")
81 : bindaddr, &(((struct sockaddr_in*)v4address)->sin_addr));
83 Log_fatal("Invalid IPv4 address supplied!");
84 else if (error == -1) {
85 Log_warn("Could not allocate IPv4 address");
90 error = inet_pton(AF_INET6, (!bindaddr6) ? ((getStrConf(BINDADDR6)) ? getStrConf(BINDADDR6) : "::")
91 : bindaddr6, &(((struct sockaddr_in6*)v6address)->sin6_addr));
93 Log_fatal("Invalid IPv6 address supplied!");
94 else if (error == -1) {
95 Log_warn("Could not allocate IPv6 address");
100 if (!hasv4 && !hasv6)
101 Log_fatal("Could not allocate IPv4 nor IPv6 address!");
103 ((struct sockaddr_in*)v4address)->sin_port = htons((bindport) ? bindport : getIntConf(BINDPORT));
104 ((struct sockaddr_in6*)v6address)->sin6_port = htons((bindport6) ? bindport6 : getIntConf(BINDPORT6));
106 addresses[0] = v4address;
107 addresses[1] = v6address;
112 void Server_runLoop(struct pollfd* pollfds)
114 int timeout, rc, clientcount;
116 etimer_t janitorTimer;
117 Timer_init(&janitorTimer);
119 while (!shutdown_server) {
120 struct sockaddr_storage remote;
123 for(i = 0; i < nofServerSocks; i++) {
124 pollfds[i].revents = 0;
127 clientcount = Client_getfds(&pollfds[nofServerSocks]);
129 timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
132 Timer_restart(&janitorTimer);
133 timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
135 rc = poll(pollfds, clientcount + nofServerSocks, timeout);
137 /* Poll timed out, do maintenance */
138 Timer_restart(&janitorTimer);
143 if (errno == EINTR) /* signal */
146 Log_fatal("poll: error %d (%s)", errno, strerror(errno));
149 /* Check for new connection */
150 for (i = 0; i < nofServerSocks / 2; i++) {
151 if (pollfds[i].revents) {
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)
163 for (i = nofServerSocks / 2; i < nofServerSocks; i++) {
164 if (pollfds[i].revents)
165 Client_read_udp(udpsocks[i - nofServerSocks / 2]);
168 for (i = 0; i < clientcount; i++) {
169 if (pollfds[nofServerSocks + i].revents & POLLIN)
170 Client_read_fd(pollfds[nofServerSocks + i].fd);
172 if (pollfds[nofServerSocks + i].revents & POLLOUT)
173 Client_write_fd(pollfds[nofServerSocks + i].fd);
178 void Server_setupTCPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds)
184 /* IPv4 socket setup */
185 sockets[0] = socket(PF_INET, SOCK_STREAM, 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);
196 pollfds[0].fd = sockets[0];
197 pollfds[0].events = POLLIN;
201 /* IPv6 socket setup */
202 sockets[1] = socket(PF_INET6, SOCK_STREAM, 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);
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;
222 void Server_setupUDPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds)
225 int sockets[2] = {-1, -1};
227 if((udpsocks = calloc(nofServerSocks / 2, sizeof(int))) == NULL)
228 Log_fatal("Out of memory (%s:%s)", __FILE__, __LINE__);
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));
235 if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0)
236 Log_warn("Server: Failed to set TOS for UDP Socket");
238 if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0)
239 Log_warn("Server: Failed to set TOS for UDP Socket");
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];
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));
254 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0)
255 Log_warn("Server: Failed to set TOS for UDP Socket");
257 if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0)
258 Log_warn("Server: Failed to set TOS for UDP Socket");
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];
270 struct pollfd *pollfds;
272 /* Figure out bind address and port */
273 struct sockaddr_storage** addresses = Server_setupAddressesAndPorts();
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");
279 /* Prepare TCP sockets */
280 Server_setupTCPSockets(addresses, pollfds);
282 /* Prepare UDP sockets */
283 Server_setupUDPSockets(addresses, pollfds);
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/");
289 /* Main server loop */
290 Server_runLoop(pollfds);
292 /* Disconnect clients and cleanup memory */
293 Client_disconnect_all();
301 void Server_shutdown()
303 shutdown_server = true;