Merge of r85:88 from branch polarssl into trunk.
[umurmur.git] / src / server.c
1 /* Copyright (C) 2009-2010, Martin Johansson <martin@fatbob.nu>
2    Copyright (C) 2005-2010, 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 TCP_SOCK 0
52 #define UDP_SOCK 1
53
54 /* globals */
55 int udpsock; 
56 bool_t shutdown_server;
57
58 void Server_run()
59 {
60         int timeout = 1000, rc;
61         struct pollfd *pollfds;
62         int tcpsock, sockopt = 1;
63         struct sockaddr_in sin;
64         int val, clientcount;
65         etimer_t janitorTimer;
66
67         /* max clients + listen sock + udp sock + client connecting that will be disconnected */
68         pollfds = malloc((getIntConf(MAX_CLIENTS) + 3) * sizeof(struct pollfd));
69         if (pollfds == NULL)
70                 Log_fatal("out of memory");
71         
72         /* Prepare TCP socket */
73         memset(&sin, 0, sizeof(sin));
74         tcpsock = socket(PF_INET, SOCK_STREAM, 0);
75         if (tcpsock < 0)
76                 Log_fatal("socket");
77         if (setsockopt(tcpsock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int)) != 0)
78                 Log_fatal("setsockopt: %s", strerror(errno));
79         sin.sin_family = AF_INET;
80         sin.sin_port = htons(getIntConf(BINDPORT));
81         sin.sin_addr.s_addr = inet_addr(getStrConf(BINDADDR)) ==  -1 ? inet_addr("0.0.0.0") : inet_addr(getStrConf(BINDADDR));
82         rc = bind(tcpsock, (struct sockaddr *) &sin, sizeof (struct sockaddr_in));
83         if (rc < 0) Log_fatal("bind: %s", strerror(errno));
84         rc = listen(tcpsock, 3);
85         if (rc < 0) Log_fatal("listen");
86         fcntl(tcpsock, F_SETFL, O_NONBLOCK);
87         
88         pollfds[LISTEN_SOCK].fd = tcpsock;
89         pollfds[LISTEN_SOCK].events = POLLIN;
90
91         /* Prepare UDP socket */
92         memset(&sin, 0, sizeof(sin));
93         udpsock = socket(PF_INET, SOCK_DGRAM, 0);
94         sin.sin_family = AF_INET;
95         sin.sin_port = htons(getIntConf(BINDPORT));
96         sin.sin_addr.s_addr = inet_addr(getStrConf(BINDADDR)) ==  -1 ? inet_addr("0.0.0.0") : inet_addr(getStrConf(BINDADDR));
97         rc = bind(udpsock, (struct sockaddr *) &sin, sizeof (struct sockaddr_in));
98         if (rc < 0)
99                 Log_fatal("bind %d %s: %s", getIntConf(BINDPORT), getStrConf(BINDADDR), strerror(errno));
100         val = 0xe0;
101         rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val));
102         if (rc < 0)
103                 Log_fatal("Server: Failed to set TOS for UDP Socket");
104         val = 0x80;
105         rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val));
106         if (rc < 0)
107                 Log_fatal("Server: Failed to set TOS for UDP Socket");
108         
109         fcntl(udpsock, F_SETFL, O_NONBLOCK);
110         pollfds[UDP_SOCK].fd = udpsock;
111         pollfds[UDP_SOCK].events = POLLIN | POLLHUP | POLLERR;
112         
113         Timer_init(&janitorTimer);
114         
115         Log_info("uMurmur version %s protocol version %d.%d.%d",
116                          UMURMUR_VERSION, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH);
117         Log_info("Visit http://code.google.com/p/umurmur/");
118         
119         /* Main server loop */
120         while (!shutdown_server) {
121                 struct sockaddr_in remote;
122                 int i;
123                 
124                 pollfds[UDP_SOCK].revents = 0;
125                 pollfds[TCP_SOCK].revents = 0;
126                 clientcount = Client_getfds(&pollfds[2]);
127                 
128                 timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
129                 if (timeout <= 0) {
130                         Client_janitor();
131                         Timer_restart(&janitorTimer);
132                         timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
133                 }
134                 rc = poll(pollfds, clientcount + 2, timeout);
135                 if (rc == 0) { /* Timeout */
136                         /* Do maintenance */
137                         Timer_restart(&janitorTimer);
138                         Client_janitor();
139                         continue;
140                 }
141                 if (rc < 0) {
142                         if (errno == EINTR) /* signal */
143                                 continue;
144                         else
145                                 Log_fatal("poll: error %d", errno);
146                 }
147                 if (pollfds[LISTEN_SOCK].revents) { /* New tcp connection */
148                         int tcpfd, flag = 1;
149                         uint32_t addrlen;
150                         addrlen = sizeof(struct sockaddr_in);
151                         tcpfd = accept(pollfds[LISTEN_SOCK].fd, (struct sockaddr*)&remote, &addrlen);
152                         fcntl(tcpfd, F_SETFL, O_NONBLOCK);
153                         setsockopt(tcpfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
154                         Log_debug("Connection from %s port %d\n", inet_ntoa(remote.sin_addr),
155                                           ntohs(remote.sin_port));
156                         Client_add(tcpfd, &remote);
157                 }
158
159                 if (pollfds[UDP_SOCK].revents) {
160                         Client_read_udp();
161                 }
162                 for (i = 0; i < clientcount; i++) {
163                         if (pollfds[i + 2].revents & POLLIN) {
164                                 Client_read_fd(pollfds[i + 2].fd);
165                         }
166                         if (pollfds[i + 2].revents & POLLOUT) {
167                                 Client_write_fd(pollfds[i + 2].fd);
168                         }
169                 }
170         }       
171
172         /* Disconnect clients */
173         Client_disconnect_all();
174         free(pollfds);
175 }
176
177 void Server_shutdown()
178 {
179         shutdown_server = true;
180 }