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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1.1.1 - (hide 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
no message

1 sysadm 1.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