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>
51 #define LISTEN_SOCK6 1
60 int udpsock, udpsock6;
61 bool_t shutdown_server;
62 extern char *bindaddr;
63 extern char *bindaddr6;
67 /* Initialize the address structures for IPv4 and IPv6 */
68 struct sockaddr_storage** Server_setupAddressesAndPorts()
70 struct sockaddr_storage** addresses = malloc(2 * sizeof(void*));
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);
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!");
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!");
90 ((struct sockaddr_in*)v4address)->sin_port = htons((bindport) ? bindport : getIntConf(BINDPORT));
91 ((struct sockaddr_in6*)v6address)->sin6_port = htons((bindport6) ? bindport6 : getIntConf(BINDPORT6));
93 addresses[0] = v4address;
94 addresses[1] = v6address;
99 void Server_runLoop(struct pollfd* pollfds)
101 int timeout = 1000, rc, clientcount;
103 etimer_t janitorTimer;
104 Timer_init(&janitorTimer);
106 while (!shutdown_server) {
107 struct sockaddr_in remote;
110 pollfds[UDP_SOCK].revents = 0;
111 pollfds[TCP_SOCK].revents = 0;
112 clientcount = Client_getfds(&pollfds[2]);
114 timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
117 Timer_restart(&janitorTimer);
118 timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
120 rc = poll(pollfds, clientcount + 2, timeout);
121 if (rc == 0) { /* Timeout */
123 Timer_restart(&janitorTimer);
128 if (errno == EINTR) /* signal */
131 Log_fatal("poll: error %d", errno);
133 if (pollfds[LISTEN_SOCK].revents) { /* New tcp connection */
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)
146 if (pollfds[UDP_SOCK].revents) {
149 for (i = 0; i < clientcount; i++) {
150 if (pollfds[i + 2].revents & POLLIN) {
151 Client_read_fd(pollfds[i + 2].fd);
153 if (pollfds[i + 2].revents & POLLOUT) {
154 Client_write_fd(pollfds[i + 2].fd);
163 struct pollfd *pollfds;
164 int tcpsock, tcpsock6, sockopt = 1;
167 in_addr_t inet_address;
169 /* max clients + listen sock + udp sock + client connecting that will be disconnected */
170 pollfds = malloc((getIntConf(MAX_CLIENTS) + 3) * sizeof(struct pollfd));
172 Log_fatal("out of memory");
174 /* Figure out bind address and port */
175 struct sockaddr_storage** addresses = Server_setupAddressesAndPorts();
177 /* Prepare TCP sockets */
178 tcpsock = socket(PF_INET, SOCK_STREAM, 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));
184 tcpsock6 = socket(PF_INET6, SOCK_STREAM, 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));
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);
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);
204 pollfds[LISTEN_SOCK].fd = tcpsock;
205 pollfds[LISTEN_SOCK].events = POLLIN;
207 pollfds[LISTEN_SOCK6].fd = tcpsock;
208 pollfds[LISTEN_SOCK6].events = POLLIN;
210 /* Prepare UDP sockets */
211 udpsock = socket(PF_INET, SOCK_DGRAM, 0);
212 udpsock6 = socket(PF_INET6, SOCK_DGRAM, 0);
214 rc = bind(udpsock, (struct sockaddr *) addresses[0], sizeof (struct sockaddr_in));
216 Log_fatal("bind %d %s: %s", getIntConf(BINDPORT), getStrConf(BINDADDR), strerror(errno));
218 rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val));
220 Log_warn("Server: Failed to set TOS for UDP Socket");
222 rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val));
224 Log_warn("Server: Failed to set TOS for UDP Socket");
226 fcntl(udpsock, F_SETFL, O_NONBLOCK);
227 pollfds[UDP_SOCK].fd = udpsock;
228 pollfds[UDP_SOCK].events = POLLIN | POLLHUP | POLLERR;
231 if (setsockopt(udpsock6, IPPROTO_IPV6, IPV6_V6ONLY, &sockopt, sizeof(int)) != 0)
232 Log_fatal("setsockopt IPv6: %s", strerror(errno));
234 rc = bind(udpsock6, (struct sockaddr *) addresses[1], sizeof (struct sockaddr_in6));
236 Log_fatal("bind %d %s: %s", getIntConf(BINDPORT), getStrConf(BINDADDR), strerror(errno));
238 rc = setsockopt(udpsock6, IPPROTO_IP, IP_TOS, &val, sizeof(val));
240 Log_warn("Server: Failed to set TOS for UDP Socket");
242 rc = setsockopt(udpsock6, IPPROTO_IP, IP_TOS, &val, sizeof(val));
244 Log_warn("Server: Failed to set TOS for UDP Socket");
246 fcntl(udpsock6, F_SETFL, O_NONBLOCK);
247 pollfds[UDP_SOCK6].fd = udpsock6;
248 pollfds[UDP_SOCK6].events = POLLIN | POLLHUP | POLLERR;
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/");
254 /* Main server loop */
255 Server_runLoop(pollfds);
257 /* Disconnect clients and cleanup memory */
258 Client_disconnect_all();
265 void Server_shutdown()
267 shutdown_server = true;