2016-09-10 03:28:11 +03:00
/*
* Connection . cpp , part of VCMI engine
*
* Authors : listed in file AUTHORS in main folder
*
* License : GNU General Public License v2 .0 or later
* Full text of license available in license . txt file , in main folder
*
*/
2017-07-13 11:26:03 +03:00
# include "StdInc.h"
# include "Connection.h"
2023-11-11 00:39:08 +02:00
# include "../networkPacks/NetPacksBase.h"
2017-07-13 11:26:03 +03:00
# include <boost/asio.hpp>
2016-09-10 03:28:11 +03:00
2022-07-26 16:07:42 +03:00
VCMI_LIB_NAMESPACE_BEGIN
2016-09-10 03:28:11 +03:00
using namespace boost ;
using namespace boost : : asio : : ip ;
2022-12-27 12:55:31 +02:00
struct ConnectionBuffers
{
boost : : asio : : streambuf readBuffer ;
boost : : asio : : streambuf writeBuffer ;
} ;
2016-09-10 03:28:11 +03:00
void CConnection : : init ( )
{
2022-12-26 20:13:07 +02:00
enableBufferedWrite = false ;
2022-12-27 12:55:31 +02:00
enableBufferedRead = false ;
connectionBuffers = std : : make_unique < ConnectionBuffers > ( ) ;
2018-01-05 20:21:07 +03:00
socket - > set_option ( boost : : asio : : ip : : tcp : : no_delay ( true ) ) ;
2021-03-05 19:26:35 +03:00
try
{
socket - > set_option ( boost : : asio : : socket_base : : send_buffer_size ( 4194304 ) ) ;
socket - > set_option ( boost : : asio : : socket_base : : receive_buffer_size ( 4194304 ) ) ;
}
catch ( const boost : : system : : system_error & e )
{
logNetwork - > error ( " error setting socket option: %s " , e . what ( ) ) ;
}
2016-09-10 03:28:11 +03:00
2016-11-13 12:44:46 +03:00
enableSmartPointerSerialization ( ) ;
2016-09-10 03:28:11 +03:00
disableStackSendingByID ( ) ;
2023-02-11 18:13:21 +03:00
# ifndef VCMI_ENDIAN_BIG
2016-09-10 03:28:11 +03:00
myEndianess = true ;
# else
myEndianess = false ;
# endif
connected = true ;
std : : string pom ;
//we got connection
2018-01-05 20:21:07 +03:00
oser & std : : string ( " Aiya! \n " ) & name & uuid & myEndianess ; //identify ourselves
iser & pom & pom & contactUuid & contactEndianess ;
logNetwork - > info ( " Established connection with %s. UUID: %s " , pom , contactUuid ) ;
mutexRead = std : : make_shared < boost : : mutex > ( ) ;
mutexWrite = std : : make_shared < boost : : mutex > ( ) ;
2016-09-10 03:28:11 +03:00
2016-10-29 19:52:19 +03:00
iser . fileVersion = SERIALIZATION_VERSION ;
2016-09-10 03:28:11 +03:00
}
2023-02-11 18:13:21 +03:00
CConnection : : CConnection ( const std : : string & host , ui16 port , std : : string Name , std : : string UUID ) :
io_service ( std : : make_shared < asio : : io_service > ( ) ) ,
iser ( this ) ,
oser ( this ) ,
name ( std : : move ( Name ) ) ,
uuid ( std : : move ( UUID ) )
2016-09-10 03:28:11 +03:00
{
2023-02-11 18:13:21 +03:00
int i = 0 ;
2016-09-10 03:28:11 +03:00
boost : : system : : error_code error = asio : : error : : host_not_found ;
2018-01-05 20:21:07 +03:00
socket = std : : make_shared < tcp : : socket > ( * io_service ) ;
2022-12-26 20:13:07 +02:00
2016-09-10 03:28:11 +03:00
tcp : : resolver resolver ( * io_service ) ;
2023-02-11 18:13:21 +03:00
tcp : : resolver : : iterator end ;
tcp : : resolver : : iterator pom ;
tcp : : resolver : : iterator endpoint_iterator = resolver . resolve ( tcp : : resolver : : query ( host , std : : to_string ( port ) ) , error ) ;
2016-09-10 03:28:11 +03:00
if ( error )
{
2017-08-11 20:03:05 +03:00
logNetwork - > error ( " Problem with resolving: \n %s " , error . message ( ) ) ;
2023-07-28 14:17:06 +03:00
throw std : : runtime_error ( " Problem with resolving " ) ;
2016-09-10 03:28:11 +03:00
}
pom = endpoint_iterator ;
if ( pom ! = end )
2017-08-10 19:39:27 +03:00
logNetwork - > info ( " Found endpoints: " ) ;
2016-09-10 03:28:11 +03:00
else
{
2017-08-10 19:39:27 +03:00
logNetwork - > error ( " Critical problem: No endpoints found! " ) ;
2023-07-28 14:17:06 +03:00
throw std : : runtime_error ( " No endpoints found! " ) ;
2016-09-10 03:28:11 +03:00
}
while ( pom ! = end )
{
2017-08-11 20:03:05 +03:00
logNetwork - > info ( " \t %d:%s " , i , ( boost : : asio : : ip : : tcp : : endpoint & ) * pom ) ;
2016-09-10 03:28:11 +03:00
pom + + ;
}
i = 0 ;
while ( endpoint_iterator ! = end )
{
2017-08-11 20:03:05 +03:00
logNetwork - > info ( " Trying connection to %s(%d) " , ( boost : : asio : : ip : : tcp : : endpoint & ) * endpoint_iterator , i + + ) ;
2016-09-10 03:28:11 +03:00
socket - > connect ( * endpoint_iterator , error ) ;
if ( ! error )
{
init ( ) ;
return ;
}
else
{
2023-07-28 14:17:06 +03:00
throw std : : runtime_error ( " Failed to connect! " ) ;
2016-09-10 03:28:11 +03:00
}
endpoint_iterator + + ;
}
}
2023-03-31 01:28:56 +03:00
2023-02-11 18:13:21 +03:00
CConnection : : CConnection ( std : : shared_ptr < TSocket > Socket , std : : string Name , std : : string UUID ) :
iser ( this ) ,
oser ( this ) ,
socket ( std : : move ( Socket ) ) ,
name ( std : : move ( Name ) ) ,
uuid ( std : : move ( UUID ) )
2016-09-10 03:28:11 +03:00
{
init ( ) ;
}
2023-02-11 18:13:21 +03:00
CConnection : : CConnection ( const std : : shared_ptr < TAcceptor > & acceptor ,
const std : : shared_ptr < boost : : asio : : io_service > & io_service ,
std : : string Name ,
std : : string UUID ) :
io_service ( io_service ) ,
iser ( this ) ,
oser ( this ) ,
name ( std : : move ( Name ) ) ,
uuid ( std : : move ( UUID ) )
2016-09-10 03:28:11 +03:00
{
boost : : system : : error_code error = asio : : error : : host_not_found ;
2018-01-05 20:21:07 +03:00
socket = std : : make_shared < tcp : : socket > ( * io_service ) ;
2016-09-10 03:28:11 +03:00
acceptor - > accept ( * socket , error ) ;
if ( error )
{
2017-08-11 20:03:05 +03:00
logNetwork - > error ( " Error on accepting: %s " , error . message ( ) ) ;
2018-01-05 20:21:07 +03:00
socket . reset ( ) ;
2016-09-10 03:28:11 +03:00
throw std : : runtime_error ( " Can't establish connection :( " ) ;
}
init ( ) ;
}
2022-12-26 20:13:07 +02:00
void CConnection : : flushBuffers ( )
{
if ( ! enableBufferedWrite )
return ;
2023-12-17 19:32:05 +02:00
if ( ! socket )
throw std : : runtime_error ( " Can't write to closed socket! " ) ;
2022-12-26 20:13:07 +02:00
try
{
2022-12-27 12:55:31 +02:00
asio : : write ( * socket , connectionBuffers - > writeBuffer ) ;
2022-12-26 20:13:07 +02:00
}
catch ( . . . )
{
//connection has been lost
connected = false ;
throw ;
}
enableBufferedWrite = false ;
}
2016-09-10 03:28:11 +03:00
int CConnection : : write ( const void * data , unsigned size )
{
2023-12-17 19:32:05 +02:00
if ( ! socket )
throw std : : runtime_error ( " Can't write to closed socket! " ) ;
2022-12-26 21:28:36 +02:00
try
2022-12-26 20:13:07 +02:00
{
2022-12-26 21:28:36 +02:00
if ( enableBufferedWrite )
{
2022-12-27 12:55:31 +02:00
std : : ostream ostream ( & connectionBuffers - > writeBuffer ) ;
2022-12-26 20:13:07 +02:00
2022-12-26 21:28:36 +02:00
ostream . write ( static_cast < const char * > ( data ) , size ) ;
2022-12-26 20:13:07 +02:00
2022-12-26 21:28:36 +02:00
return size ;
}
2022-12-26 20:13:07 +02:00
2023-02-11 18:13:21 +03:00
int ret = static_cast < int > ( asio : : write ( * socket , asio : : const_buffers_1 ( asio : : const_buffer ( data , size ) ) ) ) ;
2016-09-10 03:28:11 +03:00
return ret ;
}
catch ( . . . )
{
//connection has been lost
connected = false ;
throw ;
}
}
2022-12-26 20:13:07 +02:00
2016-09-10 03:28:11 +03:00
int CConnection : : read ( void * data , unsigned size )
{
try
{
2022-12-26 21:28:36 +02:00
if ( enableBufferedRead )
{
2022-12-27 12:55:31 +02:00
auto available = connectionBuffers - > readBuffer . size ( ) ;
2022-12-26 21:28:36 +02:00
while ( available < size )
{
2022-12-27 12:55:31 +02:00
auto bytesRead = socket - > read_some ( connectionBuffers - > readBuffer . prepare ( 1024 ) ) ;
connectionBuffers - > readBuffer . commit ( bytesRead ) ;
available = connectionBuffers - > readBuffer . size ( ) ;
2022-12-26 21:28:36 +02:00
}
2022-12-27 12:55:31 +02:00
std : : istream istream ( & connectionBuffers - > readBuffer ) ;
2022-12-26 21:28:36 +02:00
istream . read ( static_cast < char * > ( data ) , size ) ;
return size ;
}
2020-10-01 01:38:06 -07:00
int ret = static_cast < int > ( asio : : read ( * socket , asio : : mutable_buffers_1 ( asio : : mutable_buffer ( data , size ) ) ) ) ;
2016-09-10 03:28:11 +03:00
return ret ;
}
catch ( . . . )
{
//connection has been lost
connected = false ;
throw ;
}
}
2022-12-26 20:13:07 +02:00
2018-01-13 11:43:26 +03:00
CConnection : : ~ CConnection ( )
2016-09-10 03:28:11 +03:00
{
2023-12-03 18:56:23 +02:00
close ( ) ;
2016-09-10 03:28:11 +03:00
if ( handler )
2023-11-27 13:49:45 +02:00
{
// ugly workaround to avoid self-join if last strong reference to shared_ptr that owns this class has been released in this very thread, e.g. on netpack processing
if ( boost : : this_thread : : get_id ( ) ! = handler - > get_id ( ) )
handler - > join ( ) ;
else
handler - > detach ( ) ;
}
2016-09-10 03:28:11 +03:00
}
template < class T >
CConnection & CConnection : : operator & ( const T & t ) {
// throw std::exception();
//XXX this is temporaly ? solution to fix gcc (4.3.3, other?) compilation
// problem for more details contact t0@czlug.icis.pcz.pl or impono@gmail.com
// do not remove this exception it shoudnt be called
return * this ;
}
void CConnection : : close ( )
{
if ( socket )
{
2023-12-03 18:56:23 +02:00
try
{
socket - > shutdown ( boost : : asio : : ip : : tcp : : socket : : shutdown_receive ) ;
}
catch ( const boost : : system : : system_error & e )
{
logNetwork - > error ( " error closing socket: %s " , e . what ( ) ) ;
}
2016-09-10 03:28:11 +03:00
socket - > close ( ) ;
2018-01-05 20:21:07 +03:00
socket . reset ( ) ;
2016-09-10 03:28:11 +03:00
}
}
bool CConnection : : isOpen ( ) const
{
return socket & & connected ;
}
2017-08-11 20:03:05 +03:00
void CConnection : : reportState ( vstd : : CLoggerBase * out )
2016-09-10 03:28:11 +03:00
{
2017-08-10 19:39:27 +03:00
out - > debug ( " CConnection " ) ;
2016-09-10 03:28:11 +03:00
if ( socket & & socket - > is_open ( ) )
{
2017-08-10 19:39:27 +03:00
out - > debug ( " \t We have an open and valid socket " ) ;
2017-08-11 20:03:05 +03:00
out - > debug ( " \t %d bytes awaiting " , socket - > available ( ) ) ;
2016-09-10 03:28:11 +03:00
}
}
2018-02-10 21:52:23 +03:00
CPack * CConnection : : retrievePack ( )
2016-09-10 03:28:11 +03:00
{
2022-12-26 21:28:36 +02:00
enableBufferedRead = true ;
2018-01-05 20:21:07 +03:00
CPack * pack = nullptr ;
boost : : unique_lock < boost : : mutex > lock ( * mutexRead ) ;
iser & pack ;
2018-02-26 00:16:15 +08:00
logNetwork - > trace ( " Received CPack of type %s " , ( pack ? typeid ( * pack ) . name ( ) : " nullptr " ) ) ;
2018-01-05 20:21:07 +03:00
if ( pack = = nullptr )
logNetwork - > error ( " Received a nullptr CPack! You should check whether client and server ABI matches. " ) ;
2022-12-26 21:28:36 +02:00
enableBufferedRead = false ;
2018-01-05 20:21:07 +03:00
return pack ;
2016-09-10 03:28:11 +03:00
}
2018-01-05 20:21:07 +03:00
void CConnection : : sendPack ( const CPack * pack )
2016-09-10 03:28:11 +03:00
{
2018-01-05 20:21:07 +03:00
boost : : unique_lock < boost : : mutex > lock ( * mutexWrite ) ;
logNetwork - > trace ( " Sending a pack of type %s " , typeid ( * pack ) . name ( ) ) ;
2022-12-26 20:13:07 +02:00
enableBufferedWrite = true ;
2018-01-05 20:21:07 +03:00
oser & pack ;
2022-12-26 20:13:07 +02:00
flushBuffers ( ) ;
2016-09-10 03:28:11 +03:00
}
void CConnection : : disableStackSendingByID ( )
{
CSerializer : : sendStackInstanceByIds = false ;
}
void CConnection : : enableStackSendingByID ( )
{
CSerializer : : sendStackInstanceByIds = true ;
}
void CConnection : : disableSmartPointerSerialization ( )
{
iser . smartPointerSerialization = oser . smartPointerSerialization = false ;
}
2016-11-13 12:44:46 +03:00
void CConnection : : enableSmartPointerSerialization ( )
2016-09-10 03:28:11 +03:00
{
iser . smartPointerSerialization = oser . smartPointerSerialization = true ;
}
2018-01-05 20:21:07 +03:00
void CConnection : : enterLobbyConnectionMode ( )
2016-09-10 03:28:11 +03:00
{
iser . loadedPointers . clear ( ) ;
oser . savedPointers . clear ( ) ;
disableSmartVectorMemberSerialization ( ) ;
2018-01-05 20:21:07 +03:00
disableSmartPointerSerialization ( ) ;
2016-09-10 03:28:11 +03:00
}
2018-01-05 20:21:07 +03:00
void CConnection : : enterGameplayConnectionMode ( CGameState * gs )
2016-09-10 03:28:11 +03:00
{
2018-01-05 20:21:07 +03:00
enableStackSendingByID ( ) ;
2016-09-10 03:28:11 +03:00
disableSmartPointerSerialization ( ) ;
2018-01-05 20:21:07 +03:00
addStdVecItems ( gs ) ;
2016-09-10 03:28:11 +03:00
}
void CConnection : : disableSmartVectorMemberSerialization ( )
{
CSerializer : : smartVectorMembersSerialization = false ;
}
void CConnection : : enableSmartVectorMemberSerializatoin ( )
{
CSerializer : : smartVectorMembersSerialization = true ;
}
2017-08-11 16:50:00 +03:00
std : : string CConnection : : toString ( ) const
{
2018-01-05 20:21:07 +03:00
boost : : format fmt ( " Connection with %s (ID: %d UUID: %s) " ) ;
fmt % name % connectionID % uuid ;
return fmt . str ( ) ;
2017-08-11 16:50:00 +03:00
}
2022-07-26 16:07:42 +03:00
VCMI_LIB_NAMESPACE_END