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

Contents of /pvpgn-1.7.4/src/d2cs/d2gs.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
CVS Tags: arelease
Changes since 1.1: +0 -0 lines
Content type: text/x-csrc
Error occurred while calculating annotation data.
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_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