/* Library to manage state connexion Copyright (C) 2019 AleaJactaEst This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "check_memory.h" #include "state_connexion.h" #include "network_connection_core.h" #include "modules/debug/debug.h" #include "modules/networkconnection/network_data.h" inline uint32_t diff_uint32_circulate(uint32_t a, uint32_t b) { // We need managed when number 'uint32_t' exceed the capacity (32bits => 4294967296) // // So, we split in two group. // < 0...1073741824 > < 1073741825 ... 3221225472 > < 3221225472 ... 4294967295 > // Group 1 : < 0...1073741824 > + < 3221225472 ... 4294967295 > => number value : 2147483648 // Group 2 : < 1073741825 ... 3221225472 > => number value : 2147483648 // if ( a >= 1073741825 && a <= 3221225472 ) return a - b; a += 1073741825; b += 1073741825; return a - b; } inline void calculate_ack_bit(NetworkData * _data, bool ackBool) { // bool ackBool = (!_SystemMode && (_ConnectionState == Connected || _ConnectionState == Synchronize)); uint32_t i; uint32_t ackBit = (ackBool ? 1 : 0); if ( _data->_current_received_number - _data->_last_received_number < 32) { _data->_ack_bit_mask <<= _data->_current_received_number - _data->_last_received_number; _data->_ack_bit_mask |= _data->_last_ack_bit << (_data->_current_received_number - _data->_last_received_number - 1); } else { _data->_ack_bit_mask = (_data->_current_received_number - _data->_last_received_number == 32 && _data->_last_ack_bit != 0) ? 0x80000000 : 0x00000000; } _data->_last_ack_bit = ackBit; for(i=_data->_last_received_number+1;i<_data->_current_received_number;++i) _data->_long_ack_bit_field.clear_bit(i & 511); _data->_long_ack_bit_field.write(_data->_current_received_number & 0x1ff, ackBool); if ( diff_uint32_circulate(_data->_last_ack_in_long_ack, _data->_current_received_number) > 512 ) { _data->_last_ack_in_long_ack = _data->_current_received_number - 511; } _data->_last_received_number = _data->_current_received_number; } /* * StateConnectionBase */ StateConnectionBase::StateConnectionBase(NetworkConnectionCore * network) { this->_network = network; this->_data = & (network->_network_data); } /* * StateConnectionNotInitialized */ void StateConnectionNotInitialized::connect_to_server() { this->_network->_queue.clear(); this->_network->open_network(); this->_network->_state_connexion = & this->_network->_state_login; DBG_PRINT("connect_to_server"); } /* * StateConnectionLogin */ void StateConnectionLogin::send_system_quit() { DBG_PRINT("send quit to server"); BitStream msgout; msgout.put_uint32(this->_data->_current_received_number); msgout.put_bool(true); msgout.put_uint8(CLFECOMMON::SYSTEM_QUIT_CODE); msgout.put_sint32(this->_data->_quit_id); if ( this->_network->_socketUDP->put_packet_buffer(msgout.get_data()) != Error::OK ) { ERR_PRINT("Error to send disconnect"); } this->_network->_state_connexion = & this->_network->_state_quit; } void StateConnectionLogin::send_message() { BitStream msgout; msgout.put_uint32(this->_data->_current_received_number); msgout.put_bool(true); msgout.put_uint8(CLFECOMMON::SYSTEM_LOGIN_CODE); msgout.put_string_hexa32(this->_data->_user_addr); msgout.put_string_hexa32(this->_data->_user_key); msgout.put_string_hexa32(this->_data->_user_id); msgout.put_string(this->_data->_lang); Error ret; ret = this->_network->_socketUDP->put_packet_buffer(msgout.get_data()); // , msgout.get_data().size() if ( ret != Error::OK) { this->_network->close_network(); switch(ret) { case Error::ERR_CANT_CONNECT: ERR_PRINT("network connexion - Can't connect"); default: ERR_PRINT("network connexion - Unknown error"); } return; } DBG_PRINT("Connected to khganat"); this->_network->_state_connexion = & this->_network->_state_synchronize; } /* * StateConnectionSynchronize */ void StateConnectionSynchronize::send_system_quit() { DBG_PRINT("Send quit to server"); BitStream msgout; msgout.put_uint32(this->_data->_current_received_number); msgout.put_bool(true); msgout.put_uint8(CLFECOMMON::SYSTEM_QUIT_CODE); msgout.put_sint32(this->_data->_quit_id); if ( this->_network->_socketUDP->put_packet_buffer(msgout.get_data()) != Error::OK ) { ERR_PRINT("Error to send quit"); } this->_network->_state_connexion = & this->_network->_state_quit; } void StateConnectionSynchronize::send_system_ack_sync() { DBG_PRINT("Send system ACK Sync to server"); Ref msgout; msgout.instance(); msgout->put_uint32(this->_data->_current_received_number); msgout->put_bool(true); msgout->put_uint8(CLFECOMMON::SYSTEM_ACK_SYNC_CODE); msgout->put_sint32(this->_data->_last_received_number); msgout->put_sint32(this->_data->_last_ack_in_long_ack); this->_data->_long_ack_bit_field.write_serial(msgout); msgout->put_sint32(this->_data->_server_sync); if (this->_network->_socketUDP->put_packet_buffer(msgout->get_data()) != Error::OK) { ERR_PRINT("Error to send ack sync"); return; } msgout.unref(); this->_data->_client_sync = this->_data->_server_sync; this->_network->_state_connexion = & this->_network->_state_connected; } void StateConnectionSynchronize::receive_system_sync(Ref msgin) { bool valide = true; int i; DBG_PRINT("SYSTEM_SYNC_CODE\n"); uint32_t synchronize = msgin->get_uint32(); int64_t stime = msgin->get_sint64(); uint32_t latestsync = msgin->get_uint32(); PoolByteArray msg_xml = msgin->get_array_uint8(16); PoolByteArray database_xml = msgin->get_array_uint8(16); DBG_PRINT("SYSTEM_SYNC_CODE synchronize:" + uitos(synchronize) + ", stime:" + itos(stime) + ", latestsync:" + uitos(latestsync)); if ( msg_xml.size() != this->_data->_checksum_msg_xml.size() ) { valide = false; ERR_PRINTS("MSG XML is incorrect (server:" + itos(msg_xml.size()) +", client:" + itos(this->_data->_checksum_msg_xml.size()) + ")"); } else { for(i=0; i_data->_checksum_msg_xml[i] ) { valide = false; ERR_PRINTS("MSG XML is incorrect (pos:" + itos(i) +")"); } } } if ( valide == true ) { DBG_PRINT("MSG XML is correct"); this->_data->_server_sync = latestsync; this->_data->_synchronize = synchronize; this->_data->_current_server_tick = this->_data->_synchronize + this->_data->_current_received_number + 2; this->_data->_current_client_tick = this->_data->_current_server_tick + (LCT + this->_data->_ms_per_tick) / this->_data->_ms_per_tick; this->_data->_current_client_time = this->_data->_update_time - (LCT + this->_data->_ms_per_tick); //this->_state = STATE::Synchronize; } else ERR_PRINTS("MSG.XML is wrong"); } void StateConnectionSynchronize::receive_message(int index) { bool system_mode; DBG_PRINT("receive_message ..."); //this->_data->_current_received_number = current_received_number; Ref field = this->_network->_queue.get_msg(index); uint32_t current_received_number = field->get_id(); Ref msgin = field->get_msgin(); this->_data->_current_received_number = current_received_number; //Ref msgin = this->_network->_queue.get_msg(index)->get_msgin(); system_mode = msgin->get_bool(); if ( system_mode == true ) { int message = msgin->get_uint8(); switch (message) { case CLFECOMMON::SYSTEM_LOGIN_CODE: DBG_PRINT("SYSTEM_LOGIN_CODE\n"); break; case CLFECOMMON::SYSTEM_SYNC_CODE: this->receive_system_sync(msgin); break; case CLFECOMMON::SYSTEM_STALLED_CODE: DBG_PRINT("SYSTEM_STALLED_CODE\n"); break; case CLFECOMMON::SYSTEM_SERVER_DOWN_CODE: DBG_PRINT("SYSTEM_SERVER_DOWN_CODE\n"); break; case CLFECOMMON::SYSTEM_PROBE_CODE: DBG_PRINT("SYSTEM_PROBE_CODE\n"); break; default: ERR_PRINTS("Received unknown message [" + itos(message) + "]"); break; } } // this->_last_received_number = current_received_number; this->_network->_queue.erase_index(index); } void StateConnectionSynchronize::send_message() { //DEBUG_PRINTS("[%s:%d] send_system %d / %d \n", __FILE__, __LINE__, this->_data->_server_sync, this->_data->_client_sync); if ( this->_data->_server_sync != this->_data->_client_sync ) this->send_system_ack_sync(); } /* * StateConnectionConnected */ void StateConnectionConnected::send_system_quit() { DBG_PRINT("Send quit to server"); BitStream msgout; msgout.put_uint32(this->_data->_current_received_number); msgout.put_bool(true); msgout.put_uint8(CLFECOMMON::SYSTEM_QUIT_CODE); msgout.put_sint32(this->_data->_quit_id); if ( this->_network->_socketUDP->put_packet_buffer(msgout.get_data()) != Error::OK ) { ERR_PRINT("Error to send disconnect"); } this->_network->_state_connexion = & this->_network->_state_quit; } void StateConnectionConnected::send_system_disconnect() { //if ( this->_state != STATE::Connected && this->_state != STATE::ForceSynchronize ) return; DBG_PRINT("Send disconnect to server"); BitStream msgout; msgout.put_uint32(this->_data->_current_received_number); msgout.put_bool(true); msgout.put_uint8(CLFECOMMON::SYSTEM_DISCONNECTION_CODE); if ( this->_network->_socketUDP->put_packet_buffer(msgout.get_data()) != Error::OK ) { ERR_PRINT("Error to send disconnect"); } this->_network->_socketUDP->close(); // this->_state = STATE::Disconnect; this->_network->_state_connexion = & this->_network->_state_not_initialized; } void StateConnectionConnected::send_system_ack_sync() { DBG_PRINT("Send system ACK Sync to server"); Ref msgout; msgout.instance(); msgout->put_uint32(this->_data->_current_received_number); msgout->put_bool(true); msgout->put_uint8(CLFECOMMON::SYSTEM_ACK_SYNC_CODE); msgout->put_sint32(this->_data->_last_received_number); msgout->put_sint32(this->_data->_last_ack_in_long_ack); this->_data->_long_ack_bit_field.write_serial(msgout); msgout->put_sint32(this->_data->_server_sync); if (this->_network->_socketUDP->put_packet_buffer(msgout->get_data()) != Error::OK) { ERR_PRINT("Error to send ack sync"); return; } msgout.unref(); this->_data->_client_sync = this->_data->_server_sync; } void StateConnectionConnected::send_system_ack_probe() { // khanat-opennel-code/code/ryzom/server/src/frontend_service/fe_receive_sub.cpp:1121 void CFeReceiveSub::handleReceivedMsg( CClientHost *clienthost ) DBG_PRINT("Send system ACK PROBE to server"); int max = this->_data->_latest_probes.size() ; BitStream msgout; msgout.put_uint32(this->_data->_current_received_number); msgout.put_bool(true); msgout.put_uint8(CLFECOMMON::SYSTEM_ACK_PROBE_CODE); msgout.put_sint32(max); for(int i=0; i < max ; ++i ) { int data = this->_data->_latest_probes[i]; msgout.put_sint32(data); } if (this->_network->_socketUDP->put_packet_buffer(msgout.get_data()) != Error::OK) { ERR_PRINT("Error to send disconnect"); return; } this->_data->_latest_probes.clear(); } void StateConnectionConnected::receive_system_sync(Ref msgin) { bool valide = true; int i; DBG_PRINT("SYSTEM_SYNC_CODE"); uint32_t synchronize = msgin->get_uint32(); int64_t stime = msgin->get_sint64(); uint32_t latestsync = msgin->get_uint32(); PoolByteArray msg_xml = msgin->get_array_uint8(16); PoolByteArray database_xml = msgin->get_array_uint8(16); DBG_PRINT("SYSTEM_SYNC_CODE synchronize:" + uitos(synchronize) + ", stime:" + itos(stime) + ", latestsync:" + uitos(latestsync)); if ( msg_xml.size() != this->_data->_checksum_msg_xml.size() ) { valide = false; ERR_PRINTS("MSG XML is incorrect (server:" + itos(msg_xml.size()) +", client:" + itos(this->_data->_checksum_msg_xml.size()) + ")"); } else { for(i=0; i_data->_checksum_msg_xml[i] ) { valide = false; ERR_PRINTS("MSG XML is incorrect (pos:" + itos(i) +")"); } } } if ( valide == true ) { DBG_PRINT("MSG XML is correct"); this->_data->_server_sync = latestsync; this->_data->_synchronize = synchronize; this->_data->_current_server_tick = this->_data->_synchronize + this->_data->_current_received_number + 2; this->_data->_current_client_tick = this->_data->_current_server_tick + (LCT + this->_data->_ms_per_tick) / this->_data->_ms_per_tick; this->_data->_current_client_time = this->_data->_update_time - (LCT + this->_data->_ms_per_tick); //this->_state = STATE::Synchronize; } else ERR_PRINTS("MSG.XML is wrong"); } void StateConnectionConnected::receive_message(int index) { // SHOW_USAGE_MEMORY bool system_mode; //INF_PRINT("Receive application message"); Ref field = this->_network->_queue.get_msg(index); uint32_t current_received_number = field->get_id(); if (current_received_number - this->_data->_current_received_number != 1) { if(this->_network->_queue.length() >= MAX_SIZE_BIT_STREAM_QUEUE) this->_network->_state_connexion = & this->_network->_state_synchronize; return; } this->_data->_current_received_number = current_received_number; Ref msgin = field->get_msgin(); system_mode = msgin->get_bool(); if ( system_mode == true ) { //DEBUG_PRINTS("[%s:%d] system message (%d) [%d]\n", __FILE__, __LINE__, (int)current_received_number, this->_network->_queue.length()); int message = msgin->get_uint8(); switch (message) { case CLFECOMMON::SYSTEM_LOGIN_CODE: DBG_PRINT("Receive SYSTEM_LOGIN_CODE (" + itos(current_received_number) + ") [" + uitos(this->_network->_queue.length()) + "]"); break; case CLFECOMMON::SYSTEM_SYNC_CODE: DBG_PRINT("Receive SYSTEM_SYNC_CODE (" + itos(current_received_number) + ") [" + uitos(this->_network->_queue.length()) + "]"); this->receive_system_sync(msgin); break; case CLFECOMMON::SYSTEM_STALLED_CODE: DBG_PRINT("Receive SYSTEM_STALLED_CODE (" + itos(current_received_number) + ") [" + uitos(this->_network->_queue.length()) + "]"); break; case CLFECOMMON::SYSTEM_SERVER_DOWN_CODE: DBG_PRINT("Receive SYSTEM_SERVER_DOWN_CODE (" + itos(current_received_number) + ") [" + uitos(this->_network->_queue.length()) + "]"); break; case CLFECOMMON::SYSTEM_PROBE_CODE: DBG_PRINT("Receive SYSTEM_PROBE_CODE (" + itos(current_received_number) + ") [" + uitos(this->_network->_queue.length()) + "]"); this->_data->_latest_probes.append(msgin->get_sint32()); break; default: DBG_PRINT("Receive UNKNOWN SYSTEM MESSAGE [id:" + itos(message) + "] (" + itos(current_received_number) + ") [" + uitos(this->_network->_queue.length()) + "]"); //ERR_PRINTS("Received unknown message [" + itos(message) + "]"); break; } } else { DBG_PRINT("Receive application message (" + itos(current_received_number) + ") [" + uitos(this->_network->_queue.length()) + "]"); } calculate_ack_bit(this->_data, system_mode); //DBG_PRINT("Ack:" + this->_data->_long_ack_bit_field.show()); this->_network->_queue.erase_index(index); // Check in buffer if we have next if ( this->_network->_queue.is_index(index + 1) ) this->receive_message(index + 1); } void StateConnectionConnected::send_message() { if ( this->_data->_server_sync != this->_data->_client_sync ) this->send_system_ack_sync(); if (this->_data->_latest_probes.size() != 0 ) this->send_system_ack_probe(); } /* * */