static int _client_anongame_cancel(t_connection * c) { t_packet * rpacket; t_connection * tc[ANONGAME_MAX_GAMECOUNT/2]; // [quetzal] 20020809 - added a_count, so we dont refer to already destroyed anongame t_anongame *a = conn_get_anongame(c); int a_count, i; eventlog(eventlog_level_info,__FUNCTION__,"[%d] got FINDANONGAME CANCEL packet", conn_get_socket(c)); if(!a) return -1; a_count = anongame_get_count(a); // anongame_unqueue(c, anongame_get_queue(a)); // -- already doing unqueue in conn_destroy_anongame for (i=0; i < ANONGAME_MAX_GAMECOUNT/2; i++) tc[i] = anongame_get_tc(a, i); for (i=0; i < ANONGAME_MAX_GAMECOUNT/2; i++) { if (tc[i] == NULL) continue; conn_set_routeconn(tc[i], NULL); conn_destroy_anongame(tc[i]); } if (!(rpacket = packet_create(packet_class_bnet))) return -1; packet_set_size(rpacket,sizeof(t_server_findanongame_playgame_cancel)); packet_set_type(rpacket,SERVER_FINDANONGAME_PLAYGAME_CANCEL); bn_byte_set(&rpacket->u.server_findanongame_playgame_cancel.cancel,SERVER_FINDANONGAME_CANCEL); bn_int_set(&rpacket->u.server_findanongame_playgame_cancel.count, a_count); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); return 0; }
extern int message_destroy(t_message * message) { unsigned int i; if (!message) { eventlog(eventlog_level_error,"message_destroy","got NULL message"); return -1; } for (i=0; i<message->num_cached; i++) if (message->packets[i]) packet_del_ref(message->packets[i]); if (message->packets) free(message->packets); if (message->classes) free(message->classes); if (message->dstflags) free(message->dstflags); free(message); return 0; }
int on_bnetd_gameinforeq(t_connection * c, t_packet * packet) { t_packet * rpacket; t_game * game; char const * gamename; if (!(c)) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection"); return -1; } if (!(gamename = packet_get_str_const(packet,sizeof(t_bnetd_d2cs_gameinforeq),MAX_GAMENAME_LEN))) { eventlog(eventlog_level_error,__FUNCTION__,"missing or too long gamename"); return -1; } if (!(game = d2cs_gamelist_find_game(gamename))) { eventlog(eventlog_level_error,__FUNCTION__,"request for unknown game \"%s\"",gamename); return -1; } if ((rpacket=packet_create(packet_class_d2cs_bnetd))) { packet_set_size(rpacket, sizeof(t_d2cs_bnetd_gameinforeply)); packet_set_type(rpacket, D2CS_BNETD_GAMEINFOREPLY); bn_int_set(&rpacket->u.d2cs_bnetd_gameinforeply.h.seqno,0); packet_append_string(rpacket, gamename); bn_byte_set(&rpacket->u.d2cs_bnetd_gameinforeply.difficulty, game_get_gameflag_difficulty(game)); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); } 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; }
static int on_client_gamelistreq(t_connection * c, t_packet * packet) { t_packet * rpacket; t_game * game; unsigned int count; unsigned int seqno; std::time_t now; unsigned int maxlifetime; t_elem const * start_elem; t_elem const * elem; seqno=bn_short_get(packet->u.client_d2cs_gamelistreq.seqno); /* if (seqno%2) return 0; */ count=0; now=std::time(NULL); maxlifetime=prefs_get_game_maxlifetime(); elem=start_elem=gamelist_get_curr_elem(); if (!elem) elem=list_get_first_const(d2cs_gamelist()); else elem=elem_get_next_const(d2cs_gamelist(),elem); for (; elem != start_elem; elem=elem_get_next_const(d2cs_gamelist(),elem)) { if (!elem) { elem=list_get_first_const(d2cs_gamelist()); if (elem == start_elem) break; } if (!(game=(t_game*)elem_get_data(elem))) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL game"); break; } if (maxlifetime && (now-game->create_time>maxlifetime)) continue; if (!game_get_currchar(game)) continue; if (!prefs_allow_gamelist_showall()) { if (conn_get_charinfo_difficulty(c)!=game_get_gameflag_difficulty(game)) continue; } if (prefs_hide_pass_games()) if (d2cs_game_get_pass(game)) continue; if (d2cs_try_joingame(c,game,"")!=D2CS_CLIENT_JOINGAMEREPLY_SUCCEED) continue; if ((rpacket=packet_create(packet_class_d2cs))) { packet_set_size(rpacket,sizeof(t_d2cs_client_gamelistreply)); packet_set_type(rpacket,D2CS_CLIENT_GAMELISTREPLY); bn_short_set(&rpacket->u.d2cs_client_gamelistreply.seqno,seqno); bn_int_set(&rpacket->u.d2cs_client_gamelistreply.token,d2cs_game_get_id(game)); bn_byte_set(&rpacket->u.d2cs_client_gamelistreply.currchar,game_get_currchar(game)); bn_int_set(&rpacket->u.d2cs_client_gamelistreply.gameflag,game_get_gameflag(game)); packet_append_string(rpacket,d2cs_game_get_name(game)); packet_append_string(rpacket,game_get_desc(game)); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); count++; if (prefs_get_maxgamelist() && count>=prefs_get_maxgamelist()) break; } } gamelist_set_curr_elem(elem); if (count) { if ((rpacket=packet_create(packet_class_d2cs))) { packet_set_size(rpacket,sizeof(t_d2cs_client_gamelistreply)); packet_set_type(rpacket,D2CS_CLIENT_GAMELISTREPLY); bn_short_set(&rpacket->u.d2cs_client_gamelistreply.seqno,seqno); bn_int_set(&rpacket->u.d2cs_client_gamelistreply.token,0); bn_byte_set(&rpacket->u.d2cs_client_gamelistreply.currchar,0); bn_int_set(&rpacket->u.d2cs_client_gamelistreply.gameflag,0); packet_append_string(rpacket,""); packet_append_string(rpacket,""); packet_append_string(rpacket,""); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); } } return 0; }
static int on_client_joingamereq(t_connection * c, t_packet * packet) { char const * gamename; char const * gamepass; char const * charname; char const * account; t_game * game; t_d2gs * gs; int reply; unsigned int pos; unsigned int seqno; gs = NULL; pos=sizeof(t_client_d2cs_joingamereq); if (!(gamename=packet_get_str_const(packet,pos,MAX_GAMENAME_LEN))) { eventlog(eventlog_level_error,__FUNCTION__,"got bad game name"); return -1; } pos+=std::strlen(gamename)+1; if (!(gamepass=packet_get_str_const(packet,pos,MAX_GAMEPASS_LEN))) { eventlog(eventlog_level_error,__FUNCTION__,"got bad game pass"); return -1; } if (!(charname=d2cs_conn_get_charname(c))) { eventlog(eventlog_level_error,__FUNCTION__,"missing character name for connection"); return -1; } if (!(account=d2cs_conn_get_account(c))) { eventlog(eventlog_level_error,__FUNCTION__,"missing account for connection"); return -1; } if (conn_check_multilogin(c,charname)<0) { eventlog(eventlog_level_error,__FUNCTION__,"character %s is already logged in",charname); return -1; } if (!(game=d2cs_gamelist_find_game(gamename))) { eventlog(eventlog_level_info,__FUNCTION__,"game %s not found",gamename); reply=D2CS_CLIENT_JOINGAMEREPLY_NOT_EXIST; } else if (!(gs=game_get_d2gs(game))) { eventlog(eventlog_level_error,__FUNCTION__,"missing game server for game %s",gamename); reply=D2CS_CLIENT_JOINGAMEREPLY_NOT_EXIST; } else { reply=d2cs_try_joingame(c,game,gamepass); } seqno=bn_short_get(packet->u.client_d2cs_joingamereq.seqno); if (reply!=D2CS_CLIENT_JOINGAMEREPLY_SUCCEED) { t_packet * rpacket; if ((rpacket=packet_create(packet_class_d2cs))) { packet_set_size(rpacket,sizeof(t_d2cs_client_joingamereply)); packet_set_type(rpacket,D2CS_CLIENT_JOINGAMEREPLY); bn_short_set(&rpacket->u.d2cs_client_joingamereply.seqno,seqno); bn_short_set(&rpacket->u.d2cs_client_joingamereply.u1,0); bn_short_set(&rpacket->u.d2cs_client_joingamereply.gameid,0); bn_int_set(&rpacket->u.d2cs_client_joingamereply.addr,0); bn_int_set(&rpacket->u.d2cs_client_joingamereply.token,0); bn_int_set(&rpacket->u.d2cs_client_joingamereply.reply,reply); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); } } else { t_packet * gspacket; t_sq * sq; struct in_addr addr; if ((gspacket=packet_create(packet_class_d2gs))) { if ((sq=sq_create(d2cs_conn_get_sessionnum(c),packet,d2cs_game_get_id(game)))) { packet_set_size(gspacket,sizeof(t_d2cs_d2gs_joingamereq)); packet_set_type(gspacket,D2CS_D2GS_JOINGAMEREQ); bn_int_set(&gspacket->u.d2cs_d2gs_joingamereq.h.seqno,sq_get_seqno(sq)); bn_int_set(&gspacket->u.d2cs_d2gs_joingamereq.gameid, game_get_d2gs_gameid(game)); sq_set_gametoken(sq,d2gs_make_token(gs)); bn_int_set(&gspacket->u.d2cs_d2gs_joingamereq.token,sq_get_gametoken(sq)); packet_append_string(gspacket,charname); packet_append_string(gspacket,account); addr.s_addr = htonl(d2cs_conn_get_addr(c)); packet_append_string(gspacket,inet_ntoa(addr)); conn_push_outqueue(d2gs_get_connection(gs),gspacket); } packet_del_ref(gspacket); eventlog(eventlog_level_info,__FUNCTION__,"request join game %s for character %s on gs %d",gamename, charname,d2gs_get_id(gs)); } } return 0; }
static int sd_udpinput(t_addr *const curr_laddr, const t_laddr_info *laddr_info, int ssocket, int usocket) { int err; psock_t_socklen errlen; t_packet * upacket; if (laddr_info == NULL) { (void)ssocket; } err = 0; errlen = sizeof(err); if (psock_getsockopt(usocket,PSOCK_SOL_SOCKET,PSOCK_SO_ERROR,&err,&errlen)<0) { eventlog(eventlog_level_error,"sd_udpinput","[%d] unable to read socket error (psock_getsockopt: %s)",usocket,strerror(psock_errno())); return -1; } if (errlen && err) /* if it was an error, there is no packet to read */ { eventlog(eventlog_level_error,"sd_udpinput","[%d] async UDP socket error notification (psock_getsockopt: %s)",usocket,strerror(err)); return -1; } if (!(upacket = packet_create(packet_class_udp))) { eventlog(eventlog_level_error,"sd_udpinput","could not allocate raw packet for input"); return -1; } { struct sockaddr_in fromaddr; psock_t_socklen fromlen; int len; fromlen = sizeof(fromaddr); if ((len = psock_recvfrom(usocket,packet_get_raw_data_build(upacket,0),MAX_PACKET_SIZE,0,(struct sockaddr *)&fromaddr,&fromlen))<0) { if ( #ifdef PSOCK_EINTR psock_errno()!=PSOCK_EINTR && #endif #ifdef PSOCK_EAGAIN psock_errno()!=PSOCK_EAGAIN && #endif #ifdef PSOCK_EWOULDBLOCK psock_errno()!=PSOCK_EWOULDBLOCK && #endif 1) eventlog(eventlog_level_error,"sd_udpinput","could not recv UDP datagram (psock_recvfrom: %s)",strerror(psock_errno())); packet_del_ref(upacket); return -1; } if (fromaddr.sin_family!=PSOCK_AF_INET) { eventlog(eventlog_level_error,"sd_udpinput","got UDP datagram with bad address family %d",(int)fromaddr.sin_family); packet_del_ref(upacket); return -1; } packet_set_size(upacket,len); if (hexstrm) { char tempa[32]; if (!addr_get_addr_str(curr_laddr,tempa,sizeof(tempa))) strcpy(tempa,"x.x.x.x:x"); fprintf(hexstrm,"%d: recv class=%s[0x%02x] type=%s[0x%04x] from=%s to=%s length=%u\n", usocket, packet_get_class_str(upacket),(unsigned int)packet_get_class(upacket), packet_get_type_str(upacket,packet_dir_from_client),packet_get_type(upacket), addr_num_to_addr_str(ntohl(fromaddr.sin_addr.s_addr),ntohs(fromaddr.sin_port)), tempa, packet_get_size(upacket)); hexdump(hexstrm,packet_get_raw_data(upacket,0),packet_get_size(upacket)); } handle_udp_packet(usocket,ntohl(fromaddr.sin_addr.s_addr),ntohs(fromaddr.sin_port),upacket); packet_del_ref(upacket); } return 0; }
static int _client_anongame_infos(t_connection * c, t_packet const * const packet) { t_packet * rpacket; if (bn_int_get(packet->u.client_findanongame_inforeq.count) > 1) { /* reply with 0 entries found */ int temp = 0; if ((rpacket = packet_create(packet_class_bnet)) == NULL) { eventlog(eventlog_level_error, __FUNCTION__, "could not create new packet"); return -1; } packet_set_size(rpacket, sizeof(t_server_findanongame_inforeply)); packet_set_type(rpacket, SERVER_FINDANONGAME_INFOREPLY); bn_byte_set(&rpacket->u.server_findanongame_inforeply.option, CLIENT_FINDANONGAME_INFOS); bn_int_set(&rpacket->u.server_findanongame_inforeply.count, bn_int_get(packet->u.client_findanongame_inforeq.count)); bn_byte_set(&rpacket->u.server_findanongame_inforeply.noitems, 0); packet_append_data(rpacket, &temp, 1); conn_push_outqueue(c, rpacket); packet_del_ref(rpacket); } else { int i; int client_tag; int server_tag_count = 0; int client_tag_unk; int server_tag_unk; bn_int temp; char noitems; char * tmpdata; int tmplen; t_clienttag clienttag = conn_get_clienttag(c); char last_packet = 0x00; char other_packet = 0x01; char langstr[5]; t_gamelang gamelang = conn_get_gamelang(c); bn_int_tag_get((bn_int const *)&gamelang, langstr, 5); /* Send seperate packet for each item requested * sending all at once overloaded w3xp * [Omega] */ for (i = 0; i < bn_byte_get(packet->u.client_findanongame_inforeq.noitems); i++){ noitems = 0; if ((rpacket = packet_create(packet_class_bnet)) == NULL) { eventlog(eventlog_level_error, __FUNCTION__, "could not create new packet"); return -1; } /* Starting the packet stuff */ packet_set_size(rpacket, sizeof(t_server_findanongame_inforeply)); packet_set_type(rpacket, SERVER_FINDANONGAME_INFOREPLY); bn_byte_set(&rpacket->u.server_findanongame_inforeply.option, CLIENT_FINDANONGAME_INFOS); bn_int_set(&rpacket->u.server_findanongame_inforeply.count, 1); std::memcpy(&temp, (packet_get_data_const(packet, 10 + (i * 8), 4)), sizeof(int)); client_tag = bn_int_get(temp); std::memcpy(&temp, packet_get_data_const(packet, 14 + (i * 8), 4), sizeof(int)); client_tag_unk = bn_int_get(temp); switch (client_tag){ case CLIENT_FINDANONGAME_INFOTAG_URL: bn_int_set((bn_int*)&server_tag_unk, 0xBF1F1047); packet_append_data(rpacket, "LRU\0", 4); packet_append_data(rpacket, &server_tag_unk, 4); // FIXME: Maybe need do do some checks to avoid prefs empty strings. tmpdata = anongame_infos_data_get_url(clienttag, conn_get_versionid(c), &tmplen); packet_append_data(rpacket, tmpdata, tmplen); noitems++; server_tag_count++; eventlog(eventlog_level_debug, __FUNCTION__, "client_tag request tagid=(0x%01x) tag=(%s) tag_unk=(0x%04x)", i, "CLIENT_FINDANONGAME_INFOTAG_URL", client_tag_unk); break; case CLIENT_FINDANONGAME_INFOTAG_MAP: bn_int_set((bn_int*)&server_tag_unk, 0x70E2E0D5); packet_append_data(rpacket, "PAM\0", 4); packet_append_data(rpacket, &server_tag_unk, 4); tmpdata = anongame_infos_data_get_map(clienttag, conn_get_versionid(c), &tmplen); packet_append_data(rpacket, tmpdata, tmplen); noitems++; server_tag_count++; eventlog(eventlog_level_debug, __FUNCTION__, "client_tag request tagid=(0x%01x) tag=(%s) tag_unk=(0x%04x)", i, "CLIENT_FINDANONGAME_INFOTAG_MAP", client_tag_unk); break; case CLIENT_FINDANONGAME_INFOTAG_TYPE: bn_int_set((bn_int*)&server_tag_unk, 0x7C87DEEE); packet_append_data(rpacket, "EPYT", 4); packet_append_data(rpacket, &server_tag_unk, 4); tmpdata = anongame_infos_data_get_type(clienttag, conn_get_versionid(c), &tmplen); packet_append_data(rpacket, tmpdata, tmplen); noitems++; server_tag_count++; eventlog(eventlog_level_debug, __FUNCTION__, "client_tag request tagid=(0x%01x) tag=(%s) tag_unk=(0x%04x)", i, "CLIENT_FINDANONGAME_INFOTAG_TYPE", client_tag_unk); break; case CLIENT_FINDANONGAME_INFOTAG_DESC: bn_int_set((bn_int*)&server_tag_unk, 0xA4F0A22F); packet_append_data(rpacket, "CSED", 4); packet_append_data(rpacket, &server_tag_unk, 4); tmpdata = anongame_infos_data_get_desc(langstr, clienttag, conn_get_versionid(c), &tmplen); packet_append_data(rpacket, tmpdata, tmplen); eventlog(eventlog_level_debug, __FUNCTION__, "client_tag request tagid=(0x%01x) tag=(%s) tag_unk=(0x%04x)", i, "CLIENT_FINDANONGAME_INFOTAG_DESC", client_tag_unk); noitems++; server_tag_count++; break; case CLIENT_FINDANONGAME_INFOTAG_LADR: bn_int_set((bn_int*)&server_tag_unk, 0x3BADE25A); packet_append_data(rpacket, "RDAL", 4); packet_append_data(rpacket, &server_tag_unk, 4); tmpdata = anongame_infos_data_get_ladr(langstr, clienttag, conn_get_versionid(c), &tmplen); packet_append_data(rpacket, tmpdata, tmplen); noitems++; server_tag_count++; eventlog(eventlog_level_debug, __FUNCTION__, "client_tag request tagid=(0x%01x) tag=(%s) tag_unk=(0x%04x)", i, "CLIENT_FINDANONGAME_INFOTAG_LADR", client_tag_unk); break; default: eventlog(eventlog_level_debug, __FUNCTION__, "unrec client_tag request tagid=(0x%01x) tag=(0x%04x)", i, client_tag); } //Adding a last padding null-byte if (server_tag_count == bn_byte_get(packet->u.client_findanongame_inforeq.noitems)) packet_append_data(rpacket, &last_packet, 1); /* only last packet in group gets 0x00 */ else packet_append_data(rpacket, &other_packet, 1); /* the rest get 0x01 */ //Go,go,go bn_byte_set(&rpacket->u.server_findanongame_inforeply.noitems, noitems); conn_push_outqueue(c, rpacket); packet_del_ref(rpacket); } } return 0; }
extern int handle_bot_packet(t_connection * c, t_packet const * const packet) { t_packet * rpacket; if (!c) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] got NULL connection",conn_get_socket(c)); return -1; } if (!packet) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] got NULL packet",conn_get_socket(c)); return -1; } if (packet_get_class(packet)!=packet_class_raw) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] got bad packet (class %d)",conn_get_socket(c),(int)packet_get_class(packet)); return -1; } { char const * const linestr=packet_get_str_const(packet,0,MAX_MESSAGE_LEN); if (packet_get_size(packet)<2) /* empty line */ return 0; if (!linestr) { eventlog(eventlog_level_warn,__FUNCTION__,"[%d] line too long",conn_get_socket(c)); return 0; } switch (conn_get_state(c)) { case conn_state_connected: conn_add_flags(c,MF_PLUG); conn_set_clienttag(c,CLIENTTAG_BNCHATBOT_UINT); { char const * temp=linestr; if (temp[0]=='\004') /* FIXME: no echo, ignore for now (we always do no echo) */ temp = &temp[1]; if (temp[0]=='\0') /* empty line */ { conn_set_state(c,conn_state_bot_username); /* don't look for ^D or reset tag and flags */ break; } conn_set_state(c,conn_state_bot_password); if (conn_set_loggeduser(c,temp)<0) eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not set username to \"%s\"",conn_get_socket(c),temp); { char const * const msg="\r\nPassword: "******"[%d] could not create rpacket",conn_get_socket(c)); break; } #if 1 /* don't echo */ packet_append_ntstring(rpacket,conn_get_loggeduser(c)); #endif packet_append_ntstring(rpacket,msg); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); } } break; case conn_state_bot_username: conn_set_state(c,conn_state_bot_password); if (conn_set_loggeduser(c,linestr)<0) eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not set username to \"%s\"",conn_get_socket(c),linestr); { char const * const temp="\r\nPassword: "******"[%d] could not create rpacket",conn_get_socket(c)); break; } #if 1 /* don't echo */ packet_append_ntstring(rpacket,linestr); #endif packet_append_ntstring(rpacket,temp); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); } break; case conn_state_bot_password: { char const * const tempa="\r\nLogin failed.\r\n\r\nUsername: "******"\r\nAccount has no bot access.\r\n\r\nUsername: "******"[%d] could not create rpacket",conn_get_socket(c)); break; } packet_append_ntstring(rpacket,tempa); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); break; } if (connlist_find_connection_by_accountname(loggeduser)) { eventlog(eventlog_level_info,__FUNCTION__,"[%d] bot login for \"%s\" refused (already logged in)",conn_get_socket(c),loggeduser); conn_set_state(c,conn_state_bot_username); if (!(rpacket = packet_create(packet_class_raw))) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not create rpacket",conn_get_socket(c)); break; } packet_append_ntstring(rpacket,tempa); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); break; } if (!(account = accountlist_find_account(loggeduser))) { eventlog(eventlog_level_info,__FUNCTION__,"[%d] bot login for \"%s\" refused (bad account)",conn_get_socket(c),loggeduser); conn_set_state(c,conn_state_bot_username); if (!(rpacket = packet_create(packet_class_raw))) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not create rpacket",conn_get_socket(c)); break; } packet_append_ntstring(rpacket,tempa); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); break; } if ((oldstrhash1 = account_get_pass(account))) { if (hash_set_str(&oldpasshash1,oldstrhash1)<0) { eventlog(eventlog_level_info,__FUNCTION__,"[%d] bot login for \"%s\" refused (corrupted passhash1?)",conn_get_socket(c),loggeduser); conn_set_state(c,conn_state_bot_username); if (!(rpacket = packet_create(packet_class_raw))) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not create rpacket",conn_get_socket(c)); break; } packet_append_ntstring(rpacket,tempa); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); break; } testpass = xstrdup(linestr); { unsigned int i; for (i=0; i<strlen(testpass); i++) if (isupper((int)testpass[i])) testpass[i] = tolower((int)testpass[i]); } if (bnet_hash(&trypasshash1,strlen(testpass),testpass)<0) /* FIXME: force to lowercase */ { eventlog(eventlog_level_info,__FUNCTION__,"[%d] bot login for \"%s\" refused (unable to hash password)",conn_get_socket(c), loggeduser); conn_set_state(c,conn_state_bot_username); xfree((void *)testpass); if (!(rpacket = packet_create(packet_class_raw))) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not create rpacket",conn_get_socket(c)); break; } packet_append_ntstring(rpacket,tempa); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); break; } xfree((void *)testpass); if (hash_eq(trypasshash1,oldpasshash1)!=1) { eventlog(eventlog_level_info,__FUNCTION__,"[%d] bot login for \"%s\" refused (wrong password)",conn_get_socket(c), loggeduser); conn_set_state(c,conn_state_bot_username); if (!(rpacket = packet_create(packet_class_raw))) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not create rpacket",conn_get_socket(c)); break; } packet_append_ntstring(rpacket,tempa); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); break; } if (account_get_auth_botlogin(account)!=1) /* default to false */ { eventlog(eventlog_level_info,__FUNCTION__,"[%d] bot login for \"%s\" refused (no bot access)",conn_get_socket(c), loggeduser); conn_set_state(c,conn_state_bot_username); if (!(rpacket = packet_create(packet_class_raw))) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not create rpacket",conn_get_socket(c)); break; } packet_append_ntstring(rpacket,tempb); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); break; } else if (account_get_auth_lock(account)==1) /* default to false */ { eventlog(eventlog_level_info,__FUNCTION__,"[%d] bot login for \"%s\" refused (this account is locked)",conn_get_socket(c), loggeduser); conn_set_state(c,conn_state_bot_username); if (!(rpacket = packet_create(packet_class_raw))) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not create rpacket",conn_get_socket(c)); break; } packet_append_ntstring(rpacket,tempb); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); break; } eventlog(eventlog_level_info,__FUNCTION__,"[%d] \"%s\" bot logged in (correct password)",conn_get_socket(c), loggeduser); } else { eventlog(eventlog_level_info,__FUNCTION__,"[%d] \"%s\" bot logged in (no password)",conn_get_socket(c), loggeduser); } if (!(rpacket = packet_create(packet_class_raw))) /* if we got this far, let them log in even if this fails */ eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not create rpacket",conn_get_socket(c)); else { packet_append_ntstring(rpacket,"\r\n"); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); } bnetd_log(loggeduser, addr_num_to_ip_str(conn_get_addr(c)), "BOT", "LOGIN", NULL, 1, 0); conn_login(c,account,loggeduser); message_send_text(c,message_type_uniqueid,c,loggeduser); if (conn_set_channel(c,CHANNEL_NAME_CHAT)<0) conn_set_channel(c,CHANNEL_NAME_BANNED); /* should not fail */ } break; case conn_state_loggedin: { t_channel const * channel; conn_set_idletime(c); if ((channel = conn_get_channel(c))) channel_message_log(channel,c,1,linestr); /* we don't log game commands currently */ if (linestr[0]=='/') handle_command(c,linestr); else if (channel && !conn_quota_exceeded(c,linestr)) channel_message_send(channel,message_type_talk,c,linestr); /* else discard */ } break; default: eventlog(eventlog_level_error,__FUNCTION__,"[%d] unknown bot connection state %d",conn_get_socket(c),(int)conn_get_state(c)); } } return 0; }
extern int handle_file_packet(t_connection * c, t_packet const * const packet) { if (!c) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] got NULL connection",conn_get_socket(c)); return -1; } if (!packet) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] got NULL packet",conn_get_socket(c)); return -1; } /* REMOVED BY UNDYING SOULZZ 4/3/02 */ /* if (packet_get_class(packet)!=packet_class_file) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] got bad packet (class %d)",conn_get_socket(c),(int)packet_get_class(packet)); return -1; } */ switch (conn_get_state(c)) { case conn_state_connected: switch (packet_get_type(packet)) { case CLIENT_FILE_REQ: { char const * rawname; if (!(rawname = packet_get_str_const(packet,sizeof(t_client_file_req),MAX_FILENAME_STR))) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] got bad FILE_REQ (missing or too long filename)",conn_get_socket(c)); return -1; } file_send(c,rawname, bn_int_get(packet->u.client_file_req.adid), bn_int_get(packet->u.client_file_req.extensiontag), bn_int_get(packet->u.client_file_req.startoffset), 1); } break; case CLIENT_FILE_REQ2: { t_packet * rpacket = NULL; if((rpacket = packet_create(packet_class_raw))) { packet_set_size(rpacket,sizeof(t_server_file_unknown1)); bn_int_set( &rpacket->u.server_file_unknown1.unknown, 0xdeadbeef ); conn_push_outqueue(c, rpacket ); packet_del_ref( rpacket ); } conn_set_state(c, conn_state_pending_raw); break; } default: eventlog(eventlog_level_error,__FUNCTION__,"[%d] unknown file packet type 0x%04x, len %u",conn_get_socket(c),packet_get_type(packet),packet_get_size(packet)); break; } break; case conn_state_pending_raw: switch (packet_get_type(packet)) { case CLIENT_FILE_REQ3: { char rawname[MAX_FILENAME_STR]; psock_recv( conn_get_socket(c), rawname, MAX_FILENAME_STR, 0 ); file_send(c, rawname, 0, 0, 0, 1); } break; default: eventlog(eventlog_level_error, __FUNCTION__, "[%d] unknown file packet type 0x%04x, len %u",conn_get_socket(c),packet_get_type(packet),packet_get_size(packet)); break; } break; default: eventlog(eventlog_level_error,__FUNCTION__,"[%d] unknown file connection state %d",conn_get_socket(c),(int)conn_get_state(c)); } return 0; }
static int on_d2cs_charloginreq(t_connection * c, t_packet const * packet) { t_connection * client; char const * charname; char const * portrait; char const * clienttag; char * temp; unsigned int sessionnum; t_realm * realm; char const * realmname; unsigned int pos, reply; t_packet * rpacket; if (packet_get_size(packet)<sizeof(t_d2cs_bnetd_charloginreq)) { eventlog(eventlog_level_error,__FUNCTION__,"got bad packet size"); return -1; } sessionnum=bn_int_get(packet->u.d2cs_bnetd_charloginreq.sessionnum); pos=sizeof(t_d2cs_bnetd_charloginreq); if (!(charname=packet_get_str_const(packet,pos,CHAR_NAME_LEN))) { eventlog(eventlog_level_error,__FUNCTION__,"got bad character name"); return -1; } pos+=strlen(charname)+1; if (!(portrait=packet_get_str_const(packet,pos,CHAR_PORTRAIT_LEN))) { eventlog(eventlog_level_error,__FUNCTION__,"got bad character portrait"); return -1; } if (!(client=connlist_find_connection_by_sessionnum(sessionnum))) { eventlog(eventlog_level_error,__FUNCTION__,"user %d not found",sessionnum); reply = BNETD_D2CS_CHARLOGINREPLY_FAILED; } else if (!(clienttag=clienttag_uint_to_str(conn_get_clienttag(client)))) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL clienttag"); reply = BNETD_D2CS_CHARLOGINREPLY_FAILED; } else if (!(realm=conn_get_realm(client))) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL realm"); reply = BNETD_D2CS_CHARLOGINREPLY_FAILED; } else { char revtag[8]; realmname = realm_get_name(realm); temp=xmalloc(strlen(clienttag)+strlen(realmname)+1+strlen(charname)+1+ strlen(portrait)+1); reply = BNETD_D2CS_CHARLOGINREPLY_SUCCEED; strcpy(revtag,clienttag); strreverse(revtag); sprintf(temp,"%4s%s,%s,%s",revtag,realmname,charname,portrait); conn_set_charname(client,charname); conn_set_realminfo(client,temp); xfree(temp); eventlog(eventlog_level_debug,__FUNCTION__, "loaded portrait for character %s",charname); } if ((rpacket=packet_create(packet_class_d2cs_bnetd))) { packet_set_size(rpacket,sizeof(t_bnetd_d2cs_charloginreply)); packet_set_type(rpacket,BNETD_D2CS_CHARLOGINREPLY); bn_int_set(&rpacket->u.bnetd_d2cs_charloginreply.h.seqno, bn_int_get(packet->u.d2cs_bnetd_charloginreq.h.seqno)); bn_int_set(&rpacket->u.bnetd_d2cs_charloginreply.reply,reply); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); } return 0; }
static int proxy_process(unsigned short server_listen_port, struct sockaddr_in servaddr) { int lsock; struct sockaddr_in laddr; t_psock_fd_set rfds, wfds; int highest_fd; int udpsock; t_virtconn * vc; t_elem const * curr; int csocket; int ssocket; if ((udpsock = psock_socket(PSOCK_PF_INET,PSOCK_SOCK_DGRAM,PSOCK_IPPROTO_UDP))<0) { eventlog(eventlog_level_error,__FUNCTION__,"could not create UDP socket (psock_socket: %s)",pstrerror(psock_errno())); return -1; } if (psock_ctl(udpsock,PSOCK_NONBLOCK)<0) eventlog(eventlog_level_error,__FUNCTION__,"could not set UDP listen socket to non-blocking mode (psock_ctl: %s)",pstrerror(psock_errno())); if ((lsock = psock_socket(PSOCK_PF_INET,PSOCK_SOCK_STREAM,PSOCK_IPPROTO_TCP))<0) { eventlog(eventlog_level_error,__FUNCTION__,"could not create listening socket (psock_socket: %s)",pstrerror(psock_errno())); psock_close(udpsock); return -1; } { int val=1; if (psock_setsockopt(lsock,PSOCK_SOL_SOCKET,PSOCK_SO_REUSEADDR,&val,(psock_t_socklen)sizeof(int))<0) eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not set socket option SO_REUSEADDR (psock_setsockopt: %s)",lsock,pstrerror(psock_errno())); /* not a fatal error... */ } memset(&laddr,0,sizeof(laddr)); laddr.sin_family = PSOCK_AF_INET; laddr.sin_port = htons(server_listen_port); laddr.sin_addr.s_addr = htonl(INADDR_ANY); if (psock_bind(lsock,(struct sockaddr *)&laddr,(psock_t_socklen)sizeof(laddr))<0) { eventlog(eventlog_level_error,__FUNCTION__,"could not bind socket to address 0.0.0.0:%hu TCP (psock_bind: %s)",server_listen_port,pstrerror(psock_errno())); psock_close(udpsock); psock_close(lsock); return -1; } memset(&laddr,0,sizeof(laddr)); laddr.sin_family = PSOCK_AF_INET; laddr.sin_port = htons(server_listen_port); laddr.sin_addr.s_addr = htonl(INADDR_ANY); if (psock_bind(udpsock,(struct sockaddr *)&laddr,(psock_t_socklen)sizeof(laddr))<0) { eventlog(eventlog_level_error,__FUNCTION__,"could not bind socket to address 0.0.0.0:%hu UDP (psock_bind: %s)",server_listen_port,pstrerror(psock_errno())); psock_close(udpsock); psock_close(lsock); return -1; } eventlog(eventlog_level_info,__FUNCTION__,"bound to UDP port %hu",server_listen_port); /* tell socket to listen for connections */ if (psock_listen(lsock,LISTEN_QUEUE)<0) { eventlog(eventlog_level_error,__FUNCTION__,"could not listen (psock_listen: %s)",pstrerror(psock_errno())); psock_close(udpsock); psock_close(lsock); return -1; } if (psock_ctl(lsock,PSOCK_NONBLOCK)<0) eventlog(eventlog_level_error,__FUNCTION__,"could not set TCP listen socket to non-blocking mode (psock_ctl: %s)",pstrerror(psock_errno())); eventlog(eventlog_level_info,__FUNCTION__,"listening on TCP port %hu",server_listen_port); for (;;) { /* loop over all connections to create the sets for select() */ PSOCK_FD_ZERO(&rfds); PSOCK_FD_ZERO(&wfds); highest_fd = lsock; PSOCK_FD_SET(lsock,&rfds); if (udpsock>highest_fd) highest_fd = udpsock; PSOCK_FD_SET(udpsock,&rfds); LIST_TRAVERSE_CONST(virtconnlist(),curr) { vc = elem_get_data(curr); csocket = virtconn_get_client_socket(vc); if (queue_get_length((t_queue const * const *)virtconn_get_clientout_queue(vc))>0) PSOCK_FD_SET(csocket,&wfds); /* pending output, also check for writeability */ PSOCK_FD_SET(csocket,&rfds); if (csocket>highest_fd) highest_fd = csocket; switch (virtconn_get_state(vc)) { case virtconn_state_connecting: eventlog(eventlog_level_debug,__FUNCTION__,"waiting for %d to finish connecting",ssocket); ssocket = virtconn_get_server_socket(vc); PSOCK_FD_SET(ssocket,&wfds); /* wait for connect to complete */ if (ssocket>highest_fd) highest_fd = ssocket; break; case virtconn_state_connected: eventlog(eventlog_level_debug,__FUNCTION__,"checking for reading on connected socket %d",ssocket); ssocket = virtconn_get_server_socket(vc); if (queue_get_length((t_queue const * const *)virtconn_get_serverout_queue(vc))>0) PSOCK_FD_SET(ssocket,&wfds); /* pending output, also check for writeability */ PSOCK_FD_SET(ssocket,&rfds); if (ssocket>highest_fd) highest_fd = ssocket; break; default: /* avoid warning */ break; } } /* find which sockets need servicing */ if (psock_select(highest_fd+1,&rfds,&wfds,NULL,NULL)<0) { if (errno!=PSOCK_EINTR) eventlog(eventlog_level_error,__FUNCTION__,"select failed (select: %s)",pstrerror(errno)); continue; } /* check for incoming connection */ if (PSOCK_FD_ISSET(lsock,&rfds)) { int asock; struct sockaddr_in caddr; psock_t_socklen caddr_len; /* accept the connection */ caddr_len = sizeof(caddr); if ((asock = psock_accept(lsock,(struct sockaddr *)&caddr,&caddr_len))<0) { if (psock_errno()==PSOCK_EWOULDBLOCK || psock_errno()==PSOCK_ECONNABORTED) /* BSD, POSIX error for aborted connections, SYSV often uses EAGAIN */ eventlog(eventlog_level_error,__FUNCTION__,"client aborted connection (psock_accept: %s)",pstrerror(psock_errno())); else /* EAGAIN can mean out of resources _or_ connection aborted */ if (psock_errno()!=PSOCK_EINTR) eventlog(eventlog_level_error,__FUNCTION__,"could not accept new connection (psock_accept: %s)",pstrerror(psock_errno())); } else { int ssd; int val=1; eventlog(eventlog_level_info,__FUNCTION__,"[%d] accepted connection from %s:%hu",asock,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port)); if (psock_setsockopt(asock,PSOCK_SOL_SOCKET,PSOCK_SO_KEEPALIVE,&val,(psock_t_socklen)sizeof(val))<0) eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not set socket option SO_KEEPALIVE (psock_setsockopt: %s)",asock,pstrerror(psock_errno())); /* not a fatal error */ if (psock_ctl(asock,PSOCK_NONBLOCK)<0) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not set TCP socket to non-blocking mode (closing connection) (psock_ctl: %s)",asock,pstrerror(psock_errno())); psock_close(asock); } else if ((ssd = psock_socket(PSOCK_PF_INET,PSOCK_SOCK_STREAM,PSOCK_IPPROTO_TCP))<0) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] could create TCP socket (closing connection) (psock_socket: %s)",asock,pstrerror(psock_errno())); psock_close(asock); } else if (psock_ctl(ssd,PSOCK_NONBLOCK)<0) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not set TCP socket to non-blocking mode (closing connection) (psock_ctl: %s)",asock,pstrerror(psock_errno())); psock_close(ssd); psock_close(asock); } else if (!(vc = virtconn_create(asock,ssd,ntohl(caddr.sin_addr.s_addr),BNETD_MIN_TEST_PORT))) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] unable to create new connection (closing connection)",asock); psock_close(ssd); psock_close(asock); } else { memset(&caddr,0,sizeof(caddr)); caddr.sin_family = PSOCK_AF_INET; caddr.sin_port = htons(virtconn_get_udpport(vc)); caddr.sin_addr.s_addr = htonl(virtconn_get_udpaddr(vc)); eventlog(eventlog_level_info,__FUNCTION__,"[%d] addr now %s:%hu",asock,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port)); } } } eventlog(eventlog_level_debug,__FUNCTION__,"checking for incoming UDP"); if (PSOCK_FD_ISSET(udpsock,&rfds)) { t_packet * upacket; struct sockaddr_in toaddr; struct sockaddr_in fromaddr; psock_t_socklen fromlen; int len; if (!(upacket = packet_create(packet_class_raw))) eventlog(eventlog_level_error,__FUNCTION__,"could not allocate raw packet for input"); else { /* packet_set_flags(upacket,PROXY_FLAG_UDP);*/ fromlen = sizeof(fromaddr); if ((len = psock_recvfrom(udpsock,packet_get_raw_data_build(upacket,0),MAX_PACKET_SIZE,0,(struct sockaddr *)&fromaddr,&fromlen))<0) { if (psock_errno()!=PSOCK_EINTR && psock_errno()!=PSOCK_EAGAIN && psock_errno()!=PSOCK_EWOULDBLOCK) eventlog(eventlog_level_error,__FUNCTION__,"could not recv UDP datagram (psock_recvfrom: %s)",pstrerror(psock_errno())); } else { if (fromaddr.sin_family!=PSOCK_AF_INET) eventlog(eventlog_level_error,__FUNCTION__,"got UDP datagram with bad address family %d",fromaddr.sin_family); else { char tempa[32]; char tempb[32]; packet_set_size(upacket,len); if (fromaddr.sin_addr.s_addr==servaddr.sin_addr.s_addr) /* from server */ { if ((curr = list_get_first_const(virtconnlist()))) /* hack.. find proper client */ { vc = elem_get_data(curr); memset(&toaddr,0,sizeof(toaddr)); toaddr.sin_family = PSOCK_AF_INET; toaddr.sin_port = htons(virtconn_get_udpport(vc)); toaddr.sin_addr.s_addr = htonl(virtconn_get_udpaddr(vc)); eventlog(eventlog_level_info,__FUNCTION__,"[%d] addr by UDP send is %s:%hu",virtconn_get_client_socket(vc),inet_ntoa(toaddr.sin_addr),ntohs(toaddr.sin_port)); if (hexstrm) { strcpy(tempa,inet_ntoa(fromaddr.sin_addr)); strcpy(tempb,inet_ntoa(toaddr.sin_addr)); fprintf(hexstrm,"%d: srv prot=UDP from=%s:%hu to=%s:%hu length=%d\n", udpsock, tempa, ntohs(fromaddr.sin_port), tempb, ntohs(toaddr.sin_port), len); hexdump(hexstrm,packet_get_raw_data(upacket,0),len); } /*queue_push_packet(virtconn_get_clientout_queue(__));*/ /* where to queue ... */ for (;;) /* hack.. just block for now */ { if (psock_sendto(udpsock,packet_get_raw_data_const(upacket,0),len,0, (struct sockaddr *)&toaddr,(psock_t_socklen)sizeof(toaddr))<len) { if (psock_errno()==PSOCK_EINTR || psock_errno()==PSOCK_EAGAIN || psock_errno()==PSOCK_EWOULDBLOCK) continue; eventlog(eventlog_level_error,__FUNCTION__,"could not send UDP datagram to client (psock_sendto: %s)",pstrerror(psock_errno())); } break; } } } else /* from client */ { if (hexstrm) { strcpy(tempa,inet_ntoa(fromaddr.sin_addr)); strcpy(tempb,inet_ntoa(servaddr.sin_addr)); fprintf(hexstrm,"%d: clt prot=UDP from=%s:%hu to=%s:%hu length=%d\n", udpsock, tempa, ntohs(fromaddr.sin_port), tempb, ntohs(servaddr.sin_port), len); hexdump(hexstrm,packet_get_raw_data(upacket,0),len); } /*queue_push_packet(virtconn_get_serverout_queue(vc));*/ for (;;) /* hack.. just block for now */ { if (psock_sendto(udpsock,packet_get_raw_data_const(upacket,0),len,0, (struct sockaddr *)&servaddr,(psock_t_socklen)sizeof(servaddr))<len) { if (psock_errno()==PSOCK_EINTR || psock_errno()==PSOCK_EAGAIN || psock_errno()==PSOCK_EWOULDBLOCK) continue; eventlog(eventlog_level_error,__FUNCTION__,"could not send UDP datagram to server (psock_sendto: %s)",pstrerror(psock_errno())); } break; } } } } packet_del_ref(upacket); } } /* search connections for sockets that need service */ eventlog(eventlog_level_debug,__FUNCTION__,"checking for sockets that need service"); LIST_TRAVERSE_CONST(virtconnlist(),curr) { unsigned int currsize; t_packet * packet; vc = elem_get_data(curr); csocket = virtconn_get_client_socket(vc); if (virtconn_get_state(vc)==virtconn_state_connected || virtconn_get_state(vc)==virtconn_state_connecting) ssocket = virtconn_get_server_socket(vc); else ssocket = -1; eventlog(eventlog_level_debug,__FUNCTION__,"checking %d for client readability",csocket); if (PSOCK_FD_ISSET(csocket,&rfds)) { if (virtconn_get_state(vc)==virtconn_state_initial) { if (init_virtconn(vc,servaddr)<0) { virtconn_destroy(vc); continue; } } else { currsize = virtconn_get_clientin_size(vc); if (!queue_get_length(virtconn_get_clientin_queue(vc))) { switch (virtconn_get_class(vc)) { case virtconn_class_bnet: if (!(packet = packet_create(packet_class_bnet))) { eventlog(eventlog_level_error,__FUNCTION__,"could not allocate normal packet for input"); continue; } break; case virtconn_class_file: if (!(packet = packet_create(packet_class_file))) { eventlog(eventlog_level_error,__FUNCTION__,"could not allocate file packet for input"); continue; } break; case virtconn_class_bot: if (!(packet = packet_create(packet_class_raw))) { eventlog(eventlog_level_error,__FUNCTION__,"could not allocate raw packet for input"); continue; } packet_set_size(packet,1); /* start by only reading one char */ break; default: eventlog(eventlog_level_error,__FUNCTION__,"[%d] connection has bad type (closing connection)",virtconn_get_client_socket(vc)); virtconn_destroy(vc); continue; } queue_push_packet(virtconn_get_clientin_queue(vc),packet); packet_del_ref(packet); if (!queue_get_length(virtconn_get_clientin_queue(vc))) continue; /* push failed */ currsize = 0; } packet = queue_peek_packet((t_queue const * const *)virtconn_get_clientin_queue(vc)); /* avoid warning */ switch (net_recv_packet(csocket,packet,&currsize)) { case -1: virtconn_destroy(vc); continue; case 0: /* still working on it */ virtconn_set_clientin_size(vc,currsize); break; case 1: /* done reading */ if (virtconn_get_class(vc)==virtconn_class_bot && currsize<MAX_PACKET_SIZE) { char const * const temp=packet_get_raw_data_const(packet,0); if (temp[currsize-1]!='\r' && temp[currsize-1]!='\n') { virtconn_set_clientin_size(vc,currsize); packet_set_size(packet,currsize+1); break; /* no end of line, get another char */ } /* got a complete line... fall through */ } packet = queue_pull_packet(virtconn_get_clientin_queue(vc)); if (hexstrm) { fprintf(hexstrm,"%d: cli class=%s[0x%04hx] type=%s[0x%04hx] length=%hu\n", csocket, packet_get_class_str(packet),packet_get_class(packet), packet_get_type_str(packet,packet_dir_from_client),packet_get_type(packet), packet_get_size(packet)); hexdump(hexstrm,packet_get_raw_data_const(packet,0),packet_get_size(packet)); } queue_push_packet(virtconn_get_serverout_queue(vc),packet); packet_del_ref(packet); virtconn_set_clientin_size(vc,0); } } } eventlog(eventlog_level_debug,__FUNCTION__,"checking %d for server readability",ssocket); if (ssocket!=-1 && PSOCK_FD_ISSET(ssocket,&rfds)) { currsize = virtconn_get_serverin_size(vc); if (!queue_get_length(virtconn_get_serverin_queue(vc))) { switch (virtconn_get_class(vc)) { case virtconn_class_bnet: if (!(packet = packet_create(packet_class_bnet))) { eventlog(eventlog_level_error,__FUNCTION__,"could not allocate normal packet for input"); continue; } break; case virtconn_class_file: { unsigned int fileleft; if ((fileleft = virtconn_get_fileleft(vc))>0) { if (!(packet = packet_create(packet_class_raw))) { eventlog(eventlog_level_error,__FUNCTION__,"could not allocate raw file packet for input"); continue; } if (fileleft>MAX_PACKET_SIZE) packet_set_size(packet,MAX_PACKET_SIZE); else packet_set_size(packet,fileleft); } else { if (!(packet = packet_create(packet_class_file))) { eventlog(eventlog_level_error,__FUNCTION__,"could not allocate file packet for input"); continue; } } } break; case virtconn_class_bot: if (!(packet = packet_create(packet_class_raw))) { eventlog(eventlog_level_error,__FUNCTION__,"could not allocate raw packet for input"); continue; } packet_set_size(packet,MAX_PACKET_SIZE); /* read as much as possible */ break; default: eventlog(eventlog_level_error,__FUNCTION__,"[%d] connection has bad type (closing connection)",virtconn_get_client_socket(vc)); virtconn_destroy(vc); continue; } queue_push_packet(virtconn_get_serverin_queue(vc),packet); packet_del_ref(packet); if (!queue_get_length(virtconn_get_serverin_queue(vc))) continue; /* push failed */ currsize = 0; } packet = queue_peek_packet((t_queue const * const *)virtconn_get_serverin_queue(vc)); /* avoid warning */ switch (net_recv_packet(ssocket,packet,&currsize)) { case -1: virtconn_destroy(vc); continue; case 0: /* still working on it */ virtconn_set_serverin_size(vc,currsize); if (virtconn_get_class(vc)!=virtconn_class_bot || currsize<1) break; else packet_set_size(packet,currsize); /* fallthough... we take what we can get with the bot data */ case 1: /* done reading */ packet = queue_pull_packet(virtconn_get_serverin_queue(vc)); if (virtconn_get_class(vc)==virtconn_class_file) { unsigned int len=virtconn_get_fileleft(vc); if (len) virtconn_set_fileleft(vc,len-currsize); else if (packet_get_type(packet)==SERVER_FILE_REPLY && packet_get_size(packet)>=sizeof(t_server_file_reply)) virtconn_set_fileleft(vc,bn_int_get(packet->u.server_file_reply.filelen)); } queue_push_packet(virtconn_get_clientout_queue(vc),packet); packet_del_ref(packet); virtconn_set_serverin_size(vc,0); } } eventlog(eventlog_level_debug,__FUNCTION__,"checking %d for client writeability",csocket); if (PSOCK_FD_ISSET(csocket,&wfds)) { currsize = virtconn_get_clientout_size(vc); switch (net_send_packet(csocket,queue_peek_packet((t_queue const * const *)virtconn_get_clientout_queue(vc)),&currsize)) /* avoid warning */ { case -1: virtconn_destroy(vc); continue; case 0: /* still working on it */ virtconn_set_clientout_size(vc,currsize); break; case 1: /* done sending */ packet = queue_pull_packet(virtconn_get_clientout_queue(vc)); if (hexstrm) { fprintf(hexstrm,"%d: srv class=%s[0x%04hx] type=%s[0x%04hx] length=%hu\n", csocket, packet_get_class_str(packet),packet_get_class(packet), packet_get_type_str(packet,packet_dir_from_server),packet_get_type(packet), packet_get_size(packet)); hexdump(hexstrm,packet_get_raw_data(packet,0),packet_get_size(packet)); } packet_del_ref(packet); virtconn_set_clientout_size(vc,0); } } eventlog(eventlog_level_debug,__FUNCTION__,"checking %d for server writeability",ssocket); if (ssocket!=-1 && PSOCK_FD_ISSET(ssocket,&wfds)) { if (virtconn_get_state(vc)==virtconn_state_connecting) { int err; psock_t_socklen errlen; err = 0; errlen = sizeof(err); if (psock_getsockopt(ssocket,PSOCK_SOL_SOCKET,PSOCK_SO_ERROR,&err,&errlen)<0) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] unable to read socket error (psock_getsockopt[psock_connect]: %s)",virtconn_get_client_socket(vc),pstrerror(psock_errno())); virtconn_destroy(vc); continue; } if (errlen==0 || err==0) virtconn_set_state(vc,virtconn_state_connected); else { eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not connect to server (psock_getsockopt[psock_connect]: %s)",virtconn_get_client_socket(vc),pstrerror(err)); virtconn_destroy(vc); continue; } } else { currsize = virtconn_get_serverout_size(vc); switch (net_send_packet(ssocket,queue_peek_packet((t_queue const * const *)virtconn_get_serverout_queue(vc)),&currsize)) /* avoid warning */ { case -1: virtconn_destroy(vc); continue; case 0: /* still working on it */ virtconn_set_serverout_size(vc,currsize); break; case 1: /* done sending */ packet = queue_pull_packet(virtconn_get_serverout_queue(vc)); packet_del_ref(packet); virtconn_set_serverout_size(vc,0); } } } }
static int init_virtconn(t_virtconn * vc, struct sockaddr_in servaddr) { int addlen; char connect_type; /* determine connection type by first character sent by client */ addlen = psock_recv(virtconn_get_client_socket(vc),&connect_type,sizeof(char),0); if (addlen<0 && (psock_errno()==PSOCK_EINTR || psock_errno()==PSOCK_EAGAIN || psock_errno()==PSOCK_EWOULDBLOCK)) return 0; /* error occurred or connection lost */ if (addlen<1) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not get virtconn class (closing connection) (psock_recv: %s)",virtconn_get_client_socket(vc),pstrerror(psock_errno())); return -1; } switch (connect_type) { case CLIENT_INITCONN_CLASS_BNET: eventlog(eventlog_level_info,__FUNCTION__,"[%d] client initiated normal connection",virtconn_get_client_socket(vc)); virtconn_set_class(vc,virtconn_class_bnet); break; case CLIENT_INITCONN_CLASS_FILE: eventlog(eventlog_level_info,__FUNCTION__,"[%d] client initiated file download connection",virtconn_get_client_socket(vc)); virtconn_set_class(vc,virtconn_class_file); break; case CLIENT_INITCONN_CLASS_BOT: eventlog(eventlog_level_info,__FUNCTION__,"[%d] client initiated chat bot connection",virtconn_get_client_socket(vc)); virtconn_set_class(vc,virtconn_class_bot); break; default: eventlog(eventlog_level_error,__FUNCTION__,"[%d] client initiated unknown connection type 0x%02hx (length %d) (closing connection)",virtconn_get_client_socket(vc),(unsigned short)connect_type,addlen); return -1; } /* now connect to the real server */ if (psock_connect(virtconn_get_server_socket(vc),(struct sockaddr *)&servaddr,(psock_t_socklen)sizeof(servaddr))<0) { if (psock_errno()!=PSOCK_EINPROGRESS) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not connect to server (psock_connect: %s)\n",virtconn_get_client_socket(vc),pstrerror(psock_errno())); return -1; } virtconn_set_state(vc,virtconn_state_connecting); } else virtconn_set_state(vc,virtconn_state_connected); { t_packet * packet; if (!(packet = packet_create(packet_class_raw))) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not create packet",virtconn_get_client_socket(vc)); return -1; } packet_append_data(packet,&connect_type,1); queue_push_packet(virtconn_get_serverout_queue(vc),packet); packet_del_ref(packet); } return 0; }
static int sd_tcpinput(int csocket, t_connection * c) { unsigned int currsize; t_packet * packet; currsize = conn_get_in_size(c); if (!*conn_get_in_queue(c)) { switch (conn_get_class(c)) { case conn_class_init: if (!(packet = packet_create(packet_class_init))) { eventlog(eventlog_level_error,"sd_tcpinput","could not allocate init packet for input"); return -1; } break; case conn_class_d2cs_bnetd: if (!(packet = packet_create(packet_class_d2cs_bnetd))) { eventlog(eventlog_level_error,"server_process","could not allocate d2cs_bnetd packet"); return -1; } break; case conn_class_bnet: if (!(packet = packet_create(packet_class_bnet))) { eventlog(eventlog_level_error,"sd_tcpinput","could not allocate bnet packet for input"); return -1; } break; case conn_class_file: if (!(packet = packet_create(packet_class_file))) { eventlog(eventlog_level_error,"sd_tcpinput","could not allocate file packet for input"); return -1; } break; case conn_class_bits: if (!(packet = packet_create(packet_class_bits))) { eventlog(eventlog_level_error,"sd_tcpinput","could not allocate BITS packet for input"); return -1; } break; case conn_class_defer: case conn_class_bot: case conn_class_irc: case conn_class_telnet: if (!(packet = packet_create(packet_class_raw))) { eventlog(eventlog_level_error,"sd_tcpinput","could not allocate raw packet for input"); return -1; } packet_set_size(packet,1); /* start by only reading one char */ break; case conn_class_auth: if (!(packet = packet_create(packet_class_auth))) { eventlog(eventlog_level_error,"sd_tcpinput","could not allocate auth packet for input"); return -1; } break; default: eventlog(eventlog_level_error,"sd_tcpinput","[%d] connection has bad class (closing connection)",conn_get_socket(c)); conn_destroy(c); return -1; } queue_push_packet(conn_get_in_queue(c),packet); packet_del_ref(packet); if (!*conn_get_in_queue(c)) return -1; /* push failed */ currsize = 0; } packet = queue_peek_packet((t_queue const * const *)conn_get_in_queue(c)); /* avoid warning */ switch (net_recv_packet(csocket,packet,&currsize)) { case -1: eventlog(eventlog_level_debug,"sd_tcpinput","[%d] read FAILED (closing connection)",conn_get_socket(c)); conn_destroy(c); return -1; case 0: /* still working on it */ /* eventlog(eventlog_level_debug,"sd_tcpinput","[%d] still reading \"%s\" packet (%u of %u bytes so far)",conn_get_socket(c),packet_get_class_str(packet),conn_get_in_size(c),packet_get_size(packet)); */ conn_set_in_size(c,currsize); break; case 1: /* done reading */ switch (conn_get_class(c)) { case conn_class_defer: { unsigned char const * const temp=packet_get_raw_data_const(packet,0); eventlog(eventlog_level_debug,"sd_tcpinput","[%d] got first packet byte %02x",conn_get_socket(c),(unsigned int)temp[0]); if (temp[0]==(unsigned char)0xff) /* HACK: thankfully all bnet packet types end with ff */ { conn_set_class(c,conn_class_bnet); conn_set_in_size(c,currsize); packet_set_class(packet,packet_class_bnet); eventlog(eventlog_level_debug,"sd_tcpinput","[%d] defered connection class is bnet",conn_get_socket(c)); } else { conn_set_class(c,conn_class_auth); conn_set_in_size(c,currsize); packet_set_class(packet,packet_class_auth); eventlog(eventlog_level_debug,"sd_tcpinput","[%d] defered connection class is auth",conn_get_socket(c)); } } break; case conn_class_bot: case conn_class_telnet: if (currsize<MAX_PACKET_SIZE) /* if we overflow, we can't wait for the end of the line. handle_*_packet() should take care of it */ { char const * const temp=packet_get_raw_data_const(packet,0); if ((temp[currsize-1]=='\003')||(temp[currsize-1]=='\004')) { /* we have to ignore these special characters, since * some bots even send them after login (eg. UltimateBot) */ currsize--; break; } if (temp[currsize-1]!='\r' && temp[currsize-1]!='\n') { conn_set_in_size(c,currsize); packet_set_size(packet,currsize+1); break; /* no end of line, get another char */ } } /* got a complete line or overflow, so: */ /*FALLTHRU*/ default: packet = queue_pull_packet(conn_get_in_queue(c)); if (hexstrm) { fprintf(hexstrm,"%d: recv class=%s[0x%02x] type=%s[0x%04x] length=%u\n", csocket, packet_get_class_str(packet),(unsigned int)packet_get_class(packet), packet_get_type_str(packet,packet_dir_from_client),packet_get_type(packet), packet_get_size(packet)); hexdump(hexstrm,packet_get_raw_data_const(packet,0),packet_get_size(packet)); } if (conn_get_class(c)==conn_class_bot || conn_get_class(c)==conn_class_telnet) /* NUL terminate the line to make life easier */ { char * const temp=packet_get_raw_data(packet,0); if (temp[currsize-1]=='\r' || temp[currsize-1]=='\n') temp[currsize-1] = '\0'; /* have to do it here instead of above so everything is intact for the hexdump */ } { int ret; switch (conn_get_class(c)) { case conn_class_bits: #ifdef WITH_BITS ret = handle_bits_packet(c,packet); #else eventlog(eventlog_level_error,"sd_tcpinput","[%d] BITS not enabled (closing connection)",conn_get_socket(c)); ret = -1; #endif break; case conn_class_init: ret = handle_init_packet(c,packet); break; case conn_class_bnet: ret = handle_bnet_packet(c,packet); break; case conn_class_d2cs_bnetd: ret = handle_d2cs_packet(c,packet); break; case conn_class_bot: ret = handle_bot_packet(c,packet); break; case conn_class_telnet: ret = handle_telnet_packet(c,packet); break; case conn_class_file: ret = handle_file_packet(c,packet); break; case conn_class_auth: ret = handle_auth_packet(c,packet); break; case conn_class_irc: ret = handle_irc_packet(c,packet); break; default: eventlog(eventlog_level_error,"sd_tcpinput","[%d] bad packet class %d (closing connection)",conn_get_socket(c),(int)packet_get_class(packet)); ret = -1; } packet_del_ref(packet); if (ret<0) { conn_destroy(c); return -1; } } conn_set_in_size(c,0); } } return 0; }
static int on_d2cs_accountloginreq(t_connection * c, t_packet const * packet) { unsigned int sessionkey; unsigned int sessionnum; unsigned int salt; char const * account; char const * tname; t_connection * client; int reply; t_packet * rpacket; struct { bn_int salt; bn_int sessionkey; bn_int sessionnum; bn_int secret; bn_int passhash[5]; } temp; t_hash secret_hash; char const * pass_str; t_hash passhash; t_hash try_hash; if (packet_get_size(packet)<sizeof(t_d2cs_bnetd_accountloginreq)) { eventlog(eventlog_level_error,"on_d2cs_accountloginreq","got bad packet size"); return -1; } if (!(account=packet_get_str_const(packet,sizeof(t_d2cs_bnetd_accountloginreq),USER_NAME_MAX))) { eventlog(eventlog_level_error,"on_d2cs_accountloginreq","got bad account name"); return -1; } sessionkey=bn_int_get(packet->u.d2cs_bnetd_accountloginreq.sessionkey); sessionnum=bn_int_get(packet->u.d2cs_bnetd_accountloginreq.sessionnum); salt=bn_int_get(packet->u.d2cs_bnetd_accountloginreq.seqno); if (!(client=connlist_find_connection_by_sessionnum(sessionnum))) { eventlog(eventlog_level_error,"on_d2cs_accountloginreq","sessionnum %d not found",sessionnum); reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED; } else if (sessionkey!=conn_get_sessionkey(client)) { eventlog(eventlog_level_error,"on_d2cs_accountloginreq","sessionkey %d not match",sessionkey); reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED; } else if (!(tname=conn_get_username(client))) { eventlog(eventlog_level_error,"on_d2cs_accountloginreq","got NULL username"); reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED; } else if (strcasecmp(account,tname)) { eventlog(eventlog_level_error,"on_d2cs_accountloginreq","username %s not match",account); conn_unget_username(client,tname); reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED; } else { conn_unget_username(client,tname); bn_int_set(&temp.salt,salt); bn_int_set(&temp.sessionkey,sessionkey); bn_int_set(&temp.sessionnum,sessionnum); bn_int_set(&temp.secret,conn_get_secret(client)); pass_str=account_get_pass(conn_get_account(client)); if (hash_set_str(&passhash,pass_str)<0) { reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED; } else { hash_to_bnhash((t_hash const *)&passhash,temp.passhash); bnet_hash(&secret_hash,sizeof(temp),&temp); bnhash_to_hash(packet->u.d2cs_bnetd_accountloginreq.secret_hash,&try_hash); if (hash_eq(try_hash,secret_hash)==1) { eventlog(eventlog_level_debug,"on_d2cs_accountloginreq","user %s loggedin on d2cs",\ account); reply=BNETD_D2CS_ACCOUNTLOGINREPLY_SUCCEED; } else { eventlog(eventlog_level_error,"on_d2cs_accountloginreq","user %s hash not match",\ account); reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED; } } account_unget_pass(pass_str); } if ((rpacket=packet_create(packet_class_d2cs_bnetd))) { packet_set_size(rpacket,sizeof(t_bnetd_d2cs_accountloginreply)); packet_set_type(rpacket,BNETD_D2CS_ACCOUNTLOGINREPLY); bn_int_set(&rpacket->u.bnetd_d2cs_accountloginreply.h.seqno,\ bn_int_get(packet->u.d2cs_bnetd_accountloginreq.h.seqno)); bn_int_set(&rpacket->u.bnetd_d2cs_accountloginreply.reply,reply); queue_push_packet(conn_get_out_queue(c),rpacket); packet_del_ref(rpacket); } return 0; }
static int on_d2cs_charloginreq(t_connection * c, t_packet const * packet) { t_connection * client; char const * charname; char const * portrait; char const * clienttag; char * temp; unsigned int sessionnum; char const * tname; char const * realmname; unsigned int pos, reply; t_packet * rpacket; if (packet_get_size(packet)<sizeof(t_d2cs_bnetd_charloginreq)) { eventlog(eventlog_level_error,"on_d2cs_charloginreq","got bad packet size"); return -1; } sessionnum=bn_int_get(packet->u.d2cs_bnetd_charloginreq.sessionnum); pos=sizeof(t_d2cs_bnetd_charloginreq); if (!(charname=packet_get_str_const(packet,pos,CHAR_NAME_LEN))) { eventlog(eventlog_level_error,"on_d2cs_charloginreq","got bad character name"); return -1; } pos+=strlen(charname)+1; if (!(portrait=packet_get_str_const(packet,pos,CHAR_PORTRAIT_LEN))) { eventlog(eventlog_level_error,"on_d2cs_charloginreq","got bad character portrait"); return -1; } if (!(client=connlist_find_connection_by_sessionnum(sessionnum))) { eventlog(eventlog_level_error,"on_d2cs_charloginreq","user %d not found",sessionnum); reply = BNETD_D2CS_CHARLOGINREPLY_FAILED; } else if (!(clienttag=conn_get_clienttag(client))) { eventlog(eventlog_level_error,"on_d2cs_charloginreq","got NULL clienttag"); reply = BNETD_D2CS_CHARLOGINREPLY_FAILED; } else if (!(realmname=conn_get_realmname(client))) { eventlog(eventlog_level_error,"on_d2cs_charloginreq","got NULL realm name"); reply = BNETD_D2CS_CHARLOGINREPLY_FAILED; } else if (!(temp=malloc(strlen(clienttag)+strlen(realmname)+1+strlen(charname)+1+\ strlen(portrait)+1))) { eventlog(eventlog_level_error,"on_d2cs_charloginreq","error allocate temp"); reply = BNETD_D2CS_CHARLOGINREPLY_FAILED; } else { reply = BNETD_D2CS_CHARLOGINREPLY_SUCCEED; sprintf (temp,"PX2D%s,%s,%s",realmname,charname,portrait); bn_int_tag_set((bn_int *)temp,clienttag); conn_set_charname(client,charname); conn_set_realminfo(client,temp); free(temp); eventlog(eventlog_level_debug,"on_d2cs_charloginreq",\ "loaded portrait for character %s",charname); } if ((rpacket=packet_create(packet_class_d2cs_bnetd))) { packet_set_size(rpacket,sizeof(t_bnetd_d2cs_charloginreply)); packet_set_type(rpacket,BNETD_D2CS_CHARLOGINREPLY); bn_int_set(&rpacket->u.bnetd_d2cs_charloginreply.h.seqno,\ bn_int_get(packet->u.d2cs_bnetd_charloginreq.h.seqno)); bn_int_set(&rpacket->u.bnetd_d2cs_charloginreply.reply,reply); queue_push_packet(conn_get_out_queue(c),rpacket); packet_del_ref(rpacket); } return 0; }
/* Send a file. If the file doesn't exist we still need to respond * to the file request. This will set filelen to 0 and send the server * reply message and the client will be happy and not hang. */ extern int file_send(t_connection * c, char const * rawname, unsigned int adid, unsigned int etag, unsigned int startoffset, int need_header) { char const * filename; t_packet * rpacket; std::FILE * fp; unsigned int filelen; int nbytes; if (!c) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection"); return -1; } if (!rawname) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL rawname"); return -1; } if (!(rpacket = packet_create(packet_class_file))) { eventlog(eventlog_level_error,__FUNCTION__,"could not create file packet"); return -1; } packet_set_size(rpacket,sizeof(t_server_file_reply)); packet_set_type(rpacket,SERVER_FILE_REPLY); if ((filename = file_get_info(rawname,&filelen,&rpacket->u.server_file_reply.timestamp))) { if (!(fp = std::fopen(filename,"rb"))) { /* FIXME: check for lower-case version of filename */ eventlog(eventlog_level_error,__FUNCTION__, "stat() succeeded yet could not open file \"%s\" for reading (std::fopen: %s)", filename, std::strerror(errno)); filelen = 0; } xfree((void *)filename); /* avoid warning */ } else { fp = NULL; filelen = 0; bn_long_set_a_b(&rpacket->u.server_file_reply.timestamp,0,0); } if (fp) { if (startoffset<filelen) { std::fseek(fp,startoffset,SEEK_SET); } else { eventlog(eventlog_level_warn,__FUNCTION__,"[%d] startoffset is beyond end of file (%u>%u)",conn_get_socket(c),startoffset,filelen); /* Keep the real filesize. Battle.net does it the same way ... */ std::fclose(fp); fp = NULL; } } if (need_header) { /* send the header from the server with the rawname and length. */ bn_int_set(&rpacket->u.server_file_reply.filelen,filelen); bn_int_set(&rpacket->u.server_file_reply.adid,adid); bn_int_set(&rpacket->u.server_file_reply.extensiontag,etag); /* rpacket->u.server_file_reply.timestamp is set above */ packet_append_string(rpacket,rawname); conn_push_outqueue(c,rpacket); } packet_del_ref(rpacket); /* Now send the data. Since it may be longer than a packet; we use * the raw packet class. */ if (!fp) { eventlog(eventlog_level_warn,__FUNCTION__,"[%d] sending no data for file \"%s\"",conn_get_socket(c),rawname); return -1; } eventlog(eventlog_level_info,__FUNCTION__,"[%d] sending file \"%s\" of length %d",conn_get_socket(c),rawname,filelen); for (;;) { if (!(rpacket = packet_create(packet_class_raw))) { eventlog(eventlog_level_error,__FUNCTION__,"could not create raw packet"); if (std::fclose(fp)<0) eventlog(eventlog_level_error,__FUNCTION__,"could not close file \"%s\" after reading (std::fclose: %s)",rawname,std::strerror(errno)); return -1; } if ((nbytes = std::fread(packet_get_raw_data_build(rpacket,0),1,MAX_PACKET_SIZE,fp))<(int)MAX_PACKET_SIZE) { if (nbytes>0) /* send out last portion */ { packet_set_size(rpacket,nbytes); conn_push_outqueue(c,rpacket); } packet_del_ref(rpacket); if (std::ferror(fp)) eventlog(eventlog_level_error,__FUNCTION__,"read failed before EOF on file \"%s\" (std::fread: %s)",rawname,std::strerror(errno)); break; } packet_set_size(rpacket,nbytes); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); } if (std::fclose(fp)<0) eventlog(eventlog_level_error,__FUNCTION__,"could not close file \"%s\" after reading (std::fclose: %s)",rawname,std::strerror(errno)); return 0; }
/* Open portrait in Warcraft 3 user profile */ static int _client_anongame_get_icon(t_connection * c, t_packet const * const packet) { t_packet * rpacket; //BlacKDicK 04/20/2003 Need some huge re-work on this. { struct { char icon_code[4]; unsigned int portrait_code; char race; bn_short required_wins; char client_enabled; } tempicon; //FIXME: Add those to the prefs and also merge them on accoun_wrap; // FIXED BY DJP 07/16/2003 FOR 110 CHANGE ( TOURNEY & RACE WINS ) + Table_witdh short icon_req_race_wins; short icon_req_tourney_wins; int race[] = { W3_RACE_RANDOM, W3_RACE_HUMANS, W3_RACE_ORCS, W3_RACE_UNDEAD, W3_RACE_NIGHTELVES, W3_RACE_DEMONS }; char race_char[6] = { 'R', 'H', 'O', 'U', 'N', 'D' }; char icon_pos[5] = { '2', '3', '4', '5', '6', }; char table_width = 6; char table_height = 5; int i, j; char rico; unsigned int rlvl, rwins; t_clienttag clienttag; t_account * acc; char user_icon[5]; char const * uicon; clienttag = conn_get_clienttag(c); acc = conn_get_account(c); /* WAR3 uses a different table size, might change if blizzard add tournament support to RoC */ if (clienttag == CLIENTTAG_WARCRAFT3_UINT) { table_width = 5; table_height = 4; } eventlog(eventlog_level_info, __FUNCTION__, "[%d] got FINDANONGAME Get Icons packet", conn_get_socket(c)); if ((rpacket = packet_create(packet_class_bnet)) == NULL) { eventlog(eventlog_level_error, __FUNCTION__, "could not create new packet"); return -1; } packet_set_size(rpacket, sizeof(t_server_findanongame_iconreply)); packet_set_type(rpacket, SERVER_FINDANONGAME_ICONREPLY); bn_int_set(&rpacket->u.server_findanongame_iconreply.count, bn_int_get(packet->u.client_findanongame_inforeq.count)); bn_byte_set(&rpacket->u.server_findanongame_iconreply.option, CLIENT_FINDANONGAME_GET_ICON); if (prefs_get_custom_icons() == 1) { // get current custom icon t_icon_info * icon; if (icon = customicons_get_icon_by_account(acc, clienttag)) std::memcpy(&rpacket->u.server_findanongame_iconreply.curricon, icon->icon_code, 4); } else if ((uicon = account_get_user_icon(acc, clienttag))) { std::memcpy(&rpacket->u.server_findanongame_iconreply.curricon, uicon, 4); } else { account_get_raceicon(acc, &rico, &rlvl, &rwins, clienttag); std::sprintf(user_icon, "%1d%c3W", rlvl, rico); std::memcpy(&rpacket->u.server_findanongame_iconreply.curricon, user_icon, 4); } bn_byte_set(&rpacket->u.server_findanongame_iconreply.table_width, table_width); bn_byte_set(&rpacket->u.server_findanongame_iconreply.table_size, table_width*table_height); for (j = 0; j < table_height; j++){ icon_req_race_wins = anongame_infos_get_ICON_REQ(j + 1, clienttag); for (i = 0; i < table_width; i++){ tempicon.race = i; tempicon.icon_code[0] = icon_pos[j]; tempicon.icon_code[1] = race_char[i]; tempicon.icon_code[2] = '3'; tempicon.icon_code[3] = 'W'; tempicon.portrait_code = (account_icon_to_profile_icon(tempicon.icon_code, acc, clienttag)); if (i <= 4){ //Building the icon for the races bn_short_set(&tempicon.required_wins, icon_req_race_wins); if (account_get_racewins(acc, race[i], clienttag) >= icon_req_race_wins) { if (prefs_get_custom_icons() == 1) tempicon.client_enabled = 0; else tempicon.client_enabled = 1; } else{ tempicon.client_enabled = 0; } } else{ //Building the icon for the tourney icon_req_tourney_wins = anongame_infos_get_ICON_REQ_TOURNEY(j + 1); bn_short_set(&tempicon.required_wins, icon_req_tourney_wins); if (account_get_racewins(acc, race[i], clienttag) >= icon_req_tourney_wins) { if (prefs_get_custom_icons() == 1) tempicon.client_enabled = 0; else tempicon.client_enabled = 1; } else{ tempicon.client_enabled = 0; } } packet_append_data(rpacket, &tempicon, sizeof(tempicon)); } } //Go,go,go conn_push_outqueue(c, rpacket); packet_del_ref(rpacket); } return 0; }
extern int main(int argc, char * argv[]) { int a; int sd; struct sockaddr_in saddr; t_packet * packet; t_packet * rpacket; t_packet * fpacket; char const * clienttag=NULL; char const * archtag=NULL; char const * servname=NULL; unsigned short servport=0; char const * hexfile=NULL; char text[MAX_MESSAGE_LEN]; char const * reqfile=NULL; struct hostent * host; unsigned int commpos; struct termios in_attr_old; struct termios in_attr_new; int changed_in; unsigned int currsize; unsigned int filelen; unsigned int startoffset; int startoffsetoverride=0; #define EXIST_ACTION_UNSPEC -1 #define EXIST_ACTION_ASK 0 #define EXIST_ACTION_OVERWRITE 1 #define EXIST_ACTION_BACKUP 2 #define EXIST_ACTION_RESUME 3 int exist_action=EXIST_ACTION_UNSPEC; struct stat exist_buf; char const * filename; FILE * fp; FILE * hexstrm=NULL; int fd_stdin; t_bnettime bntime; time_t tm; char timestr[FILE_TIME_MAXLEN]; unsigned int screen_width,screen_height; int munged; if (argc<1 || !argv || !argv[0]) { fprintf(stderr,"bad arguments\n"); return STATUS_FAILURE; } for (a=1; a<argc; a++) if (servname && isdigit((int)argv[a][0]) && a+1>=argc) { if (str_to_ushort(argv[a],&servport)<0) { fprintf(stderr,"%s: \"%s\" should be a positive integer\n",argv[0],argv[a]); usage(argv[0]); } } else if (!servname && argv[a][0]!='-' && a+2>=argc) servname = argv[a]; else if (strcmp(argv[a],"-b")==0 || strcmp(argv[a],"--client=SEXP")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_BROODWARS; } else if (strcmp(argv[a],"-d")==0 || strcmp(argv[a],"--client=DRTL")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_DIABLORTL; } else if (strcmp(argv[a],"--client=DSHR")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_DIABLOSHR; } else if (strcmp(argv[a],"-s")==0 || strcmp(argv[a],"--client=STAR")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_STARCRAFT; } else if (strcmp(argv[a],"--client=SSHR")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_SHAREWARE; } else if (strcmp(argv[a],"-w")==0 || strcmp(argv[a],"--client=W2BN")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_WARCIIBNE; } else if (strcmp(argv[a],"--client=D2DV")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_DIABLO2DV; } else if (strcmp(argv[a],"--client=D2XP")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_DIABLO2XP; } else if (strcmp(argv[a],"--client=WAR3")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_WARCRAFT3; } else if (strncmp(argv[a],"--client=",9)==0) { fprintf(stderr,"%s: unknown client tag \"%s\"\n",argv[0],&argv[a][9]); usage(argv[0]); } else if (strncmp(argv[a],"--hexdump=",10)==0) { if (hexfile) { fprintf(stderr,"%s: hexdump file was already specified as \"%s\"\n",argv[0],hexfile); usage(argv[0]); } hexfile = &argv[a][10]; } else if (strcmp(argv[a],"--arch=IX86")==0) { if (archtag) { fprintf(stderr,"%s: client arch was already specified as \"%s\"\n",argv[0],archtag); usage(argv[0]); } archtag = ARCHTAG_WINX86; } else if (strcmp(argv[a],"--arch=PMAC")==0) { if (archtag) { fprintf(stderr,"%s: client arch was already specified as \"%s\"\n",argv[0],archtag); usage(argv[0]); } archtag = ARCHTAG_MACPPC; } else if (strcmp(argv[a],"--arch=XMAC")==0) { if (archtag) { fprintf(stderr,"%s: client arch was already specified as \"%s\"\n",argv[0],archtag); usage(argv[0]); } archtag = ARCHTAG_OSXPPC; } else if (strncmp(argv[a],"--arch=",7)==0) { fprintf(stderr,"%s: unknown arch tag \"%s\"\n",argv[0],&argv[a][9]); usage(argv[0]); } else if (strncmp(argv[a],"--startoffset=",14)==0) { if (startoffsetoverride) { fprintf(stderr,"%s: startoffset was already specified as %u\n",argv[0],startoffset); usage(argv[0]); } if (str_to_uint(&argv[a][14],&startoffset)<0) { fprintf(stderr,"%s: startoffset \"%s\" should be a positive integer\n",argv[0],&argv[a][14]); usage(argv[0]); } startoffsetoverride = 1; } else if (strncmp(argv[a],"--exists=",9)==0) { if (exist_action!=EXIST_ACTION_UNSPEC) { fprintf(stderr,"%s: exists was already specified\n",argv[0]); usage(argv[0]); } if (argv[a][9]=='o' || argv[a][9]=='O') exist_action = EXIST_ACTION_OVERWRITE; else if (argv[a][9]=='a' || argv[a][9]=='A') exist_action = EXIST_ACTION_ASK; else if (argv[a][9]=='b' || argv[a][9]=='B') exist_action = EXIST_ACTION_BACKUP; else if (argv[a][9]=='r' || argv[a][9]=='R') exist_action = EXIST_ACTION_RESUME; else { fprintf(stderr,"%s: exists must begin with a,A,o,O,b,B,r or R",argv[0]); usage(argv[0]); } } else if (strncmp(argv[a],"--file=",7)==0) { if (reqfile) { fprintf(stderr,"%s: file was already specified as \"%s\"\n",argv[0],reqfile); usage(argv[0]); } reqfile = &argv[a][7]; } else if (strcmp(argv[a],"-v")==0 || strcmp(argv[a],"--version")==0) { printf("version "BNETD_VERSION"\n"); return 0; } else if (strcmp(argv[a],"-h")==0 || strcmp(argv[a],"--help")==0 || strcmp(argv[a],"--usage")==0) usage(argv[0]); else if (strcmp(argv[a],"--client")==0 || strcmp(argv[a],"--hexdump")==0) { fprintf(stderr,"%s: option \"%s\" requires an argument\n",argv[0],argv[a]); usage(argv[0]); } else { fprintf(stderr,"%s: unknown option \"%s\"\n",argv[0],argv[a]); usage(argv[0]); } if (servport==0) servport = BNETD_SERV_PORT; if (!clienttag) clienttag = CLIENTTAG_STARCRAFT; if (!archtag) archtag = ARCHTAG_WINX86; if (!servname) servname = BNETD_DEFAULT_HOST; if (exist_action==EXIST_ACTION_UNSPEC) exist_action = EXIST_ACTION_ASK; if (hexfile) if (!(hexstrm = fopen(hexfile,"w"))) fprintf(stderr,"%s: could not open file \"%s\" for writing the hexdump (fopen: %s)",argv[0],hexfile,strerror(errno)); else fprintf(hexstrm,"# dump generated by bnftp version "BNETD_VERSION"\n"); if (psock_init()<0) { fprintf(stderr,"%s: could not inialialize socket functions\n",argv[0]); return STATUS_FAILURE; } if (!(host = gethostbyname(servname))) { fprintf(stderr,"%s: unknown host \"%s\"\n",argv[0],servname); return STATUS_FAILURE; } fd_stdin = fileno(stdin); if (tcgetattr(fd_stdin,&in_attr_old)>=0) { in_attr_new = in_attr_old; in_attr_new.c_lflag &= ~(ECHO | ICANON); /* turn off ECHO and ICANON */ in_attr_new.c_cc[VMIN] = 1; /* require reads to return at least one byte */ in_attr_new.c_cc[VTIME] = 0; /* no timeout */ tcsetattr(fd_stdin,TCSANOW,&in_attr_new); changed_in = 1; } else { fprintf(stderr,"%s: could not get terminal attributes for stdin\n",argv[0]); changed_in = 0; } if (client_get_termsize(fd_stdin,&screen_width,&screen_height)<0) { fprintf(stderr,"%s: could not determine screen size\n",argv[0]); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); return STATUS_FAILURE; } if ((sd = psock_socket(PSOCK_PF_INET,PSOCK_SOCK_STREAM,PSOCK_IPPROTO_TCP))<0) { fprintf(stderr,"%s: could not create socket (psock_socket: %s)\n",argv[0],strerror(psock_errno())); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); return STATUS_FAILURE; } memset(&saddr,0,sizeof(saddr)); saddr.sin_family = PSOCK_AF_INET; saddr.sin_port = htons(servport); memcpy(&saddr.sin_addr.s_addr,host->h_addr_list[0],host->h_length); if (psock_connect(sd,(struct sockaddr *)&saddr,sizeof(saddr))<0) { fprintf(stderr,"%s: could not connect to server \"%s\" port %hu (psock_connect: %s)\n",argv[0],servname,servport,strerror(psock_errno())); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); return STATUS_FAILURE; } printf("Connected to %s:%hu.\n",inet_ntoa(saddr.sin_addr),servport); #ifdef CLIENTDEBUG eventlog_set(stderr); #endif if (!(packet = packet_create(packet_class_init))) { fprintf(stderr,"%s: could not create packet\n",argv[0]); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); return STATUS_FAILURE; } bn_byte_set(&packet->u.client_initconn.class,CLIENT_INITCONN_CLASS_FILE); if (hexstrm) { fprintf(hexstrm,"%d: send class=%s[0x%02hx] type=%s[0x%04hx] length=%u\n", sd, packet_get_class_str(packet),(unsigned int)packet_get_class(packet), packet_get_type_str(packet,packet_dir_from_client),packet_get_type(packet), packet_get_size(packet)); hexdump(hexstrm,packet_get_raw_data(packet,0),packet_get_size(packet)); } client_blocksend_packet(sd,packet); packet_del_ref(packet); if (!(rpacket = packet_create(packet_class_file))) { fprintf(stderr,"%s: could not create packet\n",argv[0]); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); return STATUS_FAILURE; } if (!(fpacket = packet_create(packet_class_raw))) { fprintf(stderr,"%s: could not create packet\n",argv[0]); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); packet_del_ref(rpacket); return STATUS_FAILURE; } if (!reqfile) /* if not specified on the command line then prompt for it */ { munged = 1; commpos = 0; text[0] = '\0'; for (;;) { switch (client_get_comm("filename: ",text,sizeof(text),&commpos,1,munged,screen_width)) { case -1: /* cancel or error */ printf("\n"); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; case 0: /* timeout */ munged = 0; continue; case 1: munged = 0; if (text[0]=='\0') continue; printf("\n"); } break; } reqfile = text; } if (stat(reqfile,&exist_buf)==0) /* check if the file exists */ { char text2[MAX_MESSAGE_LEN]; munged = 1; commpos = 0; text2[0] = '\0'; while (exist_action==EXIST_ACTION_ASK) { switch (client_get_comm("File exists [O]verwrite, [B]ackup or [R]esume?: ",text2,sizeof(text2),&commpos,1,munged,screen_width)) { case -1: /* cancel or error */ printf("\n"); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; case 0: /* timeout */ munged = 0; continue; case 1: munged = 0; if (text2[0]=='\0') continue; printf("\n"); break; } switch (text2[0]) { case 'o': case 'O': exist_action = EXIST_ACTION_OVERWRITE; break; case 'b': case 'B': exist_action = EXIST_ACTION_BACKUP; break; case 'r': case 'R': exist_action = EXIST_ACTION_RESUME; break; default: printf("Please answer with o,O,b,B,r or R.\n"); munged = 1; continue; } break; } switch (exist_action) { case EXIST_ACTION_OVERWRITE: if (!startoffsetoverride) startoffset = 0; break; case EXIST_ACTION_BACKUP: { char * bakfile; unsigned int bnr; int renamed=0; if (!(bakfile = malloc(strlen(reqfile)+1+2+1))) /* assuming we go up to bnr 99 we need reqfile+'.'+'99'+'\0' */ { fprintf(stderr,"%s: unable to allocate memory for backup filename.\n",argv[0]); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; } for (bnr=0; bnr<100; bnr++) { sprintf(bakfile,"%s.%d",reqfile,bnr); if (stat(bakfile,&exist_buf)==0) continue; /* backup exists */ /* backup does not exist */ if (rename(reqfile,bakfile)<0) /* just rename the existing file to the backup */ fprintf(stderr,"%s: could not create backup file \"%s\" (rename: %s)\n",argv[0],bakfile,strerror(errno)); else { renamed = 1; printf("Renaming \"%s\" to \"%s\".\n",reqfile,bakfile); } break; } free(bakfile); if (!renamed) { fprintf(stderr,"%s: could not create backup for \"%s\".\n",argv[0],reqfile); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; } if (!startoffsetoverride) startoffset = 0; } break; case EXIST_ACTION_RESUME: if (!startoffsetoverride) startoffset = exist_buf.st_size; break; } } else if (!startoffsetoverride) startoffset = 0; if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); if (!(packet = packet_create(packet_class_file))) { fprintf(stderr,"%s: could not create packet\n",argv[0]); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; } packet_set_size(packet,sizeof(t_client_file_req)); packet_set_type(packet,CLIENT_FILE_REQ); bn_int_tag_set(&packet->u.client_file_req.archtag,archtag); bn_int_tag_set(&packet->u.client_file_req.clienttag,clienttag); bn_int_set(&packet->u.client_file_req.adid,0); bn_int_set(&packet->u.client_file_req.extensiontag,0); bn_int_set(&packet->u.client_file_req.startoffset,startoffset); bn_long_set_a_b(&packet->u.client_file_req.timestamp,0x00000000,0x00000000); packet_append_string(packet,reqfile); if (hexstrm) { fprintf(hexstrm,"%d: send class=%s[0x%02hx] type=%s[0x%04hx] length=%u\n", sd, packet_get_class_str(packet),(unsigned int)packet_get_class(packet), packet_get_type_str(packet,packet_dir_from_client),packet_get_type(packet), packet_get_size(packet)); hexdump(hexstrm,packet_get_raw_data(packet,0),packet_get_size(packet)); } printf("\nRequesting info..."); fflush(stdout); client_blocksend_packet(sd,packet); packet_del_ref(packet); do { if (client_blockrecv_packet(sd,rpacket)<0) { fprintf(stderr,"%s: server closed connection\n",argv[0]); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; } if (hexstrm) { fprintf(hexstrm,"%d: recv class=%s[0x%02hx] type=%s[0x%04hx] length=%u\n", sd, packet_get_class_str(rpacket),(unsigned int)packet_get_class(rpacket), packet_get_type_str(rpacket,packet_dir_from_server),packet_get_type(rpacket), packet_get_size(rpacket)); hexdump(hexstrm,packet_get_raw_data(rpacket,0),packet_get_size(rpacket)); } } while (packet_get_type(rpacket)!=SERVER_FILE_REPLY); filelen = bn_int_get(rpacket->u.server_file_reply.filelen); bn_long_to_bnettime(rpacket->u.server_file_reply.timestamp,&bntime); tm = bnettime_to_time(bntime); strftime(timestr,FILE_TIME_MAXLEN,FILE_TIME_FORMAT,localtime(&tm)); filename = packet_get_str_const(rpacket,sizeof(t_server_file_reply),MAX_FILENAME_STR); if (exist_action==EXIST_ACTION_RESUME) { if (!(fp = fopen(reqfile,"ab"))) { fprintf(stderr,"%s: could not open file \"%s\" for appending (fopen: %s)\n",argv[0],reqfile,strerror(errno)); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; } } else { if (!(fp = fopen(reqfile,"wb"))) { fprintf(stderr,"%s: could not open file \"%s\" for writing (fopen: %s)\n",argv[0],reqfile,strerror(errno)); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; } } printf("\n name: \""); str_print_term(stdout,filename,0,0); printf("\"\n changed: %s\n length: %u bytes\n",timestr,filelen); fflush(stdout); if (startoffset>0) { filelen -= startoffset; /* for resuming files */ printf("Resuming at position %u (%u bytes remaining).\n",startoffset,filelen); } printf("\nSaving to \"%s\"...",reqfile); for (currsize=0; currsize+MAX_PACKET_SIZE<=filelen; currsize+=MAX_PACKET_SIZE) { printf("."); fflush(stdout); if (client_blockrecv_raw_packet(sd,fpacket,MAX_PACKET_SIZE)<0) { printf("error\n"); fprintf(stderr,"%s: server closed connection\n",argv[0]); if (fclose(fp)<0) fprintf(stderr,"%s: could not close file \"%s\" after writing (fclose: %s)\n",argv[0],reqfile,strerror(errno)); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; } if (hexstrm) { fprintf(hexstrm,"%d: recv class=%s[0x%02hx] type=%s[0x%04hx] length=%u\n", sd, packet_get_class_str(fpacket),(unsigned int)packet_get_class(fpacket), packet_get_type_str(fpacket,packet_dir_from_server),packet_get_type(fpacket), packet_get_size(fpacket)); hexdump(hexstrm,packet_get_raw_data(fpacket,0),packet_get_size(fpacket)); } if (fwrite(packet_get_raw_data_const(fpacket,0),1,MAX_PACKET_SIZE,fp)<MAX_PACKET_SIZE) { printf("error\n"); fprintf(stderr,"%s: could not write to file \"%s\" (fwrite: %s)\n",argv[0],reqfile,strerror(errno)); if (fclose(fp)<0) fprintf(stderr,"%s: could not close file \"%s\" after writing (fclose: %s)\n",argv[0],reqfile,strerror(errno)); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; } } filelen -= currsize; if (filelen) { printf("."); fflush(stdout); if (client_blockrecv_raw_packet(sd,fpacket,filelen)<0) { printf("error\n"); fprintf(stderr,"%s: server closed connection\n",argv[0]); if (fclose(fp)<0) fprintf(stderr,"%s: could not close file \"%s\" after writing (fclose: %s)\n",argv[0],reqfile,strerror(errno)); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; } if (hexstrm) { fprintf(hexstrm,"%d: recv class=%s[0x%02hx] type=%s[0x%04hx] length=%u\n", sd, packet_get_class_str(fpacket),(unsigned int)packet_get_class(fpacket), packet_get_type_str(fpacket,packet_dir_from_server),packet_get_type(fpacket), packet_get_size(fpacket)); hexdump(hexstrm,packet_get_raw_data(fpacket,0),packet_get_size(fpacket)); } if (fwrite(packet_get_raw_data_const(fpacket,0),1,filelen,fp)<filelen) { printf("error\n"); fprintf(stderr,"%s: could not write to file \"%s\"\n",argv[0],reqfile); if (fclose(fp)<0) fprintf(stderr,"%s: could not close file \"%s\" after writing (fclose: %s)\n",argv[0],reqfile,strerror(errno)); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; } } packet_del_ref(fpacket); packet_del_ref(rpacket); if (hexstrm) { fprintf(hexstrm,"# end of dump\n"); if (fclose(hexstrm)<0) fprintf(stderr,"%s: could not close hexdump file \"%s\" after writing (fclose: %s)",argv[0],hexfile,strerror(errno)); } if (fclose(fp)<0) { fprintf(stderr,"%s: could not close file \"%s\" after writing (fclose: %s)\n",argv[0],reqfile,strerror(errno)); return STATUS_FAILURE; } printf("done\n"); return STATUS_FAILURE; }
/* tournament notice disabled at this time, but responce is sent to cleint */ static int _client_anongame_tournament(t_connection * c, t_packet const * const packet) { t_packet * rpacket; t_account * account = conn_get_account(c); t_clienttag clienttag = conn_get_clienttag(c); unsigned int start_prelim = tournament_get_start_preliminary(); unsigned int end_signup = tournament_get_end_signup(); unsigned int end_prelim = tournament_get_end_preliminary(); unsigned int start_r1 = tournament_get_start_round_1(); if ((rpacket = packet_create(packet_class_bnet)) == NULL) { eventlog(eventlog_level_error, __FUNCTION__, "could not create new packet"); return -1; } packet_set_size(rpacket, sizeof(t_server_anongame_tournament_reply)); packet_set_type(rpacket, SERVER_FINDANONGAME_TOURNAMENT_REPLY); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.option, 7); bn_int_set(&rpacket->u.server_anongame_tournament_reply.count, bn_int_get(packet->u.client_anongame_tournament_request.count)); if (!start_prelim || (end_signup <= now && tournament_user_signed_up(account) < 0) || tournament_check_client(clienttag) < 0) { /* No Tournament Notice */ bn_byte_set(&rpacket->u.server_anongame_tournament_reply.type, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown, 0); bn_short_set(&rpacket->u.server_anongame_tournament_reply.unknown4, 0); bn_int_set(&rpacket->u.server_anongame_tournament_reply.timestamp, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown5, 0); bn_short_set(&rpacket->u.server_anongame_tournament_reply.countdown, 0); bn_short_set(&rpacket->u.server_anongame_tournament_reply.unknown2, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.wins, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.losses, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.ties, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown3, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.selection, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.descnum, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.nulltag, 0); } else if (start_prelim >= now) { /* Tournament Notice */ bn_byte_set(&rpacket->u.server_anongame_tournament_reply.type, 1); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown, 0); bn_short_set(&rpacket->u.server_anongame_tournament_reply.unknown4, 0x0000); /* random */ bn_int_set(&rpacket->u.server_anongame_tournament_reply.timestamp, _tournament_time_convert(start_prelim)); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown5, 0x01); bn_short_set(&rpacket->u.server_anongame_tournament_reply.countdown, start_prelim - now); bn_short_set(&rpacket->u.server_anongame_tournament_reply.unknown2, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.wins, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.losses, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.ties, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown3, 0x00); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.selection, 2); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.descnum, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.nulltag, 0); } else if (end_signup >= now) { /* Tournament Signup Notice - Play Game Active */ bn_byte_set(&rpacket->u.server_anongame_tournament_reply.type, 2); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown, 0); bn_short_set(&rpacket->u.server_anongame_tournament_reply.unknown4, 0x0828); /* random */ bn_int_set(&rpacket->u.server_anongame_tournament_reply.timestamp, _tournament_time_convert(end_signup)); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown5, 0x01); bn_short_set(&rpacket->u.server_anongame_tournament_reply.countdown, end_signup - now); bn_short_set(&rpacket->u.server_anongame_tournament_reply.unknown2, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.wins, tournament_get_stat(account, 1)); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.losses, tournament_get_stat(account, 2)); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.ties, tournament_get_stat(account, 3)); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown3, 0x08); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.selection, 2); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.descnum, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.nulltag, 0); } else if (end_prelim >= now) { /* Tournament Prelim Period - Play Game Active */ bn_byte_set(&rpacket->u.server_anongame_tournament_reply.type, 3); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown, 0); bn_short_set(&rpacket->u.server_anongame_tournament_reply.unknown4, 0x0828); /* random */ bn_int_set(&rpacket->u.server_anongame_tournament_reply.timestamp, _tournament_time_convert(end_prelim)); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown5, 0x01); bn_short_set(&rpacket->u.server_anongame_tournament_reply.countdown, end_prelim - now); bn_short_set(&rpacket->u.server_anongame_tournament_reply.unknown2, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.wins, tournament_get_stat(account, 1)); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.losses, tournament_get_stat(account, 2)); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.ties, tournament_get_stat(account, 3)); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown3, 0x08); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.selection, 2); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.descnum, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.nulltag, 0); } else if (start_r1 >= now && (tournament_get_game_in_progress())) { /* Prelim Period Over - Shows user stats (not all prelim games finished) */ bn_byte_set(&rpacket->u.server_anongame_tournament_reply.type, 4); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown, 0); bn_short_set(&rpacket->u.server_anongame_tournament_reply.unknown4, 0x0000); /* random */ bn_int_set(&rpacket->u.server_anongame_tournament_reply.timestamp, _tournament_time_convert(start_r1)); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown5, 0x01); bn_short_set(&rpacket->u.server_anongame_tournament_reply.countdown, start_r1 - now); bn_short_set(&rpacket->u.server_anongame_tournament_reply.unknown2, 0); /* 00 00 */ bn_byte_set(&rpacket->u.server_anongame_tournament_reply.wins, tournament_get_stat(account, 1)); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.losses, tournament_get_stat(account, 2)); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.ties, tournament_get_stat(account, 3)); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown3, 0x08); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.selection, 2); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.descnum, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.nulltag, 0); } else if (!(tournament_get_in_finals_status(account))) { /* Prelim Period Over - user did not make finals - Shows user stats */ bn_byte_set(&rpacket->u.server_anongame_tournament_reply.type, 5); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown, 0); bn_short_set(&rpacket->u.server_anongame_tournament_reply.unknown4, 0); bn_int_set(&rpacket->u.server_anongame_tournament_reply.timestamp, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown5, 0); bn_short_set(&rpacket->u.server_anongame_tournament_reply.countdown, 0); bn_short_set(&rpacket->u.server_anongame_tournament_reply.unknown2, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.wins, tournament_get_stat(account, 1)); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.losses, tournament_get_stat(account, 2)); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.ties, tournament_get_stat(account, 3)); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown3, 0x04); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.selection, 2); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.descnum, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.nulltag, 0); } /* cycle through [type-6] & [type-7] packets * * use [type-6] to show client "eliminated" or "continue" * timestamp , countdown & round number (of next round) must be set if clinet continues * * use [type-7] to make cleint wait for 44FF packet option 1 to start game (A guess, not tested) * * not sure if there is overall winner packet sent at end of last final round */ // UNDONE: next two conditions never executed else if ((0)) { /* User in finals - Shows user stats and start of next round*/ bn_byte_set(&rpacket->u.server_anongame_tournament_reply.type, 6); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown, 0); bn_short_set(&rpacket->u.server_anongame_tournament_reply.unknown4, 0x0000); bn_int_set(&rpacket->u.server_anongame_tournament_reply.timestamp, _tournament_time_convert(start_r1)); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown5, 0x01); bn_short_set(&rpacket->u.server_anongame_tournament_reply.countdown, start_r1 - now); bn_short_set(&rpacket->u.server_anongame_tournament_reply.unknown2, 0x0000); /* 00 00 */ bn_byte_set(&rpacket->u.server_anongame_tournament_reply.wins, 4); /* round number */ bn_byte_set(&rpacket->u.server_anongame_tournament_reply.losses, 0); /* 0 = continue , 1= eliminated */ bn_byte_set(&rpacket->u.server_anongame_tournament_reply.ties, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown3, 0x04); /* number of rounds in finals */ bn_byte_set(&rpacket->u.server_anongame_tournament_reply.selection, 2); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.descnum, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.nulltag, 0); } else if ((0)) { /* user waiting for match to be made */ bn_byte_set(&rpacket->u.server_anongame_tournament_reply.type, 7); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown, 0); bn_short_set(&rpacket->u.server_anongame_tournament_reply.unknown4, 0); bn_int_set(&rpacket->u.server_anongame_tournament_reply.timestamp, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown5, 0); bn_short_set(&rpacket->u.server_anongame_tournament_reply.countdown, 0); bn_short_set(&rpacket->u.server_anongame_tournament_reply.unknown2, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.wins, 1); /* round number */ bn_byte_set(&rpacket->u.server_anongame_tournament_reply.losses, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.ties, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.unknown3, 0x04); /* number of finals */ bn_byte_set(&rpacket->u.server_anongame_tournament_reply.selection, 2); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.descnum, 0); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.nulltag, 0); } conn_push_outqueue(c, rpacket); packet_del_ref(rpacket); return 0; }
static int on_client_creategamereq(t_connection * c, t_packet * packet) { char const * gamename; char const * gamepass; char const * gamedesc; t_game * game; t_d2gs * gs; t_gq * gq; unsigned int tempflag,gameflag; unsigned int leveldiff, maxchar, difficulty, expansion, hardcore, ladder; unsigned int seqno, reply; unsigned int pos; t_elem * elem; pos=sizeof(t_client_d2cs_creategamereq); if (!(gamename=packet_get_str_const(packet,pos,MAX_GAMENAME_LEN))) { eventlog(eventlog_level_error,__FUNCTION__,"got bad game name"); return -1; } pos+=std::strlen(gamename)+1; if (!(gamepass=packet_get_str_const(packet,pos,MAX_GAMEPASS_LEN))) { eventlog(eventlog_level_error,__FUNCTION__,"got bad game pass"); return -1; } pos+=std::strlen(gamepass)+1; if (!(gamedesc=packet_get_str_const(packet,pos,MAX_GAMEDESC_LEN))) { eventlog(eventlog_level_error,__FUNCTION__,"got bad game desc"); return -1; } tempflag=bn_int_get(packet->u.client_d2cs_creategamereq.gameflag); leveldiff=bn_byte_get(packet->u.client_d2cs_creategamereq.leveldiff); maxchar=bn_byte_get(packet->u.client_d2cs_creategamereq.maxchar); difficulty=gameflag_get_difficulty(tempflag); if (difficulty > conn_get_charinfo_difficulty(c)) { eventlog(eventlog_level_error,__FUNCTION__,"game difficulty exceed character limit %d %d",difficulty, conn_get_charinfo_difficulty(c)); return 0; } expansion=conn_get_charinfo_expansion(c); hardcore=conn_get_charinfo_hardcore(c); ladder=conn_get_charinfo_ladder(c); gameflag=gameflag_create(ladder,expansion,hardcore,difficulty); gs = NULL; game = NULL; gq=conn_get_gamequeue(c); if (d2cs_gamelist_find_game(gamename)) { eventlog(eventlog_level_info,__FUNCTION__,"game name %s is already exist in gamelist",gamename); reply=D2CS_CLIENT_CREATEGAMEREPLY_NAME_EXIST; } else if (!gq && gqlist_find_game(gamename)) { eventlog(eventlog_level_info,__FUNCTION__,"game name %s is already exist in game queue",gamename); reply=D2CS_CLIENT_CREATEGAMEREPLY_NAME_EXIST; } else if (!(gs=d2gslist_choose_server())) { if (gq) { eventlog(eventlog_level_error,__FUNCTION__,"client %d is already in game queue",d2cs_conn_get_sessionnum(c)); conn_set_gamequeue(c,NULL); gq_destroy(gq,&elem); return 0; } else if ((gq=gq_create(d2cs_conn_get_sessionnum(c), packet, gamename))) { conn_set_gamequeue(c,gq); d2cs_send_client_creategamewait(c,gqlist_get_length()); return 0; } reply=D2CS_CLIENT_CREATEGAMEREPLY_FAILED; } else if (hardcore && conn_get_charinfo_dead(c)) { reply=D2CS_CLIENT_CREATEGAMEREPLY_FAILED; } else if (!(game=d2cs_game_create(gamename,gamepass,gamedesc,gameflag))) { reply=D2CS_CLIENT_CREATEGAMEREPLY_NAME_EXIST; } else { reply=D2CS_CLIENT_CREATEGAMEREPLY_SUCCEED; game_set_d2gs(game,gs); d2gs_add_gamenum(gs, 1); game_set_gameflag_ladder(game,ladder); game_set_gameflag_expansion(game,expansion); game_set_created(game,0); game_set_leveldiff(game,leveldiff); game_set_charlevel(game,conn_get_charinfo_level(c)); game_set_maxchar(game,maxchar); game_set_gameflag_difficulty(game,difficulty); game_set_gameflag_hardcore(game,hardcore); } seqno=bn_short_get(packet->u.client_d2cs_creategamereq.seqno); if (reply!=D2CS_CLIENT_CREATEGAMEREPLY_SUCCEED) { t_packet * rpacket; if ((rpacket=packet_create(packet_class_d2cs))) { packet_set_size(rpacket,sizeof(t_d2cs_client_creategamereply)); packet_set_type(rpacket,D2CS_CLIENT_CREATEGAMEREPLY); bn_short_set(&rpacket->u.d2cs_client_creategamereply.seqno,seqno); bn_short_set(&rpacket->u.d2cs_client_creategamereply.u1,0); bn_short_set(&rpacket->u.d2cs_client_creategamereply.gameid,0); bn_int_set(&rpacket->u.d2cs_client_creategamereply.reply,reply); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); } } else { t_packet * gspacket; t_sq * sq; struct in_addr addr; if ((gspacket=packet_create(packet_class_d2gs))) { if ((sq=sq_create(d2cs_conn_get_sessionnum(c),packet,d2cs_game_get_id(game)))) { packet_set_size(gspacket,sizeof(t_d2cs_d2gs_creategamereq)); packet_set_type(gspacket,D2CS_D2GS_CREATEGAMEREQ); bn_int_set(&gspacket->u.d2cs_d2gs_creategamereq.h.seqno,sq_get_seqno(sq)); bn_byte_set(&gspacket->u.d2cs_d2gs_creategamereq.difficulty,difficulty); bn_byte_set(&gspacket->u.d2cs_d2gs_creategamereq.hardcore,hardcore); bn_byte_set(&gspacket->u.d2cs_d2gs_creategamereq.expansion,expansion); bn_byte_set(&gspacket->u.d2cs_d2gs_creategamereq.ladder,ladder); packet_append_string(gspacket,gamename); packet_append_string(gspacket,gamepass); packet_append_string(gspacket,gamedesc); packet_append_string(gspacket,d2cs_conn_get_account(c)); packet_append_string(gspacket,d2cs_conn_get_charname(c)); addr.s_addr = htonl(d2cs_conn_get_addr(c)); packet_append_string(gspacket,inet_ntoa(addr)); conn_push_outqueue(d2gs_get_connection(gs),gspacket); } packet_del_ref(gspacket); eventlog(eventlog_level_info,__FUNCTION__,"request create game %s on gs %d",gamename,d2gs_get_id(gs)); } } return 0; }