/*
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"
#include "modules/action/action_factory.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
//
// TODO - check how server manage cyclic uint32 (receivedPacket / receivedAck)
// if not managed, hum
if ( a >= 1073741825 && a <= 3221225472 )
return a - b;
a += 1073741825;
b += 1073741825;
return a - b;
}
inline void calculate_ack_bit(NetworkData * _data, bool ackBool)
{
// khanat-opennel-code/code/ryzom/client/src/network_connection.cpp # bool CNetworkConnection::decodeHeader(CBitMemStream &msgin, bool checkMessageNumber)
// 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 )
if ( _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);
//this->_data = new Ref(network->_network_data);
//this->_data.reference_ptr(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 msg:" + itos(this->_data->_current_send_number));
BitStream msgout;
msgout.put_uint32(this->_data->_current_send_number);
msgout.put_bool(true);
msgout.put_uint8(CLFECOMMON::SYSTEM_QUIT_CODE);
msgout.put_sint32(this->_data->_quit_id);
DBG_PRINT("Send msg:" + itos(this->_data->_current_send_number) + " - " + msgout.show_detail());
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;
this->_data->_current_send_number ++;
}
void StateConnectionLogin::send_message()
{
BitStream msgout;
DBG_PRINT("Send quit to server msg:" + itos(this->_data->_current_send_number));
msgout.put_uint32(this->_data->_current_send_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;
DBG_PRINT("Send msg:" + itos(this->_data->_current_send_number) + " - " + msgout.show_detail());
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;
this->_data->_current_send_number ++;
}
/*
* StateConnectionSynchronize
*/
void StateConnectionSynchronize::send_system_quit()
{
DBG_PRINT("Send quit to server msg:" + itos(this->_data->_current_send_number));
BitStream msgout;
msgout.put_uint32(this->_data->_current_send_number);
msgout.put_bool(true);
msgout.put_uint8(CLFECOMMON::SYSTEM_QUIT_CODE);
msgout.put_sint32(this->_data->_quit_id);
DBG_PRINT("Send msg:" + itos(this->_data->_current_send_number) + " - " + msgout.show_detail());
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;
this->_data->_current_send_number ++;
}
void StateConnectionSynchronize::send_system_ack_sync()
{
DBG_PRINT("Send system ACK Sync to server msg:" + itos(this->_data->_current_send_number));
Ref msgout;
msgout.instance();
msgout->put_uint32(this->_data->_current_send_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);
DBG_PRINT("Send msg:" + itos(this->_data->_current_send_number) + " - " + msgout->show_detail());
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;
this->_data->_current_send_number ++;
}
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_PRINT("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_PRINT("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_PRINT("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_PRINT("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 msg:" + itos(this->_data->_current_send_number));
BitStream msgout;
msgout.put_uint32(this->_data->_current_send_number);
msgout.put_bool(true);
msgout.put_uint8(CLFECOMMON::SYSTEM_QUIT_CODE);
msgout.put_sint32(this->_data->_quit_id);
DBG_PRINT("Send msg:" + itos(this->_data->_current_send_number) + " - " + msgout.show_detail());
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;
this->_data->_current_send_number ++;
}
void StateConnectionConnected::send_system_disconnect()
{
//if ( this->_state != STATE::Connected && this->_state != STATE::ForceSynchronize ) return;
DBG_PRINT("Send disconnect to server msg:" + itos(this->_data->_current_send_number));
BitStream msgout;
msgout.put_uint32(this->_data->_current_send_number);
msgout.put_bool(true);
msgout.put_uint8(CLFECOMMON::SYSTEM_DISCONNECTION_CODE);
DBG_PRINT("Send msg:" + itos(this->_data->_current_send_number) + " - " + msgout.show_detail());
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;
this->_data->_current_send_number ++;
}
void StateConnectionConnected::send_system_ack_sync()
{
DBG_PRINT("Send system ACK Sync to server msg:" + itos(this->_data->_current_send_number));
Ref msgout;
msgout.instance();
msgout->put_uint32(this->_data->_current_send_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->_data->_current_send_number ++;
}
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 msg:" + itos(this->_data->_current_send_number));
int max = this->_data->_latest_probes.size() ;
BitStream msgout;
msgout.put_uint32(this->_data->_current_send_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);
}
DBG_PRINT("Send msg:" + itos(this->_data->_current_send_number) + " - " + msgout.show_detail());
if (this->_network->_socketUDP->put_packet_buffer(msgout.get_data()) != Error::OK)
{
ERR_PRINT("Error to send disconnect");
return;
}
this->_data->_latest_probes.clear();
this->_data->_current_send_number ++;
}
void StateConnectionConnected::send_normal_message()
{
// khanat-opennel-code/code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::sendNormalMessage()
DBG_PRINT("Send Normal Message msg:" + itos(this->_data->_current_send_number));
BitStream msgout;
msgout.put_uint32(this->_data->_current_send_number);
DBG_PRINT("msgout A:" + msgout.show_detail());
msgout.put_bool(false);
DBG_PRINT("msgout B:" + msgout.show_detail());
msgout.put_uint32(this->_data->_last_received_number);
DBG_PRINT("msgout C:" + msgout.show_detail());
msgout.put_uint32(this->_data->_ack_bit_mask);
DBG_PRINT("msgout D:" + msgout.show_detail());
// Method count element and send group
{
uint32_t nb = msgout.size_data() + 32 + 8;
uint8_t ele = 0;
while( (ele < this->_data->_client_messages.size()) && (ele < 255) )
{
Ref tmp = this->_data->_client_messages[ele];
++ ele;
nb += tmp->size_data();
if ( nb > 3840 ) // 3840 = 480*8
break;
}
if (ele > 0)
{
DBG_PRINT("Send message");
//msgout.put_uint32(this->_data->_current_server_tick); // Cycle
msgout.put_uint32(++this->_data->_current_client_tick); // Increase Cylce and send with new value
DBG_PRINT("msgout E:" + msgout.show_detail());
msgout.put_uint8(ele);
DBG_PRINT("msgout F:" + msgout.show_detail());
while( ele > 0 )
{
Ref tmp = this->_data->_client_messages.pop_front();
msgout.put_bitstream(tmp.ptr());
DBG_PRINT("Send message " + msgout.show_detail());
-- ele;
if ( msgout.number_bit_not_read() > 3840 ) // 3840 = 480*8
break;
}
#ifdef DEBUG_ENABLED
if ( msgout.size_data() != nb ) // 3840 = 480*8
{
ERR_PRINT("****** " + itos(msgout.size_data()) + " / " + itos(nb));
}
#endif
}
}
// Method check size and send one element
/*
while( this->_data->_client_messages.size() > 0 )
{
DBG_PRINT("Send message");
msgout.put_uint32(this->_data->_current_server_tick); // Cycle
DBG_PRINT("msgout E:" + msgout.show_detail());
msgout.put_uint8(1);
DBG_PRINT("msgout F:" + msgout.show_detail());
Ref tmp = this->_data->_client_messages.pop_front();
msgout.put_bitstream(tmp.ptr());
DBG_PRINT("Send message " + msgout.show_detail());
if ( msgout.number_bit_not_read() > 3840 ) // 3840 = 480*8
break;
}
*/
DBG_PRINT("msgout G:" + msgout.show_detail());
DBG_PRINT("Send msg:" + itos(this->_data->_current_send_number) + " - " + msgout.show_detail());
DBG_PRINT("current_received_number:" + itos(this->_data->_current_send_number) + " last_received_number:" + itos(this->_data->_last_received_number) + " ack_bit_mask:" + itos(this->_data->_ack_bit_mask));
if (this->_network->_socketUDP->put_packet_buffer(msgout.get_data()) != Error::OK)
{
ERR_PRINT("Error to send disconnect");
return;
}
this->_data->_recieved_new_server_tick = false;
this->_data->_current_send_number ++;
}
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_PRINT("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_PRINT("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_PRINT("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;
this->_data->_recieved_new_server_tick = true;
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 (current_received_number:" + itos(current_received_number) + ") [queue length:" + uitos(this->_network->_queue.length()) + "]");
ActionFactory decoder;
decoder.decode(this->_data, msgin);
}
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()
{
ActionFactory::pack(this->_data);
if ( this->_data->_server_sync != this->_data->_client_sync )
this->send_system_ack_sync();
else if (this->_data->_latest_probes.size() != 0 )
this->send_system_ack_probe();
else if (this->_data->_recieved_new_server_tick == true)
this->send_normal_message();
//else if (this->_data->_client_messages.size() > 0)
/// this->send_normal_message();
}
/*
*
*/