📄 connection.c
字号:
/* * Copyright (C) 1998 Mark Baysinger (mbaysing@ucsd.edu) * Copyright (C) 1998,1999,2000,2001 Ross Combs (rocombs@cs.nmsu.edu) * Copyright (C) 2000,2001 Marco Ziech (mmz@gmx.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. */#define CONNECTION_INTERNAL_ACCESS#include "common/setup_before.h"#include <stdio.h>// amadeo#ifdef WIN32_GUI#include <win32/winmain.h>#endif#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#include "compat/strtoul.h"#ifdef HAVE_STRING_H# include <string.h>#else# ifdef HAVE_STRINGS_H# include <strings.h># endif#endif#ifdef HAVE_ASSERT_H# include <assert.h>#endif#include "compat/strchr.h"#include "compat/strrchr.h"#include "compat/strdup.h"#include "compat/strcasecmp.h"#include "compat/strncasecmp.h"#include <errno.h>#include "compat/strerror.h"#ifdef HAVE_UNISTD_H# include <unistd.h>#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/difftime.h"#ifdef HAVE_SYS_TYPES_H# include <sys/types.h>#endif#ifdef HAVE_SYS_SOCKET_H# include <sys/socket.h>#endif#include "compat/socket.h"#include "compat/psock.h"#include "common/eventlog.h"#include "common/addr.h"#include "account.h"#include "account_wrap.h"#include "realm.h"#include "channel.h"#include "game.h"#include "common/queue.h"#include "tick.h"#include "common/packet.h"#include "common/tag.h"#include "common/bn_type.h"#include "message.h"#include "common/version.h"#include "prefs.h"#include "common/util.h"#include "common/list.h"#include "watch.h"#include "timer.h"#include "irc.h"#include "ipban.h"#include "game_conv.h"#include "udptest_send.h"#include "character.h"#include "versioncheck.h"#include "common/bnet_protocol.h"#include "common/field_sizes.h"#include "anongame.h"#include "clan.h"#include "connection.h"#include "topic.h"#include "server.h"#include "handle_d2cs.h"#include "command_groups.h"#include "attrlayer.h"#include "common/rcm.h"#include "common/fdwatch.h"#include "common/elist.h"#include "common/xalloc.h"#include "common/setup_after.h"/* types and data structures used for the connlist array */typedef struct { t_connection *c; t_elist freelist;} t_conn_entry;t_conn_entry *connarray = NULL;t_elist arrayflist;static int totalcount=0;static t_list * conn_head=NULL;static t_list * conn_dead=NULL;static void conn_send_welcome(t_connection * c);static void conn_send_issue(t_connection * c);static int connarray_create(void);static void connarray_destroy(void);static t_connection *connarray_get_conn(unsigned index);static unsigned connarray_add_conn(t_connection *c);static void connarray_del_conn(unsigned index);static void conn_send_welcome(t_connection * c){ char const * filename; FILE * fp; if (!c) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection"); return; } if (c->protocol.cflags & conn_flags_welcomed) return; if ((conn_get_class(c)==conn_class_irc)|| (conn_get_class(c)==conn_class_wol)) { c->protocol.cflags|= conn_flags_welcomed; return; } if ((filename = prefs_get_motdfile())) { if ((fp = fopen(filename,"r"))) { message_send_file(c,fp); if (fclose(fp)<0) { eventlog(eventlog_level_error,__FUNCTION__,"could not close MOTD file \"%s\" after reading (fopen: %s)",filename,pstrerror(errno)); } } else { eventlog(eventlog_level_error,__FUNCTION__,"could not open MOTD file \"%s\" for reading (fopen: %s)",filename,pstrerror(errno)); } } c->protocol.cflags|= conn_flags_welcomed;}static void conn_send_issue(t_connection * c){ char const * filename; FILE * fp; if (!c) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection"); return; } if ((filename = prefs_get_issuefile())) if ((fp = fopen(filename,"r"))) { message_send_file(c,fp); if (fclose(fp)<0) eventlog(eventlog_level_error,__FUNCTION__,"could not close issue file \"%s\" after reading (fopen: %s)",filename,pstrerror(errno)); } else eventlog(eventlog_level_error,__FUNCTION__,"could not open issue file \"%s\" for reading (fopen: %s)",filename,pstrerror(errno)); else eventlog(eventlog_level_debug,__FUNCTION__,"no issue file");}// [zap-zero] 20020629extern void conn_shutdown(t_connection * c, time_t now, t_timer_data foo){ if (!c) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection"); return; } if (now==(time_t)0) /* zero means user logged out before expiration */ { eventlog(eventlog_level_trace,__FUNCTION__,"[%d] connection allready closed",conn_get_socket(c)); return; } eventlog(eventlog_level_trace,__FUNCTION__,"[%d] closing connection",conn_get_socket(c)); conn_set_state(c, conn_state_destroy);}extern void conn_test_latency(t_connection * c, time_t now, t_timer_data delta){ t_packet * packet; if (!c) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection"); return; } if (now==(time_t)0) /* zero means user logged out before expiration */ return; if (conn_get_state(c)==conn_state_destroy) // [zap-zero] 20020910 return; // state_destroy: do nothing if ((conn_get_class(c)==conn_class_irc)|| (conn_get_class(c)==conn_class_wol)) { /* We should start pinging the client after we received the first line ... */ /* NOTE: RFC2812 only suggests that PINGs are being sent * if no other activity is detected. However it explecitly * allows PINGs to be sent if there is activity on this * connection. In other words we just don't care :) */ if (conn_get_ircping(c)!=0) { eventlog(eventlog_level_warn,__FUNCTION__,"[%d] ping timeout (closing connection)",conn_get_socket(c)); conn_set_latency(c,0); conn_set_state(c,conn_state_destroy); } irc_send_ping(c); } else if(conn_get_class(c)==conn_class_w3route) { if(!(packet = packet_create(packet_class_w3route))) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] packet_create failed",conn_get_socket(c)); } else { packet_set_size(packet,sizeof(t_server_w3route_echoreq)); packet_set_type(packet,SERVER_W3ROUTE_ECHOREQ); bn_int_set(&packet->u.server_w3route_echoreq.ticks,get_ticks()); conn_push_outqueue(c, packet); packet_del_ref(packet); } } else { /* FIXME: I think real Battle.net sends these even before login */ if (!conn_get_game(c)) { if ((packet = packet_create(packet_class_bnet))) { packet_set_size(packet,sizeof(t_server_echoreq)); packet_set_type(packet,SERVER_ECHOREQ); bn_int_set(&packet->u.server_echoreq.ticks,get_ticks()); conn_push_outqueue(c,packet); packet_del_ref(packet); } else { eventlog(eventlog_level_error,__FUNCTION__,"could not create packet"); } } } if (timerlist_add_timer(c,now+(time_t)delta.n,conn_test_latency,delta)<0) eventlog(eventlog_level_error,__FUNCTION__,"could not add timer");}static void conn_send_nullmsg(t_connection * c, time_t now, t_timer_data delta){ if (!c) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection"); return; } if (now==(time_t)0) /* zero means user logged out before expiration */ return; message_send_text(c,message_type_null,c,NULL); if (timerlist_add_timer(c,now+(time_t)delta.n,conn_send_nullmsg,delta)<0) eventlog(eventlog_level_error,__FUNCTION__,"could not add timer");}extern char const * conn_class_get_str(t_conn_class class){ switch (class) { case conn_class_init: return "init"; case conn_class_bnet: return "bnet"; case conn_class_file: return "file"; case conn_class_bot: return "bot"; case conn_class_d2cs_bnetd: return "d2cs_bnetd"; case conn_class_telnet: return "telnet"; case conn_class_irc: return "irc"; case conn_class_wol: return "wol"; case conn_class_none: return "none"; case conn_class_w3route: return "w3route"; default: return "UNKNOWN"; }}extern char const * conn_state_get_str(t_conn_state state){ switch (state) { case conn_state_empty: return "empty"; case conn_state_initial: return "initial"; case conn_state_connected: return "connected"; case conn_state_bot_username: return "bot_username"; case conn_state_bot_password: return "bot_password"; case conn_state_loggedin: return "loggedin"; case conn_state_destroy: return "destroy"; case conn_state_untrusted: return "untrusted"; case conn_state_pending_raw: return "pending_raw"; default: return "UNKNOWN"; }}extern int conn_set_realm_cb(void *data, void *newref);extern t_connection * conn_create(int tsock, int usock, unsigned int real_local_addr, unsigned short real_local_port, unsigned int local_addr, unsigned short local_port, unsigned int addr, unsigned short port){ t_connection * temp; if (tsock<0) { eventlog(eventlog_level_error,__FUNCTION__,"got bad TCP socket %d",tsock); return NULL; } if (usock<-1) /* -1 is allowed for some connection classes like bot, irc, and telnet */ { eventlog(eventlog_level_error,__FUNCTION__,"got bad UDP socket %d",usock); return NULL; } temp = xmalloc(sizeof(t_connection)); temp->socket.tcp_sock = tsock; temp->socket.tcp_addr = addr; temp->socket.tcp_port = port; temp->socket.udp_sock = usock; temp->socket.udp_addr = addr; /* same for now but client can request it to be different */ temp->socket.local_addr = local_addr; temp->socket.local_port = local_port; temp->socket.real_local_addr = real_local_addr; temp->socket.real_local_port = real_local_port; temp->socket.udp_port = port; temp->socket.fdw_idx = -1; temp->protocol.class = conn_class_init; temp->protocol.state = conn_state_initial; temp->protocol.sessionkey = ((unsigned int)rand())^((unsigned int)now+(unsigned int)real_local_port); temp->protocol.sessionnum = connarray_add_conn(temp); temp->protocol.secret = ((unsigned int)rand())^(totalcount+((unsigned int)now)); temp->protocol.flags = MF_PLUG; temp->protocol.latency = 0; temp->protocol.chat.dnd = NULL; temp->protocol.chat.away = NULL; temp->protocol.chat.ignore_list = NULL; temp->protocol.chat.ignore_count = 0; temp->protocol.chat.quota.totcount = 0; temp->protocol.chat.quota.list = list_create(); temp->protocol.client.versionid = 0; temp->protocol.client.gameversion = 0; temp->protocol.client.checksum = 0; temp->protocol.client.archtag = 0; temp->protocol.client.clienttag = 0; temp->protocol.client.clientver = NULL; temp->protocol.client.gamelang = 0; temp->protocol.client.country = NULL; temp->protocol.client.tzbias = 0; temp->protocol.client.host = NULL; temp->protocol.client.user = NULL; temp->protocol.client.clientexe = NULL; temp->protocol.client.owner = NULL; temp->protocol.client.cdkey = NULL; temp->protocol.client.versioncheck = NULL; temp->protocol.account = NULL; temp->protocol.chat.channel = NULL; temp->protocol.chat.last_message = now; temp->protocol.chat.lastsender = NULL; temp->protocol.chat.irc.ircline = NULL; temp->protocol.chat.irc.ircping = 0; temp->protocol.chat.irc.ircpass = NULL; temp->protocol.chat.tmpOP_channel = NULL; temp->protocol.chat.tmpVOICE_channel = NULL; temp->protocol.game = NULL; temp->protocol.queues.outqueue = NULL; temp->protocol.queues.outsize = 0; temp->protocol.queues.outsizep = 0; temp->protocol.queues.inqueue = NULL; temp->protocol.queues.insize = 0; temp->protocol.loggeduser = NULL; temp->protocol.d2.realm = NULL; rcm_regref_init(&temp->protocol.d2.realm_regref,&conn_set_realm_cb,temp); temp->protocol.d2.character = NULL; temp->protocol.d2.realminfo = NULL; temp->protocol.d2.charname = NULL; temp->protocol.w3.w3_playerinfo = NULL; temp->protocol.w3.routeconn = NULL; temp->protocol.w3.anongame = NULL; temp->protocol.w3.anongame_search_starttime = 0; temp->protocol.bound = NULL; elist_init(&temp->protocol.timers); temp->protocol.wol.ingame = 0; temp->protocol.wol.codepage = 0; temp->protocol.wol.locale = 0; temp->protocol.wol.gameType = 0; temp->protocol.wol.apgar = NULL; temp->protocol.wol.gameOptions = NULL; temp->protocol.cr_time = now; temp->protocol.passfail_count = 0; temp->protocol.cflags = 0; list_prepend_data(conn_head,temp); eventlog(eventlog_level_info,__FUNCTION__,"[%d][%d] sessionkey=0x%08x sessionnum=0x%08x",temp->socket.tcp_sock,temp->socket.udp_sock,temp->protocol.sessionkey,temp->protocol.sessionnum); return temp;}extern t_anongame * conn_create_anongame(t_connection *c){ t_anongame * temp; int i; if(c->protocol.w3.anongame) { eventlog(eventlog_level_error,__FUNCTION__,"anongame already allocated"); return c->protocol.w3.anongame; } temp = xmalloc(sizeof(t_anongame)); temp->count = 0; temp->id = 0; temp->tid = 0; for (i=0; i < ANONGAME_MAX_GAMECOUNT/2; i++) temp->tc[i] = NULL; temp->race = 0; temp->playernum = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -