/[LeafOK_CVS]/pvpgn-1.7.4/src/d2cs/server.c
ViewVC logotype

Contents of /pvpgn-1.7.4/src/d2cs/server.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (show annotations)
Sat Jun 24 09:19:48 2006 UTC (19 years, 8 months ago) by sysadm
Branch: MAIN
CVS Tags: pvpgn_1-7-4-0_MIL, HEAD
Changes since 1.2: +1 -0 lines
Content type: text/x-csrc
no message

1 /*
2 * Copyright (C) 2000,2001 Onlyer (onlyer@263.net)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18 #include "common/setup_before.h"
19 #include "setup.h"
20
21 #ifdef HAVE_STRING_H
22 # include <string.h>
23 #else
24 # ifdef HAVE_STRINGS_H
25 # include <strings.h>
26 # endif
27 # ifdef HAVE_MEMORY_H
28 # include <memory.h>
29 # endif
30 #endif
31 #ifdef STDC_HEADERS
32 # include <stdlib.h>
33 #else
34 # ifdef HAVE_MALLOC_H
35 # include <malloc.h>
36 # endif
37 #endif
38 #include "compat/memset.h"
39 #include <errno.h>
40 #include "compat/strerror.h"
41 #ifdef TIME_WITH_SYS_TIME
42 # include <time.h>
43 # include <sys/time.h>
44 #else
45 # ifdef HAVE_SYS_TIME_H
46 # include <sys/time.h>
47 # else
48 # include <time.h>
49 # endif
50 #endif
51 #ifdef HAVE_FCNTL_H
52 # include <fcntl.h>
53 #else
54 # ifdef HAVE_SYS_FILE_H
55 # include <sys/file.h>
56 # endif
57 #endif
58 #ifdef HAVE_UNISTD_H
59 # include <unistd.h>
60 #endif
61 #ifdef HAVE_SYS_SOCKET_H
62 # include <sys/socket.h>
63 #endif
64 #include "compat/psock.h"
65 #ifdef HAVE_SYS_TYPES_H
66 # include <sys/types.h>
67 #endif
68 #ifdef HAVE_NETINET_IN_H
69 # include <netinet/in.h>
70 #endif
71 #include "compat/netinet_in.h"
72 #ifdef HAVE_ARPA_INET_H
73 # include <arpa/inet.h>
74 #endif
75 #include "compat/inet_ntoa.h"
76 #include "compat/psock.h"
77
78 #include "d2gs.h"
79 #include "net.h"
80 #include "s2s.h"
81 #include "gamequeue.h"
82 #include "game.h"
83 #include "connection.h"
84 #include "d2charstatus.h"
85 #include "serverqueue.h"
86 #include "common/fdwatch.h"
87 #include "server.h"
88 #include "prefs.h"
89 #include "d2ladder.h"
90 #ifndef WIN32
91 #include "handle_signal.h"
92 #endif
93 #include "common/addr.h"
94 #include "common/list.h"
95 #include "common/hashtable.h"
96 #include "common/eventlog.h"
97 #ifdef WIN32
98 # include <conio.h> /* for kbhit() and getch() */
99 #endif
100 #include "common/setup_after.h"
101 #include "cmdline_parse.h"
102
103 static int server_listen(void);
104 static int server_accept(int sock);
105 static int server_handle_timed_event(void);
106 static int server_handle_socket(void);
107 static int server_loop(void);
108 static int server_cleanup(void);
109
110 t_addrlist * server_listen_addrs;
111 extern int g_ServiceStatus;
112
113 static int server_listen(void)
114 {
115 t_addr * curr_laddr;
116 t_addr_data laddr_data;
117 int sock;
118
119 if (!(server_listen_addrs=addrlist_create(prefs_get_servaddrs(),INADDR_ANY,D2CS_SERVER_PORT))) {
120 eventlog(eventlog_level_error,__FUNCTION__,"error create listening address list");
121 return -1;
122 }
123 BEGIN_LIST_TRAVERSE_DATA(server_listen_addrs,curr_laddr)
124 {
125 sock=net_listen(addr_get_ip(curr_laddr),addr_get_port(curr_laddr),PSOCK_SOCK_STREAM);
126 if (sock<0) {
127 eventlog(eventlog_level_error,__FUNCTION__,"error listen socket");
128 return -1;
129 }
130
131 if (psock_ctl(sock,PSOCK_NONBLOCK)<0) {
132 eventlog(eventlog_level_error,__FUNCTION__,"error set listen socket in non-blocking mode");
133 }
134
135 laddr_data.i = sock;
136 addr_set_data(curr_laddr,laddr_data);
137
138 if (fdwatch_add_fd(sock, fdwatch_type_read, d2cs_server_handle_accept, curr_laddr)<0) {
139 eventlog(eventlog_level_error,__FUNCTION__,"error adding socket %d to fdwatch pool (max sockets?)",sock);
140 psock_close(sock);
141 return -1;
142 }
143
144 eventlog(eventlog_level_info,__FUNCTION__,"listen on %s", addr_num_to_addr_str(addr_get_ip(curr_laddr),addr_get_port(curr_laddr)));
145 }
146 END_LIST_TRAVERSE_DATA()
147 return 0;
148 }
149
150 static int server_accept(int sock)
151 {
152 int csock;
153 struct sockaddr_in caddr, raddr;
154 psock_t_socklen caddr_len, raddr_len;
155 int val;
156 unsigned int ip;
157 unsigned short port;
158 t_connection *cc;
159
160 caddr_len=sizeof(caddr);
161 memset(&caddr,0,sizeof(caddr));
162 csock=psock_accept(sock,(struct sockaddr *)&caddr,&caddr_len);
163 if (csock<0) {
164 eventlog(eventlog_level_error,__FUNCTION__,"error accept new connection");
165 return -1;
166 } else eventlog(eventlog_level_info,__FUNCTION__,"accept connection from %s",inet_ntoa(caddr.sin_addr));
167
168 val=1;
169 if (psock_setsockopt(csock, PSOCK_SOL_SOCKET, PSOCK_SO_KEEPALIVE, &val,sizeof(val))<0) {
170 eventlog(eventlog_level_warn,__FUNCTION__,"error set sock option keep alive");
171 }
172 if (psock_ctl(csock, PSOCK_NONBLOCK)<0) {
173 eventlog(eventlog_level_error,__FUNCTION__,"error set socket to non-blocking mode");
174 psock_close(csock);
175 return -1;
176 }
177
178 raddr_len=sizeof(raddr);
179 memset(&raddr,0,sizeof(raddr));
180 ip=port=0;
181 if (psock_getsockname(csock,(struct sockaddr *)&raddr,&raddr_len)<0) {
182 eventlog(eventlog_level_warn,__FUNCTION__,"unable to get local socket info");
183 } else {
184 if (raddr.sin_family!=PSOCK_AF_INET) {
185 eventlog(eventlog_level_warn,__FUNCTION__,"got bad socket family %d",raddr.sin_family);
186 } else {
187 ip=ntohl(raddr.sin_addr.s_addr);
188 port=ntohs(raddr.sin_port);
189 }
190 }
191 if (!(cc = d2cs_conn_create(csock,ip,port,ntohl(caddr.sin_addr.s_addr),ntohs(caddr.sin_port)))) {
192 eventlog(eventlog_level_error,__FUNCTION__,"error create new connection");
193 psock_close(csock);
194 return -1;
195 }
196 if (conn_add_fd(cc, fdwatch_type_read, d2cs_server_handle_tcp)<0) {
197 eventlog(eventlog_level_error,__FUNCTION__,"error adding socket %d to fdwatch pool (max sockets?)",csock);
198 d2cs_conn_set_state(cc,conn_state_destroy);
199 return -1;
200 }
201
202 return 0;
203 }
204
205 static int server_handle_timed_event(void)
206 {
207 static time_t prev_list_purgetime=0;
208 static time_t prev_gamequeue_checktime=0;
209 static time_t prev_s2s_checktime=0;
210 static time_t prev_sq_checktime=0;
211 static time_t prev_d2ladder_refresh_time=0;
212 static time_t prev_s2s_keepalive_time=0;
213 static time_t prev_timeout_checktime;
214 static time_t prev_dump_charstatus_list_interval=0;
215 time_t now;
216
217 now=time(NULL);
218 if (now-prev_list_purgetime>(signed)prefs_get_list_purgeinterval()) {
219 hashtable_purge(d2cs_connlist());
220 d2cs_gamelist_check_voidgame();
221 prev_list_purgetime=now;
222 }
223 if (now-prev_gamequeue_checktime>(signed)prefs_get_gamequeue_checkinterval()) {
224 gqlist_update_all_clients();
225 prev_gamequeue_checktime=now;
226 }
227 if (now-prev_s2s_checktime>(signed)prefs_get_s2s_retryinterval()) {
228 s2s_check();
229 prev_s2s_checktime=now;
230 }
231 if (now-prev_sq_checktime>(signed)prefs_get_sq_checkinterval()) {
232 sqlist_check_timeout();
233 prev_sq_checktime=now;
234 }
235 if (now-prev_d2ladder_refresh_time>(signed)prefs_get_d2ladder_refresh_interval()) {
236 d2ladder_refresh();
237 prev_d2ladder_refresh_time=now;
238 }
239 if (now-prev_s2s_keepalive_time>(signed)prefs_get_s2s_keepalive_interval()) {
240 d2gs_keepalive();
241 prev_s2s_keepalive_time=now;
242 }
243 if (now-prev_timeout_checktime>(signed)prefs_get_timeout_checkinterval()) {
244 connlist_check_timeout();
245 prev_timeout_checktime=now;
246 }
247 /* by Leaflet */
248 if (now-prev_dump_charstatus_list_interval>(signed)prefs_dump_charstatus_list_interval()) {
249 charstatus_list_dump(cmdline_get_charstatus_file());
250 prev_dump_charstatus_list_interval=now;
251 }
252 return 0;
253 }
254
255 extern int d2cs_server_handle_accept(void *data, t_fdwatch_type rw)
256 {
257 int sock;
258
259 sock = addr_get_data((t_addr *)data).i;
260 server_accept(sock);
261 return 0;
262 }
263
264 extern int d2cs_server_handle_tcp(void *data, t_fdwatch_type rw)
265 {
266 t_connection *c = (t_connection *)data;
267
268 if (rw & fdwatch_type_read) conn_add_socket_flag(c,SOCKET_FLAG_READ);
269 if (rw & fdwatch_type_write) conn_add_socket_flag(c,SOCKET_FLAG_WRITE);
270 if (conn_handle_socket(c)<0)
271 d2cs_conn_set_state(c, conn_state_destroy);
272
273 return 0;
274 }
275
276 static int server_handle_socket(void)
277 {
278 switch (fdwatch(BNETD_POLL_INTERVAL)) {
279 case -1:
280 if (
281 #ifdef PSOCK_EINTR
282 psock_errno()!=PSOCK_EINTR &&
283 #endif
284 1) {
285 eventlog(eventlog_level_error,__FUNCTION__,"select failed (select: %s)",pstrerror(psock_errno()));
286 return -1;
287 }
288 /* fall through */
289 case 0:
290 return 0;
291 default:
292 break;
293 }
294
295 fdwatch_handle();
296
297 return 0;
298 }
299
300 static int server_loop(void)
301 {
302 unsigned int count;
303
304 count=0;
305 while (1) {
306
307 #ifdef WIN32
308 if (g_ServiceStatus<0 && kbhit() && getch()=='q')
309 signal_quit_wrapper();
310 if (g_ServiceStatus == 0) signal_quit_wrapper();
311
312 while (g_ServiceStatus == 2) Sleep(1000);
313 #endif
314
315 if (handle_signal()<0) break;
316 if (++count>=(1000/BNETD_POLL_INTERVAL)) {
317 server_handle_timed_event();
318 count=0;
319 }
320 server_handle_socket();
321 d2cs_connlist_reap();
322 }
323 return 0;
324 }
325
326 static int server_cleanup(void)
327 {
328 t_addr * curr_laddr;
329 int sock;
330
331 BEGIN_LIST_TRAVERSE_DATA(server_listen_addrs,curr_laddr)
332 {
333 sock=addr_get_data(curr_laddr).i;
334 psock_close(sock);
335 }
336 END_LIST_TRAVERSE_DATA()
337 addrlist_destroy(server_listen_addrs);
338 return 0;
339 }
340
341 extern int d2cs_server_process(void)
342 {
343 #ifndef WIN32
344 handle_signal_init();
345 #endif
346 if (psock_init()<0) {
347 eventlog(eventlog_level_error,__FUNCTION__,"failed to init network");
348 return -1;
349 }
350 eventlog(eventlog_level_info,__FUNCTION__,"network initialized");
351 if (s2s_init()<0) {
352 eventlog(eventlog_level_error,__FUNCTION__,"failed to init s2s connection");
353 return -1;
354 }
355 if (server_listen()<0) {
356 eventlog(eventlog_level_error,__FUNCTION__,"failed to setup listen socket");
357 return -1;
358 }
359 eventlog(eventlog_level_info,__FUNCTION__,"entering server loop");
360 server_loop();
361 eventlog(eventlog_level_info,__FUNCTION__,"exit from server loop,cleanup");
362 server_cleanup();
363 return 0;
364 }

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1