@ -19,45 +19,41 @@
# include "../../safeguards.h"
/**
* Create a packet that is used to read from a network socket
* @ param cs the socket handler associated with the socket we are reading from
* Create a packet that is used to read from a network socket .
* @ param cs The socket handler associated with the socket we are reading from .
* @ param initial_read_size The initial amount of data to transfer from the socket into the
* packet . This defaults to just the required bytes to determine the
* packet ' s size . That default is the wanted for streams such as TCP
* as you do not want to read data of the next packet yet . For UDP
* you need to read the whole packet at once otherwise you might
* loose some the data of the packet , so there you pass the maximum
* size for the packet you expect from the network .
*/
Packet : : Packet ( NetworkSocketHandler * cs )
Packet : : Packet ( NetworkSocketHandler * cs , size_t initial_read_size ) : pos ( 0 )
{
assert ( cs ! = nullptr ) ;
this - > cs = cs ;
this - > pos = 0 ; // We start reading from here
this - > size = 0 ;
this - > buffer = MallocT < byte > ( SHRT_MAX ) ;
this - > cs = cs ;
this - > buffer . resize ( initial_read_size ) ;
}
/**
* Creates a packet to send
* @ param type of the packet to send
*/
Packet : : Packet ( PacketType type )
Packet : : Packet ( PacketType type ) : pos ( 0 ) , cs ( nullptr )
{
this - > buffer = MallocT < byte > ( SHRT_MAX ) ;
this - > ResetState ( type ) ;
}
/**
* Free the buffer of this packet .
*/
Packet : : ~ Packet ( )
{
free ( this - > buffer ) ;
}
void Packet : : ResetState ( PacketType type )
{
this - > cs = nullptr ;
this - > cs = nullptr ;
this - > buffer . clear ( ) ;
/* Skip the size so we can write that in before sending the packet */
this - > pos = 0 ;
this - > size = sizeof ( PacketSize ) ;
this - > buffer [ this - > size + + ] = type ;
/* Allocate space for the the size so we can write that in just before sending the packet. */
this - > Send_uint16 ( 0 ) ;
this - > Send_uint8 ( type ) ;
}
/**
@ -67,10 +63,21 @@ void Packet::PrepareToSend()
{
assert ( this - > cs = = nullptr ) ;
this - > buffer [ 0 ] = GB ( this - > size , 0 , 8 ) ;
this - > buffer [ 1 ] = GB ( this - > size , 8 , 8 ) ;
this - > buffer [ 0 ] = GB ( this - > Size( ) , 0 , 8 ) ;
this - > buffer [ 1 ] = GB ( this - > Size( ) , 8 , 8 ) ;
this - > pos = 0 ; // We start reading from here
this - > buffer . shrink_to_fit ( ) ;
}
/**
* Is it safe to write to the packet , i . e . didn ' t we run over the buffer ?
* @ param bytes_to_write The amount of bytes we want to try to write .
* @ return True iff the given amount of bytes can be written to the packet .
*/
bool Packet : : CanWriteToPacket ( size_t bytes_to_write )
{
return this - > Size ( ) + bytes_to_write < SHRT_MAX ;
}
/*
@ -100,8 +107,8 @@ void Packet::Send_bool(bool data)
*/
void Packet : : Send_uint8 ( uint8 data )
{
assert ( this - > size < SHRT_MAX - sizeof ( data ) ) ;
this - > buffer [this - > size + + ] = data ;
assert ( this - > CanWriteToPacket( sizeof ( data ) ) ) ;
this - > buffer .emplace_back ( data ) ;
}
/**
@ -110,9 +117,11 @@ void Packet::Send_uint8(uint8 data)
*/
void Packet : : Send_uint16 ( uint16 data )
{
assert ( this - > size < SHRT_MAX - sizeof ( data ) ) ;
this - > buffer [ this - > size + + ] = GB ( data , 0 , 8 ) ;
this - > buffer [ this - > size + + ] = GB ( data , 8 , 8 ) ;
assert ( this - > CanWriteToPacket ( sizeof ( data ) ) ) ;
this - > buffer . insert ( this - > buffer . end ( ) , {
( uint8 ) GB ( data , 0 , 8 ) ,
( uint8 ) GB ( data , 8 , 8 ) ,
} ) ;
}
/**
@ -121,11 +130,13 @@ void Packet::Send_uint16(uint16 data)
*/
void Packet : : Send_uint32 ( uint32 data )
{
assert ( this - > size < SHRT_MAX - sizeof ( data ) ) ;
this - > buffer [ this - > size + + ] = GB ( data , 0 , 8 ) ;
this - > buffer [ this - > size + + ] = GB ( data , 8 , 8 ) ;
this - > buffer [ this - > size + + ] = GB ( data , 16 , 8 ) ;
this - > buffer [ this - > size + + ] = GB ( data , 24 , 8 ) ;
assert ( this - > CanWriteToPacket ( sizeof ( data ) ) ) ;
this - > buffer . insert ( this - > buffer . end ( ) , {
( uint8 ) GB ( data , 0 , 8 ) ,
( uint8 ) GB ( data , 8 , 8 ) ,
( uint8 ) GB ( data , 16 , 8 ) ,
( uint8 ) GB ( data , 24 , 8 ) ,
} ) ;
}
/**
@ -134,15 +145,17 @@ void Packet::Send_uint32(uint32 data)
*/
void Packet : : Send_uint64 ( uint64 data )
{
assert ( this - > size < SHRT_MAX - sizeof ( data ) ) ;
this - > buffer [ this - > size + + ] = GB ( data , 0 , 8 ) ;
this - > buffer [ this - > size + + ] = GB ( data , 8 , 8 ) ;
this - > buffer [ this - > size + + ] = GB ( data , 16 , 8 ) ;
this - > buffer [ this - > size + + ] = GB ( data , 24 , 8 ) ;
this - > buffer [ this - > size + + ] = GB ( data , 32 , 8 ) ;
this - > buffer [ this - > size + + ] = GB ( data , 40 , 8 ) ;
this - > buffer [ this - > size + + ] = GB ( data , 48 , 8 ) ;
this - > buffer [ this - > size + + ] = GB ( data , 56 , 8 ) ;
assert ( this - > CanWriteToPacket ( sizeof ( data ) ) ) ;
this - > buffer . insert ( this - > buffer . end ( ) , {
( uint8 ) GB ( data , 0 , 8 ) ,
( uint8 ) GB ( data , 8 , 8 ) ,
( uint8 ) GB ( data , 16 , 8 ) ,
( uint8 ) GB ( data , 24 , 8 ) ,
( uint8 ) GB ( data , 32 , 8 ) ,
( uint8 ) GB ( data , 40 , 8 ) ,
( uint8 ) GB ( data , 48 , 8 ) ,
( uint8 ) GB ( data , 56 , 8 ) ,
} ) ;
}
/**
@ -153,9 +166,24 @@ void Packet::Send_uint64(uint64 data)
void Packet : : Send_string ( const char * data )
{
assert ( data ! = nullptr ) ;
/* The <= *is* valid due to the fact that we are comparing sizes and not the index. */
assert ( this - > size + strlen ( data ) + 1 < = SHRT_MAX ) ;
while ( ( this - > buffer [ this - > size + + ] = * data + + ) ! = ' \0 ' ) { }
/* Length of the string + 1 for the '\0' termination. */
assert ( this - > CanWriteToPacket ( strlen ( data ) + 1 ) ) ;
while ( this - > buffer . emplace_back ( * data + + ) ! = ' \0 ' ) { }
}
/**
* Send as many of the bytes as possible in the packet . This can mean
* that it is possible that not all bytes are sent . To cope with this
* the function returns the amount of bytes that were actually sent .
* @ param begin The begin of the buffer to send .
* @ param end The end of the buffer to send .
* @ return The number of bytes that were added to this packet .
*/
size_t Packet : : Send_bytes ( const byte * begin , const byte * end )
{
size_t amount = std : : min < size_t > ( end - begin , SHRT_MAX - this - > Size ( ) ) ;
this - > buffer . insert ( this - > buffer . end ( ) , begin , begin + amount ) ;
return amount ;
}
/**
@ -165,9 +193,8 @@ void Packet::Send_string(const char *data)
void Packet : : Send_binary ( const char * data , const size_t size )
{
assert ( data ! = nullptr ) ;
assert ( this - > size + size < = SHRT_MAX ) ;
memcpy ( & this - > buffer [ this - > size ] , data , size ) ;
this - > size + = ( PacketSize ) size ;
assert ( this - > CanWriteToPacket ( size ) ) ;
this - > buffer . insert ( this - > buffer . end ( ) , data , data + size ) ;
}
@ -179,33 +206,72 @@ void Packet::Send_binary(const char *data, const size_t size)
/**
* Is it safe to read from the packet , i . e . didn ' t we run over the buffer ?
* @ param bytes_to_read The amount of bytes we want to try to read .
* @ param non_fatal True if a false return value is considered non - fatal , and will not raise an error .
* Is it safe to read from the packet , i . e . didn ' t we run over the buffer ?
* In case \ c close_connection is true , the connection will be closed when one would
* overrun the buffer . When it is false , the connection remains untouched .
* @ param bytes_to_read The amount of bytes we want to try to read .
* @ param close_connection Whether to close the connection if one cannot read that amount .
* @ return True if that is safe , otherwise false .
*/
bool Packet : : CanReadFromPacket ( uin t bytes_to_read , bool non_fatal )
bool Packet : : CanReadFromPacket ( size_ t bytes_to_read , bool close_co nnecti on)
{
/* Don't allow reading from a quit client/client who send bad data */
if ( this - > cs - > HasClientQuit ( ) ) return false ;
/* Check if variable is within packet-size */
if ( this - > pos + bytes_to_read > this - > size ) {
if ( ! non_fatal ) this - > cs - > NetworkSocketHandler : : CloseConnection ( ) ;
if ( this - > pos + bytes_to_read > this - > Size( ) ) {
if ( close_connection ) this - > cs - > NetworkSocketHandler : : CloseConnection ( ) ;
return false ;
}
return true ;
}
/**
* Check whether the packet , given the position of the " write " pointer , has read
* enough of the packet to contain its size .
* @ return True iff there is enough data in the packet to contain the packet ' s size .
*/
bool Packet : : HasPacketSizeData ( ) const
{
return this - > pos > = sizeof ( PacketSize ) ;
}
/**
* Get the number of bytes in the packet .
* When sending a packet this is the size of the data up to that moment .
* When receiving a packet ( before PrepareToRead ) this is the allocated size for the data to be read .
* When reading a packet ( after PrepareToRead ) this is the full size of the packet .
* @ return The packet ' s size .
*/
size_t Packet : : Size ( ) const
{
return this - > buffer . size ( ) ;
}
size_t Packet : : ReadRawPacketSize ( ) const
{
return ( size_t ) this - > buffer [ 0 ] + ( ( size_t ) this - > buffer [ 1 ] < < 8 ) ;
}
/**
* Reads the packet size from the raw packet and stores it in the packet - > size
* @ return True iff the packet size seems plausible .
*/
void Packet : : ReadRawPacketSize ( )
bool Packet : : Parse PacketSize( )
{
assert ( this - > cs ! = nullptr ) ;
this - > size = ( PacketSize ) this - > buffer [ 0 ] ;
this - > size + = ( PacketSize ) this - > buffer [ 1 ] < < 8 ;
size_t size = ( size_t ) this - > buffer [ 0 ] ;
size + = ( size_t ) this - > buffer [ 1 ] < < 8 ;
/* If the size of the packet is less than the bytes required for the size and type of
* the packet , or more than the allowed limit , then something is wrong with the packet .
* In those cases the packet can generally be regarded as containing garbage data . */
if ( size < sizeof ( PacketSize ) + sizeof ( PacketType ) ) return false ;
this - > buffer . resize ( size ) ;
this - > pos = sizeof ( PacketSize ) ;
return true ;
}
/**
@ -213,12 +279,20 @@ void Packet::ReadRawPacketSize()
*/
void Packet : : PrepareToRead ( )
{
this - > ReadRawPacketSize ( ) ;
/* Put the position on the right place */
this - > pos = sizeof ( PacketSize ) ;
}
/**
* Get the \ c PacketType from this packet .
* @ return The packet type .
*/
PacketType Packet : : GetPacketType ( ) const
{
assert ( this - > Size ( ) > = sizeof ( PacketSize ) + sizeof ( PacketType ) ) ;
return static_cast < PacketType > ( buffer [ sizeof ( PacketSize ) ] ) ;
}
/**
* Read a boolean from the packet .
* @ return The read data .
@ -236,7 +310,7 @@ uint8 Packet::Recv_uint8()
{
uint8 n ;
if ( ! this - > CanReadFromPacket ( sizeof ( n ) )) return 0 ;
if ( ! this - > CanReadFromPacket ( sizeof ( n ) , true )) return 0 ;
n = this - > buffer [ this - > pos + + ] ;
return n ;
@ -250,7 +324,7 @@ uint16 Packet::Recv_uint16()
{
uint16 n ;
if ( ! this - > CanReadFromPacket ( sizeof ( n ) )) return 0 ;
if ( ! this - > CanReadFromPacket ( sizeof ( n ) , true )) return 0 ;
n = ( uint16 ) this - > buffer [ this - > pos + + ] ;
n + = ( uint16 ) this - > buffer [ this - > pos + + ] < < 8 ;
@ -265,7 +339,7 @@ uint32 Packet::Recv_uint32()
{
uint32 n ;
if ( ! this - > CanReadFromPacket ( sizeof ( n ) )) return 0 ;
if ( ! this - > CanReadFromPacket ( sizeof ( n ) , true )) return 0 ;
n = ( uint32 ) this - > buffer [ this - > pos + + ] ;
n + = ( uint32 ) this - > buffer [ this - > pos + + ] < < 8 ;
@ -282,7 +356,7 @@ uint64 Packet::Recv_uint64()
{
uint64 n ;
if ( ! this - > CanReadFromPacket ( sizeof ( n ) )) return 0 ;
if ( ! this - > CanReadFromPacket ( sizeof ( n ) , true )) return 0 ;
n = ( uint64 ) this - > buffer [ this - > pos + + ] ;
n + = ( uint64 ) this - > buffer [ this - > pos + + ] < < 8 ;
@ -311,13 +385,13 @@ void Packet::Recv_string(char *buffer, size_t size, StringValidationSettings set
if ( cs - > HasClientQuit ( ) ) return ;
pos = this - > pos ;
while ( - - size > 0 & & pos < this - > size & & ( * buffer + + = this - > buffer [ pos + + ] ) ! = ' \0 ' ) { }
while ( - - size > 0 & & pos < this - > Size( ) & & ( * buffer + + = this - > buffer [ pos + + ] ) ! = ' \0 ' ) { }
if ( size = = 0 | | pos = = this - > size ) {
if ( size = = 0 | | pos = = this - > Size( ) ) {
* buffer = ' \0 ' ;
/* If size was sooner to zero then the string in the stream
* skip till the \ 0 , so than packet can be read out correctly for the rest */
while ( pos < this - > size & & this - > buffer [ pos ] ! = ' \0 ' ) pos + + ;
while ( pos < this - > Size( ) & & this - > buffer [ pos ] ! = ' \0 ' ) pos + + ;
pos + + ;
}
this - > pos = pos ;
@ -325,6 +399,15 @@ void Packet::Recv_string(char *buffer, size_t size, StringValidationSettings set
str_validate ( bufp , last , settings ) ;
}
/**
* Get the amount of bytes that are still available for the Transfer functions .
* @ return The number of bytes that still have to be transfered .
*/
size_t Packet : : RemainingBytesToTransfer ( ) const
{
return this - > Size ( ) - this - > pos ;
}
/**
* Reads a string till it finds a ' \0 ' in the stream .
* @ param buffer The buffer to put the data into .
@ -335,8 +418,8 @@ void Packet::Recv_string(std::string &buffer, StringValidationSettings settings)
/* Don't allow reading from a closed socket */
if ( cs - > HasClientQuit ( ) ) return ;
size_t length = ttd_strnlen ( ( const char * ) ( this - > buffer + this - > pos ) , this - > size - this - > pos - 1 ) ;
buffer . assign ( ( const char * ) ( this - > buffer + this - > pos ) , length ) ;
size_t length = ttd_strnlen ( ( const char * ) ( this - > buffer . data ( ) + this - > pos ) , this - > Size( ) - this - > pos - 1 ) ;
buffer . assign ( ( const char * ) ( this - > buffer . data ( ) + this - > pos ) , length ) ;
this - > pos + = length + 1 ;
str_validate_inplace ( buffer , settings ) ;
}
@ -348,7 +431,7 @@ void Packet::Recv_string(std::string &buffer, StringValidationSettings settings)
*/
void Packet : : Recv_binary ( char * buffer , size_t size )
{
if ( ! this - > CanReadFromPacket ( size )) return ;
if ( ! this - > CanReadFromPacket ( size , true )) return ;
memcpy ( buffer , & this - > buffer [ this - > pos ] , size ) ;
this - > pos + = ( PacketSize ) size ;
@ -361,7 +444,7 @@ void Packet::Recv_binary(char *buffer, size_t size)
*/
void Packet : : Recv_binary ( std : : string & buffer , size_t size )
{
if ( ! this - > CanReadFromPacket ( size )) return ;
if ( ! this - > CanReadFromPacket ( size , true )) return ;
buffer . assign ( ( const char * ) & this - > buffer [ this - > pos ] , size ) ;
this - > pos + = ( PacketSize ) size ;