int chlogif_parse(int fd) { struct char_session_data* sd = NULL; // only process data from the login-server if( fd != login_fd ) { ShowDebug("parse_fromlogin: Disconnecting invalid session #%d (is not the login-server)\n", fd); do_close(fd); return 0; } if( session[fd]->flag.eof ) { do_close(fd); login_fd = -1; chlogif_on_disconnect(); return 0; } else if ( session[fd]->flag.ping ) {/* we've reached stall time */ if( DIFF_TICK(last_tick, session[fd]->rdata_tick) > (stall_time * 2) ) {/* we can't wait any longer */ set_eof(fd); return 0; } else if( session[fd]->flag.ping != 2 ) { /* we haven't sent ping out yet */ WFIFOHEAD(fd,2);// sends a ping packet to login server (will receive pong 0x2718) WFIFOW(fd,0) = 0x2719; WFIFOSET(fd,2); session[fd]->flag.ping = 2; } } sd = (struct char_session_data*)session[fd]->session_data; while(RFIFOREST(fd) >= 2) { // -1: Login server is not connected // 0: Avoid processing followup packets (prev was probably incomplete) packet // 1: Continue parsing int next = 1; uint16 command = RFIFOW(fd,0); switch( command ) { case 0x2711: next = chlogif_parse_ackconnect(fd,sd); break; case 0x2713: next = chlogif_parse_ackaccreq(fd, sd); break; case 0x2717: next = chlogif_parse_reqaccdata(fd, sd); break; case 0x2718: next = chlogif_parse_keepalive(fd, sd); break; case 0x2721: next = chlogif_parse_AccInfoAck(fd); break; case 0x2723: next = chlogif_parse_ackchangesex(fd, sd); break; case 0x2726: next = chlogif_parse_ack_global_accreg(fd, sd); break; case 0x2731: next = chlogif_parse_accbannotification(fd, sd); break; case 0x2734: next = chlogif_parse_askkick(fd,sd); break; case 0x2735: next = chlogif_parse_updip(fd,sd); break; case 0x2743: next = chlogif_parse_vipack(fd); break; default: ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command); set_eof(fd); return 0; } if (next == 0) return 0; //do not parse next data } RFIFOFLUSH(fd); return 0; }
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 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 tcp_connection::handle_read(const boost::system::error_code &error, size_t bytes_transferred) { if (!socket_.is_open() && !flags.eof) { set_eof(); } if (flags.eof) return; if (error) { set_eof(); do_close(); } else if (bytes_transferred == 0) { set_eof(); do_close(); } else { rdata_size += bytes_transferred; if (parse_) parse_((pointer)this->shared_from_this()); RFIFOFLUSH(this); start_read(); } }
/** * Entry point from char-server to log-server. * Function that checks incoming command, then splits it to the correct handler. * @param fd: file descriptor to parse, (link to char-serv) * @return 0=invalid server,marked for disconnection,unknow packet; 1=success */ int logchrif_parse(int fd){ int cid; //char-serv id uint32 ipl; char ip[16]; ARR_FIND( 0, ARRAYLENGTH(ch_server), cid, ch_server[cid].fd == fd ); if( cid == ARRAYLENGTH(ch_server) ){// not a char server ShowDebug("logchrif_parse: Disconnecting invalid session #%d (is not a char-server)\n", fd); set_eof(fd); do_close(fd); return 0; } if( session[fd]->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 ){ int 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 }
/** * Check here hacker for duplicate item in trade * normal client refuse to have 2 same types of item (except equipment) in same trade window * normal client authorise only no equipped item and only from inventory * This function could end player connection if too much hack is detected * @param sd : player to check * @return -1:zeny hack, 0:all fine, 1:item hack */ int impossible_trade_check(struct map_session_data *sd) { struct item inventory[MAX_INVENTORY]; char message_to_gm[200]; int i, index; nullpo_retr(1, sd); if(sd->deal.zeny > sd->status.zeny) { pc_setglobalreg(sd,"ZENY_HACKER",1); return -1; } // get inventory of player memcpy(&inventory, &sd->status.inventory, sizeof(struct item) * MAX_INVENTORY); // remove this part: arrows can be trade and equipped // re-added! [celest] // remove equipped items (they can not be trade) for (i = 0; i < MAX_INVENTORY; i++) if (inventory[i].nameid > 0 && inventory[i].equip && !(inventory[i].equip & EQP_AMMO)) memset(&inventory[i], 0, sizeof(struct item)); // check items in player inventory for(i = 0; i < 10; i++) { if (!sd->deal.item[i].amount) continue; index = sd->deal.item[i].index; if (inventory[index].amount < sd->deal.item[i].amount) { // if more than the player have -> hack sprintf(message_to_gm, msg_txt(sd,538), sd->status.name, sd->status.account_id); // Hack on trade: character '%s' (account: %d) try to trade more items that he has. intif_wis_message_to_gm(wisp_server_name, PC_PERM_RECEIVE_HACK_INFO, message_to_gm); sprintf(message_to_gm, msg_txt(sd,539), inventory[index].amount, inventory[index].nameid, sd->deal.item[i].amount); // This player has %d of a kind of item (id: %d), and try to trade %d of them. intif_wis_message_to_gm(wisp_server_name, PC_PERM_RECEIVE_HACK_INFO, message_to_gm); // if we block people if (battle_config.ban_hack_trade < 0) { chrif_req_login_operation(-1, sd->status.name, CHRIF_OP_LOGIN_BLOCK, 0, 0, 0); // type: 1 - block set_eof(sd->fd); // forced to disconnect because of the hack // message about the ban strcpy(message_to_gm, msg_txt(sd,540)); // This player has been definitively blocked. // if we ban people } else if (battle_config.ban_hack_trade > 0) { chrif_req_login_operation(-1, sd->status.name, CHRIF_OP_LOGIN_BAN, battle_config.ban_hack_trade*60, 0, 0); // type: 2 - ban (year, month, day, hour, minute, second) set_eof(sd->fd); // forced to disconnect because of the hack // message about the ban sprintf(message_to_gm, msg_txt(sd,507), battle_config.ban_hack_trade); // This player has been banned for %d minute(s). } else // message about the ban strcpy(message_to_gm, msg_txt(sd,508)); // This player hasn't been banned (Ban option is disabled). intif_wis_message_to_gm(wisp_server_name, PC_PERM_RECEIVE_HACK_INFO, message_to_gm); return 1; } inventory[index].amount -= sd->deal.item[i].amount; // remove item from inventory } return 0; }
static int recv_to_fifo(int fd) { int len; if( (fd<0) || (fd>=FD_SETSIZE) || (NULL==session[fd]) ) return -1; if(session[fd]->eof) return -1; #ifdef __WIN32 len=recv(fd,(char *)session[fd]->rdata+session[fd]->rdata_size, RFIFOSPACE(fd), 0); if (len == SOCKET_ERROR) { if (WSAGetLastError() == WSAECONNABORTED) { ShowWarning("recv_to_fifo: software de conexao cancelado na sessao #%d\n", fd); FD_CLR(fd, &readfds); //Remove the socket so the select() won't hang on it. // exit(1); //Windows can't really recover from this one. [Skotlex] } if (WSAGetLastError() != WSAEWOULDBLOCK) { // ShowDebug("recv_to_fifo: error %d, ending connection #%d\n", WSAGetLastError(), fd); set_eof(fd); } return 0; } #else len=read(fd,session[fd]->rdata+session[fd]->rdata_size, RFIFOSPACE(fd)); if (len == -1) { if (errno == ECONNABORTED) { ShowFatalError("recv_to_fifo: Quebra de conexao (software de conexao cancelado na sessao #%d)\n", fd); // exit(1); //Temporal debug, maybe this can be fixed. } if (errno != EAGAIN) { //Connection error. // perror("closing session: recv_to_fifo"); set_eof(fd); } return 0; } #endif if (len <= 0) { //Normal connection end. set_eof(fd); return 0; } session[fd]->rdata_size+=len; session[fd]->rdata_tick = last_tick; return 0; }
/* * Called to indicate that we have just read an EOF from the device. */ void DEVICE::set_ateof() { set_eof(); file_addr = 0; file_size = 0; block_num = 0; }
int chlogif_parse_askkick(int fd, struct char_session_data* sd){ if (RFIFOREST(fd) < 6) return 0; else { DBMap* online_char_db = char_get_onlinedb(); DBMap* auth_db = char_get_authdb(); int aid = RFIFOL(fd,2); struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, aid); RFIFOSKIP(fd,6); if( character != NULL ) {// account is already marked as online! if( character->server > -1 ) { //Kick it from the map server it is on. mapif_disconnectplayer(map_server[character->server].fd, character->account_id, character->char_id, 2); if (character->waiting_disconnect == INVALID_TIMER) character->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, char_chardb_waiting_disconnect, character->account_id, 0); } else {// Manual kick from char server. struct char_session_data *tsd; int i; ARR_FIND( 0, fd_max, i, session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid ); if( i < fd_max ) { chclif_send_auth_result(i,2); //Send "Someone has already logged in with this id" set_eof(i); } else // still moving to the map-server char_set_char_offline(-1, aid); } } idb_remove(auth_db, aid);// reject auth attempts from map-server } return 1; }
int send_from_fifo(int fd) { int len; if( !session_isValid(fd) ) return -1; if( session[fd]->wdata_size == 0 ) return 0; // nothing to send len = sSend(fd, (const char *) session[fd]->wdata, (int)session[fd]->wdata_size, 0); if( len == SOCKET_ERROR ) {//An exception has occured if( sErrno != S_EWOULDBLOCK ) { //ShowDebug("send_from_fifo: error %d, ending connection #%d\n", sErrno, fd); session[fd]->wdata_size = 0; //Clear the send queue as we can't send anymore. [Skotlex] set_eof(fd); } return 0; } if( len > 0 ) { // some data could not be transferred? // shift unsent data to the beginning of the queue if( (size_t)len < session[fd]->wdata_size ) memmove(session[fd]->wdata, session[fd]->wdata + len, session[fd]->wdata_size - len); session[fd]->wdata_size -= len; } return 0; }
/* * Called to indicate that we have just read an EOF from the device. */ void generic_tape_device::set_ateof() { set_eof(); file++; file_addr = 0; file_size = 0; block_num = 0; }
/* * Called to indicate that we have just read an * EOF from the device. */ void DEVICE::set_ateof() { set_eof(); if (is_tape()) { file++; } file_addr = 0; file_size = 0; block_num = 0; }
/*========================================== * Request char server to change sex of char (modified by Yor) *------------------------------------------*/ int chrif_changedsex(int fd) { int acc, sex; struct map_session_data *sd; acc = RFIFOL(fd,2); sex = RFIFOL(fd,6); if ( battle_config.etc_log ) ShowNotice("chrif_changedsex %d.\n", acc); sd = map_id2sd(acc); if ( sd ) { //Normally there should not be a char logged on right now! if ( sd->status.sex == sex ) return 0; //Do nothing? Likely safe. sd->status.sex = !sd->status.sex; // reset skill of some job if ((sd->class_&MAPID_UPPERMASK) == MAPID_BARDDANCER) { int i, idx = 0; // remove specifical skills of Bard classes for(i = 315; i <= 322; i++) { idx = skill->get_index(i); if (sd->status.skill[idx].id > 0 && sd->status.skill[idx].flag == SKILL_FLAG_PERMANENT) { sd->status.skill_point += sd->status.skill[idx].lv; sd->status.skill[idx].id = 0; sd->status.skill[idx].lv = 0; } } // remove specifical skills of Dancer classes for(i = 323; i <= 330; i++) { idx = skill->get_index(i); if (sd->status.skill[idx].id > 0 && sd->status.skill[idx].flag == SKILL_FLAG_PERMANENT) { sd->status.skill_point += sd->status.skill[idx].lv; sd->status.skill[idx].id = 0; sd->status.skill[idx].lv = 0; } } clif->updatestatus(sd, SP_SKILLPOINT); // change job if necessary if (sd->status.sex) //Changed from Dancer sd->status.class_ -= 1; else //Changed from Bard sd->status.class_ += 1; //sd->class_ needs not be updated as both Dancer/Bard are the same. } // save character sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters // do same modify in login-server for the account, but no in char-server (it ask again login_id1 to login, and don't remember it) clif->message(sd->fd, msg_txt(409)); //"Your sex has been changed (need disconnection by the server)..." set_eof(sd->fd); // forced to disconnect for the change map_quit(sd); // Remove leftovers (e.g. autotrading) [Paradox924X] } return 0; }
void tcp_connection::handle_write(const boost::system::error_code &error) { if (!error) { wdata_size = 0; } else { set_eof(); do_close(); } }
/** * Load permission for player based on group id * @param sd Player */ void pc_group_pc_load(struct map_session_data * sd) { GroupSettings *group = NULL; if ((group = id2group(sd->group_id)) == NULL) { ShowWarning("pc_group_pc_load: %s (AID:%d) logged in with unknown group id (%d)! kicking...\n", sd->status.name, sd->status.account_id, sd->group_id); set_eof(sd->fd); return; } sd->permissions = group->e_permissions; sd->group_pos = group->group_pos; sd->group_level = group->level; }
void rewind_recording( void) { if(replay.game_is_being_recorded) { /* This is unnecessary, because it is called from reset_player_queues, */ /* which is always called from revert_game */ set_eof(replay.recording_file_refnum, sizeof(struct recording_header)); set_fpos(replay.recording_file_refnum, sizeof(struct recording_header)); replay.header.length= sizeof(struct recording_header); } return; }
/*========================================== * Disconnection of a player (account has been banned of has a status, from login-server) by [Yor] *------------------------------------------*/ int chrif_accountban(int fd) { int acc; struct map_session_data *sd; acc = RFIFOL(fd,2); if (battle_config.etc_log) ShowNotice("chrif_accountban %d.\n", acc); sd = map_id2sd(acc); if (acc < 0 || sd == NULL) { ShowError("chrif_accountban failed - player not online.\n"); return 0; } sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters if (RFIFOB(fd,6) == 0) // 0: change of statut, 1: ban { switch (RFIFOL(fd,7)) { // status or final date of a banishment case 1: clif_displaymessage(sd->fd, "Your account has 'Unregistered'."); break; case 2: clif_displaymessage(sd->fd, "Your account has an 'Incorrect Password'..."); break; case 3: clif_displaymessage(sd->fd, "Your account has expired."); break; case 4: clif_displaymessage(sd->fd, "Your account has been rejected from server."); break; case 5: clif_displaymessage(sd->fd, "Your account has been blocked by the GM Team."); break; case 6: clif_displaymessage(sd->fd, "Your Game's EXE file is not the latest version."); break; case 7: clif_displaymessage(sd->fd, "Your account has been prohibited to log in."); break; case 8: clif_displaymessage(sd->fd, "Server is jammed due to over populated."); break; case 9: clif_displaymessage(sd->fd, "Your account has not more authorised."); break; case 100: clif_displaymessage(sd->fd, "Your account has been totally erased."); break; default: clif_displaymessage(sd->fd, "Your account has not more authorised."); break; } } else if (RFIFOB(fd,6) == 1) // 0: change of statut, 1: ban { time_t timestamp; char tmpstr[2048]; timestamp = (time_t)RFIFOL(fd,7); // status or final date of a banishment strcpy(tmpstr, "Your account has been banished until "); strftime(tmpstr + strlen(tmpstr), 24, "%d-%m-%Y %H:%M:%S", localtime(×tamp)); clif_displaymessage(sd->fd, tmpstr); } set_eof(sd->fd); // forced to disconnect for the change map_quit(sd); // Remove leftovers (e.g. autotrading) [Paradox924X] return 0; }
/*========================================== * Disconnection of a player (account has been banned of has a status, from login-server) by [Yor] *------------------------------------------*/ int chrif_accountban(int fd) { int acc; struct map_session_data *sd; acc = RFIFOL(fd,2); if (battle_config.etc_log) ShowNotice("chrif_accountban %d.\n", acc); sd = map_id2sd(acc); if (acc < 0 || sd == NULL) { ShowError("chrif_accountban failed - player not online.\n"); return 0; } sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters if (RFIFOB(fd,6) == 0) // 0: change of statut, 1: ban { switch (RFIFOL(fd,7)) { // status or final date of a banishment case 1: clif_displaymessage(sd->fd, "Your account has 'Unregistered'."); break; case 2: clif_displaymessage(sd->fd, "Senha incorreta..."); break; case 3: clif_displaymessage(sd->fd, "Sua conta expirou."); break; case 4: clif_displaymessage(sd->fd, "Sua conta foi rejeitada pelo map-server."); break; case 5: clif_displaymessage(sd->fd, "Sua conta foi bloqueada pela staff do server."); break; case 6: clif_displaymessage(sd->fd, "Seu EXE do jogo nуo estс na њltima versуo."); break; case 7: clif_displaymessage(sd->fd, "Sua conta foi proibida de fazer login."); break; case 8: clif_displaymessage(sd->fd, "Servidor estс lotado."); break; case 9: clif_displaymessage(sd->fd, "Your account has not more authorised."); break; case 100: clif_displaymessage(sd->fd, "Sua conta foi totalmente apagada."); break; default: clif_displaymessage(sd->fd, "Your account has not more authorised."); break; } } else if (RFIFOB(fd,6) == 1) // 0: change of statut, 1: ban { time_t timestamp; char tmpstr[2048]; timestamp = (time_t)RFIFOL(fd,7); // status or final date of a banishment strcpy(tmpstr, "Sua conta foi banida atщ "); strftime(tmpstr + strlen(tmpstr), 24, "%d-%m-%Y %H:%M:%S", localtime(×tamp)); clif_displaymessage(sd->fd, tmpstr); } set_eof(sd->fd); // forced to disconnect for the change map_quit(sd); // Remove leftovers (e.g. autotrading) [Paradox924X] return 0; }
/*========================================== * Disconnection of a player (account has been banned of has a status, from login-server) by [Yor] *------------------------------------------*/ int chrif_accountban(int fd) { int acc; struct map_session_data *sd; acc = RFIFOL(fd,2); if (battle_config.etc_log) ShowNotice("chrif_accountban %d.\n", acc); sd = map_id2sd(acc); if (acc < 0 || sd == NULL) { ShowError("chrif_accountban falhou - personagem nao encontrado.\n"); return 0; } sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters if (RFIFOB(fd,6) == 0) // 0: change of statut, 1: ban { switch (RFIFOL(fd,7)) { // status or final date of a banishment case 1: clif_displaymessage(sd->fd, "Sua conta encontra-se 'N�o Registrada'."); break; case 2: clif_displaymessage(sd->fd, "Sua conta encontra-se com a 'Senha Incorreta'..."); break; case 3: clif_displaymessage(sd->fd, "Sua conta foi expirada."); break; case 4: clif_displaymessage(sd->fd, "Sua conta foi rejeitada pelo servidor."); break; case 5: clif_displaymessage(sd->fd, "Sua conta foi bloqueada pela Equipe de GMs."); break; case 6: clif_displaymessage(sd->fd, "Seu execut�vel do jogo n�o encontra-se na �ltima vers�o."); break; case 7: clif_displaymessage(sd->fd, "Sua conta est� proibida de se conectar."); break; case 8: clif_displaymessage(sd->fd, "Servidor encontra-se lotado devido ao excesso de usu�rios."); break; case 9: clif_displaymessage(sd->fd, "Sua conta n�o est� mais autorizada ao acesso."); break; case 100: clif_displaymessage(sd->fd, "Sua conta foi totalmente apagada."); break; default: clif_displaymessage(sd->fd, "Sua conta n�o est� mais autorizada ao acesso."); break; } } else if (RFIFOB(fd,6) == 1) // 0: change of statut, 1: ban { time_t timestamp; char tmpstr[2048]; timestamp = (time_t)RFIFOL(fd,7); // status or final date of a banishment strcpy(tmpstr, "Sua conta foi banida at� "); strftime(tmpstr + strlen(tmpstr), 24, "%d-%m-%Y %H:%M:%S", localtime(×tamp)); clif_displaymessage(sd->fd, tmpstr); } set_eof(sd->fd); // forced to disconnect for the change map_quit(sd); // Remove leftovers (e.g. autotrading) [Paradox924X] return 0; }
int send_from_fifo(int fd) { ssize_t len; if( !sockt->session_isValid(fd) ) return -1; if( session[fd]->wdata_size == 0 ) return 0; // nothing to send len = sSend(fd, (const char *) session[fd]->wdata, (int)session[fd]->wdata_size, MSG_NOSIGNAL); if( len == SOCKET_ERROR ) {//An exception has occured if( sErrno != S_EWOULDBLOCK ) { //ShowDebug("send_from_fifo: %s, ending connection #%d\n", error_msg(), fd); #ifdef SHOW_SERVER_STATS socket_data_qo -= session[fd]->wdata_size; #endif session[fd]->wdata_size = 0; //Clear the send queue as we can't send anymore. [Skotlex] set_eof(fd); } return 0; } if( len > 0 ) { // some data could not be transferred? // shift unsent data to the beginning of the queue if( (size_t)len < session[fd]->wdata_size ) memmove(session[fd]->wdata, session[fd]->wdata + len, session[fd]->wdata_size - len); session[fd]->wdata_size -= len; #ifdef SHOW_SERVER_STATS socket_data_o += len; socket_data_qo -= len; if (!session[fd]->flag.server) { socket_data_co += len; } #endif } return 0; }
/** * Make a player join a channel * - Add player to channel user list * - Add channel to user channel list * @param channel: Channel data * @param sd: Player data * @return * 0: Success * -1: Invalid channel or player * -2: Player already in channel * -3: Player banned * -4: Reached max limit */ int channel_join(struct Channel *channel, struct map_session_data *sd) { if(!channel || !sd) return -1; if(sd->state.autotrade) return 0; // fake success if(channel_haspc(channel,sd)==1) return -2; if (!pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) && !channel_pccheckgroup(channel, sd->group_id)) return -2; if(channel_haspcbanned(channel,sd)==1){ char output[CHAT_SIZE_MAX]; sprintf(output, msg_txt(sd,1438),channel->name); //You're currently banned from the '%s' channel. clif_displaymessage(sd->fd, output); return -3; } if (channel->type == CHAN_TYPE_PRIVATE && db_size(channel->users) >= channel_config.private_channel.max_member) { char output[CHAT_SIZE_MAX]; sprintf(output, msg_txt(sd,760), channel->name, channel_config.private_channel.max_member); // You cannot join channel '%s'. Limit of %d has been met. clif_displaymessage(sd->fd, output); return -4; } RECREATE(sd->channels, struct Channel *, ++sd->channel_count); sd->channels[ sd->channel_count - 1 ] = channel; idb_put(channel->users, sd->status.char_id, sd); RECREATE(sd->channel_tick, t_tick, sd->channel_count); sd->channel_tick[sd->channel_count-1] = 0; if( sd->stealth ) { sd->stealth = false; } else if( channel->opt & CHAN_OPT_ANNOUNCE_JOIN ) { char output[CHAT_SIZE_MAX]; safesnprintf(output, CHAT_SIZE_MAX, msg_txt(sd,761), channel->alias, sd->status.name); // %s %s has joined. clif_channel_msg(channel,output,channel->color); } /* someone is cheating, we kindly disconnect the bastard */ if( sd->channel_count > 200 ) { set_eof(sd->fd); } return 0; }
/*========================================== * Request auth confirmation *------------------------------------------*/ void chrif_authreq(struct map_session_data *sd) { struct auth_node *node= chrif_search(sd->bl.id); if( node != NULL || !chrif_isconnected() ) { set_eof(sd->fd); return; } WFIFOHEAD(char_fd,19); WFIFOW(char_fd,0) = 0x2b26; WFIFOL(char_fd,2) = sd->status.account_id; WFIFOL(char_fd,6) = sd->status.char_id; WFIFOL(char_fd,10) = sd->login_id1; WFIFOB(char_fd,14) = sd->status.sex; WFIFOL(char_fd,15) = htonl(session[sd->fd]->client_addr); WFIFOSET(char_fd,19); chrif_sd_to_auth(sd, ST_LOGIN); }
int cOStream::Read(const char *buf, int len) { if (!good()) { return -1; } if (buf==nullptr || len <= 0) return 0; if (len > size()) { len = size(); } memcpy(buf, data(), len); pos_ = len; if (pos() == size()) { set_eof(true); } return len; }
int chlogif_parse_ackconnect(int fd, struct char_session_data* sd){ if (RFIFOREST(fd) < 3) return 0; if (RFIFOB(fd,2)) { //printf("connect login server error : %d\n", RFIFOB(fd,2)); ShowError("Can not connect to login-server.\n"); ShowError("The server communication passwords (default s1/p1) are probably invalid.\n"); ShowError("Also, please make sure your login db has the correct communication username/passwords and the gender of the account is S.\n"); ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n"); set_eof(fd); return 0; } else { ShowStatus("Connected to login-server (connection #%d).\n", fd); chlogif_on_ready(); } RFIFOSKIP(fd,3); return 1; }
/*========================================== * Disconnection of a player (account has been deleted in login-server) by [Yor] *------------------------------------------*/ int chrif_accountdeletion(int fd) { int acc; struct map_session_data *sd; acc = RFIFOL(fd,2); if (battle_config.etc_log) ShowNotice("chrif_accountdeletion %d.\n", acc); sd = map_id2sd(acc); if (acc > 0) { if (sd != NULL) { sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters clif_displaymessage(sd->fd, "Your account has been deleted (disconnection)..."); set_eof(sd->fd); // forced to disconnect for the change } } else { if (sd != NULL) ShowError("chrif_accountdeletion failed - player not online.\n"); } return 0; }
/*========================================== * Disconnection of a player (account has been banned of has a status, from login-server) by [Yor] *------------------------------------------*/ int chrif_accountban(int fd) { int acc; struct map_session_data *sd; acc = RFIFOL(fd,2); if ( battle_config.etc_log ) ShowNotice("chrif_accountban %d.\n", acc); sd = map_id2sd(acc); if ( acc < 0 || sd == NULL ) { ShowError("chrif_accountban failed - player not online.\n"); return 0; } sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters if (RFIFOB(fd,6) == 0) { // 0: change of statut, 1: ban int ret_status = RFIFOL(fd,7); // status or final date of a banishment if(0<ret_status && ret_status<=9) clif->message(sd->fd, msg_txt(411+ret_status)); else if(ret_status==100) clif->message(sd->fd, msg_txt(421)); else clif->message(sd->fd, msg_txt(420)); //"Your account has not more authorised." } else if (RFIFOB(fd,6) == 1) { // 0: change of statut, 1: ban time_t timestamp; char tmpstr[2048]; timestamp = (time_t)RFIFOL(fd,7); // status or final date of a banishment strcpy(tmpstr, msg_txt(423)); //"Your account has been banished until " strftime(tmpstr + strlen(tmpstr), 24, "%d-%m-%Y %H:%M:%S", localtime(×tamp)); clif->message(sd->fd, tmpstr); } set_eof(sd->fd); // forced to disconnect for the change map_quit(sd); // Remove leftovers (e.g. autotrading) [Paradox924X] return 0; }
/*========================================== * *------------------------------------------*/ int chrif_parse(int fd) { int packet_len, cmd; // only process data from the char-server if ( fd != char_fd ) { ShowDebug("chrif_parse: Disconnecting invalid session #%d (is not the char-server)\n", fd); do_close(fd); return 0; } if ( session[fd]->flag.eof ) { do_close(fd); char_fd = -1; chrif_on_disconnect(); return 0; } else if ( session[fd]->flag.ping ) {/* we've reached stall time */ if( DIFF_TICK(last_tick, session[fd]->rdata_tick) > (stall_time * 2) ) {/* we can't wait any longer */ set_eof(fd); return 0; } else if( session[fd]->flag.ping != 2 ) { /* we haven't sent ping out yet */ chrif_keepalive(fd); session[fd]->flag.ping = 2; } } while ( RFIFOREST(fd) >= 2 ) { cmd = RFIFOW(fd,0); if (cmd < 0x2af8 || cmd >= 0x2af8 + ARRAYLENGTH(packet_len_table) || packet_len_table[cmd-0x2af8] == 0) { int r = intif_parse(fd); // Passed on to the intif if (r == 1) continue; // Treated in intif if (r == 2) return 0; // Didn't have enough data (len==-1) ShowWarning("chrif_parse: session #%d, intif_parse failed (unrecognized command 0x%.4x).\n", fd, cmd); set_eof(fd); return 0; } if ( ( packet_len = packet_len_table[cmd-0x2af8] ) == -1) { // dynamic-length packet, second WORD holds the length if (RFIFOREST(fd) < 4) return 0; packet_len = RFIFOW(fd,2); } if ((int)RFIFOREST(fd) < packet_len) return 0; //ShowDebug("Received packet 0x%4x (%d bytes) from char-server (connection %d)\n", RFIFOW(fd,0), packet_len, fd); switch(cmd) { case 0x2af9: chrif_connectack(fd); break; case 0x2afb: chrif_sendmapack(fd); break; case 0x2afd: chrif_authok(fd); break; case 0x2b00: map_setusers(RFIFOL(fd,2)); chrif_keepalive(fd); break; case 0x2b03: clif->charselectok(RFIFOL(fd,2), RFIFOB(fd,6)); break; case 0x2b04: chrif_recvmap(fd); break; case 0x2b06: chrif_changemapserverack(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14), RFIFOW(fd,18), RFIFOW(fd,20), RFIFOW(fd,22), RFIFOL(fd,24), RFIFOW(fd,28)); break; case 0x2b09: map_addnickdb(RFIFOL(fd,2), (char*)RFIFOP(fd,6)); break; case 0x2b0a: socket_datasync(fd, false); break; case 0x2b0d: chrif_changedsex(fd); break; case 0x2b0f: chrif_char_ask_name_answer(RFIFOL(fd,2), (char*)RFIFOP(fd,6), RFIFOW(fd,30), RFIFOW(fd,32)); break; case 0x2b12: chrif_divorceack(RFIFOL(fd,2), RFIFOL(fd,6)); break; case 0x2b14: chrif_accountban(fd); break; case 0x2b1b: chrif_recvfamelist(fd); break; case 0x2b1d: chrif_load_scdata(fd); break; case 0x2b1e: chrif_update_ip(fd); break; case 0x2b1f: chrif_disconnectplayer(fd); break; case 0x2b20: chrif_removemap(fd); break; case 0x2b21: chrif_save_ack(fd); break; case 0x2b22: chrif_updatefamelist_ack(fd); break; case 0x2b24: chrif_keepalive_ack(fd); break; case 0x2b25: chrif_deadopt(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break; case 0x2b27: chrif_authfail(fd); break; default: ShowError("chrif_parse : unknown packet (session #%d): 0x%x. Disconnecting.\n", fd, cmd); set_eof(fd); return 0; } if ( fd == char_fd ) //There's the slight chance we lost the connection during parse, in which case this would segfault if not checked [Skotlex] RFIFOSKIP(fd, packet_len); } return 0; }
static int send_from_fifo(int fd) { int len; if( !session_isValid(fd) ) return -1; // if (s->eof) // if we close connection, we can not send last information (you're been disconnected, etc...) [Yor] // return -1; /* // clear write buffer if not connected <- I really like more the idea of sending the last information. [Skotlex] if( session[fd]->eof ) { session[fd]->wdata_size = 0; return -1; } */ if (session[fd]->wdata_size == 0) return 0; #ifdef __WIN32 len=send(fd, (const char *)session[fd]->wdata,session[fd]->wdata_size, 0); if (len == SOCKET_ERROR) { if (WSAGetLastError() == WSAECONNABORTED) { ShowWarning("send_from_fifo: software de conexao cancelado na sessao #%d\n", fd); session[fd]->wdata_size = 0; //Clear the send queue as we can't send anymore. [Skotlex] set_eof(fd); FD_CLR(fd, &readfds); //Remove the socket so the select() won't hang on it. } if (WSAGetLastError() != WSAEWOULDBLOCK) { // ShowDebug("send_from_fifo: error %d, ending connection #%d\n", WSAGetLastError(), fd); session[fd]->wdata_size = 0; //Clear the send queue as we can't send anymore. [Skotlex] set_eof(fd); } return 0; } #else len=write(fd,session[fd]->wdata,session[fd]->wdata_size); if (len == -1) { if (errno == ECONNABORTED) { ShowFatalError("send_from_fifo: Quebra de conexao (software de conexao cancelado na sessao #%d)\n", fd); session[fd]->wdata_size = 0; //Clear the send queue as we can't send anymore. [Skotlex] set_eof(fd); } if (errno != EAGAIN) { // perror("closing session: send_from_fifo"); session[fd]->wdata_size = 0; //Clear the send queue as we can't send anymore. [Skotlex] set_eof(fd); } return 0; } #endif //{ int i; ShowMessage("send %d : ",fd); for(i=0;i<len;i++){ ShowMessage("%02x ",session[fd]->wdata[i]); } ShowMessage("\n");} if(len>0){ if((unsigned int)len<session[fd]->wdata_size){ memmove(session[fd]->wdata,session[fd]->wdata+len,session[fd]->wdata_size-len); session[fd]->wdata_size-=len; } else { session[fd]->wdata_size=0; } } return 0; }
// 0x7944 - request account id lookup by name (response: 0x7945) // 0x7946 - request account name lookup by id (response: 0x7947) // 0x7952 - request account information lookup by name (response: 0x7953) // 0x7954 - request account information lookup by id (response: 0x7953) //--------------------------------------- int parse_admin(int fd) { unsigned int i, j; char* account_name; struct mmo_account acc; uint32 ipl = session[fd]->client_addr; char ip[16]; ip2str(ipl, ip); if( session[fd]->flag.eof ) { do_close(fd); ShowInfo("Remote administration has disconnected (session #%d).\n", fd); return 0; } while( RFIFOREST(fd) >= 2 ) { uint16 command = RFIFOW(fd,0); switch( command ) { case 0x7530: // Request of the server version ShowStatus("'ladmin': Sending of the server version (ip: %s)\n", ip); WFIFOHEAD(fd,10); WFIFOW(fd,0) = 0x7531; WFIFOB(fd,2) = ATHENA_MAJOR_VERSION; WFIFOB(fd,3) = ATHENA_MINOR_VERSION; WFIFOB(fd,4) = ATHENA_REVISION; WFIFOB(fd,5) = ATHENA_RELEASE_FLAG; WFIFOB(fd,6) = ATHENA_OFFICIAL_FLAG; WFIFOB(fd,7) = ATHENA_SERVER_LOGIN; WFIFOW(fd,8) = ATHENA_MOD_VERSION; WFIFOSET(fd,10); RFIFOSKIP(fd,2); break; /* case 0x7920: // Request of an accounts list if (RFIFOREST(fd) < 10) return 0; { int st, ed; uint16 len; CREATE_BUFFER(id, int, auth_num); st = RFIFOL(fd,2); ed = RFIFOL(fd,6); RFIFOSKIP(fd,10); WFIFOW(fd,0) = 0x7921; if (st < 0) st = 0; if (ed > END_ACCOUNT_NUM || ed < st || ed <= 0) ed = END_ACCOUNT_NUM; ShowStatus("'ladmin': Sending an accounts list (ask: from %d to %d, ip: %s)\n", st, ed, ip); // Sort before send for(i = 0; i < auth_num; i++) { unsigned int k; id[i] = i; for(j = 0; j < i; j++) { if (auth_dat[id[i]].account_id < auth_dat[id[j]].account_id) { for(k = i; k > j; k--) { id[k] = id[k-1]; } id[j] = i; // id[i] break; } } } // Sending accounts information len = 4; for(i = 0; i < auth_num && len < 30000; i++) { int account_id = auth_dat[id[i]].account_id; // use sorted index if (account_id >= st && account_id <= ed) { j = id[i]; WFIFOL(fd,len) = account_id; WFIFOB(fd,len+4) = (unsigned char)isGM(account_id); memcpy(WFIFOP(fd,len+5), auth_dat[j].userid, 24); WFIFOB(fd,len+29) = auth_dat[j].sex; WFIFOL(fd,len+30) = auth_dat[j].logincount; if (auth_dat[j].state == 0 && auth_dat[j].unban_time != 0) // if no state and banished WFIFOL(fd,len+34) = 7; // 6 = Your are Prohibited to log in until %s else WFIFOL(fd,len+34) = auth_dat[j].state; len += 38; } } WFIFOW(fd,2) = len; WFIFOSET(fd,len); //if (id) free(id); DELETE_BUFFER(id); } break; */ case 0x7930: // Request for an account creation if (RFIFOREST(fd) < 91) return 0; { struct mmo_account ma; safestrncpy(ma.userid, (char*)RFIFOP(fd, 2), sizeof(ma.userid)); safestrncpy(ma.pass, (char*)RFIFOP(fd,26), sizeof(ma.pass)); ma.sex = RFIFOB(fd,50); safestrncpy(ma.email, (char*)RFIFOP(fd,51), sizeof(ma.email)); safestrncpy(ma.lastlogin, "-", sizeof(ma.lastlogin)); ShowNotice("'ladmin': Account creation request (account: %s pass: %s, sex: %c, email: %s, ip: %s)\n", ma.userid, ma.pass, ma.sex, ma.email, ip); WFIFOW(fd,0) = 0x7931; WFIFOL(fd,2) = mmo_auth_new(ma.userid, ma.pass, ma.sex, ip); safestrncpy((char*)WFIFOP(fd,6), ma.userid, 24); WFIFOSET(fd,30); } RFIFOSKIP(fd,91); break; /* case 0x7932: // Request for an account deletion if (RFIFOREST(fd) < 26) return 0; { struct mmo_account acc; char* account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; WFIFOW(fd,0) = 0x7933; if( accounts->load_str(accounts, &acc, account_name) ) { // Char-server is notified of deletion (for characters deletion). unsigned char buf[65535]; WBUFW(buf,0) = 0x2730; WBUFL(buf,2) = acc.account_id; charif_sendallwos(-1, buf, 6); // send answer memcpy(WFIFOP(fd,6), acc.userid, 24); WFIFOL(fd,2) = acc.account_id; // delete account memset(acc.userid, '\0', sizeof(acc.userid)); auth_dat[i].account_id = -1; mmo_auth_sync(); } else { WFIFOL(fd,2) = -1; memcpy(WFIFOP(fd,6), account_name, 24); ShowNotice("'ladmin': Attempt to delete an unknown account (account: %s, ip: %s)\n", account_name, ip); } WFIFOSET(fd,30); } RFIFOSKIP(fd,26); break; */ case 0x7934: // Request to change a password if (RFIFOREST(fd) < 50) return 0; { struct mmo_account acc; char* account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; WFIFOW(fd,0) = 0x7935; if( accounts->load_str(accounts, &acc, account_name) ) { WFIFOL(fd,2) = acc.account_id; safestrncpy((char*)WFIFOP(fd,6), acc.userid, 24); safestrncpy(acc.pass, (char*)RFIFOP(fd,26), 24); ShowNotice("'ladmin': Modification of a password (account: %s, new password: %s, ip: %s)\n", acc.userid, acc.pass, ip); accounts->save(accounts, &acc); } else { WFIFOL(fd,2) = -1; safestrncpy((char*)WFIFOP(fd,6), account_name, 24); ShowNotice("'ladmin': Attempt to modify the password of an unknown account (account: %s, ip: %s)\n", account_name, ip); } WFIFOSET(fd,30); } RFIFOSKIP(fd,50); break; case 0x7936: // Request to modify a state if (RFIFOREST(fd) < 50) return 0; { struct mmo_account acc; char* account_name = (char*)RFIFOP(fd,2); uint32 state = RFIFOL(fd,26); account_name[23] = '\0'; WFIFOW(fd,0) = 0x7937; if( accounts->load_str(accounts, &acc, account_name) ) { memcpy(WFIFOP(fd,6), acc.userid, 24); WFIFOL(fd,2) = acc.account_id; if (acc.state == state) ShowNotice("'ladmin': Modification of a state, but the state of the account already has this value (account: %s, received state: %d, ip: %s)\n", account_name, state, ip); else { ShowNotice("'ladmin': Modification of a state (account: %s, new state: %d, ip: %s)\n", acc.userid, state, ip); if (acc.state == 0) { unsigned char buf[16]; WBUFW(buf,0) = 0x2731; WBUFL(buf,2) = acc.account_id; WBUFB(buf,6) = 0; // 0: change of statut, 1: ban WBUFL(buf,7) = state; // status or final date of a banishment charif_sendallwos(-1, buf, 11); } acc.state = state; accounts->save(accounts, &acc); } } else { ShowNotice("'ladmin': Attempt to modify the state of an unknown account (account: %s, received state: %d, ip: %s)\n", account_name, state, ip); WFIFOL(fd,2) = -1; memcpy(WFIFOP(fd,6), account_name, 24); } WFIFOL(fd,30) = state; WFIFOSET(fd,34); } RFIFOSKIP(fd,50); break; /* case 0x7938: // Request for servers list and # of online players { uint8 server_num = 0; ShowStatus("'ladmin': Sending of servers list (ip: %s)\n", ip); for(i = 0; i < MAX_SERVERS; i++) { if (server[i].fd >= 0) { WFIFOL(fd,4+server_num*32) = htonl(server[i].ip); WFIFOW(fd,4+server_num*32+4) = htons(server[i].port); memcpy(WFIFOP(fd,4+server_num*32+6), server[i].name, 20); WFIFOW(fd,4+server_num*32+26) = server[i].users; WFIFOW(fd,4+server_num*32+28) = server[i].maintenance; WFIFOW(fd,4+server_num*32+30) = server[i].new_; server_num++; } } WFIFOW(fd,0) = 0x7939; WFIFOW(fd,2) = 4 + 32 * server_num; WFIFOSET(fd,4+32*server_num); RFIFOSKIP(fd,2); break; } case 0x793a: // Request to password check if (RFIFOREST(fd) < 50) return 0; WFIFOW(fd,0) = 0x793b; WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; remove_control_chars(account_name); if( accounts->load_str(accounts, &acc, account_name) ) { char pass[25]; memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); memcpy(pass, RFIFOP(fd,26), 24); pass[24] = '\0'; remove_control_chars(pass); if (strcmp(acc.pass, pass) == 0) { WFIFOL(fd,2) = acc.account_id; ShowNotice("'ladmin': Check of password OK (account: %s, password: %s, ip: %s)\n", acc.userid, acc.pass, ip); } else { ShowNotice("'ladmin': Failure of password check (account: %s, proposed pass: %s, ip: %s)\n", acc.userid, pass, ip); } } else { memcpy(WFIFOP(fd,6), account_name, 24); ShowNotice("'ladmin': Attempt to check the password of an unknown account (account: %s, ip: %s)\n", account_name, ip); } WFIFOSET(fd,30); RFIFOSKIP(fd,50); break; case 0x793c: // Request to modify sex if (RFIFOREST(fd) < 27) return 0; WFIFOW(fd,0) = 0x793d; WFIFOL(fd,2) = 0xFFFFFFFF; // -1 account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; remove_control_chars(account_name); memcpy(WFIFOP(fd,6), account_name, 24); { char sex; sex = RFIFOB(fd,26); if (sex != 'F' && sex != 'M') { if (sex > 31) ShowNotice("'ladmin': Attempt to give an invalid sex (account: %s, received sex: %c, ip: %s)\n", account_name, sex, ip); else ShowNotice("'ladmin': Attempt to give an invalid sex (account: %s, received sex: 'control char', ip: %s)\n", account_name, ip); } else { if( accounts->load_str(accounts, &acc, account_name) ) { memcpy(WFIFOP(fd,6), acc.userid, 24); if (acc.sex != sex) { unsigned char buf[16]; ShowNotice("'ladmin': Modification of a sex (account: %s, new sex: %c, ip: %s)\n", acc.userid, sex, ip); WFIFOL(fd,2) = acc.account_id; acc.sex = sex; accounts->save(accounts, &acc); // send to all char-server the change WBUFW(buf,0) = 0x2723; WBUFL(buf,2) = acc.account_id; WBUFB(buf,6) = acc.sex; charif_sendallwos(-1, buf, 7); } else { ShowNotice("'ladmin': Modification of a sex, but the sex is already the good sex (account: %s, sex: %c, ip: %s)\n", acc.userid, sex, ip); } } else { ShowNotice("'ladmin': Attempt to modify the sex of an unknown account (account: %s, received sex: %c, ip: %s)\n", account_name, sex, ip); } } } WFIFOSET(fd,30); RFIFOSKIP(fd,27); break; case 0x793e: // Request to modify GM level if (RFIFOREST(fd) < 27) return 0; WFIFOW(fd,0) = 0x793f; WFIFOL(fd,2) = 0xFFFFFFFF; // -1 account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; remove_control_chars(account_name); memcpy(WFIFOP(fd,6), account_name, 24); { char new_gm_level; new_gm_level = RFIFOB(fd,26); if( new_gm_level < 0 || new_gm_level > 99 ) ShowNotice("'ladmin': Attempt to give an invalid GM level (account: %s, received GM level: %d, ip: %s)\n", account_name, (int)new_gm_level, ip); else if( !accounts->load_str(accounts, &acc, account_name) ) ShowNotice("'ladmin': Attempt to modify the GM level of an unknown account (account: %s, received GM level: %d, ip: %s)\n", account_name, (int)new_gm_level, ip); else { memcpy(WFIFOP(fd,6), acc.userid, 24); if (isGM(acc.account_id) == new_gm_level) ShowNotice("'ladmin': Attempt to modify of a GM level, but the GM level is already the good GM level (account: %s (%d), GM level: %d, ip: %s)\n", acc.userid, acc.account_id, (int)new_gm_level, ip); else { //TODO: change level } } } WFIFOSET(fd,30); RFIFOSKIP(fd,27); break; case 0x7940: // Request to modify e-mail if (RFIFOREST(fd) < 66) return 0; WFIFOW(fd,0) = 0x7941; WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; remove_control_chars(account_name); memcpy(WFIFOP(fd,6), account_name, 24); { char email[40]; memcpy(email, RFIFOP(fd,26), 40); if (e_mail_check(email) == 0) { ShowNotice("'ladmin': Attempt to give an invalid e-mail (account: %s, ip: %s)\n", account_name, ip); } else { remove_control_chars(email); i = search_account_index(account_name); if (i != -1) { memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); memcpy(auth_dat[i].email, email, 40); WFIFOL(fd,2) = auth_dat[i].account_id; ShowNotice("'ladmin': Modification of an email (account: %s, new e-mail: %s, ip: %s)\n", auth_dat[i].userid, email, ip); mmo_auth_sync(); } else { ShowNotice("'ladmin': Attempt to modify the e-mail of an unknown account (account: %s, received e-mail: %s, ip: %s)\n", account_name, email, ip); } } } WFIFOSET(fd,30); RFIFOSKIP(fd,66); break; case 0x7942: // Request to modify memo field if ((int)RFIFOREST(fd) < 28 || (int)RFIFOREST(fd) < (28 + RFIFOW(fd,26))) return 0; WFIFOW(fd,0) = 0x7943; WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; remove_control_chars(account_name); i = search_account_index(account_name); if (i != -1) { int size_of_memo = sizeof(auth_dat[i].memo); memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); memset(auth_dat[i].memo, '\0', size_of_memo); if (RFIFOW(fd,26) == 0) { strncpy(auth_dat[i].memo, "-", size_of_memo); } else if (RFIFOW(fd,26) > size_of_memo - 1) { memcpy(auth_dat[i].memo, RFIFOP(fd,28), size_of_memo - 1); } else { memcpy(auth_dat[i].memo, RFIFOP(fd,28), RFIFOW(fd,26)); } auth_dat[i].memo[size_of_memo - 1] = '\0'; remove_control_chars(auth_dat[i].memo); WFIFOL(fd,2) = auth_dat[i].account_id; ShowNotice("'ladmin': Modification of a memo field (account: %s, new memo: %s, ip: %s)\n", auth_dat[i].userid, auth_dat[i].memo, ip); mmo_auth_sync(); } else { memcpy(WFIFOP(fd,6), account_name, 24); ShowNotice("'ladmin': Attempt to modify the memo field of an unknown account (account: %s, ip: %s)\n", account_name, ip); } WFIFOSET(fd,30); RFIFOSKIP(fd,28 + RFIFOW(fd,26)); break; case 0x7944: // Request to found an account id if (RFIFOREST(fd) < 26) return 0; WFIFOW(fd,0) = 0x7945; WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; remove_control_chars(account_name); i = search_account_index(account_name); if (i != -1) { memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); WFIFOL(fd,2) = auth_dat[i].account_id; ShowNotice("'ladmin': Request (by the name) of an account id (account: %s, id: %d, ip: %s)\n", auth_dat[i].userid, auth_dat[i].account_id, ip); } else { memcpy(WFIFOP(fd,6), account_name, 24); ShowNotice("'ladmin': ID request (by the name) of an unknown account (account: %s, ip: %s)\n", account_name, ip); } WFIFOSET(fd,30); RFIFOSKIP(fd,26); break; case 0x7946: // Request to found an account name if (RFIFOREST(fd) < 6) return 0; WFIFOW(fd,0) = 0x7947; WFIFOL(fd,2) = RFIFOL(fd,2); memset(WFIFOP(fd,6), '\0', 24); for(i = 0; i < auth_num; i++) { if (auth_dat[i].account_id == (int)RFIFOL(fd,2)) { strncpy((char*)WFIFOP(fd,6), auth_dat[i].userid, 24); ShowNotice("'ladmin': Request (by id) of an account name (account: %s, id: %d, ip: %s)\n", auth_dat[i].userid, RFIFOL(fd,2), ip); break; } } if (i == auth_num) { ShowNotice("'ladmin': Name request (by id) of an unknown account (id: %d, ip: %s)\n", RFIFOL(fd,2), ip); strncpy((char*)WFIFOP(fd,6), "", 24); } WFIFOSET(fd,30); RFIFOSKIP(fd,6); break; case 0x7948: // Request to change the validity limit (timestamp) (absolute value) if (RFIFOREST(fd) < 30) return 0; { time_t timestamp; char tmpstr[2048]; WFIFOW(fd,0) = 0x7949; WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; remove_control_chars(account_name); timestamp = (time_t)RFIFOL(fd,26); strftime(tmpstr, 24, login_config.date_format, localtime(×tamp)); i = search_account_index(account_name); if (i != -1) { memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); ShowNotice("'ladmin': Change of a validity limit (account: %s, new validity: %d (%s), ip: %s)\n", auth_dat[i].userid, timestamp, (timestamp == 0 ? "unlimited" : tmpstr), ip); auth_dat[i].expiration_time = timestamp; WFIFOL(fd,2) = auth_dat[i].account_id; mmo_auth_sync(); } else { memcpy(WFIFOP(fd,6), account_name, 24); ShowNotice("'ladmin': Attempt to change the validity limit of an unknown account (account: %s, received validity: %d (%s), ip: %s)\n", account_name, timestamp, (timestamp == 0 ? "unlimited" : tmpstr), ip); } WFIFOL(fd,30) = (unsigned int)timestamp; } WFIFOSET(fd,34); RFIFOSKIP(fd,30); break; case 0x794a: // Request to change the final date of a banishment (timestamp) (absolute value) if (RFIFOREST(fd) < 30) return 0; { time_t timestamp; char tmpstr[2048]; WFIFOW(fd,0) = 0x794b; WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; remove_control_chars(account_name); timestamp = (time_t)RFIFOL(fd,26); if (timestamp <= time(NULL)) timestamp = 0; strftime(tmpstr, 24, login_config.date_format, localtime(×tamp)); i = search_account_index(account_name); if (i != -1) { memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); WFIFOL(fd,2) = auth_dat[i].account_id; ShowNotice("'ladmin': Change of the final date of a banishment (account: %s, new final date of banishment: %d (%s), ip: %s)\n", auth_dat[i].userid, timestamp, (timestamp == 0 ? "no banishment" : tmpstr), ip); if (auth_dat[i].unban_time != timestamp) { if (timestamp != 0) { unsigned char buf[16]; WBUFW(buf,0) = 0x2731; WBUFL(buf,2) = auth_dat[i].account_id; WBUFB(buf,6) = 1; // 0: change of statut, 1: ban WBUFL(buf,7) = (unsigned int)timestamp; // status or final date of a banishment charif_sendallwos(-1, buf, 11); } auth_dat[i].unban_time = timestamp; mmo_auth_sync(); } } else { memcpy(WFIFOP(fd,6), account_name, 24); ShowNotice("'ladmin': Attempt to change the final date of a banishment of an unknown account (account: %s, received final date of banishment: %d (%s), ip: %s)\n", account_name, timestamp, (timestamp == 0 ? "no banishment" : tmpstr), ip); } WFIFOL(fd,30) = (unsigned int)timestamp; } WFIFOSET(fd,34); RFIFOSKIP(fd,30); break; case 0x794c: // Request to change the final date of a banishment (timestamp) (relative change) if (RFIFOREST(fd) < 38) return 0; { time_t timestamp; struct tm *tmtime; char tmpstr[2048]; WFIFOW(fd,0) = 0x794d; WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; remove_control_chars(account_name); i = search_account_index(account_name); if (i != -1) { WFIFOL(fd,2) = auth_dat[i].account_id; memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); if (auth_dat[i].unban_time == 0 || auth_dat[i].unban_time < time(NULL)) timestamp = time(NULL); else timestamp = auth_dat[i].unban_time; tmtime = localtime(×tamp); tmtime->tm_year = tmtime->tm_year + (short)RFIFOW(fd,26); tmtime->tm_mon = tmtime->tm_mon + (short)RFIFOW(fd,28); tmtime->tm_mday = tmtime->tm_mday + (short)RFIFOW(fd,30); tmtime->tm_hour = tmtime->tm_hour + (short)RFIFOW(fd,32); tmtime->tm_min = tmtime->tm_min + (short)RFIFOW(fd,34); tmtime->tm_sec = tmtime->tm_sec + (short)RFIFOW(fd,36); timestamp = mktime(tmtime); if (timestamp != -1) { if (timestamp <= time(NULL)) timestamp = 0; strftime(tmpstr, 24, login_config.date_format, localtime(×tamp)); ShowNotice("'ladmin': Adjustment of a final date of a banishment (account: %s, (%+d y %+d m %+d d %+d h %+d mn %+d s) -> new validity: %d (%s), ip: %s)\n", auth_dat[i].userid, (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), timestamp, (timestamp == 0 ? "no banishment" : tmpstr), ip); if (auth_dat[i].unban_time != timestamp) { if (timestamp != 0) { unsigned char buf[16]; WBUFW(buf,0) = 0x2731; WBUFL(buf,2) = auth_dat[i].account_id; WBUFB(buf,6) = 1; // 0: change of statut, 1: ban WBUFL(buf,7) = (unsigned int)timestamp; // status or final date of a banishment charif_sendallwos(-1, buf, 11); } auth_dat[i].unban_time = timestamp; mmo_auth_sync(); } } else { strftime(tmpstr, 24, login_config.date_format, localtime(&auth_dat[i].unban_time)); ShowNotice("'ladmin': Impossible to adjust the final date of a banishment (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> ???, ip: %s)\n", auth_dat[i].userid, auth_dat[i].unban_time, (auth_dat[i].unban_time == 0 ? "no banishment" : tmpstr), (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), ip); } WFIFOL(fd,30) = (unsigned long)auth_dat[i].unban_time; } else { memcpy(WFIFOP(fd,6), account_name, 24); ShowNotice("'ladmin': Attempt to adjust the final date of a banishment of an unknown account (account: %s, ip: %s)\n", account_name, ip); WFIFOL(fd,30) = 0; } } WFIFOSET(fd,34); RFIFOSKIP(fd,38); break; case 0x794e: // Request to send a broadcast message if (RFIFOREST(fd) < 8 || RFIFOREST(fd) < (8 + RFIFOL(fd,4))) return 0; WFIFOW(fd,0) = 0x794f; WFIFOW(fd,2) = 0xFFFF; // WTF??? if (RFIFOL(fd,4) < 1) { ShowNotice("'ladmin': Receiving a message for broadcast, but message is void (ip: %s)\n", ip); } else { // at least 1 char-server for(i = 0; i < MAX_SERVERS; i++) if (server[i].fd >= 0) break; if (i == MAX_SERVERS) { ShowNotice("'ladmin': Receiving a message for broadcast, but no char-server is online (ip: %s)\n", ip); } else { unsigned char buf[32000]; char message[32000]; WFIFOW(fd,2) = 0; memset(message, '\0', sizeof(message)); memcpy(message, RFIFOP(fd,8), RFIFOL(fd,4)); message[sizeof(message)-1] = '\0'; remove_control_chars(message); if (RFIFOW(fd,2) == 0) ShowNotice("'ladmin': Receiving a message for broadcast (message (in yellow): %s, ip: %s)\n", message, ip); else ShowNotice("'ladmin': Receiving a message for broadcast (message (in blue): %s, ip: %s)\n", message, ip); // send same message to all char-servers (no answer) memcpy(WBUFP(buf,0), RFIFOP(fd,0), 8 + RFIFOL(fd,4)); WBUFW(buf,0) = 0x2726; charif_sendallwos(-1, buf, 8 + RFIFOL(fd,4)); } } WFIFOSET(fd,4); RFIFOSKIP(fd,8 + RFIFOL(fd,4)); break; case 0x7950: // Request to change the validity limite (timestamp) (relative change) if (RFIFOREST(fd) < 38) return 0; { time_t timestamp; struct tm *tmtime; char tmpstr[2048]; char tmpstr2[2048]; WFIFOW(fd,0) = 0x7951; WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; remove_control_chars(account_name); i = search_account_index(account_name); if (i != -1) { WFIFOL(fd,2) = auth_dat[i].account_id; memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); timestamp = auth_dat[i].expiration_time; if (timestamp == 0 || timestamp < time(NULL)) timestamp = time(NULL); tmtime = localtime(×tamp); tmtime->tm_year = tmtime->tm_year + (short)RFIFOW(fd,26); tmtime->tm_mon = tmtime->tm_mon + (short)RFIFOW(fd,28); tmtime->tm_mday = tmtime->tm_mday + (short)RFIFOW(fd,30); tmtime->tm_hour = tmtime->tm_hour + (short)RFIFOW(fd,32); tmtime->tm_min = tmtime->tm_min + (short)RFIFOW(fd,34); tmtime->tm_sec = tmtime->tm_sec + (short)RFIFOW(fd,36); timestamp = mktime(tmtime); if (timestamp != -1) { strftime(tmpstr, 24, login_config.date_format, localtime(&auth_dat[i].expiration_time)); strftime(tmpstr2, 24, login_config.date_format, localtime(×tamp)); ShowNotice("'ladmin': Adjustment of a validity limit (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> new validity: %d (%s), ip: %s)\n", auth_dat[i].userid, auth_dat[i].expiration_time, (auth_dat[i].expiration_time == 0 ? "unlimited" : tmpstr), (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), timestamp, (timestamp == 0 ? "unlimited" : tmpstr2), ip); auth_dat[i].expiration_time = timestamp; mmo_auth_sync(); WFIFOL(fd,30) = (unsigned long)auth_dat[i].expiration_time; } else { strftime(tmpstr, 24, login_config.date_format, localtime(&auth_dat[i].expiration_time)); ShowNotice("'ladmin': Impossible to adjust a validity limit (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> ???, ip: %s)\n", auth_dat[i].userid, auth_dat[i].expiration_time, (auth_dat[i].expiration_time == 0 ? "unlimited" : tmpstr), (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), ip); WFIFOL(fd,30) = 0; } } else { memcpy(WFIFOP(fd,6), account_name, 24); ShowNotice("'ladmin': Attempt to adjust the validity limit of an unknown account (account: %s, ip: %s)\n", account_name, ip); WFIFOL(fd,30) = 0; } WFIFOSET(fd,34); } RFIFOSKIP(fd,38); break; */ case 0x7952: // Request about informations of an account (by account name) if (RFIFOREST(fd) < 26) return 0; { struct mmo_account acc; WFIFOW(fd,0) = 0x7953; account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; if( accounts->load_str(accounts, &acc, account_name) ) { ShowNotice("'ladmin': Sending information of an account (request by the name; account: %s, id: %d, ip: %s)\n", acc.userid, acc.account_id, ip); WFIFOL(fd,2) = acc.account_id; WFIFOB(fd,6) = acc.level; safestrncpy((char*)WFIFOP(fd,7), acc.userid, 24); WFIFOB(fd,31) = acc.sex; WFIFOL(fd,32) = acc.logincount; WFIFOL(fd,36) = acc.state; safestrncpy((char*)WFIFOP(fd,40), "-", 20); // error message (removed) safestrncpy((char*)WFIFOP(fd,60), acc.lastlogin, 24); safestrncpy((char*)WFIFOP(fd,84), acc.last_ip, 16); safestrncpy((char*)WFIFOP(fd,100), acc.email, 40); WFIFOL(fd,140) = (unsigned long)acc.expiration_time; WFIFOL(fd,144) = (unsigned long)acc.unban_time; WFIFOW(fd,148) = 0; // previously, this was strlen(memo), and memo went afterwards } else { ShowNotice("'ladmin': Attempt to obtain information (by the name) of an unknown account (account: %s, ip: %s)\n", account_name, ip); WFIFOL(fd,2) = -1; safestrncpy((char*)WFIFOP(fd,7), account_name, 24); // not found } WFIFOSET(fd,150); } RFIFOSKIP(fd,26); break; case 0x7954: // Request about information of an account (by account id) if (RFIFOREST(fd) < 6) return 0; { struct mmo_account acc; int account_id = RFIFOL(fd,2); WFIFOHEAD(fd,150); WFIFOW(fd,0) = 0x7953; WFIFOL(fd,2) = account_id; if( accounts->load_num(accounts, &acc, account_id) ) { ShowNotice("'ladmin': Sending information of an account (request by the id; account: %s, id: %d, ip: %s)\n", acc.userid, account_id, ip); WFIFOB(fd,6) = acc.level; safestrncpy((char*)WFIFOP(fd,7), acc.userid, 24); WFIFOB(fd,31) = acc.sex; WFIFOL(fd,32) = acc.logincount; WFIFOL(fd,36) = acc.state; safestrncpy((char*)WFIFOP(fd,40), "-", 20); // error message (removed) safestrncpy((char*)WFIFOP(fd,60), acc.lastlogin, 24); safestrncpy((char*)WFIFOP(fd,84), acc.last_ip, 16); safestrncpy((char*)WFIFOP(fd,100), acc.email, 40); WFIFOL(fd,140) = (unsigned long)acc.expiration_time; WFIFOL(fd,144) = (unsigned long)acc.unban_time; WFIFOW(fd,148) = 0; // previously, this was strlen(memo), and memo went afterwards } else { ShowNotice("'ladmin': Attempt to obtain information (by the id) of an unknown account (id: %d, ip: %s)\n", account_id, ip); safestrncpy((char*)WFIFOP(fd,7), "", 24); // not found } WFIFOSET(fd,150); } RFIFOSKIP(fd,6); break; default: ShowStatus("'ladmin': End of connection, unknown packet (ip: %s)\n", ip); set_eof(fd); return 0; } } RFIFOSKIP(fd,RFIFOREST(fd)); return 0; }
/*========================================== * *------------------------------------------*/ int chrif_parse(int fd) { int packet_len, cmd; // only process data from the char-server if (fd != char_fd) { ShowDebug("chrif_parse: Disconnecting invalid session #%d (is not the char-server)\n", fd); do_close(fd); return 0; } if (session[fd]->flag.eof) { if (chrif_connected == 1) chrif_disconnect(fd); do_close(fd); return 0; } while (RFIFOREST(fd) >= 2) { cmd = RFIFOW(fd,0); if (cmd < 0x2af8 || cmd >= 0x2af8 + ARRAYLENGTH(packet_len_table) || packet_len_table[cmd-0x2af8] == 0) { int r = intif_parse(fd); // intifに渡す if (r == 1) continue; // intifで処理した if (r == 2) return 0; // intifで処理したが、データが足りない ShowWarning("chrif_parse: session #%d, intif_parse failed (unrecognized command 0x%.4x).\n", fd, cmd); set_eof(fd); return 0; } packet_len = packet_len_table[cmd-0x2af8]; if (packet_len == -1) { // dynamic-length packet, second WORD holds the length if (RFIFOREST(fd) < 4) return 0; packet_len = RFIFOW(fd,2); } if ((int)RFIFOREST(fd) < packet_len) return 0; //ShowDebug("Received packet 0x%4x (%d bytes) from char-server (connection %d)\n", RFIFOW(fd,0), packet_len, fd); switch(cmd) { case 0x2af9: chrif_connectack(fd); break; case 0x2afb: chrif_sendmapack(fd); break; case 0x2afd: chrif_authok(fd); break; case 0x2b00: map_setusers(RFIFOL(fd,2)); chrif_keepalive(fd); break; case 0x2b03: clif_charselectok(RFIFOL(fd,2)); break; case 0x2b04: chrif_recvmap(fd); break; case 0x2b06: chrif_changemapserverack(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14), RFIFOW(fd,18), RFIFOW(fd,20), RFIFOW(fd,22), RFIFOL(fd,24), RFIFOW(fd,28)); break; case 0x2b07: clif_updatemaxid(RFIFOL(fd,2), RFIFOL(fd,6)); break; case 0x2b09: map_addnickdb(RFIFOL(fd,2), (char*)RFIFOP(fd,6)); break; case 0x2b0b: chrif_changedgm(fd); break; case 0x2b0d: chrif_changedsex(fd); break; case 0x2b0f: chrif_char_ask_name_answer(RFIFOL(fd,2), (char*)RFIFOP(fd,6), RFIFOW(fd,30), RFIFOW(fd,32)); break; case 0x2b12: chrif_divorce(RFIFOL(fd,2), RFIFOL(fd,6)); break; case 0x2b13: chrif_accountdeletion(fd); break; case 0x2b14: chrif_accountban(fd); break; case 0x2b15: chrif_recvgmaccounts(fd); break; case 0x2b1b: chrif_recvfamelist(fd); break; case 0x2b1d: chrif_load_scdata(fd); break; case 0x2b1e: chrif_update_ip(fd); break; case 0x2b1f: chrif_disconnectplayer(fd); break; case 0x2b20: chrif_removemap(fd); break; case 0x2b21: chrif_save_ack(fd); break; case 0x2b22: chrif_updatefamelist_ack(fd); break; case 0x2b24: chrif_keepalive_ack(fd); break; default: ShowError("chrif_parse : unknown packet (session #%d): 0x%x. Disconnecting.\n", fd, cmd); set_eof(fd); return 0; } if (fd == char_fd) //There's the slight chance we lost the connection during parse, in which case this would segfault if not checked [Skotlex] RFIFOSKIP(fd, packet_len); } return 0; }