d2gs.c
上传用户:tany51
上传日期:2013-06-12
资源大小:1397k
文件大小:11k
- /*
- * Copyright (C) 2000,2001 Onlyer (onlyer@263.net)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- #include "common/setup_before.h"
- #include "setup.h"
- #ifdef HAVE_STDDEF_H
- # include <stddef.h>
- #else
- # ifndef NULL
- # define NULL ((void *)0)
- # endif
- #endif
- #ifdef STDC_HEADERS
- # include <stdlib.h>
- #else
- # ifdef HAVE_MALLOC_H
- # include <malloc.h>
- # endif
- #endif
- #ifdef HAVE_STRING_H
- # include <string.h>
- #else
- # ifdef HAVE_STRINGS_H
- # include <strings.h>
- # endif
- #endif
- #include "compat/strsep.h"
- #include "compat/char_bit.h"
- #ifdef HAVE_SYS_TYPES_H
- # include <sys/types.h> /* needed to include netinet/in.h */
- #endif
- #ifdef HAVE_SYS_SOCKET_H
- # include <sys/socket.h>
- #endif
- #include "compat/socket.h"
- #ifdef HAVE_SYS_PARAM_H
- # include <sys/param.h>
- #endif
- #ifdef HAVE_NETINET_IN_H
- # include <netinet/in.h>
- #endif
- #include "compat/netinet_in.h"
- #ifdef HAVE_ARPA_INET_H
- # include <arpa/inet.h> /* FIXME: probably not needed... do some systems put types in here or something? */
- #endif
- #ifdef TIME_WITH_SYS_TIME
- # include <sys/time.h>
- # include <time.h>
- #else
- # ifdef HAVE_SYS_TIME_H
- # include <sys/time.h>
- # else
- # include <time.h>
- # endif
- #endif
- #include "compat/psock.h"
- #include "d2gs.h"
- #include "game.h"
- #include "net.h"
- #include "bit.h"
- #include "prefs.h"
- #include "connection.h"
- #include "common/introtate.h"
- #include "common/addr.h"
- #include "common/list.h"
- #include "common/eventlog.h"
- #include "common/setup_after.h"
- static t_list * d2gslist_head=NULL;
- static unsigned int d2gs_id=0;
- static unsigned int total_d2gs=0;
- extern t_list * d2gslist(void)
- {
- return d2gslist_head;
- }
- extern int d2gslist_create(void)
- {
- if (!(d2gslist_head=list_create())) return -1;
- return d2gslist_reload(prefs_get_d2gs_list());
- }
- extern int d2gslist_reload(char const * gslist)
- {
- char * templist;
- char * s, * temp;
- t_d2gs * gs;
- unsigned int ip;
- unsigned int resolveipaddr;
- if (!d2gslist_head) return -1;
- BEGIN_LIST_TRAVERSE_DATA(d2gslist_head,gs)
- {
- BIT_CLR_FLAG(gs->flag, D2GS_FLAG_VALID);
- }
- END_LIST_TRAVERSE_DATA()
- /* FIXME: use addr.h addrlist code */
- if (!(templist=strdup(gslist))) return -1;
- temp=templist;
- while ((s=strsep(&temp, ","))) {
- host_lookup(s, &resolveipaddr);
- if ((ip=net_inet_addr(addr_num_to_ip_str(resolveipaddr)))==~0UL) {
- eventlog(eventlog_level_error,__FUNCTION__,"got bad ip address %s", addr_num_to_ip_str(resolveipaddr));
- continue;
- }
- if (!(gs=d2gslist_find_gs_by_ip(ntohl(ip)))) {
- gs=d2gs_create(addr_num_to_ip_str(resolveipaddr));
- }
- if (gs) BIT_SET_FLAG(gs->flag, D2GS_FLAG_VALID);
- }
- free(templist);
- BEGIN_LIST_TRAVERSE_DATA(d2gslist_head,gs)
- {
- if (!BIT_TST_FLAG(gs->flag, D2GS_FLAG_VALID)) {
- d2gs_destroy(gs);
- }
- }
- END_LIST_TRAVERSE_DATA()
- return 0;
- }
- extern int d2gslist_destroy(void)
- {
- t_d2gs * gs;
- BEGIN_LIST_TRAVERSE_DATA_CONST(d2gslist_head,gs)
- {
- d2gs_destroy(gs);
- }
- END_LIST_TRAVERSE_DATA_CONST()
- if (list_destroy(d2gslist_head)<0) {
- eventlog(eventlog_level_error,__FUNCTION__,"error destroy d2gs list");
- return -1;
- }
- d2gslist_head=NULL;
- return 0;
- }
- extern t_d2gs * d2gslist_find_gs_by_ip(unsigned int ip)
- {
- t_d2gs * gs;
- BEGIN_LIST_TRAVERSE_DATA_CONST(d2gslist_head,gs)
- {
- if (gs->ip==ip) return gs;
- }
- END_LIST_TRAVERSE_DATA_CONST()
- return NULL;
- }
- extern t_d2gs * d2gslist_find_gs(unsigned int id)
- {
- t_d2gs * gs;
- BEGIN_LIST_TRAVERSE_DATA_CONST(d2gslist_head,gs)
- {
- if (gs->id==id) return gs;
- }
- END_LIST_TRAVERSE_DATA_CONST()
- return NULL;
- }
- extern t_d2gs * d2gs_create(char const * ipaddr)
- {
- t_d2gs * gs;
- unsigned int ip;
- ASSERT(ipaddr,NULL);
- if ((ip=net_inet_addr(ipaddr))==~0UL) {
- eventlog(eventlog_level_error,__FUNCTION__,"got bad ip address %s",ipaddr);
- return NULL;
- }
- if (d2gslist_find_gs_by_ip(ntohl(ip))) {
- eventlog(eventlog_level_error,__FUNCTION__,"game server %s already in list",ipaddr);
- return NULL;
- }
- if (!(gs=malloc(sizeof(t_d2gs)))) {;
- eventlog(eventlog_level_error,__FUNCTION__,"error allocate memory");
- return NULL;
- }
- gs->ip=ntohl(ip);
- gs->id=++d2gs_id;
- gs->active=0;
- gs->token=0;
- gs->state=d2gs_state_none;
- gs->gamenum=0;
- gs->maxgame=0;
- gs->connection=NULL;
- if (list_append_data(d2gslist_head,gs)<0) {
- eventlog(eventlog_level_error,__FUNCTION__,"error add gs to list");
- free(gs);
- return NULL;
- }
- eventlog(eventlog_level_info,__FUNCTION__,"added game server %s (id: %d) to list",ipaddr,gs->id);
- return gs;
- }
- extern int d2gs_destroy(t_d2gs * gs)
- {
- ASSERT(gs,-1);
- if (list_remove_data(d2gslist_head,gs)<0) {
- eventlog(eventlog_level_error,__FUNCTION__,"error remove gs from list");
- return -1;
- }
- if (gs->active && gs->connection) {
- d2cs_conn_set_state(gs->connection, conn_state_destroy);
- d2gs_deactive(gs, gs->connection);
- }
- eventlog(eventlog_level_info,__FUNCTION__,"removed game server %s (id: %d) from list",addr_num_to_ip_str(gs->ip),gs->id);
- free(gs);
- return 0;
- }
- extern t_d2gs * d2gslist_get_server_by_id(unsigned int id)
- {
- t_d2gs * gs;
- BEGIN_LIST_TRAVERSE_DATA_CONST(d2gslist_head,gs)
- {
- if (gs->id==id) return gs;
- }
- END_LIST_TRAVERSE_DATA_CONST()
- return NULL;
- }
-
- extern t_d2gs * d2gslist_choose_server(void)
- {
- t_d2gs * gs;
- t_d2gs * ogs;
- unsigned int percent;
- unsigned int min_percent=100;
- ogs=NULL;
- BEGIN_LIST_TRAVERSE_DATA_CONST(d2gslist_head,gs)
- {
- if (!gs->active) continue;
- if (!gs->connection) continue;
- if (gs->state!=d2gs_state_authed) continue;
- if (!gs->maxgame) continue;
- if (gs->gamenum>=gs->maxgame) continue;
- percent=100*gs->gamenum/gs->maxgame;
- if (percent<min_percent) {
- min_percent=percent;
- ogs=gs;
- }
- }
- END_LIST_TRAVERSE_DATA_CONST()
- return ogs;
- }
- extern int d2gs_set_state(t_d2gs * gs, t_d2gs_state state)
- {
- ASSERT(gs,-1);
- gs->state=state;
- return 0;
- }
- extern t_d2gs_state d2gs_get_state(t_d2gs const * gs)
- {
- ASSERT(gs,d2gs_state_none);
- return gs->state;
- }
- extern int d2gs_add_gamenum(t_d2gs * gs, int number)
- {
- ASSERT(gs,-1);
- gs->gamenum += number;
- return 0;
- }
- extern unsigned int d2gs_get_gamenum(t_d2gs const * gs)
- {
- ASSERT(gs,0);
- return gs->gamenum;
- }
- extern int d2gs_set_maxgame(t_d2gs * gs,unsigned int maxgame)
- {
- ASSERT(gs,-1);
- gs->maxgame=maxgame;
- return 0;
- }
- extern unsigned int d2gs_get_maxgame(t_d2gs const * gs)
- {
- ASSERT(gs,0);
- return gs->maxgame;
- }
- extern unsigned int d2gs_get_id(t_d2gs const * gs)
- {
- ASSERT(gs,0);
- return gs->id;
- }
- extern unsigned int d2gs_get_ip(t_d2gs const * gs)
- {
- ASSERT(gs,0);
- return gs->ip;
- }
- extern unsigned int d2gs_get_token(t_d2gs const * gs)
- {
- return gs->token;
- }
- extern unsigned int d2gs_make_token(t_d2gs * gs)
- {
- return ((unsigned int)rand())^((++(gs->token))+((unsigned int)time(NULL)));
- }
- extern t_connection * d2gs_get_connection(t_d2gs const * gs)
- {
- ASSERT(gs,NULL);
- return gs->connection;
- }
- extern int d2gs_active(t_d2gs * gs, t_connection * c)
- {
- ASSERT(gs,-1);
- ASSERT(c,-1);
- if (gs->active && gs->connection) {
- eventlog(eventlog_level_warn,__FUNCTION__,"game server %d is already actived, deactive previous connection first",gs->id);
- d2gs_deactive(gs, gs->connection);
- }
- total_d2gs++;
- eventlog(eventlog_level_info,__FUNCTION__,"game server %s (id: %d) actived (%d total)",addr_num_to_addr_str(d2cs_conn_get_addr(c),
- d2cs_conn_get_port(c)),gs->id,total_d2gs);
- gs->state=d2gs_state_authed;
- gs->connection=c;
- gs->active=1;
- gs->gamenum=0;
- gs->maxgame=0;
- return 0;
- }
- extern int d2gs_deactive(t_d2gs * gs, t_connection * c)
- {
- t_game * game;
- ASSERT(gs,-1);
- if (!gs->active || !gs->connection) {
- eventlog(eventlog_level_warn,__FUNCTION__,"game server %d is not actived yet", gs->id);
- return -1;
- }
- if (gs->connection != c) {
- eventlog(eventlog_level_debug,__FUNCTION__,"game server %d connection mismatch,ignore it", gs->id);
- return 0;
- }
- total_d2gs--;
- 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);
- gs->state=d2gs_state_none;
- gs->connection=NULL;
- gs->active=0;
- gs->maxgame=0;
- eventlog(eventlog_level_info,__FUNCTION__,"destroying all games on game server %d",gs->id);
- BEGIN_LIST_TRAVERSE_DATA(d2cs_gamelist(),game)
- {
- if (game_get_d2gs(game)==gs) game_destroy(game);
- }
- END_LIST_TRAVERSE_DATA()
- if (gs->gamenum!=0) {
- eventlog(eventlog_level_error,__FUNCTION__,"game server %d deactived but still with games left",gs->id);
- }
- gs->gamenum=0;
- return 0;
- }
- extern unsigned int d2gs_calc_checksum(t_connection * c)
- {
- unsigned int sessionnum, checksum, port, addr;
- unsigned int i, len, ch;
- char const * realmname;
- char const * password;
- ASSERT(c,0);
- sessionnum=d2cs_conn_get_sessionnum(c);
- checksum=prefs_get_d2gs_checksum();
- port=d2cs_conn_get_port(c);
- addr=d2cs_conn_get_addr(c);
- realmname=prefs_get_realmname();
- password=prefs_get_d2gs_password();
- len=strlen(realmname);
- for (i=0; i<len ; i++) {
- ch = (unsigned int)(unsigned char) realmname[i];
- checksum ^= ROTL(sessionnum,i, sizeof(unsigned int) * CHAR_BIT);
- checksum ^= ROTL(port , ch, sizeof(unsigned int) * CHAR_BIT);
- }
- len=strlen(password);
- for (i=0; i<len ; i++) {
- ch = (unsigned int)(unsigned char) password[i];
- checksum ^= ROTL(sessionnum,i, sizeof(unsigned int) * CHAR_BIT);
- checksum ^= ROTL(port , ch, sizeof(unsigned int) * CHAR_BIT);
- }
- checksum ^= addr;
- return checksum;
- }
- extern int d2gs_keepalive(void)
- {
- t_packet * packet;
- t_d2gs * gs;
- if (!(packet=packet_create(packet_class_d2gs))) {
- eventlog(eventlog_level_error,__FUNCTION__,"error creating packet");
- return -1;
- }
- packet_set_size(packet,sizeof(t_d2cs_d2gs_echoreq));
- packet_set_type(packet,D2CS_D2GS_ECHOREQ);
- /* FIXME: sequence number not set */
- bn_int_set(&packet->u.d2cs_d2gs.h.seqno,0);
- BEGIN_LIST_TRAVERSE_DATA(d2gslist_head,gs)
- {
- if (gs->active && gs->connection) {
- conn_push_outqueue(gs->connection,packet);
- }
- }
- END_LIST_TRAVERSE_DATA()
- packet_del_ref(packet);
- return 0;
- }
- extern int d2gs_restart_all_gs(void)
- {
- t_packet * packet;
- t_d2gs * gs;
-
- if (!(packet=packet_create(packet_class_d2gs))) {
- eventlog(eventlog_level_error, __FUNCTION__, "error creating packet");
- return -1;
- }
- packet_set_size(packet,sizeof(t_d2cs_d2gs_control));
- packet_set_type(packet,D2CS_D2GS_CONTROL);
- /* FIXME: sequence number not set */
- bn_int_set(&packet->u.d2cs_d2gs.h.seqno,0);
- bn_int_set(&packet->u.d2cs_d2gs_control.cmd, D2CS_D2GS_CONTROL_CMD_RESTART);
- bn_int_set(&packet->u.d2cs_d2gs_control.value, prefs_get_d2gs_restart_delay());
-
- BEGIN_LIST_TRAVERSE_DATA(d2gslist_head,gs)
- {
- if (gs->connection) {
- conn_push_outqueue(gs->connection,packet);
- }
- }
-
- END_LIST_TRAVERSE_DATA()
- packet_del_ref(packet);
- return 0;
- }