int recv_to_fifo(int fd) { int len; if( !session_isActive(fd) ) return -1; len = sRecv(fd, (char *) session[fd]->rdata + session[fd]->rdata_size, (int)RFIFOSPACE(fd), 0); if( len == SOCKET_ERROR ) {//An exception has occured if( sErrno != S_EWOULDBLOCK ) { //ShowDebug("recv_to_fifo: code %d, closing connection #%d\n", sErrno, fd); set_eof(fd); } return 0; } if( len == 0 ) {//Normal connection end. set_eof(fd); return 0; } session[fd]->rdata_size += len; session[fd]->rdata_tick = last_tick; return 0; }
int chlogif_parse_ackaccreq(int fd, struct char_session_data* sd){ if (RFIFOREST(fd) < 21) return 0; { uint32 account_id = RFIFOL(fd,2); uint32 login_id1 = RFIFOL(fd,6); uint32 login_id2 = RFIFOL(fd,10); uint8 sex = RFIFOB(fd,14); uint8 result = RFIFOB(fd,15); int request_id = RFIFOL(fd,16); uint8 clienttype = RFIFOB(fd,20); RFIFOSKIP(fd,21); if( session_isActive(request_id) && (sd=(struct char_session_data*)session[request_id]->session_data) && !sd->auth && sd->account_id == account_id && sd->login_id1 == login_id1 && sd->login_id2 == login_id2 && sd->sex == sex ) { int client_fd = request_id; sd->clienttype = clienttype; switch( result ) { case 0:// ok char_auth_ok(client_fd, sd); break; case 1:// auth failed chclif_reject(client_fd,0); // rejected from server break; } } } return 1; }
/** * Player requesting to change map-serv * @param fd: wich fd to parse from * @return : 0 not enough data received, 1 success */ int chmapif_parse_reqchangemapserv(int fd){ if (RFIFOREST(fd) < 39) return 0; { int map_id, map_fd = -1; struct mmo_charstatus* char_data; struct mmo_charstatus char_dat; DBMap* char_db_ = char_get_chardb(); map_id = char_search_mapserver(RFIFOW(fd,18), ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port. if (map_id >= 0) map_fd = map_server[map_id].fd; //Char should just had been saved before this packet, so this should be safe. [Skotlex] char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14)); if (char_data == NULL) { //Really shouldn't happen. char_mmo_char_fromsql(RFIFOL(fd,14), &char_dat, true); char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14)); } if( runflag == CHARSERVER_ST_RUNNING && session_isActive(map_fd) && char_data ) { //Send the map server the auth of this player. struct online_char_data* data; struct auth_node* node; DBMap* auth_db = char_get_authdb(); DBMap* online_char_db = char_get_onlinedb(); int aid = RFIFOL(fd,2); //Update the "last map" as this is where the player must be spawned on the new map server. char_data->last_point.map = RFIFOW(fd,18); char_data->last_point.x = RFIFOW(fd,20); char_data->last_point.y = RFIFOW(fd,22); char_data->sex = RFIFOB(fd,30); // create temporary auth entry CREATE(node, struct auth_node, 1); node->account_id = aid; node->char_id = RFIFOL(fd,14); node->login_id1 = RFIFOL(fd,6); node->login_id2 = RFIFOL(fd,10); node->sex = RFIFOB(fd,30); node->expiration_time = 0; // FIXME (this thing isn't really supported we could as well purge it instead of fixing) node->ip = ntohl(RFIFOL(fd,31)); node->group_id = RFIFOL(fd,35); node->changing_mapservers = 1; idb_put(auth_db, aid, node); data = idb_ensure(online_char_db, aid, char_create_online_data); data->char_id = char_data->char_id; data->server = map_id; //Update server where char is. //Reply with an ack. chmapif_changemapserv_ack(fd,0); } else { //Reply with nak chmapif_changemapserv_ack(fd,1); } RFIFOSKIP(fd,39); }
int recv_to_fifo(int fd) { int len; if( !session_isActive(fd) ) return -1; len = sRecv(fd, (char *) session[fd]->rdata + session[fd]->rdata_size, (int)RFIFOSPACE(fd), 0); if( len == SOCKET_ERROR ) { //An exception has occured if( sErrno != S_EWOULDBLOCK ) { //ShowDebug("recv_to_fifo: %s, closing connection #%d\n", error_msg(), fd); set_eof(fd); } return 0; } if( len == 0 ) { //Normal connection end. set_eof(fd); return 0; } session[fd]->rdata_size += len; session[fd]->rdata_tick = last_tick; #ifdef SHOW_SERVER_STATS socket_data_i += len; socket_data_qi += len; if (!session[fd]->flag.server) { socket_data_ci += len; } #endif return 0; }
void mapif_parse_accinfo2(bool success, int map_fd, int u_fd, int u_aid, int account_id, const char *userid, const char *user_pass, const char *email, const char *last_ip, const char *lastlogin, const char *pin_code, const char *birthdate, int group_id, int logincount, int state) { if (map_fd <= 0 || !session_isActive(map_fd)) return; // check if we have a valid fd if(!success) { inter_msg_to_fd(map_fd, u_fd, u_aid, "No account with ID '%d' was found.", account_id); return; } inter_msg_to_fd(map_fd, u_fd, u_aid, read_message("Source.char.inter_parse_accinfo_s7"), account_id); inter_msg_to_fd(map_fd, u_fd, u_aid, read_message("Source.char.inter_parse_accinfo_s8"), userid, group_id, state); if(user_pass && *user_pass != '\0') { /* password is only received if your gm level is greater than the one you're searching for */ if(pin_code && *pin_code != '\0') inter_msg_to_fd(map_fd, u_fd, u_aid, read_message("Source.char.inter_parse_accinfo_s17"), user_pass, pin_code); else inter_msg_to_fd(map_fd, u_fd, u_aid, read_message("Source.char.inter_parse_accinfo_s9"), user_pass); } inter_msg_to_fd(map_fd, u_fd, u_aid, read_message("Source.char.inter_parse_accinfo_s10"), email, birthdate); inter_msg_to_fd(map_fd, u_fd, u_aid, read_message("Source.char.inter_parse_accinfo_s11"), last_ip, geoip_getcountry(str2ip(last_ip))); inter_msg_to_fd(map_fd, u_fd, u_aid, read_message("Source.char.inter_parse_accinfo_s12"), logincount, lastlogin); inter_msg_to_fd(map_fd, u_fd, u_aid, read_message("Source.char.inter_parse_accinfo_s13")); if(SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`, `name`, `char_num`, `class`, `base_level`, `job_level`, `online` " "FROM `%s` WHERE `account_id` = '%d' ORDER BY `char_num` LIMIT %d", char_db, account_id, MAX_CHARS) || Sql_NumRows(sql_handle) == 0) { if(Sql_NumRows(sql_handle) == 0) { inter_msg_to_fd(map_fd, u_fd, u_aid, read_message("Source.char.inter_parse_accinfo_s14")); } else { inter_msg_to_fd(map_fd, u_fd, u_aid, read_message("Source.char.inter_parse_accinfo_s15")); Sql_ShowDebug(sql_handle); } } else { while(SQL_SUCCESS == Sql_NextRow(sql_handle)) { char *data; int char_id, class_; short char_num, base_level, job_level, online; char name[NAME_LENGTH]; Sql_GetData(sql_handle, 0, &data, NULL); char_id = atoi(data); Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name)); Sql_GetData(sql_handle, 2, &data, NULL); char_num = atoi(data); Sql_GetData(sql_handle, 3, &data, NULL); class_ = atoi(data); Sql_GetData(sql_handle, 4, &data, NULL); base_level = atoi(data); Sql_GetData(sql_handle, 5, &data, NULL); job_level = atoi(data); Sql_GetData(sql_handle, 6, &data, NULL); online = atoi(data); inter_msg_to_fd(map_fd, u_fd, u_aid, read_message("Source.char.inter_parse_accinfo_s16"), char_num, char_id, name, job_name(class_), base_level, job_level, online?"On":"Off"); } } Sql_FreeResult(sql_handle); return; }
// Save account_reg into sql (type=2) int mapif_parse_Registry(int fd) { int account_id = RFIFOL(fd, 4), char_id = RFIFOL(fd, 8), count = RFIFOW(fd, 12); if( count ) { int cursor = 14, i; bool isLoginActive = session_isActive(login_fd); if( isLoginActive ) chlogif_upd_global_accreg(account_id,char_id); for(i = 0; i < count; i++) { size_t lenkey = RFIFOB( fd, cursor ); const char* src_key= RFIFOCP(fd, cursor + 1); std::string key( src_key, lenkey ); cursor += lenkey + 1; unsigned int index = RFIFOL(fd, cursor); cursor += 4; switch (RFIFOB(fd, cursor++)) { // int case 0: { intptr_t lVal = RFIFOL( fd, cursor ); inter_savereg( account_id, char_id, key.c_str(), index, lVal, false ); cursor += 4; break; } case 1: inter_savereg(account_id,char_id,key.c_str(),index,0,false); break; // str case 2: { size_t len_val = RFIFOB( fd, cursor ); const char* src_val= RFIFOCP(fd, cursor + 1); std::string sval( src_val, len_val ); cursor += len_val + 1; inter_savereg( account_id, char_id, key.c_str(), index, (intptr_t)sval.c_str(), true ); break; } case 3: inter_savereg(account_id,char_id,key.c_str(),index,0,true); break; default: ShowError("mapif_parse_Registry: unknown type %d\n",RFIFOB(fd, cursor - 1)); return 1; } } if (isLoginActive) chlogif_prepsend_global_accreg(); } return 0; }
/*====================================== * CORE : Socket Sub Function *--------------------------------------*/ void set_eof(int fd) { if(session_isActive(fd)) { #ifdef SEND_SHORTLIST // Add this socket to the shortlist for eof handling. send_shortlist_add_fd(fd); #endif session[fd]->flag.eof = 1; } }
/** * Show account info from login-server to user */ void mapif_accinfo_ack(bool success, int map_fd, int u_fd, int u_aid, int account_id, int8 type, int group_id, int logincount, int state, const char *email, const char *last_ip, const char *lastlogin, const char *birthdate, const char *user_pass, const char *pincode, const char *userid) { if (map_fd <= 0 || !session_isActive(map_fd)) return; // check if we have a valid fd if (!success) { inter_to_fd(map_fd, u_fd, u_aid, (char *)msg_txt(216), account_id); return; } if (type == 1) { //type 1 we don't want all the info [lighta] @CHECKME mapif_acc_info_ack(map_fd, u_fd, account_id, userid); return; } inter_to_fd(map_fd, u_fd, u_aid, (char *)msg_txt(217), account_id); inter_to_fd(map_fd, u_fd, u_aid, (char *)msg_txt(218), userid, group_id, state); inter_to_fd(map_fd, u_fd, u_aid, (char *)msg_txt(219), user_pass[0] != '\0' ? user_pass : msg_txt(220), pincode[0] != '\0' ? msg_txt(220) : pincode); inter_to_fd(map_fd, u_fd, u_aid, (char *)msg_txt(221), email, birthdate); inter_to_fd(map_fd, u_fd, u_aid, (char *)msg_txt(222), last_ip, geoip_getcountry(str2ip(last_ip))); inter_to_fd(map_fd, u_fd, u_aid, (char *)msg_txt(223), logincount, lastlogin); inter_to_fd(map_fd, u_fd, u_aid, (char *)msg_txt(224)); if ( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`, `name`, `char_num`, `class`, `base_level`, `job_level`, `online` FROM `%s` WHERE `account_id` = '%d' ORDER BY `char_num` LIMIT %d", schema_config.char_db, account_id, MAX_CHARS) || Sql_NumRows(sql_handle) == 0 ) { if( Sql_NumRows(sql_handle) == 0 ) inter_to_fd(map_fd, u_fd, u_aid, (char *)msg_txt(226)); else { inter_to_fd(map_fd, u_fd, u_aid, (char *)msg_txt(213)); Sql_ShowDebug(sql_handle); } } else { while ( SQL_SUCCESS == Sql_NextRow(sql_handle) ) { uint32 char_id, class_; short char_num, base_level, job_level, online; char name[NAME_LENGTH]; char *data; Sql_GetData(sql_handle, 0, &data, NULL); char_id = atoi(data); Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name)); Sql_GetData(sql_handle, 2, &data, NULL); char_num = atoi(data); Sql_GetData(sql_handle, 3, &data, NULL); class_ = atoi(data); Sql_GetData(sql_handle, 4, &data, NULL); base_level = atoi(data); Sql_GetData(sql_handle, 5, &data, NULL); job_level = atoi(data); Sql_GetData(sql_handle, 6, &data, NULL); online = atoi(data); inter_to_fd(map_fd, u_fd, u_aid, (char *)msg_txt(225), char_num, char_id, name, job_name(class_), base_level, job_level, online?"Online":"Offline"); } } Sql_FreeResult(sql_handle); }
void mapif_parse_accinfo2(bool success, int map_fd, int u_fd, int u_aid, int account_id, const char *userid, const char *user_pass, const char *email, const char *last_ip, const char *lastlogin, const char *pin_code, const char *birthdate, int group_id, int logincount, int state) { if (map_fd <= 0 || !session_isActive(map_fd)) return; // check if we have a valid fd if (!success) { inter_msg_to_fd(map_fd, u_fd, u_aid, "Nenhuma conta com ID '%d' foi encontrada.", account_id); return; } inter_msg_to_fd(map_fd, u_fd, u_aid, "-- Conta %d --", account_id); inter_msg_to_fd(map_fd, u_fd, u_aid, "Usuário: %s | Nível de Conta: %d | Estado: %d", userid, group_id, state); if (user_pass && *user_pass != '\0') { /* password is only received if your gm level is greater than the one you're searching for */ if (pin_code && *pin_code != '\0') inter_msg_to_fd(map_fd, u_fd, u_aid, "Senha: %s (PIN:%s)", user_pass, pin_code); else inter_msg_to_fd(map_fd, u_fd, u_aid, "Senha: %s", user_pass ); } inter_msg_to_fd(map_fd, u_fd, u_aid, "E-mail da conta: %s | Data de Aniversário: %s", email, birthdate); inter_msg_to_fd(map_fd, u_fd, u_aid, "Último IP: %s (%s)", last_ip, geoip_getcountry(str2ip(last_ip))); inter_msg_to_fd(map_fd, u_fd, u_aid, "Este usuário já logou %d vezes. Última vez em: %s", logincount, lastlogin); inter_msg_to_fd(map_fd, u_fd, u_aid, "-- Detalhes do Personagem --"); if ( SQL_ERROR == SQL->Query(sql_handle, "SELECT `char_id`, `name`, `char_num`, `class`, `base_level`, `job_level`, `online` " "FROM `%s` WHERE `account_id` = '%d' ORDER BY `char_num` LIMIT %d", char_db, account_id, MAX_CHARS) || SQL->NumRows(sql_handle) == 0 ) { if (SQL->NumRows(sql_handle) == 0) { inter_msg_to_fd(map_fd, u_fd, u_aid, "Esta conta não possui personagens."); } else { inter_msg_to_fd(map_fd, u_fd, u_aid, "Falha na pesquisa de dados."); Sql_ShowDebug(sql_handle); } } else { while ( SQL_SUCCESS == SQL->NextRow(sql_handle) ) { char *data; int char_id, class_; short char_num, base_level, job_level, online; char name[NAME_LENGTH]; SQL->GetData(sql_handle, 0, &data, NULL); char_id = atoi(data); SQL->GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name)); SQL->GetData(sql_handle, 2, &data, NULL); char_num = atoi(data); SQL->GetData(sql_handle, 3, &data, NULL); class_ = atoi(data); SQL->GetData(sql_handle, 4, &data, NULL); base_level = atoi(data); SQL->GetData(sql_handle, 5, &data, NULL); job_level = atoi(data); SQL->GetData(sql_handle, 6, &data, NULL); online = atoi(data); inter_msg_to_fd(map_fd, u_fd, u_aid, "[Slot/CID: %d/%d] %s | %s | Nível: %d/%d | %s", char_num, char_id, name, job_name(class_), base_level, job_level, online?"On":"Off"); } } SQL->FreeResult(sql_handle); return; }
void mapif_parse_accinfo2(bool success, int map_fd, int u_fd, int u_aid, int account_id, const char *userid, const char *user_pass, const char *email, const char *last_ip, const char *lastlogin, const char *pin_code, const char *birthdate, int group_id, int logincount, int state) { if (map_fd <= 0 || !session_isActive(map_fd)) return; // check if we have a valid fd if (!success) { inter_msg_to_fd(map_fd, u_fd, u_aid, "No account with ID '%d' was found.", account_id); return; } inter_msg_to_fd(map_fd, u_fd, u_aid, "-- Account %d --", account_id); inter_msg_to_fd(map_fd, u_fd, u_aid, "User: %s | GM Group: %d | State: %d", userid, group_id, state); if (user_pass && *user_pass != '\0') { /* password is only received if your gm level is greater than the one you're searching for */ if (pin_code && *pin_code != '\0') inter_msg_to_fd(map_fd, u_fd, u_aid, "Password: %s (PIN:%s)", user_pass, pin_code); else inter_msg_to_fd(map_fd, u_fd, u_aid, "Password: %s", user_pass ); } inter_msg_to_fd(map_fd, u_fd, u_aid, "Account e-mail: %s | Birthdate: %s", email, birthdate); inter_msg_to_fd(map_fd, u_fd, u_aid, "Last IP: %s (%s)", last_ip, geoip_getcountry(str2ip(last_ip))); inter_msg_to_fd(map_fd, u_fd, u_aid, "This user has logged %d times, the last time were at %s", logincount, lastlogin); inter_msg_to_fd(map_fd, u_fd, u_aid, "-- Character Details --"); if ( SQL_ERROR == SQL->Query(sql_handle, "SELECT `char_id`, `name`, `char_num`, `class`, `base_level`, `job_level`, `online` " "FROM `%s` WHERE `account_id` = '%d' ORDER BY `char_num` LIMIT %d", char_db, account_id, MAX_CHARS) || SQL->NumRows(sql_handle) == 0 ) { if (SQL->NumRows(sql_handle) == 0) { inter_msg_to_fd(map_fd, u_fd, u_aid, "This account doesn't have characters."); } else { inter_msg_to_fd(map_fd, u_fd, u_aid, "An error occurred, bother your admin about it."); Sql_ShowDebug(sql_handle); } } else { while ( SQL_SUCCESS == SQL->NextRow(sql_handle) ) { char *data; int char_id, class_; short char_num, base_level, job_level, online; char name[NAME_LENGTH]; SQL->GetData(sql_handle, 0, &data, NULL); char_id = atoi(data); SQL->GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name)); SQL->GetData(sql_handle, 2, &data, NULL); char_num = atoi(data); SQL->GetData(sql_handle, 3, &data, NULL); class_ = atoi(data); SQL->GetData(sql_handle, 4, &data, NULL); base_level = atoi(data); SQL->GetData(sql_handle, 5, &data, NULL); job_level = atoi(data); SQL->GetData(sql_handle, 6, &data, NULL); online = atoi(data); inter_msg_to_fd(map_fd, u_fd, u_aid, "[Slot/CID: %d/%d] %s | %s | Level: %d/%d | %s", char_num, char_id, name, job_name(class_), base_level, job_level, online?"On":"Off"); } } SQL->FreeResult(sql_handle); return; }
// Save account_reg into sql (type=2) int mapif_parse_Registry(int fd) { int account_id = RFIFOL(fd, 4), char_id = RFIFOL(fd, 8), count = RFIFOW(fd, 12); if( count ) { int cursor = 14, i; char key[32], sval[254]; unsigned int index; bool isLoginActive = session_isActive(login_fd); if( isLoginActive ) global_accreg_to_login_start(account_id,char_id); for(i = 0; i < count; i++) { safestrncpy(key, (char*)RFIFOP(fd, cursor + 1), RFIFOB(fd, cursor)); cursor += RFIFOB(fd, cursor) + 1; index = RFIFOL(fd, cursor); cursor += 4; switch (RFIFOB(fd, cursor++)) { /* int */ case 0: inter_savereg(account_id,char_id,key,index,RFIFOL(fd, cursor),false); cursor += 4; break; case 1: inter_savereg(account_id,char_id,key,index,0,false); break; /* str */ case 2: safestrncpy(sval, (char*)RFIFOP(fd, cursor + 1), RFIFOB(fd, cursor)); cursor += RFIFOB(fd, cursor) + 1; inter_savereg(account_id,char_id,key,index,(intptr_t)sval,true); break; case 3: inter_savereg(account_id,char_id,key,index,0,true); break; default: ShowError("mapif_parse_Registry: unknown type %d\n",RFIFOB(fd, cursor - 1)); return 1; } } if( isLoginActive ) global_accreg_to_login_send(); } return 0; }
int chlogif_parse_ackaccreq(int fd, struct char_session_data* sd){ if (RFIFOREST(fd) < 25) return 0; { int account_id = RFIFOL(fd,2); uint32 login_id1 = RFIFOL(fd,6); uint32 login_id2 = RFIFOL(fd,10); uint8 sex = RFIFOB(fd,14); uint8 result = RFIFOB(fd,15); int request_id = RFIFOL(fd,16); uint32 version = RFIFOL(fd,20); uint8 clienttype = RFIFOB(fd,24); RFIFOSKIP(fd,25); if( session_isActive(request_id) && (sd=(struct char_session_data*)session[request_id]->session_data) && !sd->auth && sd->account_id == account_id && sd->login_id1 == login_id1 && sd->login_id2 == login_id2 && sd->sex == sex ) { int client_fd = request_id; sd->version = version; sd->clienttype = clienttype; if(sd->version != date2version(PACKETVER)) ShowWarning("s aid=%d has an incorect version=%d in clientinfo. Server compiled for %d\n", sd->account_id,sd->version,date2version(PACKETVER)); switch( result ) { case 0:// ok char_auth_ok(client_fd, sd); break; case 1:// auth failed WFIFOHEAD(client_fd,3); WFIFOW(client_fd,0) = 0x6c; WFIFOB(client_fd,2) = 0;// rejected from server WFIFOSET(client_fd,3); break; } } } return 1; }
/*====================================== * CORE : Socket Sub Function *-------------------------------------- */ static void set_eof(int fd) { //Marks a connection eof and invokes the parse_function to disconnect it right away. [Skotlex] if (session_isActive(fd)) session[fd]->eof=1; }
/** * Auth successful, inform client and create a temp auth_node. * @param sd: player session */ static void logclif_auth_ok(struct login_session_data* sd) { int fd = sd->fd; uint32 ip = session[fd]->client_addr; uint8 server_num, n; uint32 subnet_char_ip; struct auth_node* node; int i; #if PACKETVER < 20170315 int cmd = 0x69; // AC_ACCEPT_LOGIN int header = 47; int size = 32; #else int cmd = 0xac4; // AC_ACCEPT_LOGIN3 int header = 64; int size = 160; #endif if( runflag != LOGINSERVER_ST_RUNNING ){ // players can only login while running logclif_sent_auth_result(fd,1); // server closed return; } if( login_config.group_id_to_connect >= 0 && sd->group_id != login_config.group_id_to_connect ) { ShowStatus("Connection refused: the required group id for connection is %d (account: %s, group: %d).\n", login_config.group_id_to_connect, sd->userid, sd->group_id); logclif_sent_auth_result(fd,1); // server closed return; } else if( login_config.min_group_id_to_connect >= 0 && login_config.group_id_to_connect == -1 && sd->group_id < login_config.min_group_id_to_connect ) { ShowStatus("Connection refused: the minimum group id required for connection is %d (account: %s, group: %d).\n", login_config.min_group_id_to_connect, sd->userid, sd->group_id); logclif_sent_auth_result(fd,1); // server closed return; } server_num = 0; for( i = 0; i < ARRAYLENGTH(ch_server); ++i ) if( session_isActive(ch_server[i].fd) ) server_num++; if( server_num == 0 ) {// if no char-server, don't send void list of servers, just disconnect the player with proper message ShowStatus("Connection refused: there is no char-server online (account: %s).\n", sd->userid); logclif_sent_auth_result(fd,1); // server closed return; } { struct online_login_data* data = (struct online_login_data*)idb_get(online_db, sd->account_id); if( data ) {// account is already marked as online! if( data->char_server > -1 ) {// Request char servers to kick this account out. [Skotlex] uint8 buf[6]; ShowNotice("User '%s' is already online - Rejected.\n", sd->userid); WBUFW(buf,0) = 0x2734; WBUFL(buf,2) = sd->account_id; logchrif_sendallwos(-1, buf, 6); if( data->waiting_disconnect == INVALID_TIMER ) data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, login_waiting_disconnect_timer, sd->account_id, 0); logclif_sent_auth_result(fd,8); // 08 = Server still recognizes your last login return; } else if( data->char_server == -1 ) {// client has authed but did not access char-server yet // wipe previous session idb_remove(auth_db, sd->account_id); login_remove_online_user(sd->account_id); data = NULL; } } } login_log(ip, sd->userid, 100, "login ok"); ShowStatus("Connection of the account '%s' accepted.\n", sd->userid); WFIFOHEAD(fd,header+size*server_num); WFIFOW(fd,0) = cmd; WFIFOW(fd,2) = header+size*server_num; WFIFOL(fd,4) = sd->login_id1; WFIFOL(fd,8) = sd->account_id; WFIFOL(fd,12) = sd->login_id2; WFIFOL(fd,16) = 0; // in old version, that was for ip (not more used) //memcpy(WFIFOP(fd,20), sd->lastlogin, 24); // in old version, that was for name (not more used) memset(WFIFOP(fd,20), 0, 24); WFIFOW(fd,44) = 0; // unknown WFIFOB(fd,46) = sex_str2num(sd->sex); #if PACKETVER >= 20170315 memset(WFIFOP(fd,47),0,17); // Unknown #endif for( i = 0, n = 0; i < ARRAYLENGTH(ch_server); ++i ) { if( !session_isValid(ch_server[i].fd) ) continue; subnet_char_ip = lan_subnetcheck(ip); // Advanced subnet check [LuzZza] WFIFOL(fd,header+n*size) = htonl((subnet_char_ip) ? subnet_char_ip : ch_server[i].ip); WFIFOW(fd,header+n*size+4) = ntows(htons(ch_server[i].port)); // [!] LE byte order here [!] memcpy(WFIFOP(fd,header+n*size+6), ch_server[i].name, 20); WFIFOW(fd,header+n*size+26) = ch_server[i].users; WFIFOW(fd,header+n*size+28) = ch_server[i].type; WFIFOW(fd,header+n*size+30) = ch_server[i].new_; #if PACKETVER >= 20170315 memset(WFIFOP(fd, header+n*size+32), 0, 128); // Unknown #endif n++; } WFIFOSET(fd,header+size*server_num); // create temporary auth entry CREATE(node, struct auth_node, 1); node->account_id = sd->account_id; node->login_id1 = sd->login_id1; node->login_id2 = sd->login_id2; node->sex = sd->sex; node->ip = ip; node->clienttype = sd->clienttype; idb_put(auth_db, sd->account_id, node); { struct online_login_data* data; // mark client as 'online' data = login_add_online_user(-1, sd->account_id); // schedule deletion of this node data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, login_waiting_disconnect_timer, sd->account_id, 0); } }