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; }
int realloc_fifo(int fd, unsigned int rfifo_size, unsigned int wfifo_size) { if( !session_isValid(fd) ) return 0; if( session[fd]->max_rdata != rfifo_size && session[fd]->rdata_size < rfifo_size) { RECREATE(session[fd]->rdata, unsigned char, rfifo_size); session[fd]->max_rdata = rfifo_size; }
static void delete_session(int fd) { if(session_isValid(fd)) { aFree(session[fd]->rdata); aFree(session[fd]->wdata); aFree(session[fd]->session_data); aFree(session[fd]); session[fd] = NULL; } }
/** * Handles save reg data from map server and distributes accordingly. * * @param val either str or int, depending on type * @param type false when int, true otherwise **/ void inter_savereg(uint32 account_id, uint32 char_id, const char *key, unsigned int index, intptr_t val, bool is_string) { char esc_val[254*2+1]; char esc_key[32*2+1]; Sql_EscapeString(sql_handle, esc_key, key); if( is_string && val ) { Sql_EscapeString(sql_handle, esc_val, (char*)val); } if( key[0] == '#' && key[1] == '#' ) { // global account reg if( session_isValid(login_fd) ) chlogif_send_global_accreg(key,index,val,is_string); else { ShowError("Login server unavailable, can't perform update on '%s' variable for AID:%d CID:%d\n",key,account_id,char_id); } } else if ( key[0] == '#' ) { // local account reg if( is_string ) { if( val ) { if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`account_id`,`key`,`index`,`value`) VALUES ('%d','%s','%u','%s')", schema_config.acc_reg_str_table, account_id, esc_key, index, esc_val) ) Sql_ShowDebug(sql_handle); } else { if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `key` = '%s' AND `index` = '%u' LIMIT 1", schema_config.acc_reg_str_table, account_id, esc_key, index) ) Sql_ShowDebug(sql_handle); } } else { if( val ) { if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`account_id`,`key`,`index`,`value`) VALUES ('%d','%s','%u','%d')", schema_config.acc_reg_num_table, account_id, esc_key, index, (int)val) ) Sql_ShowDebug(sql_handle); } else { if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `key` = '%s' AND `index` = '%u' LIMIT 1", schema_config.acc_reg_num_table, account_id, esc_key, index) ) Sql_ShowDebug(sql_handle); } } } else { /* char reg */ if( is_string ) { if( val ) { if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`char_id`,`key`,`index`,`value`) VALUES ('%d','%s','%u','%s')", schema_config.char_reg_str_table, char_id, esc_key, index, esc_val) ) Sql_ShowDebug(sql_handle); } else { if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d' AND `key` = '%s' AND `index` = '%u' LIMIT 1", schema_config.char_reg_str_table, char_id, esc_key, index) ) Sql_ShowDebug(sql_handle); } } else { if( val ) { if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`char_id`,`key`,`index`,`value`) VALUES ('%d','%s','%u','%d')", schema_config.char_reg_num_table, char_id, esc_key, index, (int)val) ) Sql_ShowDebug(sql_handle); } else { if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d' AND `key` = '%s' AND `index` = '%u' LIMIT 1", schema_config.char_reg_num_table, char_id, esc_key, index) ) Sql_ShowDebug(sql_handle); } } } }
/** * 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 */ int logchrif_sendallwos(int sfd, uint8* buf, size_t len) { int i, c; for( i = 0, c = 0; i < ARRAYLENGTH(ch_server); ++i ) { int 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; }
static void delete_session(int fd) { if( session_isValid(fd) ) { #ifdef SHOW_SERVER_STATS socket_data_qi -= session[fd]->rdata_size - session[fd]->rdata_pos; socket_data_qo -= session[fd]->wdata_size; #endif aFree(session[fd]->rdata); aFree(session[fd]->wdata); aFree(session[fd]->session_data); aFree(session[fd]); session[fd] = NULL; } }
/** * Handles save reg data from map server and distributes accordingly. * * @param val either str or int, depending on type * @param type false when int, true otherwise **/ void inter_savereg(int account_id, int char_id, const char *key, unsigned int index, intptr_t val, bool is_string) { /* to login server we go! */ if( key[0] == '#' && key[1] == '#' ) {/* global account reg */ if( session_isValid(login_fd) ) global_accreg_to_login_add(key,index,val,is_string); else { ShowError("Login server unavailable, cant perform update on '%s' variable for AID:%d CID:%d\n",key,account_id,char_id); } } else if ( key[0] == '#' ) {/* local account reg */ if( is_string ) { if( val ) { if( SQL_ERROR == SQL->Query(sql_handle, "REPLACE INTO `%s` (`account_id`,`key`,`index`,`value`) VALUES ('%d','%s','%u','%s')", acc_reg_str_db, account_id, key, index, (char*)val) ) Sql_ShowDebug(sql_handle); } else { if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `key` = '%s' AND `index` = '%u' LIMIT 1", acc_reg_str_db, account_id, key, index) ) Sql_ShowDebug(sql_handle); } } else { if( val ) { if( SQL_ERROR == SQL->Query(sql_handle, "REPLACE INTO `%s` (`account_id`,`key`,`index`,`value`) VALUES ('%d','%s','%u','%d')", acc_reg_num_db, account_id, key, index, (int)val) ) Sql_ShowDebug(sql_handle); } else { if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `key` = '%s' AND `index` = '%u' LIMIT 1", acc_reg_num_db, account_id, key, index) ) Sql_ShowDebug(sql_handle); } } } else { /* char reg */ if( is_string ) { if( val ) { if( SQL_ERROR == SQL->Query(sql_handle, "REPLACE INTO `%s` (`char_id`,`key`,`index`,`value`) VALUES ('%d','%s','%u','%s')", char_reg_str_db, char_id, key, index, (char*)val) ) Sql_ShowDebug(sql_handle); } else { if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d' AND `key` = '%s' AND `index` = '%u' LIMIT 1", char_reg_str_db, char_id, key, index) ) Sql_ShowDebug(sql_handle); } } else { if( val ) { if( SQL_ERROR == SQL->Query(sql_handle, "REPLACE INTO `%s` (`char_id`,`key`,`index`,`value`) VALUES ('%d','%s','%u','%d')", char_reg_num_db, char_id, key, index, (int)val) ) Sql_ShowDebug(sql_handle); } else { if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d' AND `key` = '%s' AND `index` = '%u' LIMIT 1", char_reg_num_db, char_id, key, index) ) Sql_ShowDebug(sql_handle); } } } }
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, 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; }
static void delete_session(int fd) { if( session_isValid(fd) ) { unsigned int i; #ifdef SHOW_SERVER_STATS socket_data_qi -= session[fd]->rdata_size - session[fd]->rdata_pos; socket_data_qo -= session[fd]->wdata_size; #endif aFree(session[fd]->rdata); aFree(session[fd]->wdata); if( session[fd]->session_data ) aFree(session[fd]->session_data); for(i = 0; i < session[fd]->hdatac; i++) { if( session[fd]->hdata[i]->flag.free ) { aFree(session[fd]->hdata[i]->data); aFree(session[fd]->hdata[i]); } } if( session[fd]->hdata ) aFree(session[fd]->hdata); aFree(session[fd]); session[fd] = NULL; } }
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; }
/** * 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); } }
/** * Char-server request to connect to the login-server. * This is needed to exchange packets. * @param fd: file descriptor to parse from (client) * @param sd: client session * @param ip: ipv4 address (client) * @return 0 packet received too shirt, 1 success */ static int logclif_parse_reqcharconnec(int fd, struct login_session_data *sd, char* ip){ if (RFIFOREST(fd) < 86) return 0; else { int result; char server_name[20]; char message[256]; uint32 server_ip; uint16 server_port; uint16 type; uint16 new_; safestrncpy(sd->userid, RFIFOCP(fd,2), NAME_LENGTH); safestrncpy(sd->passwd, RFIFOCP(fd,26), NAME_LENGTH); if( login_config.use_md5_passwds ) MD5_String(sd->passwd, sd->passwd); sd->passwdenc = 0; server_ip = ntohl(RFIFOL(fd,54)); server_port = ntohs(RFIFOW(fd,58)); safestrncpy(server_name, RFIFOCP(fd,60), 20); type = RFIFOW(fd,82); new_ = RFIFOW(fd,84); RFIFOSKIP(fd,86); ShowInfo("Connection request of the char-server '%s' @ %u.%u.%u.%u:%u (account: '%s', ip: '%s')\n", server_name, CONVIP(server_ip), server_port, sd->userid, ip); sprintf(message, "charserver - %s@%u.%u.%u.%u:%u", server_name, CONVIP(server_ip), server_port); login_log(session[fd]->client_addr, sd->userid, 100, message); result = login_mmo_auth(sd, true); if( runflag == LOGINSERVER_ST_RUNNING && result == -1 && sd->sex == 'S' && sd->account_id < ARRAYLENGTH(ch_server) && !session_isValid(ch_server[sd->account_id].fd) ) { ShowStatus("Connection of the char-server '%s' accepted.\n", server_name); safestrncpy(ch_server[sd->account_id].name, server_name, sizeof(ch_server[sd->account_id].name)); ch_server[sd->account_id].fd = fd; ch_server[sd->account_id].ip = server_ip; ch_server[sd->account_id].port = server_port; ch_server[sd->account_id].users = 0; ch_server[sd->account_id].type = type; ch_server[sd->account_id].new_ = new_; session[fd]->func_parse = logchrif_parse; session[fd]->flag.server = 1; realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); // send connection success WFIFOHEAD(fd,3); WFIFOW(fd,0) = 0x2711; WFIFOB(fd,2) = 0; WFIFOSET(fd,3); } else { ShowNotice("Connection of the char-server '%s' REFUSED.\n", server_name); WFIFOHEAD(fd,3); WFIFOW(fd,0) = 0x2711; WFIFOB(fd,2) = 3; WFIFOSET(fd,3); } } return 1; }