static int on_bnetd_authreply(t_connection * c, t_packet * packet) { unsigned int reply; reply=bn_int_get(packet->u.bnetd_d2cs_authreply.reply); if (reply == BNETD_D2CS_AUTHREPLY_SUCCEED) { eventlog(eventlog_level_info,__FUNCTION__,"authed by bnetd"); d2cs_conn_set_state(c,conn_state_authed); } else { eventlog(eventlog_level_error,__FUNCTION__,"failed to auth by bnetd (error=%d)",reply); d2cs_conn_set_state(c,conn_state_destroy); } return 0; }
static int on_d2cs_initconn(t_connection * c) { eventlog(eventlog_level_info,__FUNCTION__,"[%d] client initiated d2cs connection",d2cs_conn_get_socket(c)); d2cs_conn_set_class(c,conn_class_d2cs); d2cs_conn_set_state(c,conn_state_connected); return 0; }
static int on_d2gs_initconn(t_connection * c) { t_d2gs * gs; eventlog(eventlog_level_info,__FUNCTION__,"[%d] client initiated d2gs connection",d2cs_conn_get_socket(c)); if (!(gs=d2gslist_find_gs_by_ip(d2cs_conn_get_addr(c)))) { // reload list and see if any dns addy's has changed if (d2gslist_reload(prefs_get_d2gs_list())<0) { eventlog(eventlog_level_error,__FUNCTION__,"error reloading game server list,exitting"); return -1; } //recheck if (!(gs=d2gslist_find_gs_by_ip(d2cs_conn_get_addr(c)))) { eventlog(eventlog_level_error,__FUNCTION__,"d2gs connection from invalid ip address %s",addr_num_to_ip_str(d2cs_conn_get_addr(c))); return -1; } } d2cs_conn_set_class(c,conn_class_d2gs); d2cs_conn_set_state(c,conn_state_connected); conn_set_d2gs_id(c,d2gs_get_id(gs)); if (handle_d2gs_init(c)<0) { eventlog(eventlog_level_error,__FUNCTION__,"failed to init d2gs connection"); return -1; } return 0; }
static int on_bnetd_accountloginreply(t_connection * c, t_packet * packet) { unsigned int seqno; t_sq * sq; t_packet * opacket, * rpacket; t_connection * client; int result, reply; char const * account; t_elem * elem; if (!packet || !c) return -1; seqno=bn_int_get(packet->u.d2cs_bnetd.h.seqno); if (!(sq=sqlist_find_sq(seqno))) { eventlog(eventlog_level_error,__FUNCTION__,"seqno %d not found",seqno); return -1; } if (!(client=d2cs_connlist_find_connection_by_sessionnum(sq_get_clientid(sq)))) { eventlog(eventlog_level_error,__FUNCTION__,"client %d not found",sq_get_clientid(sq)); sq_destroy(sq,&elem); return -1; } if (!(opacket=sq_get_packet(sq))) { eventlog(eventlog_level_error,__FUNCTION__,"previous packet missing (seqno: %d)",seqno); sq_destroy(sq,&elem); return -1; } result=bn_int_get(packet->u.bnetd_d2cs_accountloginreply.reply); if (result==BNETD_D2CS_CHARLOGINREPLY_SUCCEED) { reply=D2CS_CLIENT_LOGINREPLY_SUCCEED; account=packet_get_str_const(opacket,sizeof(t_client_d2cs_loginreq),MAX_CHARNAME_LEN); d2cs_conn_set_account(client,account); d2cs_conn_set_state(client,conn_state_authed); eventlog(eventlog_level_info,__FUNCTION__,"account %s authed",account); } else { eventlog(eventlog_level_warn,__FUNCTION__,"client %d login request was rejected by bnetd",sq_get_clientid(sq)); reply=D2CS_CLIENT_LOGINREPLY_BADPASS; } if ((rpacket=packet_create(packet_class_d2cs))) { packet_set_size(rpacket,sizeof(t_d2cs_client_loginreply)); packet_set_type(rpacket,D2CS_CLIENT_LOGINREPLY); bn_int_set(&rpacket->u.d2cs_client_loginreply.reply,reply); conn_push_outqueue(client,rpacket); packet_del_ref(rpacket); } sq_destroy(sq,&elem); return 0; }
extern int bnetd_check(void) { static unsigned int prev_connecting_checktime=0; if (bnetd_connection) { if (d2cs_conn_get_state(bnetd_connection)==conn_state_connecting) { if (time(NULL) - prev_connecting_checktime > prefs_get_s2s_timeout()) { eventlog(eventlog_level_warn,__FUNCTION__,"connection to bnetd s2s timeout"); d2cs_conn_set_state(bnetd_connection,conn_state_destroy); return -1; } } return 0; } if (!(bnetd_connection=s2s_create(prefs_get_bnetdaddr(),BNETD_SERV_PORT,conn_class_bnetd))) { return -1; } if (d2cs_conn_get_state(bnetd_connection)==conn_state_init) { handle_bnetd_init(bnetd_connection); } else { prev_connecting_checktime=time(NULL); } return 0; }
static int on_bnetd_charloginreply(t_connection * c, t_packet * packet) { unsigned int seqno; t_sq * sq; t_connection * client; t_packet * opacket, * rpacket; int result, reply, type; char const * charname; t_elem * elem; if (!packet || !c) return -1; seqno=bn_int_get(packet->u.d2cs_bnetd.h.seqno); if (!(sq=sqlist_find_sq(seqno))) { eventlog(eventlog_level_error,__FUNCTION__,"seqno %d not found",seqno); return -1; } if (!(client=d2cs_connlist_find_connection_by_sessionnum(sq_get_clientid(sq)))) { eventlog(eventlog_level_error,__FUNCTION__,"client %d not found",sq_get_clientid(sq)); sq_destroy(sq,&elem); return -1; } if (!(opacket=sq_get_packet(sq))) { eventlog(eventlog_level_error,__FUNCTION__,"previous packet missing (seqno: %d)",seqno); sq_destroy(sq,&elem); return -1; } type=packet_get_type(opacket); result=bn_int_get(packet->u.bnetd_d2cs_charloginreply.reply); if (type==CLIENT_D2CS_CREATECHARREQ) { charname=packet_get_str_const(opacket,sizeof(t_client_d2cs_createcharreq),MAX_CHARNAME_LEN); if (result==BNETD_D2CS_CHARLOGINREPLY_SUCCEED) { if (conn_check_multilogin(client,charname)<0) { eventlog(eventlog_level_error,__FUNCTION__,"character %s is already logged in",charname); reply = D2CS_CLIENT_CHARLOGINREPLY_FAILED; } else { reply= D2CS_CLIENT_CREATECHARREPLY_SUCCEED; eventlog(eventlog_level_info,__FUNCTION__,"character %s authed",charname); d2cs_conn_set_charname(client,charname); d2cs_conn_set_state(client,conn_state_char_authed); } } else { reply = D2CS_CLIENT_CREATECHARREPLY_FAILED; eventlog(eventlog_level_error,__FUNCTION__,"failed to auth character %s",charname); } if ((rpacket=packet_create(packet_class_d2cs))) { packet_set_size(rpacket,sizeof(t_d2cs_client_createcharreply)); packet_set_type(rpacket,D2CS_CLIENT_CREATECHARREPLY); bn_int_set(&rpacket->u.d2cs_client_createcharreply.reply,reply); conn_push_outqueue(client,rpacket); packet_del_ref(rpacket); } } else if (type==CLIENT_D2CS_CHARLOGINREQ) { charname=packet_get_str_const(opacket,sizeof(t_client_d2cs_charloginreq),MAX_CHARNAME_LEN); if (result==BNETD_D2CS_CHARLOGINREPLY_SUCCEED) { if (conn_check_multilogin(client,charname)<0) { eventlog(eventlog_level_error,__FUNCTION__,"character %s is already logged in",charname); reply = D2CS_CLIENT_CHARLOGINREPLY_FAILED; } else { reply = D2CS_CLIENT_CHARLOGINREPLY_SUCCEED; eventlog(eventlog_level_info,__FUNCTION__,"character %s authed",charname); d2cs_conn_set_charname(client,charname); d2cs_conn_set_state(client,conn_state_char_authed); } } else { reply = D2CS_CLIENT_CHARLOGINREPLY_FAILED; eventlog(eventlog_level_error,__FUNCTION__,"failed to auth character %s",charname); } if ((rpacket=packet_create(packet_class_d2cs))) { packet_set_size(rpacket,sizeof(t_d2cs_client_charloginreply)); packet_set_type(rpacket,D2CS_CLIENT_CHARLOGINREPLY); bn_int_set(&rpacket->u.d2cs_client_charloginreply.reply,reply); conn_push_outqueue(client,rpacket); packet_del_ref(rpacket); } } else { eventlog(eventlog_level_error,__FUNCTION__,"got bad packet type %d",type); sq_destroy(sq,&elem); return -1; } sq_destroy(sq,&elem); return 0; }
extern t_connection * s2s_create(char const * server, unsigned short def_port, t_conn_class cclass) { struct sockaddr_in addr, laddr; psock_t_socklen laddr_len; unsigned int ip; unsigned short port; int sock, connected; t_connection * c; char * p, * tserver; ASSERT(server,NULL); tserver=xstrdup(server); p=std::strchr(tserver,':'); if (p) { port=(unsigned short)std::strtoul(p+1,NULL,10); *p='\0'; } else { port=def_port; } if ((sock=net_socket(PSOCK_SOCK_STREAM))<0) { eventlog(eventlog_level_error,__FUNCTION__,"error creating s2s socket"); xfree(tserver); return NULL; } std::memset(&addr,0,sizeof(addr)); addr.sin_family = PSOCK_AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr= net_inet_addr(tserver); xfree(tserver); eventlog(eventlog_level_info,__FUNCTION__,"try make s2s connection to {}",server); if (psock_connect(sock,(struct sockaddr *)&addr,sizeof(addr))<0) { if (psock_errno()!=PSOCK_EWOULDBLOCK && psock_errno() != PSOCK_EINPROGRESS) { eventlog(eventlog_level_error,__FUNCTION__,"error connecting to {} (psock_connect: {})",server,pstrerror(psock_errno())); psock_close(sock); return NULL; } connected=0; eventlog(eventlog_level_info,__FUNCTION__,"connection to s2s server {} is in progress",server); } else { connected=1; eventlog(eventlog_level_info,__FUNCTION__,"connected to s2s server {}",server); } laddr_len=sizeof(laddr); std::memset(&laddr,0,sizeof(laddr)); ip=port=0; if (psock_getsockname(sock,(struct sockaddr *)&laddr,&laddr_len)<0) { eventlog(eventlog_level_error,__FUNCTION__,"unable to get local socket info"); } else { if (laddr.sin_family != PSOCK_AF_INET) { eventlog(eventlog_level_error,__FUNCTION__,"got bad socket family {}",laddr.sin_family); } else { ip=ntohl(laddr.sin_addr.s_addr); port=ntohs(laddr.sin_port); } } if (!(c=d2cs_conn_create(sock,ip,port, ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port)))) { eventlog(eventlog_level_error,__FUNCTION__,"error create s2s connection"); psock_close(sock); return NULL; } if (connected) { if (conn_add_fd(c,fdwatch_type_read, d2cs_server_handle_tcp)<0) { eventlog(eventlog_level_error, __FUNCTION__, "error adding socket {} to fdwatch pool (max sockets?)",sock); d2cs_conn_set_state(c,conn_state_destroy); return NULL; } d2cs_conn_set_state(c,conn_state_init); } else { if (conn_add_fd(c, fdwatch_type_write, d2cs_server_handle_tcp)<0) { eventlog(eventlog_level_error, __FUNCTION__, "error adding socket {} to fdwatch pool (max sockets?)",sock); d2cs_conn_set_state(c,conn_state_destroy); return NULL; } d2cs_conn_set_state(c,conn_state_connecting); } d2cs_conn_set_class(c,cclass); return c; }