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

Annotation of /pvpgn-1.7.4/src/d2cs/d2gs.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
CVS Tags: arelease
Changes since 1.1: +0 -0 lines
Content type: text/x-csrc
no message

1 sysadm 1.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_STDDEF_H
22     # include <stddef.h>
23     #else
24     # ifndef NULL
25     # define NULL ((void *)0)
26     # endif
27     #endif
28     #ifdef STDC_HEADERS
29     # include <stdlib.h>
30     #else
31     # ifdef HAVE_MALLOC_H
32     # include <malloc.h>
33     # endif
34     #endif
35     #ifdef HAVE_STRING_H
36     # include <string.h>
37     #else
38     # ifdef HAVE_STRINGS_H
39     # include <strings.h>
40     # endif
41     #endif
42     #include "compat/strsep.h"
43     #include "compat/char_bit.h"
44     #ifdef HAVE_SYS_TYPES_H
45     # include <sys/types.h> /* needed to include netinet/in.h */
46     #endif
47     #ifdef HAVE_SYS_SOCKET_H
48     # include <sys/socket.h>
49     #endif
50     #include "compat/socket.h"
51     #ifdef HAVE_SYS_PARAM_H
52     # include <sys/param.h>
53     #endif
54     #ifdef HAVE_NETINET_IN_H
55     # include <netinet/in.h>
56     #endif
57     #include "compat/netinet_in.h"
58     #ifdef HAVE_ARPA_INET_H
59     # include <arpa/inet.h> /* FIXME: probably not needed... do some systems put types in here or something? */
60     #endif
61     #ifdef TIME_WITH_SYS_TIME
62     # include <sys/time.h>
63     # include <time.h>
64     #else
65     # ifdef HAVE_SYS_TIME_H
66     # include <sys/time.h>
67     # else
68     # include <time.h>
69     # endif
70     #endif
71     #include "compat/psock.h"
72     #include <regex.h>
73    
74     #include "d2gs.h"
75     #include "game.h"
76     #include "net.h"
77     #include "bit.h"
78     #include "prefs.h"
79     #include "connection.h"
80     #include "common/introtate.h"
81     #include "common/addr.h"
82     #include "common/list.h"
83     #include "common/eventlog.h"
84     #include "common/xalloc.h"
85     #include "common/setup_after.h"
86    
87     static t_list * d2gslist_head=NULL;
88     static unsigned int d2gs_id=0;
89     static unsigned int total_d2gs=0;
90    
91     /* Added by Leaflet at 2006-06-05 Begin */
92     // TODO: Rewriting these code is requied
93     // All these configuration should be put into a seperate configuration file
94    
95     struct serve_scope_addr {
96     regex_t *preg;
97     unsigned short deny;
98     struct serve_scope_addr *next;
99     };
100    
101     struct serve_scope_addr_list {
102     unsigned int ip;
103     struct serve_scope_addr *head;
104     struct serve_scope_addr_list *next;
105     };
106    
107     static struct serve_scope_addr_list *serve_scope_list = NULL;
108    
109     extern int serve_scope_list_load(const char *filename)
110     {
111     FILE *fp;
112     char temp[256], buffer[256];
113     int section_begin = 0;
114     struct serve_scope_addr_list *current_list, *new_list;
115     struct serve_scope_addr *current_addr, *new_addr;
116    
117     unsigned int ip;
118    
119     if ((fp=fopen(filename, "r"))== NULL)
120     {
121     eventlog(eventlog_level_error, __FUNCTION__, "unable to read file %s", filename);
122     return -1;
123     }
124    
125     while(fgets(buffer, 255, fp))
126     {
127     switch(buffer[0])
128     {
129     case '!': // Begin of new server section
130     new_list = (struct serve_scope_addr_list *)malloc(sizeof(struct serve_scope_addr_list));
131     if (sscanf(buffer, "%*c %s", temp) == EOF)
132     continue;
133     if ((ip=net_inet_addr(temp))==~0U) {
134     eventlog(eventlog_level_error,__FUNCTION__,"got bad ip address %s",temp);
135     serve_scope_list_unload();
136     return -2;
137     }
138    
139     if (!serve_scope_list)
140     serve_scope_list = new_list;
141     else
142     current_list->next = new_list;
143     current_list = new_list;
144     current_list->head = NULL;
145     current_list->next = NULL;
146    
147     current_list->ip = ntohl(ip);
148     break;
149     case '@':
150     case '~':
151     new_addr = (struct serve_scope_addr *)malloc(sizeof(struct serve_scope_addr));
152     if (sscanf(buffer, "%*c %s", temp) == EOF)
153     continue;
154    
155     if (!current_list->head)
156     current_list->head = new_addr;
157     else
158     current_addr->next = new_addr;
159     current_addr = new_addr;
160     current_addr->next = NULL;
161    
162     current_addr->preg = (regex_t *) malloc (sizeof (regex_t));
163     if (regcomp (current_addr->preg, temp, REG_EXTENDED|REG_NOSUB) != 0)
164     {
165     eventlog(eventlog_level_error,__FUNCTION__,"Compile regular expression pattern failed %s",temp);
166     free (current_addr->preg);
167     serve_scope_list_unload();
168     return -3;
169     }
170     current_addr->deny = (buffer[0]=='~');
171    
172     break;
173     }
174     }
175    
176     return 0;
177     }
178    
179     extern void serve_scope_list_unload(void)
180     {
181     struct serve_scope_addr_list *current_list;
182     struct serve_scope_addr *current_addr;
183    
184     while(serve_scope_list)
185     {
186     current_list = serve_scope_list;
187     serve_scope_list = serve_scope_list->next;
188     while(current_list->head)
189     {
190     current_addr = current_list->head;
191     current_list->head = current_list->head->next;
192     regfree(current_addr->preg);
193     free(current_addr->preg);
194     free(current_addr);
195     }
196     free(current_list);
197     }
198     }
199    
200     extern int serve_scope_list_validate(unsigned int ip, t_connection *c)
201     {
202     struct serve_scope_addr_list *current_list;
203     struct serve_scope_addr *current_addr;
204     regmatch_t pmatch[10];
205    
206     struct sockaddr_in tsa;
207    
208     memset(&tsa,0,sizeof(tsa));
209     tsa.sin_family = PSOCK_AF_INET;
210     tsa.sin_port = htons((unsigned short)0);
211     tsa.sin_addr.s_addr = htonl(c->addr);
212    
213     current_list = serve_scope_list;
214     while(current_list)
215     {
216     if (current_list->ip == ip)
217     {
218     current_addr = current_list->head;
219     while(current_addr)
220     {
221     if (!regexec (current_addr->preg, inet_ntoa(tsa.sin_addr), 0, pmatch, 0))
222     return current_addr->deny; // Match
223     current_addr = current_addr->next;
224     }
225     return 1; // No match serve scope
226     }
227     current_list = current_list->next;
228     }
229    
230     return 0; // No match game server
231     }
232    
233     /* End */
234    
235     extern t_list * d2gslist(void)
236     {
237     return d2gslist_head;
238     }
239    
240     extern int d2gslist_create(void)
241     {
242     d2gslist_head=list_create();
243     return d2gslist_reload(prefs_get_d2gs_list());
244     }
245    
246     extern int d2gslist_reload(char const * gslist)
247     {
248     t_addrlist * gsaddrs;
249     t_d2gs * gs;
250    
251     if (!d2gslist_head) return -1;
252    
253     BEGIN_LIST_TRAVERSE_DATA(d2gslist_head,gs)
254     {
255     BIT_CLR_FLAG(gs->flag, D2GS_FLAG_VALID);
256     }
257     END_LIST_TRAVERSE_DATA()
258    
259     gsaddrs = addrlist_create(gslist, INADDR_ANY, 0);
260     if (gsaddrs) {
261     t_elem const *acurr;
262     t_addr * curr_laddr;
263    
264     LIST_TRAVERSE_CONST(gsaddrs, acurr)
265     {
266     curr_laddr = (t_addr*)elem_get_data(acurr);
267     if (!curr_laddr) {
268     eventlog(eventlog_level_error, __FUNCTION__, "found NULL value in gslist");
269     continue;
270     }
271     if (!(gs=d2gslist_find_gs_by_ip(addr_get_ip(curr_laddr))))
272     gs = d2gs_create(addr_num_to_ip_str(addr_get_ip(curr_laddr)));
273     if (gs) BIT_SET_FLAG(gs->flag, D2GS_FLAG_VALID);
274     }
275     addrlist_destroy(gsaddrs);
276     }
277    
278     BEGIN_LIST_TRAVERSE_DATA(d2gslist_head,gs)
279     {
280     if (!BIT_TST_FLAG(gs->flag, D2GS_FLAG_VALID)) {
281     d2gs_destroy(gs,&curr_elem_);
282     }
283     }
284     END_LIST_TRAVERSE_DATA()
285    
286     return 0;
287     }
288    
289     extern int d2gslist_destroy(void)
290     {
291     t_d2gs * gs;
292    
293     BEGIN_LIST_TRAVERSE_DATA_CONST(d2gslist_head,gs)
294     {
295     d2gs_destroy(gs,(t_elem **)&curr_elem_);
296     }
297     END_LIST_TRAVERSE_DATA_CONST()
298     d2cs_connlist_reap();
299    
300     if (list_destroy(d2gslist_head)<0) {
301     eventlog(eventlog_level_error,__FUNCTION__,"error destroy d2gs list");
302     return -1;
303     }
304     d2gslist_head=NULL;
305    
306     return 0;
307     }
308    
309     extern t_d2gs * d2gslist_find_gs_by_ip(unsigned int ip)
310     {
311     t_d2gs * gs;
312    
313     BEGIN_LIST_TRAVERSE_DATA_CONST(d2gslist_head,gs)
314     {
315     if (gs->ip==ip) return gs;
316     }
317     END_LIST_TRAVERSE_DATA_CONST()
318     return NULL;
319     }
320    
321     extern t_d2gs * d2gslist_find_gs(unsigned int id)
322     {
323     t_d2gs * gs;
324    
325     BEGIN_LIST_TRAVERSE_DATA_CONST(d2gslist_head,gs)
326     {
327     if (gs->id==id) return gs;
328     }
329     END_LIST_TRAVERSE_DATA_CONST()
330     return NULL;
331     }
332    
333     extern t_d2gs * d2gs_create(char const * ipaddr)
334     {
335     t_d2gs * gs;
336     unsigned int ip;
337    
338     ASSERT(ipaddr,NULL);
339     if ((ip=net_inet_addr(ipaddr))==~0U) {
340     eventlog(eventlog_level_error,__FUNCTION__,"got bad ip address %s",ipaddr);
341     return NULL;
342     }
343     if (d2gslist_find_gs_by_ip(ntohl(ip))) {
344     eventlog(eventlog_level_error,__FUNCTION__,"game server %s already in list",ipaddr);
345     return NULL;
346     }
347     gs=xmalloc(sizeof(t_d2gs));
348     gs->ip=ntohl(ip);
349     gs->id=++d2gs_id;
350     gs->active=0;
351     gs->token=0;
352     gs->state=d2gs_state_none;
353     gs->gamenum=0;
354     gs->maxgame=0;
355     gs->connection=NULL;
356    
357     if (list_append_data(d2gslist_head,gs)<0) {
358     eventlog(eventlog_level_error,__FUNCTION__,"error add gs to list");
359     xfree(gs);
360     return NULL;
361     }
362     eventlog(eventlog_level_info,__FUNCTION__,"added game server %s (id: %d) to list",ipaddr,gs->id);
363     return gs;
364     }
365    
366     extern int d2gs_destroy(t_d2gs * gs, t_elem ** curr)
367     {
368     ASSERT(gs,-1);
369     if (list_remove_data(d2gslist_head,gs,curr)<0) {
370     eventlog(eventlog_level_error,__FUNCTION__,"error remove gs from list");
371     return -1;
372     }
373     if (gs->active && gs->connection) {
374     d2cs_conn_set_state(gs->connection, conn_state_destroy);
375     d2gs_deactive(gs, gs->connection);
376     }
377     eventlog(eventlog_level_info,__FUNCTION__,"removed game server %s (id: %d) from list",addr_num_to_ip_str(gs->ip),gs->id);
378     xfree(gs);
379     return 0;
380     }
381    
382     extern t_d2gs * d2gslist_get_server_by_id(unsigned int id)
383     {
384     t_d2gs * gs;
385    
386     BEGIN_LIST_TRAVERSE_DATA_CONST(d2gslist_head,gs)
387     {
388     if (gs->id==id) return gs;
389     }
390     END_LIST_TRAVERSE_DATA_CONST()
391     return NULL;
392     }
393    
394     extern t_d2gs * d2gslist_choose_server(t_connection * c)
395     {
396     t_d2gs * gs;
397     t_d2gs * ogs;
398     unsigned int percent;
399     unsigned int min_percent=100;
400    
401     ogs=NULL;
402     BEGIN_LIST_TRAVERSE_DATA_CONST(d2gslist_head,gs)
403     {
404     if (!gs->active) continue;
405     if (!gs->connection) continue;
406     if (gs->state!=d2gs_state_authed) continue;
407     if (!gs->maxgame) continue;
408     if (gs->gamenum>=gs->maxgame) continue;
409    
410     /* Added by Leaflet at 2006-06-05 -- Begin */
411     if (serve_scope_list_validate (gs->ip, c)) continue;
412     /* End */
413    
414     percent=100*gs->gamenum/gs->maxgame;
415     if (percent<min_percent) {
416     min_percent=percent;
417     ogs=gs;
418     }
419     }
420     END_LIST_TRAVERSE_DATA_CONST()
421     return ogs;
422     }
423    
424     extern int d2gs_set_state(t_d2gs * gs, t_d2gs_state state)
425     {
426     ASSERT(gs,-1);
427     gs->state=state;
428     return 0;
429     }
430    
431     extern t_d2gs_state d2gs_get_state(t_d2gs const * gs)
432     {
433     ASSERT(gs,d2gs_state_none);
434     return gs->state;
435     }
436    
437     extern int d2gs_add_gamenum(t_d2gs * gs, int number)
438     {
439     ASSERT(gs,-1);
440     gs->gamenum += number;
441     return 0;
442     }
443    
444     extern unsigned int d2gs_get_gamenum(t_d2gs const * gs)
445     {
446     ASSERT(gs,0);
447     return gs->gamenum;
448     }
449    
450    
451     extern int d2gs_set_maxgame(t_d2gs * gs,unsigned int maxgame)
452     {
453     ASSERT(gs,-1);
454     gs->maxgame=maxgame;
455     return 0;
456     }
457    
458     extern unsigned int d2gs_get_maxgame(t_d2gs const * gs)
459     {
460     ASSERT(gs,0);
461     return gs->maxgame;
462     }
463    
464     extern unsigned int d2gs_get_id(t_d2gs const * gs)
465     {
466     ASSERT(gs,0);
467     return gs->id;
468     }
469    
470     extern unsigned int d2gs_get_ip(t_d2gs const * gs)
471     {
472     ASSERT(gs,0);
473     return gs->ip;
474     }
475    
476     extern unsigned int d2gs_get_token(t_d2gs const * gs)
477     {
478     return gs->token;
479     }
480    
481     extern unsigned int d2gs_make_token(t_d2gs * gs)
482     {
483     return ((unsigned int)rand())^((++(gs->token))+((unsigned int)time(NULL)));
484     }
485    
486     extern t_connection * d2gs_get_connection(t_d2gs const * gs)
487     {
488     ASSERT(gs,NULL);
489     return gs->connection;
490     }
491    
492     extern int d2gs_active(t_d2gs * gs, t_connection * c)
493     {
494     ASSERT(gs,-1);
495     ASSERT(c,-1);
496    
497     if (gs->active && gs->connection) {
498     eventlog(eventlog_level_warn,__FUNCTION__,"game server %d is already actived, deactive previous connection first",gs->id);
499     d2gs_deactive(gs, gs->connection);
500     }
501     total_d2gs++;
502     eventlog(eventlog_level_info,__FUNCTION__,"game server %s (id: %d) actived (%d total)",addr_num_to_addr_str(d2cs_conn_get_addr(c),
503     d2cs_conn_get_port(c)),gs->id,total_d2gs);
504     gs->state=d2gs_state_authed;
505     gs->connection=c;
506     gs->active=1;
507     gs->gamenum=0;
508     gs->maxgame=0;
509     return 0;
510     }
511    
512     extern int d2gs_deactive(t_d2gs * gs, t_connection * c)
513     {
514     t_game * game;
515    
516     ASSERT(gs,-1);
517     if (!gs->active || !gs->connection) {
518     eventlog(eventlog_level_warn,__FUNCTION__,"game server %d is not actived yet", gs->id);
519     return -1;
520     }
521     if (gs->connection != c) {
522     eventlog(eventlog_level_debug,__FUNCTION__,"game server %d connection mismatch,ignore it", gs->id);
523     return 0;
524     }
525     total_d2gs--;
526     eventlog(eventlog_level_info,__FUNCTION__,"game server %s (id: %d) deactived (%d left)",addr_num_to_addr_str(d2cs_conn_get_addr(gs->connection),d2cs_conn_get_port(gs->connection)),gs->id,total_d2gs);
527     gs->state=d2gs_state_none;
528     gs->connection=NULL;
529     gs->active=0;
530     gs->maxgame=0;
531     eventlog(eventlog_level_info,__FUNCTION__,"destroying all games on game server %d",gs->id);
532     BEGIN_LIST_TRAVERSE_DATA(d2cs_gamelist(),game)
533     {
534     if (game_get_d2gs(game)==gs) game_destroy(game,&curr_elem_);
535     }
536     END_LIST_TRAVERSE_DATA()
537     if (gs->gamenum!=0) {
538     eventlog(eventlog_level_error,__FUNCTION__,"game server %d deactived but still with games left",gs->id);
539     }
540     gs->gamenum=0;
541     return 0;
542     }
543    
544     extern unsigned int d2gs_calc_checksum(t_connection * c)
545     {
546     unsigned int sessionnum, checksum, port, addr;
547     unsigned int i, len, ch;
548     char const * realmname;
549     char const * password;
550    
551     ASSERT(c,0);
552     sessionnum=d2cs_conn_get_sessionnum(c);
553     checksum=prefs_get_d2gs_checksum();
554     port=d2cs_conn_get_port(c);
555     addr=d2cs_conn_get_addr(c);
556     realmname=prefs_get_realmname();
557     password=prefs_get_d2gs_password();
558    
559     len=strlen(realmname);
560     for (i=0; i<len ; i++) {
561     ch = (unsigned int)(unsigned char) realmname[i];
562     checksum ^= ROTL(sessionnum,i, sizeof(unsigned int) * CHAR_BIT);
563     checksum ^= ROTL(port , ch, sizeof(unsigned int) * CHAR_BIT);
564     }
565     len=strlen(password);
566     for (i=0; i<len ; i++) {
567     ch = (unsigned int)(unsigned char) password[i];
568     checksum ^= ROTL(sessionnum,i, sizeof(unsigned int) * CHAR_BIT);
569     checksum ^= ROTL(port , ch, sizeof(unsigned int) * CHAR_BIT);
570     }
571     checksum ^= addr;
572     return checksum;
573     }
574    
575     extern int d2gs_keepalive(void)
576     {
577     t_packet * packet;
578     t_d2gs * gs;
579    
580     if (!(packet=packet_create(packet_class_d2gs))) {
581     eventlog(eventlog_level_error,__FUNCTION__,"error creating packet");
582     return -1;
583     }
584     packet_set_size(packet,sizeof(t_d2cs_d2gs_echoreq));
585     packet_set_type(packet,D2CS_D2GS_ECHOREQ);
586     /* FIXME: sequence number not set */
587     bn_int_set(&packet->u.d2cs_d2gs.h.seqno,0);
588     BEGIN_LIST_TRAVERSE_DATA(d2gslist_head,gs)
589     {
590     if (gs->active && gs->connection) {
591     conn_push_outqueue(gs->connection,packet);
592     }
593     }
594     END_LIST_TRAVERSE_DATA()
595     packet_del_ref(packet);
596     return 0;
597     }
598    
599     extern int d2gs_restart_all_gs(void)
600     {
601     t_packet * packet;
602     t_d2gs * gs;
603    
604     if (!(packet=packet_create(packet_class_d2gs))) {
605     eventlog(eventlog_level_error, __FUNCTION__, "error creating packet");
606     return -1;
607     }
608     packet_set_size(packet,sizeof(t_d2cs_d2gs_control));
609     packet_set_type(packet,D2CS_D2GS_CONTROL);
610     /* FIXME: sequence number not set */
611     bn_int_set(&packet->u.d2cs_d2gs.h.seqno,0);
612     bn_int_set(&packet->u.d2cs_d2gs_control.cmd, D2CS_D2GS_CONTROL_CMD_RESTART);
613     bn_int_set(&packet->u.d2cs_d2gs_control.value, prefs_get_d2gs_restart_delay());
614    
615     BEGIN_LIST_TRAVERSE_DATA(d2gslist_head,gs)
616     {
617     if (gs->connection) {
618     conn_push_outqueue(gs->connection,packet);
619     }
620     }
621    
622     END_LIST_TRAVERSE_DATA()
623     packet_del_ref(packet);
624     return 0;
625     }
626    

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