// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder #include "loginchrif.hpp" #include #include #include //show notice #include //wfifo session #include //safeprint32 #include //difftick #include "account.hpp" #include "login.hpp" #include "loginlog.hpp" //early declaration void logchrif_on_disconnect(int32 id); /** * Packet send to all char-servers, except one. (wos: without our self) * @param sfd: fd to discard sending to * @param buf: packet to send in form of an array buffer * @param len: size of packet * @return : the number of char-serv the packet was sent to */ int32 logchrif_sendallwos(int32 sfd, uint8* buf, size_t len) { int32 i, c; for( i = 0, c = 0; i < ARRAYLENGTH(ch_server); ++i ) { int32 fd = ch_server[i].fd; if( session_isValid(fd) && fd != sfd ){ WFIFOHEAD(fd,len); memcpy(WFIFOP(fd,0), buf, len); WFIFOSET(fd,len); ++c; } } return c; } /** * Timered function to synchronize ip addresses. * Requesting all char to update their registered ip and transmit their new ip. * Performed each ip_sync_interval. * @param tid: timer id * @param tick: tick of execution * @param id: unused * @param data: unused * @return 0 */ TIMER_FUNC(logchrif_sync_ip_addresses){ uint8 buf[2]; ShowInfo("IP Sync in progress...\n"); WBUFW(buf,0) = 0x2735; logchrif_sendallwos(-1, buf, 2); return 0; } /// Parsing handlers /** * Request from char-server to authenticate an account. * @param fd: fd to parse from (char-serv) * @param id: id of char-serv * @param ip: char-serv ip (used for info) * @return 0 not enough info transmitted, 1 success */ int32 logchrif_parse_reqauth(int32 fd, int32 id,char* ip){ if( RFIFOREST(fd) < 23 ) return 0; else{ uint32 account_id = RFIFOL(fd,2); uint32 login_id1 = RFIFOL(fd,6); uint32 login_id2 = RFIFOL(fd,10); uint8 sex = RFIFOB(fd,14); //uint32 ip_ = ntohl(RFIFOL(fd,15)); int32 request_id = RFIFOL(fd,19); RFIFOSKIP(fd,23); struct auth_node* node = login_get_auth_node( account_id ); if( global_core->is_running() && node != nullptr && node->account_id == account_id && node->login_id1 == login_id1 && node->login_id2 == login_id2 && node->sex == sex_num2str(sex) /*&& node->ip == ip_*/ ){// found //ShowStatus("Char-server '%s': authentication of the account %d accepted (ip: %s).\n", server[id].name, account_id, ip); // send ack WFIFOHEAD(fd,21); WFIFOW(fd,0) = 0x2713; WFIFOL(fd,2) = account_id; WFIFOL(fd,6) = login_id1; WFIFOL(fd,10) = login_id2; WFIFOB(fd,14) = sex; WFIFOB(fd,15) = 0;// ok WFIFOL(fd,16) = request_id; WFIFOB(fd,20) = node->clienttype; WFIFOSET(fd,21); // each auth entry can only be used once login_remove_auth_node( account_id ); }else{// authentication not found ShowStatus("Char-server '%s': authentication of the account %d REFUSED (ip: %s).\n", ch_server[id].name, account_id, ip); WFIFOHEAD(fd,21); WFIFOW(fd,0) = 0x2713; WFIFOL(fd,2) = account_id; WFIFOL(fd,6) = login_id1; WFIFOL(fd,10) = login_id2; WFIFOB(fd,14) = sex; WFIFOB(fd,15) = 1;// auth failed WFIFOL(fd,16) = request_id; WFIFOB(fd,20) = 0; WFIFOSET(fd,21); } } return 1; } /** * Receive a request to update user count for char-server identified by id. * @param fd: fd to parse from (char-serv) * @param id: id of char-serv * @return 0 not enough info transmitted, 1 success */ int32 logchrif_parse_ackusercount(int32 fd, int32 id){ if( RFIFOREST(fd) < 6 ) return 0; else{ int32 users = RFIFOL(fd,2); RFIFOSKIP(fd,6); // how many users on world? (update) if( ch_server[id].users != users ){ ShowStatus("set users %s : %d\n", ch_server[id].name, users); ch_server[id].users = users; } } return 1; } /** * Transmit account data to char_server * S 2717 aid.W email.40B exp_time.L group_id.B char_slot.B birthdate.11B pincode.5B pincode_change.L * isvip.1B char_vip.1B max_billing.1B (tot 75) * @return -1 : account not found, 1:sucess */ int32 logchrif_send_accdata(int32 fd, uint32 aid) { struct mmo_account acc; time_t expiration_time = 0; char email[40] = ""; int32 group_id = 0; char birthdate[10+1] = ""; char pincode[PINCODE_LENGTH+1]; char isvip = false; uint8 char_slots = MIN_CHARS, char_vip = 0, char_billing = MAX_CHAR_BILLING; AccountDB* accounts = login_get_accounts_db(); memset(pincode,0,PINCODE_LENGTH+1); if( !accounts->load_num(accounts, &acc, aid) ) return -1; else { safestrncpy(email, acc.email, sizeof(email)); expiration_time = acc.expiration_time; group_id = acc.group_id; safestrncpy(birthdate, acc.birthdate, sizeof(birthdate)); safestrncpy(pincode, acc.pincode, sizeof(pincode)); char_slots = login_config.char_per_account; // Respect account information from login-server if( acc.char_slots > 0 ){ char_slots = acc.char_slots; } #ifdef VIP_ENABLE char_vip = login_config.vip_sys.char_increase; if( acc.vip_time > time(nullptr) ) { isvip = true; char_slots += char_vip; } #endif } WFIFOHEAD(fd,75); WFIFOW(fd,0) = 0x2717; WFIFOL(fd,2) = aid; safestrncpy(WFIFOCP(fd,6), email, 40); WFIFOL(fd,46) = (uint32)expiration_time; WFIFOB(fd,50) = (unsigned char)group_id; WFIFOB(fd,51) = char_slots; safestrncpy(WFIFOCP(fd,52), birthdate, 10+1); safestrncpy(WFIFOCP(fd,63), pincode, 4+1 ); WFIFOL(fd,68) = (uint32)acc.pincode_change; WFIFOB(fd,72) = isvip; WFIFOB(fd,73) = char_vip; WFIFOB(fd,74) = char_billing; WFIFOSET(fd,75); return 1; } /** * Transmit vip specific data to char-serv (will be transfered to mapserv) * @param fd * @param acc * @param flag 0x1: VIP, 0x2: GM, 0x4: Show rates on player * @param mapfd */ int32 logchrif_sendvipdata(int32 fd, struct mmo_account* acc, unsigned char flag, int32 mapfd) { #ifdef VIP_ENABLE WFIFOHEAD(fd,19); WFIFOW(fd,0) = 0x2743; WFIFOL(fd,2) = acc->account_id; WFIFOL(fd,6) = (int)acc->vip_time; WFIFOB(fd,10) = flag; WFIFOL(fd,11) = acc->group_id; //new group id WFIFOL(fd,15) = mapfd; //link to mapserv WFIFOSET(fd,19); logchrif_send_accdata(fd,acc->account_id); //refresh char with new setting #endif return 1; } /** * Receive a request for account data reply by sending all mmo_account information. * @param fd: fd to parse from (char-serv) * @param id: id of char-serv * @param ip: char-serv ip (used for info) * @return 0 not enough info transmitted, 1 success */ int32 logchrif_parse_reqaccdata(int32 fd, int32 id, char *ip){ if( RFIFOREST(fd) < 6 ) return 0; else { uint32 aid = RFIFOL(fd,2); RFIFOSKIP(fd,6); if( logchrif_send_accdata(fd,aid) < 0 ) ShowNotice("Char-server '%s': account %d NOT found (ip: %s).\n", ch_server[id].name, aid, ip); } return 1; } /** * Ping request from char-server to send a reply. * @param fd: fd to parse from (char-serv) * @return 1 success */ int32 logchrif_parse_keepalive(int32 fd){ RFIFOSKIP(fd,2); WFIFOHEAD(fd,2); WFIFOW(fd,0) = 0x2718; WFIFOSET(fd,2); return 1; } /** * Map server send information to change an email of an account via char-server. * 0x2722 .L .40B .40B * @param fd: fd to parse from (char-serv) * @param id: id of char-serv * @param ip: char-serv ip (used for info) * @return 0 not enough info transmitted, 1 success */ int32 logchrif_parse_reqchangemail(int32 fd, int32 id, char* ip){ if (RFIFOREST(fd) < 86) return 0; else{ struct mmo_account acc; AccountDB* accounts = login_get_accounts_db(); char actual_email[40]; char new_email[40]; uint32 account_id = RFIFOL(fd,2); safestrncpy(actual_email, RFIFOCP(fd,6), 40); safestrncpy(new_email, RFIFOCP(fd,46), 40); RFIFOSKIP(fd, 86); if( e_mail_check(actual_email) == 0 ) ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual email is invalid (account: %d, ip: %s)\n", ch_server[id].name, account_id, ip); else if( e_mail_check(new_email) == 0 ) ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a invalid new e-mail (account: %d, ip: %s)\n", ch_server[id].name, account_id, ip); else if( strcmpi(new_email, "a@a.com") == 0 ) ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a default e-mail (account: %d, ip: %s)\n", ch_server[id].name, account_id, ip); else if( !accounts->load_num(accounts, &acc, account_id) ) ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but account doesn't exist (account: %d, ip: %s).\n", ch_server[id].name, account_id, ip); else if( strcmpi(acc.email, actual_email) != 0 ) ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual e-mail is incorrect (account: %d (%s), actual e-mail: %s, proposed e-mail: %s, ip: %s).\n", ch_server[id].name, account_id, acc.userid, acc.email, actual_email, ip); else{ safestrncpy(acc.email, new_email, 40); ShowNotice("Char-server '%s': Modify an e-mail on an account (@email GM command) (account: %d (%s), new e-mail: %s, ip: %s).\n", ch_server[id].name, account_id, acc.userid, new_email, ip); // Save accounts->save(accounts, &acc, false); } } return 1; } /** * Receiving an account state update request from a map-server (relayed via char-server). * @param fd: fd to parse from (char-serv) * @param id: id of char-serv * @param ip: char-serv ip (used for info) * @return 0 not enough info transmitted, 1 success * TODO seems pretty damn close to logchrif_parse_reqbanacc */ int32 logchrif_parse_requpdaccstate(int32 fd, int32 id, char* ip){ if (RFIFOREST(fd) < 10) return 0; else{ struct mmo_account acc; uint32 account_id = RFIFOL(fd,2); uint32 state = RFIFOL(fd,6); AccountDB* accounts = login_get_accounts_db(); RFIFOSKIP(fd,10); if( !accounts->load_num(accounts, &acc, account_id) ) ShowNotice("Char-server '%s': Error of Status change (account: %d not found, suggested status %d, ip: %s).\n", ch_server[id].name, account_id, state, ip); else if( acc.state == state ) ShowNotice("Char-server '%s': Error of Status change - actual status is already the good status (account: %d, status %d, ip: %s).\n", ch_server[id].name, account_id, state, ip); else{ ShowNotice("Char-server '%s': Status change (account: %d, new status %d, ip: %s).\n", ch_server[id].name, account_id, state, ip); acc.state = state; // Save accounts->save(accounts, &acc, false); // notify other servers if (state != 0){ uint8 buf[11]; WBUFW(buf,0) = 0x2731; WBUFL(buf,2) = account_id; WBUFB(buf,6) = 0; // 0: change of state, 1: ban WBUFL(buf,7) = state; // status or final date of a banishment logchrif_sendallwos(-1, buf, 11); } } } return 1; } /** * Receiving a ban request from map-server via char-server. * @param fd: fd to parse from (char-serv) * @param id: id of char-serv * @param ip: char-serv ip (used for info) * @return 0 not enough info transmitted, 1 success * TODO check logchrif_parse_requpdaccstate for possible merge */ int32 logchrif_parse_reqbanacc(int32 fd, int32 id, char* ip){ if (RFIFOREST(fd) < 10) return 0; else{ struct mmo_account acc; AccountDB* accounts = login_get_accounts_db(); uint32 account_id = RFIFOL(fd,2); int32 timediff = RFIFOL(fd,6); RFIFOSKIP(fd,10); if( !accounts->load_num(accounts, &acc, account_id) ) ShowNotice("Char-server '%s': Error of ban request (account: %d not found, ip: %s).\n", ch_server[id].name, account_id, ip); else{ time_t timestamp; if (acc.unban_time == 0 || acc.unban_time < time(nullptr)) timestamp = time(nullptr); // new ban else timestamp = acc.unban_time; // add to existing ban timestamp += timediff; if (timestamp == -1) ShowNotice("Char-server '%s': Error of ban request (account: %d, invalid date, ip: %s).\n", ch_server[id].name, account_id, ip); else if( timestamp <= time(nullptr) || timestamp == 0 ) ShowNotice("Char-server '%s': Error of ban request (account: %d, new date unbans the account, ip: %s).\n", ch_server[id].name, account_id, ip); else{ uint8 buf[11]; char tmpstr[24]; timestamp2string(tmpstr, sizeof(tmpstr), timestamp, login_config.date_format); ShowNotice("Char-server '%s': Ban request (account: %d, new final date of banishment: %s, ip: %s).\n", ch_server[id].name, account_id, tmpstr, ip); acc.unban_time = timestamp; // Save accounts->save(accounts, &acc, false); WBUFW(buf,0) = 0x2731; WBUFL(buf,2) = account_id; WBUFB(buf,6) = 1; // 0: change of status, 1: ban WBUFL(buf,7) = (uint32)timestamp; // status or final date of a banishment logchrif_sendallwos(-1, buf, 11); } } } return 1; } /** * Receiving a sex change request (sex is reversed). * @param fd: fd to parse from (char-serv) * @param id: id of char-serv * @param ip: char-serv ip (used for info) * @return 0 not enough info transmitted, 1 success */ int32 logchrif_parse_reqchgsex(int32 fd, int32 id, char* ip){ if( RFIFOREST(fd) < 6 ) return 0; else{ struct mmo_account acc; AccountDB* accounts = login_get_accounts_db(); uint32 account_id = RFIFOL(fd,2); RFIFOSKIP(fd,6); if( !accounts->load_num(accounts, &acc, account_id) ) ShowNotice("Char-server '%s': Error of sex change (account: %d not found, ip: %s).\n", ch_server[id].name, account_id, ip); else if( acc.sex == 'S' ) ShowNotice("Char-server '%s': Error of sex change - account to change is a Server account (account: %d, ip: %s).\n", ch_server[id].name, account_id, ip); else{ unsigned char buf[7]; char sex = ( acc.sex == 'M' ) ? 'F' : 'M'; //Change gender ShowNotice("Char-server '%s': Sex change (account: %d, new sex %c, ip: %s).\n", ch_server[id].name, account_id, sex, ip); acc.sex = sex; // Save accounts->save(accounts, &acc, false); // announce to other servers WBUFW(buf,0) = 0x2723; WBUFL(buf,2) = account_id; WBUFB(buf,6) = sex_str2num(sex); logchrif_sendallwos(-1, buf, 7); } } return 1; } /** * We receive account_reg2 from a char-server, and we send them to other char-servers. * @param fd: fd to parse from (char-serv) * @param id: id of char-serv * @param ip: char-serv ip (used for info) * @return 0 not enough info transmitted, 1 success */ int32 logchrif_parse_upd_global_accreg(int32 fd, int32 id, char* ip){ if( RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2) ) return 0; else{ struct mmo_account acc; AccountDB* accounts = login_get_accounts_db(); uint32 account_id = RFIFOL(fd,4); if( !accounts->load_num(accounts, &acc, account_id) ) ShowStatus("Char-server '%s': receiving (from the char-server) of account_reg2 (account: %d not found, ip: %s).\n", ch_server[id].name, account_id, ip); else mmo_save_global_accreg(accounts,fd,account_id,RFIFOL(fd, 8)); RFIFOSKIP(fd,RFIFOW(fd,2)); } return 1; } /** * Receiving an unban request from map-server via char-server. * @param fd: fd to parse from (char-serv) * @param id: id of char-serv * @param ip: char-serv ip (used for info) * @return 0 not enough info transmitted, 1 success */ int32 logchrif_parse_requnbanacc(int32 fd, int32 id, char* ip){ if( RFIFOREST(fd) < 6 ) return 0; else{ struct mmo_account acc; AccountDB* accounts = login_get_accounts_db(); uint32 account_id = RFIFOL(fd,2); RFIFOSKIP(fd,6); if( !accounts->load_num(accounts, &acc, account_id) ) ShowNotice("Char-server '%s': Error of UnBan request (account: %d not found, ip: %s).\n", ch_server[id].name, account_id, ip); else if( acc.unban_time == 0 ) ShowNotice("Char-server '%s': Error of UnBan request (account: %d, no change for unban date, ip: %s).\n", ch_server[id].name, account_id, ip); else{ ShowNotice("Char-server '%s': UnBan request (account: %d, ip: %s).\n", ch_server[id].name, account_id, ip); acc.unban_time = 0; accounts->save(accounts, &acc, false); } } return 1; } /** * Set account_id to online. * @author [Wizputer] * @param fd: fd to parse from (char-serv) * @param id: id of char-serv * @return 0 not enough info transmitted, 1 success */ int32 logchrif_parse_setacconline(int32 fd, int32 id){ if( RFIFOREST(fd) < 6 ) return 0; login_add_online_user(id, RFIFOL(fd,2)); RFIFOSKIP(fd,6); return 1; } /** * Set account_id to offline. * @author [Wizputer] * @param fd: fd to parse from (char-serv) * @return 0 not enough info transmitted, 1 success */ int32 logchrif_parse_setaccoffline(int32 fd){ if( RFIFOREST(fd) < 6 ) return 0; login_remove_online_user(RFIFOL(fd,2)); RFIFOSKIP(fd,6); return 1; } /** * Receive list of all online accounts. * @author [Skotlex] * @param fd: fd to parse from (char-serv) * @param id: id of char-serv * @return 0 not enough info transmitted, 1 success */ int32 logchrif_parse_updonlinedb(int32 fd, int32 id){ if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) return 0; else{ //Set all chars from this char-server offline first login_online_db_setoffline( id ); for( uint32 i = 0, users = RFIFOW(fd, 4); i < users; i++) { uint32 aid = RFIFOL(fd,6+i*4); login_add_online_user( id, aid ); } RFIFOSKIP(fd,RFIFOW(fd,2)); } return 1; } /** * Request account_reg2 for a character. * @param fd: fd to parse from (char-serv) * @return 0 not enough info transmitted, 1 success */ int32 logchrif_parse_req_global_accreg(int32 fd){ if (RFIFOREST(fd) < 10) return 0; else{ AccountDB* accounts = login_get_accounts_db(); uint32 account_id = RFIFOL(fd,2); uint32 char_id = RFIFOL(fd,6); RFIFOSKIP(fd,10); mmo_send_global_accreg(accounts,fd,account_id,char_id); } return 1; } /** * Received new charip from char-serv, update information. * @param fd: char-serv file descriptor * @param id: char-serv id * @return 0 not enough info transmitted, 1 success */ int32 logchrif_parse_updcharip(int32 fd, int32 id){ if( RFIFOREST(fd) < 6 ) return 0; ch_server[id].ip = ntohl(RFIFOL(fd,2)); ShowInfo("Updated IP of Server #%d to %d.%d.%d.%d.\n",id, CONVIP(ch_server[id].ip)); RFIFOSKIP(fd,6); return 1; } /** * Request to set all accounts offline. * @param fd: fd to parse from (char-serv) * @param id: id of char-serv (char-serv) * @return 1 success */ int32 logchrif_parse_setalloffline(int32 fd, int32 id){ ShowInfo("Setting accounts from char-server %d offline.\n", id); login_online_db_setoffline( id ); RFIFOSKIP(fd,2); return 1; } #if PACKETVER_SUPPORTS_PINCODE /** * Request to change PIN Code for an account. * @param fd: fd to parse from (char-serv) * @return 0 fail (packet does not have enough data), 1 success */ int32 logchrif_parse_updpincode(int32 fd){ if( RFIFOREST(fd) < 8 + PINCODE_LENGTH+1 ) return 0; else{ struct mmo_account acc; AccountDB* accounts = login_get_accounts_db(); if( accounts->load_num(accounts, &acc, RFIFOL(fd,4) ) ){ strncpy( acc.pincode, RFIFOCP(fd,8), PINCODE_LENGTH+1 ); acc.pincode_change = time( nullptr ); accounts->save(accounts, &acc, false); } RFIFOSKIP(fd,8 + PINCODE_LENGTH+1); } return 1; } /** * PIN Code was incorrectly entered too many times. * @param fd: fd to parse from (char-serv) * @return 0 fail (packet does not have enough data), 1 success (continue parsing) */ int32 logchrif_parse_pincode_authfail(int32 fd){ if( RFIFOREST(fd) < 6 ) return 0; else{ struct mmo_account acc; AccountDB* accounts = login_get_accounts_db(); if( accounts->load_num(accounts, &acc, RFIFOL(fd,2) ) ){ struct online_login_data* ld = login_get_online_user( acc.account_id ); if( ld == nullptr ){ return 0; } login_log( host2ip(acc.last_ip), acc.userid, 100, "PIN Code check failed" ); } login_remove_online_user(acc.account_id); RFIFOSKIP(fd,6); } return 1; } #endif /** * Received a vip data reqest from char * type is the query to perform * 0x1 : Select info and update old_groupid * 0x2 : VIP duration is changed by atcommand or script * 0x8 : First request on player login * @param fd link to charserv * @return 0 missing data, 1 succeeded */ int32 logchrif_parse_reqvipdata(int32 fd) { #ifdef VIP_ENABLE if( RFIFOREST(fd) < 15 ) return 0; else { //request vip info struct mmo_account acc; AccountDB* accounts = login_get_accounts_db(); int32 aid = RFIFOL(fd,2); int8 flag = RFIFOB(fd,6); int32 timediff = RFIFOL(fd,7); int32 mapfd = RFIFOL(fd,11); RFIFOSKIP(fd,15); if( accounts->load_num(accounts, &acc, aid ) ) { time_t now = time(nullptr); time_t vip_time = acc.vip_time; bool isvip = false; if( acc.group_id > login_config.vip_sys.group ) { //Don't change group if it's higher. logchrif_sendvipdata(fd,&acc,0x2|((flag&0x8)?0x4:0),mapfd); return 1; } if( flag&2 ) { if(!vip_time) vip_time = now; //new entry vip_time += timediff; // set new duration } if( now < vip_time ) { //isvip if(acc.group_id != login_config.vip_sys.group){ //only upd this if we're not vip already acc.old_group = acc.group_id; if( acc.char_slots == 0 ){ acc.char_slots = MIN_CHARS; } acc.char_slots += login_config.vip_sys.char_increase; } acc.group_id = login_config.vip_sys.group; isvip = true; } else { //expired or @vip -xx vip_time = 0; if(acc.group_id == login_config.vip_sys.group){ //prevent alteration in case account wasn't registered as vip yet acc.group_id = acc.old_group; if( acc.char_slots == 0 ){ acc.char_slots = MIN_CHARS; }else{ acc.char_slots -= login_config.vip_sys.char_increase; } } acc.old_group = 0; } acc.vip_time = vip_time; accounts->save(accounts,&acc, false); if( flag&1 ) logchrif_sendvipdata(fd,&acc,((isvip)?0x1:0)|((flag&0x8)?0x4:0),mapfd); } } #endif return 1; } /** * IA 0x2720 * Get account info that asked by inter/char-server */ int32 logchrif_parse_accinfo(int32 fd) { if( RFIFOREST(fd) < 19 ) return 0; else { int32 map_fd = RFIFOL(fd, 2), u_fd = RFIFOL(fd, 6), u_aid = RFIFOL(fd, 10), account_id = RFIFOL(fd, 14); int8 type = RFIFOB(fd, 18); AccountDB* accounts = login_get_accounts_db(); struct mmo_account acc; RFIFOSKIP(fd,19); // Send back the result to char-server if (accounts->load_num(accounts, &acc, account_id)) { int32 len = 122 + NAME_LENGTH; //ShowInfo("Found account info for %d, requested by %d\n", account_id, u_aid); WFIFOHEAD(fd, len); WFIFOW(fd, 0) = 0x2721; WFIFOL(fd, 2) = map_fd; WFIFOL(fd, 6) = u_fd; WFIFOL(fd, 10) = u_aid; WFIFOL(fd, 14) = account_id; WFIFOB(fd, 18) = (1<flag.eof ){ do_close(fd); ch_server[cid].fd = -1; logchrif_on_disconnect(cid); return 0; } ipl = ch_server[cid].ip; ip2str(ipl, ip); while( RFIFOREST(fd) >= 2 ){ int32 next = 1; // 0: avoid processing followup packets (prev was probably incomplete) packet, 1: Continue parsing uint16 command = RFIFOW(fd,0); switch( command ){ case 0x2712: next = logchrif_parse_reqauth(fd, cid, ip); break; case 0x2714: next = logchrif_parse_ackusercount(fd, cid); break; case 0x2716: next = logchrif_parse_reqaccdata(fd, cid, ip); break; case 0x2719: next = logchrif_parse_keepalive(fd); break; case 0x2720: next = logchrif_parse_accinfo(fd); break; //@accinfo from inter-server case 0x2722: next = logchrif_parse_reqchangemail(fd,cid,ip); break; case 0x2724: next = logchrif_parse_requpdaccstate(fd,cid,ip); break; case 0x2725: next = logchrif_parse_reqbanacc(fd,cid,ip); break; case 0x2727: next = logchrif_parse_reqchgsex(fd,cid,ip); break; case 0x2728: next = logchrif_parse_upd_global_accreg(fd,cid,ip); break; case 0x272a: next = logchrif_parse_requnbanacc(fd,cid,ip); break; case 0x272b: next = logchrif_parse_setacconline(fd,cid); break; case 0x272c: next = logchrif_parse_setaccoffline(fd); break; case 0x272d: next = logchrif_parse_updonlinedb(fd,cid); break; case 0x272e: next = logchrif_parse_req_global_accreg(fd); break; case 0x2736: next = logchrif_parse_updcharip(fd,cid); break; case 0x2737: next = logchrif_parse_setalloffline(fd,cid); break; #if PACKETVER_SUPPORTS_PINCODE case 0x2738: next = logchrif_parse_updpincode(fd); break; case 0x2739: next = logchrif_parse_pincode_authfail(fd); break; #endif case 0x2742: next = logchrif_parse_reqvipdata(fd); break; //Vip sys default: ShowError("logchrif_parse: Unknown packet 0x%x from a char-server! Disconnecting!\n", command); set_eof(fd); return 0; } // switch if (next == 0) return 0; } // while return 1; //or 0 } /// Constructor destructor and signal handlers /** * Initializes a server structure. * @param id: id of char-serv (should be >0, FIXME) */ void logchrif_server_init(int32 id) { memset(&ch_server[id], 0, sizeof(ch_server[id])); ch_server[id].fd = -1; } /** * Destroys a server structure. * @param id: id of char-serv (should be >0, FIXME) */ void logchrif_server_destroy(int32 id){ if( ch_server[id].fd != -1 ) { do_close(ch_server[id].fd); ch_server[id].fd = -1; } } /** * Resets all the data related to a server. * Actually destroys then recreates the struct. * @param id: id of char-serv (should be >0, FIXME) */ void logchrif_server_reset(int32 id) { login_online_db_setoffline(id); //Set all chars from this char server to offline. logchrif_server_destroy(id); logchrif_server_init(id); } /** * Called when the connection to Char Server is disconnected. * @param id: id of char-serv (should be >0, FIXME) */ void logchrif_on_disconnect(int32 id) { ShowStatus("Char-server '%s' has disconnected.\n", ch_server[id].name); logchrif_server_reset(id); } /** * loginchrif constructor * Initialisation, function called at start of the login-serv. */ void do_init_loginchrif(void){ int32 i; for( i = 0; i < ARRAYLENGTH(ch_server); ++i ) logchrif_server_init(i); // add timer to detect ip address change and perform update if (login_config.ip_sync_interval) { add_timer_func_list(logchrif_sync_ip_addresses, "sync_ip_addresses"); add_timer_interval(gettick() + login_config.ip_sync_interval, logchrif_sync_ip_addresses, 0, 0, login_config.ip_sync_interval); } } /** * Signal handler * This function attempts to properly close the server when an interrupt signal is received. * current signal catch : SIGTERM, SIGINT */ void do_shutdown_loginchrif(void){ int32 id; for( id = 0; id < ARRAYLENGTH(ch_server); ++id ) logchrif_server_reset(id); } /** * loginchrif destructor * dealloc..., function called at exit of the login-serv */ void do_final_loginchrif(void){ int32 i; for( i = 0; i < ARRAYLENGTH(ch_server); ++i ) logchrif_server_destroy(i); }