/[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.2 - (show annotations)
Mon Jun 12 18:31:17 2006 UTC (19 years, 9 months ago) by sysadm
Branch: MAIN
CVS Tags: pvpgn_1-7-4-0_MIL, HEAD
Changes since 1.1: +1 -145 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
73 #include "d2gs.h"
74 #include "game.h"
75 #include "net.h"
76 #include "bit.h"
77 #include "prefs.h"
78 #include "gs_scope.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 extern t_list * d2gslist(void)
92 {
93 return d2gslist_head;
94 }
95
96 extern int d2gslist_create(void)
97 {
98 d2gslist_head=list_create();
99 return d2gslist_reload(prefs_get_d2gs_list());
100 }
101
102 extern int d2gslist_reload(char const * gslist)
103 {
104 t_addrlist * gsaddrs;
105 t_d2gs * gs;
106
107 if (!d2gslist_head) return -1;
108
109 BEGIN_LIST_TRAVERSE_DATA(d2gslist_head,gs)
110 {
111 BIT_CLR_FLAG(gs->flag, D2GS_FLAG_VALID);
112 }
113 END_LIST_TRAVERSE_DATA()
114
115 gsaddrs = addrlist_create(gslist, INADDR_ANY, 0);
116 if (gsaddrs) {
117 t_elem const *acurr;
118 t_addr * curr_laddr;
119
120 LIST_TRAVERSE_CONST(gsaddrs, acurr)
121 {
122 curr_laddr = (t_addr*)elem_get_data(acurr);
123 if (!curr_laddr) {
124 eventlog(eventlog_level_error, __FUNCTION__, "found NULL value in gslist");
125 continue;
126 }
127 if (!(gs=d2gslist_find_gs_by_ip(addr_get_ip(curr_laddr))))
128 gs = d2gs_create(addr_num_to_ip_str(addr_get_ip(curr_laddr)));
129 if (gs) BIT_SET_FLAG(gs->flag, D2GS_FLAG_VALID);
130 }
131 addrlist_destroy(gsaddrs);
132 }
133
134 BEGIN_LIST_TRAVERSE_DATA(d2gslist_head,gs)
135 {
136 if (!BIT_TST_FLAG(gs->flag, D2GS_FLAG_VALID)) {
137 d2gs_destroy(gs,&curr_elem_);
138 }
139 }
140 END_LIST_TRAVERSE_DATA()
141
142 return 0;
143 }
144
145 extern int d2gslist_destroy(void)
146 {
147 t_d2gs * gs;
148
149 BEGIN_LIST_TRAVERSE_DATA_CONST(d2gslist_head,gs)
150 {
151 d2gs_destroy(gs,(t_elem **)&curr_elem_);
152 }
153 END_LIST_TRAVERSE_DATA_CONST()
154 d2cs_connlist_reap();
155
156 if (list_destroy(d2gslist_head)<0) {
157 eventlog(eventlog_level_error,__FUNCTION__,"error destroy d2gs list");
158 return -1;
159 }
160 d2gslist_head=NULL;
161
162 return 0;
163 }
164
165 extern t_d2gs * d2gslist_find_gs_by_ip(unsigned int ip)
166 {
167 t_d2gs * gs;
168
169 BEGIN_LIST_TRAVERSE_DATA_CONST(d2gslist_head,gs)
170 {
171 if (gs->ip==ip) return gs;
172 }
173 END_LIST_TRAVERSE_DATA_CONST()
174 return NULL;
175 }
176
177 extern t_d2gs * d2gslist_find_gs(unsigned int id)
178 {
179 t_d2gs * gs;
180
181 BEGIN_LIST_TRAVERSE_DATA_CONST(d2gslist_head,gs)
182 {
183 if (gs->id==id) return gs;
184 }
185 END_LIST_TRAVERSE_DATA_CONST()
186 return NULL;
187 }
188
189 extern t_d2gs * d2gs_create(char const * ipaddr)
190 {
191 t_d2gs * gs;
192 unsigned int ip;
193
194 ASSERT(ipaddr,NULL);
195 if ((ip=net_inet_addr(ipaddr))==~0U) {
196 eventlog(eventlog_level_error,__FUNCTION__,"got bad ip address %s",ipaddr);
197 return NULL;
198 }
199 if (d2gslist_find_gs_by_ip(ntohl(ip))) {
200 eventlog(eventlog_level_error,__FUNCTION__,"game server %s already in list",ipaddr);
201 return NULL;
202 }
203 gs=xmalloc(sizeof(t_d2gs));
204 gs->ip=ntohl(ip);
205 gs->id=++d2gs_id;
206 gs->active=0;
207 gs->token=0;
208 gs->state=d2gs_state_none;
209 gs->gamenum=0;
210 gs->maxgame=0;
211 gs->connection=NULL;
212
213 if (list_append_data(d2gslist_head,gs)<0) {
214 eventlog(eventlog_level_error,__FUNCTION__,"error add gs to list");
215 xfree(gs);
216 return NULL;
217 }
218 eventlog(eventlog_level_info,__FUNCTION__,"added game server %s (id: %d) to list",ipaddr,gs->id);
219 return gs;
220 }
221
222 extern int d2gs_destroy(t_d2gs * gs, t_elem ** curr)
223 {
224 ASSERT(gs,-1);
225 if (list_remove_data(d2gslist_head,gs,curr)<0) {
226 eventlog(eventlog_level_error,__FUNCTION__,"error remove gs from list");
227 return -1;
228 }
229 if (gs->active && gs->connection) {
230 d2cs_conn_set_state(gs->connection, conn_state_destroy);
231 d2gs_deactive(gs, gs->connection);
232 }
233 eventlog(eventlog_level_info,__FUNCTION__,"removed game server %s (id: %d) from list",addr_num_to_ip_str(gs->ip),gs->id);
234 xfree(gs);
235 return 0;
236 }
237
238 extern t_d2gs * d2gslist_get_server_by_id(unsigned int id)
239 {
240 t_d2gs * gs;
241
242 BEGIN_LIST_TRAVERSE_DATA_CONST(d2gslist_head,gs)
243 {
244 if (gs->id==id) return gs;
245 }
246 END_LIST_TRAVERSE_DATA_CONST()
247 return NULL;
248 }
249
250 extern t_d2gs * d2gslist_choose_server(t_connection * c)
251 {
252 t_d2gs * gs;
253 t_d2gs * ogs;
254 unsigned int percent;
255 unsigned int min_percent=100;
256
257 ogs=NULL;
258 BEGIN_LIST_TRAVERSE_DATA_CONST(d2gslist_head,gs)
259 {
260 if (!gs->active) continue;
261 if (!gs->connection) continue;
262 if (gs->state!=d2gs_state_authed) continue;
263 if (!gs->maxgame) continue;
264 if (gs->gamenum>=gs->maxgame) continue;
265
266 /* Added by Leaflet at 2006-06-05 -- Begin */
267 if (serve_scope_list_validate (gs->ip, c)) continue;
268 /* End */
269
270 percent=100*gs->gamenum/gs->maxgame;
271 if (percent<min_percent) {
272 min_percent=percent;
273 ogs=gs;
274 }
275 }
276 END_LIST_TRAVERSE_DATA_CONST()
277 return ogs;
278 }
279
280 extern int d2gs_set_state(t_d2gs * gs, t_d2gs_state state)
281 {
282 ASSERT(gs,-1);
283 gs->state=state;
284 return 0;
285 }
286
287 extern t_d2gs_state d2gs_get_state(t_d2gs const * gs)
288 {
289 ASSERT(gs,d2gs_state_none);
290 return gs->state;
291 }
292
293 extern int d2gs_add_gamenum(t_d2gs * gs, int number)
294 {
295 ASSERT(gs,-1);
296 gs->gamenum += number;
297 return 0;
298 }
299
300 extern unsigned int d2gs_get_gamenum(t_d2gs const * gs)
301 {
302 ASSERT(gs,0);
303 return gs->gamenum;
304 }
305
306
307 extern int d2gs_set_maxgame(t_d2gs * gs,unsigned int maxgame)
308 {
309 ASSERT(gs,-1);
310 gs->maxgame=maxgame;
311 return 0;
312 }
313
314 extern unsigned int d2gs_get_maxgame(t_d2gs const * gs)
315 {
316 ASSERT(gs,0);
317 return gs->maxgame;
318 }
319
320 extern unsigned int d2gs_get_id(t_d2gs const * gs)
321 {
322 ASSERT(gs,0);
323 return gs->id;
324 }
325
326 extern unsigned int d2gs_get_ip(t_d2gs const * gs)
327 {
328 ASSERT(gs,0);
329 return gs->ip;
330 }
331
332 extern unsigned int d2gs_get_token(t_d2gs const * gs)
333 {
334 return gs->token;
335 }
336
337 extern unsigned int d2gs_make_token(t_d2gs * gs)
338 {
339 return ((unsigned int)rand())^((++(gs->token))+((unsigned int)time(NULL)));
340 }
341
342 extern t_connection * d2gs_get_connection(t_d2gs const * gs)
343 {
344 ASSERT(gs,NULL);
345 return gs->connection;
346 }
347
348 extern int d2gs_active(t_d2gs * gs, t_connection * c)
349 {
350 ASSERT(gs,-1);
351 ASSERT(c,-1);
352
353 if (gs->active && gs->connection) {
354 eventlog(eventlog_level_warn,__FUNCTION__,"game server %d is already actived, deactive previous connection first",gs->id);
355 d2gs_deactive(gs, gs->connection);
356 }
357 total_d2gs++;
358 eventlog(eventlog_level_info,__FUNCTION__,"game server %s (id: %d) actived (%d total)",addr_num_to_addr_str(d2cs_conn_get_addr(c),
359 d2cs_conn_get_port(c)),gs->id,total_d2gs);
360 gs->state=d2gs_state_authed;
361 gs->connection=c;
362 gs->active=1;
363 gs->gamenum=0;
364 gs->maxgame=0;
365 return 0;
366 }
367
368 extern int d2gs_deactive(t_d2gs * gs, t_connection * c)
369 {
370 t_game * game;
371
372 ASSERT(gs,-1);
373 if (!gs->active || !gs->connection) {
374 eventlog(eventlog_level_warn,__FUNCTION__,"game server %d is not actived yet", gs->id);
375 return -1;
376 }
377 if (gs->connection != c) {
378 eventlog(eventlog_level_debug,__FUNCTION__,"game server %d connection mismatch,ignore it", gs->id);
379 return 0;
380 }
381 total_d2gs--;
382 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);
383 gs->state=d2gs_state_none;
384 gs->connection=NULL;
385 gs->active=0;
386 gs->maxgame=0;
387 eventlog(eventlog_level_info,__FUNCTION__,"destroying all games on game server %d",gs->id);
388 BEGIN_LIST_TRAVERSE_DATA(d2cs_gamelist(),game)
389 {
390 if (game_get_d2gs(game)==gs) game_destroy(game,&curr_elem_);
391 }
392 END_LIST_TRAVERSE_DATA()
393 if (gs->gamenum!=0) {
394 eventlog(eventlog_level_error,__FUNCTION__,"game server %d deactived but still with games left",gs->id);
395 }
396 gs->gamenum=0;
397 return 0;
398 }
399
400 extern unsigned int d2gs_calc_checksum(t_connection * c)
401 {
402 unsigned int sessionnum, checksum, port, addr;
403 unsigned int i, len, ch;
404 char const * realmname;
405 char const * password;
406
407 ASSERT(c,0);
408 sessionnum=d2cs_conn_get_sessionnum(c);
409 checksum=prefs_get_d2gs_checksum();
410 port=d2cs_conn_get_port(c);
411 addr=d2cs_conn_get_addr(c);
412 realmname=prefs_get_realmname();
413 password=prefs_get_d2gs_password();
414
415 len=strlen(realmname);
416 for (i=0; i<len ; i++) {
417 ch = (unsigned int)(unsigned char) realmname[i];
418 checksum ^= ROTL(sessionnum,i, sizeof(unsigned int) * CHAR_BIT);
419 checksum ^= ROTL(port , ch, sizeof(unsigned int) * CHAR_BIT);
420 }
421 len=strlen(password);
422 for (i=0; i<len ; i++) {
423 ch = (unsigned int)(unsigned char) password[i];
424 checksum ^= ROTL(sessionnum,i, sizeof(unsigned int) * CHAR_BIT);
425 checksum ^= ROTL(port , ch, sizeof(unsigned int) * CHAR_BIT);
426 }
427 checksum ^= addr;
428 return checksum;
429 }
430
431 extern int d2gs_keepalive(void)
432 {
433 t_packet * packet;
434 t_d2gs * gs;
435
436 if (!(packet=packet_create(packet_class_d2gs))) {
437 eventlog(eventlog_level_error,__FUNCTION__,"error creating packet");
438 return -1;
439 }
440 packet_set_size(packet,sizeof(t_d2cs_d2gs_echoreq));
441 packet_set_type(packet,D2CS_D2GS_ECHOREQ);
442 /* FIXME: sequence number not set */
443 bn_int_set(&packet->u.d2cs_d2gs.h.seqno,0);
444 BEGIN_LIST_TRAVERSE_DATA(d2gslist_head,gs)
445 {
446 if (gs->active && gs->connection) {
447 conn_push_outqueue(gs->connection,packet);
448 }
449 }
450 END_LIST_TRAVERSE_DATA()
451 packet_del_ref(packet);
452 return 0;
453 }
454
455 extern int d2gs_restart_all_gs(void)
456 {
457 t_packet * packet;
458 t_d2gs * gs;
459
460 if (!(packet=packet_create(packet_class_d2gs))) {
461 eventlog(eventlog_level_error, __FUNCTION__, "error creating packet");
462 return -1;
463 }
464 packet_set_size(packet,sizeof(t_d2cs_d2gs_control));
465 packet_set_type(packet,D2CS_D2GS_CONTROL);
466 /* FIXME: sequence number not set */
467 bn_int_set(&packet->u.d2cs_d2gs.h.seqno,0);
468 bn_int_set(&packet->u.d2cs_d2gs_control.cmd, D2CS_D2GS_CONTROL_CMD_RESTART);
469 bn_int_set(&packet->u.d2cs_d2gs_control.value, prefs_get_d2gs_restart_delay());
470
471 BEGIN_LIST_TRAVERSE_DATA(d2gslist_head,gs)
472 {
473 if (gs->connection) {
474 conn_push_outqueue(gs->connection,packet);
475 }
476 }
477
478 END_LIST_TRAVERSE_DATA()
479 packet_del_ref(packet);
480 return 0;
481 }
482

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