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>
59 bool_t shutdown_server;
60 extern char *bindaddr;
61 extern char *bindaddr6;
65 struct sockaddr_storage** Server_setupAddressesAndPorts()
67 struct sockaddr_storage** addresses;
69 struct sockaddr_storage* v4address = calloc(1, sizeof(struct sockaddr_storage));
70 v4address->ss_family = AF_INET;
71 v4address->ss_len = sizeof(struct sockaddr_storage);
72 struct sockaddr_storage* v6address = calloc(1, sizeof(struct sockaddr_storage));
73 v6address->ss_family = AF_INET;
74 v6address->ss_len = sizeof(struct sockaddr_storage);
78 error = inet_pton(AF_INET, (!bindaddr) ? ((getStrConf(BINDADDR)) ? getStrConf(BINDADDR) : "0.0.0.0")
79 : bindaddr, &(((struct sockaddr_in*)v4address)->sin_addr));
80 if (error == 0) Log_fatal("Invalid IPv4 address supplied!");
82 error = inet_pton(AF_INET, (!bindaddr6) ? ((getStrConf(BINDADDR6)) ? getStrConf(BINDADDR6) : "::")
83 : bindaddr6, &(((struct sockaddr_in6*)v6address)->sin6_addr));
84 if (error == 0) Log_fatal("Invalid IPv6 address supplied!");
86 ((struct sockaddr_in*)v4address)->sin_port = htons((bindport) ? bindport : getIntConf(BINDPORT));
87 ((struct sockaddr_in6*)v6address)->sin6_port = htons((bindport) ? bindport : getIntConf(BINDPORT));
89 addresses[0] = v4address;
90 addresses[1] = v6address;
95 void Server_runLoop(struct pollfd* pollfds)
97 int timeout = 1000, rc, clientcount;
98 etimer_t janitorTimer;
100 Timer_init(&janitorTimer);
102 while (!shutdown_server) {
103 struct sockaddr_in remote;
106 pollfds[UDP_SOCK].revents = 0;
107 pollfds[TCP_SOCK].revents = 0;
108 clientcount = Client_getfds(&pollfds[2]);
110 timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
113 Timer_restart(&janitorTimer);
114 timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
116 rc = poll(pollfds, clientcount + 2, timeout);
117 if (rc == 0) { /* Timeout */
119 Timer_restart(&janitorTimer);
124 if (errno == EINTR) /* signal */
127 Log_fatal("poll: error %d", errno);
129 if (pollfds[LISTEN_SOCK].revents) { /* New tcp connection */
132 addrlen = sizeof(struct sockaddr_in);
133 tcpfd = accept(pollfds[LISTEN_SOCK].fd, (struct sockaddr*)&remote, &addrlen);
134 fcntl(tcpfd, F_SETFL, O_NONBLOCK);
135 setsockopt(tcpfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
136 Log_debug("Connection from %s port %d\n", inet_ntoa(remote.sin_addr),
137 ntohs(remote.sin_port));
138 if (Client_add(tcpfd, &remote) < 0)
142 if (pollfds[UDP_SOCK].revents) {
145 for (i = 0; i < clientcount; i++) {
146 if (pollfds[i + 2].revents & POLLIN) {
147 Client_read_fd(pollfds[i + 2].fd);
149 if (pollfds[i + 2].revents & POLLOUT) {
150 Client_write_fd(pollfds[i + 2].fd);
159 struct pollfd *pollfds;
160 int tcpsock, sockopt = 1;
161 struct sockaddr_in sin;
164 in_addr_t inet_address;
166 /* max clients + listen sock + udp sock + client connecting that will be disconnected */
167 pollfds = malloc((getIntConf(MAX_CLIENTS) + 3) * sizeof(struct pollfd));
169 Log_fatal("out of memory");
171 /* Figure out bind address and port */
172 struct sockaddr_storage** addresses = Server_setupAddressesAndPorts();
174 /* Prepare TCP socket */
175 memset(&sin, 0, sizeof(sin));
176 tcpsock = socket(PF_INET, SOCK_STREAM, 0);
179 if (setsockopt(tcpsock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int)) != 0)
180 Log_fatal("setsockopt: %s", strerror(errno));
181 sin.sin_family = AF_INET;
183 sin.sin_addr.s_addr = inet_address;
185 rc = bind(tcpsock, (struct sockaddr *) &sin, sizeof (struct sockaddr_in));
186 if (rc < 0) Log_fatal("bind: %s", strerror(errno));
187 rc = listen(tcpsock, 3);
188 if (rc < 0) Log_fatal("listen");
189 fcntl(tcpsock, F_SETFL, O_NONBLOCK);
191 pollfds[LISTEN_SOCK].fd = tcpsock;
192 pollfds[LISTEN_SOCK].events = POLLIN;
194 /* Prepare UDP socket */
195 memset(&sin, 0, sizeof(sin));
196 udpsock = socket(PF_INET, SOCK_DGRAM, 0);
197 sin.sin_family = AF_INET;
199 sin.sin_addr.s_addr = inet_address;
201 rc = bind(udpsock, (struct sockaddr *) &sin, sizeof (struct sockaddr_in));
203 Log_fatal("bind %d %s: %s", getIntConf(BINDPORT), getStrConf(BINDADDR), strerror(errno));
205 rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val));
207 Log_warn("Server: Failed to set TOS for UDP Socket");
209 rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val));
211 Log_warn("Server: Failed to set TOS for UDP Socket");
213 fcntl(udpsock, F_SETFL, O_NONBLOCK);
214 pollfds[UDP_SOCK].fd = udpsock;
215 pollfds[UDP_SOCK].events = POLLIN | POLLHUP | POLLERR;
217 Log_info("uMurmur version %s ('%s') protocol version %d.%d.%d",
218 UMURMUR_VERSION, UMURMUR_CODENAME, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH);
219 Log_info("Visit http://code.google.com/p/umurmur/");
221 /* Main server loop */
222 Server_runLoop(pollfds);
224 /* Disconnect clients */
225 Client_disconnect_all();
229 void Server_shutdown()
231 shutdown_server = true;