/[LeafOK_CVS]/pvpgn-1.7.4/src/d2dbs/dbserver.c
ViewVC logotype

Contents of /pvpgn-1.7.4/src/d2dbs/dbserver.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1.1.1 - (show annotations) (vendor branch)
Tue Jun 6 03:41:38 2006 UTC (19 years, 9 months ago) by sysadm
Branch: GNU, MAIN
CVS Tags: arelease, HEAD
Changes since 1.1: +0 -0 lines
Content type: text/x-csrc
Error occurred while calculating annotation data.
no message

1 /*
2 * Copyright (C) 2001 sousou (liupeng.cs@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_STDDEF_H
22 # include <stddef.h>
23 #else
24 # ifndef NULL
25 # define NULL ((void *)0)
26 # endif
27 #endif
28 #include <stdio.h>
29 #ifdef STDC_HEADERS
30 # include <stdlib.h>
31 #else
32 # ifdef HAVE_MALLOC_H
33 # include <malloc.h>
34 # endif
35 #endif
36 #ifdef HAVE_UNISTD_H
37 # include <unistd.h>
38 #endif
39 #ifdef HAVE_FCNTL_H
40 # include <fcntl.h>
41 #else
42 # ifdef HAVE_SYS_FILE_H
43 # include <sys/file.h>
44 # endif
45 #endif
46 #ifdef HAVE_STRING_H
47 # include <string.h>
48 #else
49 # ifdef HAVE_STRINGS_H
50 # include <strings.h>
51 # endif
52 # ifdef HAVE_MEMORY_H
53 # include <memory.h>
54 # endif
55 #endif
56 #include "compat/memset.h"
57 #include <errno.h>
58 #include "compat/strerror.h"
59 #ifdef TIME_WITH_SYS_TIME
60 # include <time.h>
61 # include <sys/time.h>
62 #else
63 # ifdef HAVE_SYS_TIME_H
64 # include <sys/time.h>
65 # else
66 # include <time.h>
67 # endif
68 #endif
69 #ifdef HAVE_SYS_TYPES_H
70 # include <sys/types.h>
71 #endif
72 #ifdef HAVE_SYS_SOCKET_H
73 # include <sys/socket.h>
74 #endif
75 #include "compat/socket.h"
76 #ifdef HAVE_SYS_PARAM_H
77 # include <sys/param.h>
78 #endif
79 #ifdef HAVE_NETINET_IN_H
80 # include <netinet/in.h>
81 #endif
82 #include "compat/netinet_in.h"
83 #ifdef HAVE_ARPA_INET_H
84 # include <arpa/inet.h>
85 #endif
86 #include "compat/inet_ntoa.h"
87 #include "compat/psock.h"
88 #include "common/network.h"
89
90 #include "dbserver.h"
91 #include "charlock.h"
92 #include "d2ladder.h"
93 #include "dbspacket.h"
94 #include "prefs.h"
95 #include "handle_signal.h"
96 #include "common/list.h"
97 #include "common/eventlog.h"
98 #ifdef WIN32
99 # include <conio.h> /* for kbhit() and getch() */
100 #endif
101 #include "common/addr.h"
102 #include "common/xalloc.h"
103 #include "common/setup_after.h"
104
105
106 static int dbs_packet_gs_id = 0;
107 static t_preset_d2gsid *preset_d2gsid_head = NULL;
108 t_list * dbs_server_connection_list = NULL;
109 int dbs_server_listen_socket=-1;
110 extern int g_ServiceStatus;
111
112 /* dbs_server_main
113 * The module's driver function -- we just call other functions and
114 * interpret their results.
115 */
116
117 static int dbs_handle_timed_events(void);
118 static void dbs_on_exit(void);
119
120 int dbs_server_init(void);
121 void dbs_server_loop(int ListeningSocket);
122 int dbs_server_setup_fdsets(fd_set * pReadFDs, fd_set * pWriteFDs,
123 fd_set * pExceptFDs, int ListeningSocket ) ;
124 BOOL dbs_server_read_data(t_d2dbs_connection* conn) ;
125 BOOL dbs_server_write_data(t_d2dbs_connection* conn) ;
126 int dbs_server_list_add_socket(int sd, unsigned int ipaddr);
127 static int setsockopt_keepalive(int sock);
128 static unsigned int get_preset_d2gsid(unsigned int ipaddr);
129
130
131 int dbs_server_main(void)
132 {
133 eventlog(eventlog_level_info,__FUNCTION__,"establishing the listener...");
134 dbs_server_listen_socket = dbs_server_init();
135 if (dbs_server_listen_socket<0) {
136 eventlog(eventlog_level_error,__FUNCTION__,"dbs_server_init error ");
137 return 3;
138 }
139 eventlog(eventlog_level_info,__FUNCTION__,"waiting for connections...");
140 dbs_server_loop(dbs_server_listen_socket);
141 dbs_on_exit();
142 return 0;
143 }
144
145 /* dbs_server_init
146 * Sets up a listener on the given interface and port, returning the
147 * listening socket if successful; if not, returns -1.
148 */
149 /* FIXME: No it doesn't! pcAddress is not ever referenced in this
150 * function.
151 * CreepLord: Fixed much better way (will accept dns hostnames)
152 */
153 int dbs_server_init(void)
154 {
155 int sd;
156 struct sockaddr_in sinInterface;
157 int val;
158 t_addr * servaddr;
159
160 dbs_server_connection_list=list_create();
161
162 if (d2dbs_d2ladder_init()==-1)
163 {
164 eventlog(eventlog_level_error,__FUNCTION__,"d2ladder_init() failed");
165 return -1;
166 }
167
168 if (cl_init(DEFAULT_HASHTBL_LEN, DEFAULT_GS_MAX)==-1)
169 {
170 eventlog(eventlog_level_error,__FUNCTION__,"cl_init() failed");
171 return -1;
172 }
173
174 if (psock_init()<0)
175 {
176 eventlog(eventlog_level_error,__FUNCTION__,"psock_init() failed");
177 return -1;
178 }
179
180 sd = psock_socket(PSOCK_PF_INET, PSOCK_SOCK_STREAM, PSOCK_IPPROTO_TCP);
181 if (sd==-1)
182 {
183 eventlog(eventlog_level_error,__FUNCTION__,"psock_socket() failed : %s",pstrerror(psock_errno()));
184 return -1;
185 }
186
187 val = 1;
188 if (psock_setsockopt(sd, PSOCK_SOL_SOCKET, PSOCK_SO_REUSEADDR, &val, sizeof(val)) < 0)
189 {
190 eventlog(eventlog_level_error,__FUNCTION__,"psock_setsockopt() failed : %s",pstrerror(psock_errno()));
191 }
192
193 if (!(servaddr=addr_create_str(d2dbs_prefs_get_servaddrs(),INADDR_ANY,DEFAULT_LISTEN_PORT)))
194 {
195 eventlog(eventlog_level_error,__FUNCTION__,"could not get servaddr");
196 return -1;
197 }
198
199 sinInterface.sin_family = PSOCK_AF_INET;
200 sinInterface.sin_addr.s_addr = htonl(addr_get_ip(servaddr));
201 sinInterface.sin_port = htons(addr_get_port(servaddr));
202 if (psock_bind(sd, (struct sockaddr*)&sinInterface, (psock_t_socklen)sizeof(struct sockaddr_in)) < 0)
203 {
204 eventlog(eventlog_level_error,__FUNCTION__,"psock_bind() failed : %s",pstrerror(psock_errno()));
205 return -1;
206 }
207 if (psock_listen(sd, LISTEN_QUEUE) < 0)
208 {
209 eventlog(eventlog_level_error,__FUNCTION__,"psock_listen() failed : %s",pstrerror(psock_errno()));
210 return -1;
211 }
212 addr_destroy(servaddr);
213 return sd;
214 }
215
216
217 /* dbs_server_setup_fdsets
218 * Set up the three FD sets used with select() with the sockets in the
219 * connection list. Also add one for the listener socket, if we have
220 * one.
221 */
222
223 int dbs_server_setup_fdsets(t_psock_fd_set * pReadFDs, t_psock_fd_set * pWriteFDs, t_psock_fd_set * pExceptFDs, int lsocket)
224 {
225 t_elem const * elem;
226 t_d2dbs_connection* it;
227 int highest_fd;
228
229 PSOCK_FD_ZERO(pReadFDs);
230 PSOCK_FD_ZERO(pWriteFDs);
231 PSOCK_FD_ZERO(pExceptFDs); /* FIXME: don't check these... remove this code */
232 /* Add the listener socket to the read and except FD sets, if there is one. */
233 if (lsocket >= 0) {
234 PSOCK_FD_SET(lsocket, pReadFDs);
235 PSOCK_FD_SET(lsocket, pExceptFDs);
236 }
237 highest_fd=lsocket;
238
239 LIST_TRAVERSE_CONST(dbs_server_connection_list,elem)
240 {
241 if (!(it=elem_get_data(elem))) continue;
242 if (it->nCharsInReadBuffer < (kBufferSize-kMaxPacketLength)) {
243 /* There's space in the read buffer, so pay attention to incoming data. */
244 PSOCK_FD_SET(it->sd, pReadFDs);
245 }
246 if (it->nCharsInWriteBuffer > 0) {
247 PSOCK_FD_SET(it->sd, pWriteFDs);
248 }
249 PSOCK_FD_SET(it->sd, pExceptFDs);
250 if (highest_fd < it->sd) highest_fd=it->sd;
251 }
252 return highest_fd;
253 }
254
255 /* dbs_server_read_data
256 * Data came in on a client socket, so read it into the buffer. Returns
257 * false on failure, or when the client closes its half of the
258 * connection. (EAGAIN doesn't count as a failure.)
259 */
260 BOOL dbs_server_read_data(t_d2dbs_connection* conn)
261 {
262 int nBytes;
263
264 nBytes = net_recv(conn->sd, conn->ReadBuf + conn->nCharsInReadBuffer,
265 kBufferSize - conn->nCharsInReadBuffer);
266
267 if (nBytes < 0) return FALSE;
268 conn->nCharsInReadBuffer += nBytes;
269 return TRUE;
270 }
271
272
273 /* dbs_server_write_data
274 * The connection is writable, so send any pending data. Returns
275 * false on failure. (EAGAIN doesn't count as a failure.)
276 */
277 BOOL dbs_server_write_data(t_d2dbs_connection* conn)
278 {
279 int nBytes ;
280
281 nBytes = net_send(conn->sd, conn->WriteBuf,
282 conn->nCharsInWriteBuffer > kMaxPacketLength ? kMaxPacketLength : conn->nCharsInWriteBuffer);
283
284 if (nBytes < 0) return FALSE;
285
286 conn->nCharsInWriteBuffer -= nBytes;
287 if (conn->nCharsInWriteBuffer)
288 memmove(conn->WriteBuf, conn->WriteBuf + nBytes, conn->nCharsInWriteBuffer);
289
290 return TRUE;
291 }
292
293 int dbs_server_list_add_socket(int sd, unsigned int ipaddr)
294 {
295 t_d2dbs_connection *it;
296 struct in_addr in;
297
298 it=xmalloc(sizeof(t_d2dbs_connection));
299 memset(it, 0, sizeof(t_d2dbs_connection));
300 it->sd=sd;
301 it->ipaddr=ipaddr;
302 it->major=0;
303 it->minor=0;
304 it->type=0;
305 it->stats=0;
306 it->verified=0;
307 it->serverid=get_preset_d2gsid(ipaddr);
308 it->last_active=time(NULL);
309 it->nCharsInReadBuffer=0;
310 it->nCharsInWriteBuffer=0;
311 list_append_data(dbs_server_connection_list,it);
312 in.s_addr = htonl(ipaddr);
313 strncpy(it->serverip, inet_ntoa(in), sizeof(it->serverip)-1);
314
315 return 1;
316 }
317
318 static int dbs_handle_timed_events(void)
319 {
320 static time_t prev_ladder_save_time=0;
321 static time_t prev_keepalive_save_time=0;
322 static time_t prev_timeout_checktime=0;
323 time_t now;
324
325 now=time(NULL);
326 if (now-prev_ladder_save_time>(signed)prefs_get_laddersave_interval()) {
327 d2ladder_saveladder();
328 prev_ladder_save_time=now;
329 }
330 if (now-prev_keepalive_save_time>(signed)prefs_get_keepalive_interval()) {
331 dbs_keepalive();
332 prev_keepalive_save_time=now;
333 }
334 if (now-prev_timeout_checktime>(signed)d2dbs_prefs_get_timeout_checkinterval()) {
335 dbs_check_timeout();
336 prev_timeout_checktime=now;
337 }
338 return 0;
339 }
340
341 void dbs_server_loop(int lsocket)
342 {
343 struct sockaddr_in sinRemote;
344 int sd ;
345 fd_set ReadFDs, WriteFDs, ExceptFDs;
346 t_elem * elem;
347 t_d2dbs_connection* it;
348 BOOL bOK ;
349 const char* pcErrorType ;
350 struct timeval tv;
351 int highest_fd;
352 psock_t_socklen nAddrSize = sizeof(sinRemote);
353
354 while (1) {
355
356 #ifdef WIN32
357 if (g_ServiceStatus<0 && kbhit() && getch()=='q')
358 d2dbs_signal_quit_wrapper();
359 if (g_ServiceStatus == 0) d2dbs_signal_quit_wrapper();
360
361 while (g_ServiceStatus == 2) Sleep(1000);
362 #endif
363
364 if (d2dbs_handle_signal()<0) break;
365
366 dbs_handle_timed_events();
367 highest_fd=dbs_server_setup_fdsets(&ReadFDs, &WriteFDs, &ExceptFDs, lsocket);
368
369 tv.tv_sec = 0;
370 tv.tv_usec = SELECT_TIME_OUT;
371 switch (psock_select(highest_fd+1, &ReadFDs, &WriteFDs, &ExceptFDs, &tv) ) {
372 case -1:
373 eventlog(eventlog_level_error,__FUNCTION__,"psock_select() failed : %s",pstrerror(psock_errno()));
374 continue;
375 case 0:
376 continue;
377 default:
378 break;
379 }
380
381 if (PSOCK_FD_ISSET(lsocket, &ReadFDs)) {
382 sd = psock_accept(lsocket, (struct sockaddr*)&sinRemote, &nAddrSize);
383 if (sd == -1) {
384 eventlog(eventlog_level_error,__FUNCTION__,"psock_accept() failed : %s",pstrerror(psock_errno()));
385 return;
386 }
387
388 eventlog(eventlog_level_info,__FUNCTION__,"accepted connection from %s:%d , socket %d .",
389 inet_ntoa(sinRemote.sin_addr) , ntohs(sinRemote.sin_port), sd);
390 eventlog_step(prefs_get_logfile_gs(),eventlog_level_info,__FUNCTION__,"accepted connection from %s:%d , socket %d .",
391 inet_ntoa(sinRemote.sin_addr) , ntohs(sinRemote.sin_port), sd);
392 setsockopt_keepalive(sd);
393 dbs_server_list_add_socket(sd, ntohl(sinRemote.sin_addr.s_addr));
394 if (psock_ctl(sd,PSOCK_NONBLOCK)<0) {
395 eventlog(eventlog_level_error,__FUNCTION__,"could not set TCP socket [%d] to non-blocking mode (closing connection) (psock_ctl: %s)", sd,pstrerror(psock_errno()));
396 psock_close(sd);
397 }
398 } else if (PSOCK_FD_ISSET(lsocket, &ExceptFDs)) {
399 eventlog(eventlog_level_error,__FUNCTION__,"exception on listening socket");
400 /* FIXME: exceptions are not errors with TCP, they are out-of-band data */
401 return;
402 }
403
404 LIST_TRAVERSE(dbs_server_connection_list,elem)
405 {
406 bOK = TRUE;
407 pcErrorType = 0;
408
409 if (!(it=elem_get_data(elem))) continue;
410 if (PSOCK_FD_ISSET(it->sd, &ExceptFDs)) {
411 bOK = FALSE;
412 pcErrorType = "General socket error"; /* FIXME: no no no no no */
413 PSOCK_FD_CLR(it->sd, &ExceptFDs);
414 } else {
415
416 if (PSOCK_FD_ISSET(it->sd, &ReadFDs)) {
417 bOK = dbs_server_read_data(it);
418 pcErrorType = "Read error";
419 PSOCK_FD_CLR(it->sd, &ReadFDs);
420 }
421
422 if (PSOCK_FD_ISSET(it->sd, &WriteFDs)) {
423 bOK = dbs_server_write_data(it);
424 pcErrorType = "Write error";
425 PSOCK_FD_CLR(it->sd, &WriteFDs);
426 }
427 }
428
429 if (!bOK) {
430 int err, errno2;
431 psock_t_socklen errlen;
432
433 err = 0;
434 errlen = sizeof(err);
435 errno2 = psock_errno();
436
437 if (psock_getsockopt(it->sd, PSOCK_SOL_SOCKET, PSOCK_SO_ERROR, &err, &errlen)==0) {
438 if (errlen && err!=0) {
439 err = err ? err : errno2;
440 eventlog(eventlog_level_error,__FUNCTION__,"data socket error : %s(%d)",pstrerror(err),err);
441 }
442 }
443 dbs_server_shutdown_connection(it);
444 list_remove_elem(dbs_server_connection_list,&elem);
445 } else {
446 if (dbs_packet_handle(it)==-1) {
447 eventlog(eventlog_level_error,__FUNCTION__,"dbs_packet_handle() failed");
448 dbs_server_shutdown_connection(it);
449 list_remove_elem(dbs_server_connection_list,&elem);
450 }
451 }
452 }
453 }
454 }
455
456 static void dbs_on_exit(void)
457 {
458 t_elem * elem;
459 t_d2dbs_connection * it;
460
461 if (dbs_server_listen_socket>=0)
462 psock_close(dbs_server_listen_socket);
463 dbs_server_listen_socket=-1;
464
465 LIST_TRAVERSE(dbs_server_connection_list,elem)
466 {
467 if (!(it=elem_get_data(elem))) continue;
468 dbs_server_shutdown_connection(it);
469 list_remove_elem(dbs_server_connection_list,&elem);
470 }
471 cl_destroy();
472 d2dbs_d2ladder_destroy();
473 list_destroy(dbs_server_connection_list);
474 if (preset_d2gsid_head)
475 {
476 t_preset_d2gsid * curr;
477 t_preset_d2gsid * next;
478
479 for (curr=preset_d2gsid_head; curr; curr=next)
480 {
481 next = curr->next;
482 xfree(curr);
483 }
484 }
485 eventlog(eventlog_level_info,__FUNCTION__,"dbserver stopped");
486 }
487
488 int dbs_server_shutdown_connection(t_d2dbs_connection* conn)
489 {
490 psock_shutdown(conn->sd, PSOCK_SHUT_RDWR) ;
491 psock_close(conn->sd);
492 if (conn->verified && conn->type==CONNECT_CLASS_D2GS_TO_D2DBS) {
493 eventlog(eventlog_level_info,__FUNCTION__,"unlock all characters on gs %s(%d)",conn->serverip,conn->serverid);
494 eventlog_step(prefs_get_logfile_gs(),eventlog_level_info,__FUNCTION__,"unlock all characters on gs %s(%d)",conn->serverip,conn->serverid);
495 eventlog_step(prefs_get_logfile_gs(),eventlog_level_info,__FUNCTION__,"close connection to gs on socket %d", conn->sd);
496 cl_unlock_all_char_by_gsid(conn->serverid);
497 }
498 xfree(conn);
499 return 1;
500 }
501
502 static int setsockopt_keepalive(int sock)
503 {
504 int optval;
505 psock_t_socklen optlen;
506
507 optval = 1;
508 optlen = sizeof(optval);
509 if (psock_setsockopt(sock, PSOCK_SOL_SOCKET, PSOCK_SO_KEEPALIVE, &optval, optlen)) {
510 eventlog(eventlog_level_info,__FUNCTION__,"failed set KEEPALIVE for socket %d, errno=%d", sock, psock_errno());
511 return -1;
512 } else {
513 eventlog(eventlog_level_info,__FUNCTION__,"set KEEPALIVE option for socket %d", sock);
514 return 0;
515 }
516 }
517
518 static unsigned int get_preset_d2gsid(unsigned int ipaddr)
519 {
520 t_preset_d2gsid *pgsid;
521
522 pgsid = preset_d2gsid_head;
523 while (pgsid)
524 {
525 if (pgsid->ipaddr == ipaddr)
526 return pgsid->d2gsid;
527 pgsid = pgsid->next;
528 }
529 /* not found, build a new item */
530 pgsid = xmalloc(sizeof(t_preset_d2gsid));
531 pgsid->ipaddr = ipaddr;
532 pgsid->d2gsid = ++dbs_packet_gs_id;
533 /* add to list */
534 pgsid->next = preset_d2gsid_head;
535 preset_d2gsid_head = pgsid;
536 return preset_d2gsid_head->d2gsid;
537 }

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