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;
97 int timeout = 1000, rc;
98 struct pollfd *pollfds;
99 int tcpsock, sockopt = 1;
100 struct sockaddr_in sin;
101 int val, clientcount;
102 etimer_t janitorTimer;
104 in_addr_t inet_address;
106 /* max clients + listen sock + udp sock + client connecting that will be disconnected */
107 pollfds = malloc((getIntConf(MAX_CLIENTS) + 3) * sizeof(struct pollfd));
109 Log_fatal("out of memory");
111 /* Figure out bind address and port */
113 port = htons(bindport);
115 port = htons(getIntConf(BINDPORT));
117 if (bindaddr != NULL && inet_addr(bindaddr) != -1)
118 inet_address = inet_addr(bindaddr);
119 else if (inet_addr(getStrConf(BINDADDR)) != -1)
120 inet_address = inet_addr(getStrConf(BINDADDR));
122 inet_address = inet_addr("0.0.0.0");
123 Log_info("Bind to %s:%hu", inet_address == 0 ? "*" : inet_ntoa(*((struct in_addr *)&inet_address)), ntohs(port));
125 /* Prepare TCP socket */
126 memset(&sin, 0, sizeof(sin));
127 tcpsock = socket(PF_INET, SOCK_STREAM, 0);
130 if (setsockopt(tcpsock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int)) != 0)
131 Log_fatal("setsockopt: %s", strerror(errno));
132 sin.sin_family = AF_INET;
134 sin.sin_addr.s_addr = inet_address;
136 rc = bind(tcpsock, (struct sockaddr *) &sin, sizeof (struct sockaddr_in));
137 if (rc < 0) Log_fatal("bind: %s", strerror(errno));
138 rc = listen(tcpsock, 3);
139 if (rc < 0) Log_fatal("listen");
140 fcntl(tcpsock, F_SETFL, O_NONBLOCK);
142 pollfds[LISTEN_SOCK].fd = tcpsock;
143 pollfds[LISTEN_SOCK].events = POLLIN;
145 /* Prepare UDP socket */
146 memset(&sin, 0, sizeof(sin));
147 udpsock = socket(PF_INET, SOCK_DGRAM, 0);
148 sin.sin_family = AF_INET;
150 sin.sin_addr.s_addr = inet_address;
152 rc = bind(udpsock, (struct sockaddr *) &sin, sizeof (struct sockaddr_in));
154 Log_fatal("bind %d %s: %s", getIntConf(BINDPORT), getStrConf(BINDADDR), strerror(errno));
156 rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val));
158 Log_warn("Server: Failed to set TOS for UDP Socket");
160 rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val));
162 Log_warn("Server: Failed to set TOS for UDP Socket");
164 fcntl(udpsock, F_SETFL, O_NONBLOCK);
165 pollfds[UDP_SOCK].fd = udpsock;
166 pollfds[UDP_SOCK].events = POLLIN | POLLHUP | POLLERR;
168 Timer_init(&janitorTimer);
170 Log_info("uMurmur version %s ('%s') protocol version %d.%d.%d",
171 UMURMUR_VERSION, UMURMUR_CODENAME, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH);
172 Log_info("Visit http://code.google.com/p/umurmur/");
174 /* Main server loop */
175 while (!shutdown_server) {
176 struct sockaddr_in remote;
179 pollfds[UDP_SOCK].revents = 0;
180 pollfds[TCP_SOCK].revents = 0;
181 clientcount = Client_getfds(&pollfds[2]);
183 timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
186 Timer_restart(&janitorTimer);
187 timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
189 rc = poll(pollfds, clientcount + 2, timeout);
190 if (rc == 0) { /* Timeout */
192 Timer_restart(&janitorTimer);
197 if (errno == EINTR) /* signal */
200 Log_fatal("poll: error %d", errno);
202 if (pollfds[LISTEN_SOCK].revents) { /* New tcp connection */
205 addrlen = sizeof(struct sockaddr_in);
206 tcpfd = accept(pollfds[LISTEN_SOCK].fd, (struct sockaddr*)&remote, &addrlen);
207 fcntl(tcpfd, F_SETFL, O_NONBLOCK);
208 setsockopt(tcpfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
209 Log_debug("Connection from %s port %d\n", inet_ntoa(remote.sin_addr),
210 ntohs(remote.sin_port));
211 if (Client_add(tcpfd, &remote) < 0)
215 if (pollfds[UDP_SOCK].revents) {
218 for (i = 0; i < clientcount; i++) {
219 if (pollfds[i + 2].revents & POLLIN) {
220 Client_read_fd(pollfds[i + 2].fd);
222 if (pollfds[i + 2].revents & POLLOUT) {
223 Client_write_fd(pollfds[i + 2].fd);
228 /* Disconnect clients */
229 Client_disconnect_all();
233 void Server_shutdown()
235 shutdown_server = true;