2020-03-25 15:49:13 +01:00
# include "../../../VoIPController.h"
2020-03-21 21:33:51 +01:00
# include "PacketStructs.h"
2020-01-25 20:45:43 +01:00
using namespace tgvoip ;
2020-03-21 21:33:51 +01:00
bool Packet : : parseLegacy ( const BufferInputStream & in , const VersionInfo & ver )
{
2020-03-24 15:07:56 +01:00
legacy = true ;
2020-03-25 15:49:13 +01:00
2020-03-21 21:33:51 +01:00
// Version-specific extraction of legacy packet fields ackId (last received packet seq on remote), (incoming packet seq) pseq, (ack mask) acks, (packet type) type, (flags) pflags, packet length
uint32_t ackId ; // Last received packet seqno on remote
uint32_t pseq ; // Incoming packet seqno
uint32_t acks ; // Ack mask
unsigned char type , pflags ; // Packet type, flags
size_t packetInnerLen = 0 ;
2020-03-25 21:38:07 +01:00
if ( ver . isLegacy ( ) )
2020-03-21 21:33:51 +01:00
{
if ( ! (
in . TryRead ( type ) & &
in . TryRead ( ackId ) & &
in . TryRead ( pseq ) & &
in . TryRead ( acks ) & &
in . TryRead ( pflags ) ) )
return false ;
packetInnerLen = in . Remaining ( ) ;
}
else if ( ! parseLegacyLegacy ( in , type , ackId , pseq , acks , pflags , packetInnerLen , ver . peerVersion ) )
{
return false ;
}
this - > legacySeq = pseq ;
this - > ackSeq = ackId ;
this - > ackMask = acks ;
// Extra data
if ( pflags & XPFLAG_HAS_EXTRA )
{
if ( ! in . TryRead ( extraSignaling , ver ) )
return false ;
}
if ( pflags & XPFLAG_HAS_RECV_TS )
{
if ( ! in . TryRead ( recvTS ) )
return false ;
}
if ( auto extra = Extra : : chooseFromType ( type ) )
{
if ( ! extra - > parse ( in , ver ) )
return false ;
extraSignaling . v . push_back ( Wrapped < Extra > ( std : : move ( extra ) ) ) ;
streamId = 0 ;
}
else if ( type = = PKT_STREAM_EC )
{
if ( ver . peerVersion < 7 )
{
uint8_t count ;
if ( ! ( in . TryRead ( streamId ) & & in . TryRead ( seq ) & & in . TryRead ( count ) ) )
return false ;
seq / = 60 ; // Constant frame duration
2020-03-25 15:49:13 +01:00
seq + = 1 ; // Account for seq starting at 1
2020-03-21 21:33:51 +01:00
for ( uint8_t i = 0 ; i < std : : min ( count , uint8_t { 8 } ) ; i + + )
{
if ( ! in . TryRead ( extraEC . v [ i ] , ver ) )
return false ;
}
for ( uint8_t i = count > 8 ? 8 - count : 0 ; i > 0 ; i - - )
{
Wrapped < Bytes > ignored ;
if ( ! in . TryRead ( ignored , ver ) )
return false ;
}
}
else
{
// Ignore video FEC for now
}
}
else if ( type = = PKT_STREAM_DATA | | type = = PKT_STREAM_DATA_X2 | | type = = PKT_STREAM_DATA_X3 )
{
for ( uint8_t count = PKT_STREAM_DATA ? 1 : PKT_STREAM_DATA_X2 ? 2 : 3 ; count > 0 ; - - count )
{
Packet * packet = this ;
if ( count > 1 )
{
otherPackets . push_back ( Packet ( ) ) ;
packet = & otherPackets . back ( ) ;
packet - > legacy = true ;
}
uint8_t flags ;
uint16_t len ;
if ( ! ( in . TryRead ( packet - > streamId ) & &
in . TryRead ( flags ) & &
flags & STREAM_DATA_FLAG_LEN16
? in . TryRead ( len )
: in . TryReadCompat < uint8_t > ( len ) & &
in . TryRead ( packet - > seq ) ) ) // damn you autoindentation
return false ;
packet - > seq / = 60 ; // Constant frame duration
bool fragmented = static_cast < bool > ( len & STREAM_DATA_XFLAG_FRAGMENTED ) ;
bool extraFEC = static_cast < bool > ( len & STREAM_DATA_XFLAG_EXTRA_FEC ) ;
bool keyframe = static_cast < bool > ( len & STREAM_DATA_XFLAG_KEYFRAME ) ;
if ( fragmented )
{
packet - > eFlags | = EFlags : : Fragmented ;
if ( ! in . TryRead ( packet - > fragmentIndex ) )
return false ;
if ( ! in . TryRead ( packet - > fragmentCount ) )
return false ;
}
if ( keyframe )
{
packet - > eFlags | = EFlags : : Keyframe ;
}
2020-03-24 21:59:49 +01:00
packet - > data = std : : make_unique < Buffer > ( len & 0x7FF ) ;
if ( ! in . TryRead ( * packet - > data ) )
2020-03-21 21:33:51 +01:00
return false ;
2020-01-27 16:02:59 +01:00
2020-03-21 21:33:51 +01:00
if ( extraFEC )
{
uint8_t count ;
if ( ! in . TryRead ( count ) )
return false ;
for ( uint8_t i = 0 ; i < std : : min ( count , uint8_t { 8 } ) ; i + + )
{
if ( ! in . TryRead ( packet - > extraEC . v [ i ] , ver ) )
return false ;
}
for ( uint8_t i = count > 8 ? 8 - count : 0 ; i > 0 ; i - - )
{
Wrapped < Bytes > ignored ;
if ( ! in . TryRead ( ignored , ver ) )
return false ;
}
}
}
}
return true ;
}
2020-03-25 21:38:07 +01:00
void Packet : : serializeLegacy ( std : : vector < std : : pair < Buffer , bool > > & outArray , const VersionInfo & ver , const int state , const unsigned char * callID )
2020-01-25 20:45:43 +01:00
{
2020-03-21 21:33:51 +01:00
auto originalLegacySeq = legacySeq ;
std : : vector < Wrapped < Extra > > separatePackets ;
std : : vector < Wrapped < Extra > > allowedExtras ;
std : : partition_copy (
std : : make_move_iterator ( extraSignaling . begin ( ) ) ,
std : : make_move_iterator ( extraSignaling . end ( ) ) ,
std : : back_inserter ( separatePackets ) ,
std : : back_inserter ( allowedExtras ) ,
[ peerVersion = ver . peerVersion ] ( const Wrapped < Extra > & extra ) { // Deliver as packet if
return extra . d - > chooseType ( peerVersion ) ! = PKT_NOP ;
} ) ;
for ( const auto & extra : separatePackets )
{
BufferOutputStream out ( 1500 ) ;
uint8_t type = extra . d - > chooseType ( ver . peerVersion ) ;
2020-03-25 21:38:07 +01:00
LOGW ( " Serializing separate legacy packet of type %s " , VoIPController : : GetPacketTypeString ( type ) . c_str ( ) ) ;
2020-03-21 21:33:51 +01:00
if ( ver . peerVersion > = 8 | | ( ! ver . peerVersion & & ver . connectionMaxLayer > = 92 ) )
{
writePacketHeaderLegacy ( out , ver , legacySeq , ackSeq , ackMask , type , allowedExtras ) ;
2020-03-25 21:38:07 +01:00
out . Write ( * extra . d , ver ) ;
2020-03-21 21:33:51 +01:00
}
else
{
BufferOutputStream accumulator ( 1500 ) ;
2020-03-25 21:38:07 +01:00
accumulator . Write ( * extra . d , ver ) ;
2020-03-21 21:33:51 +01:00
writePacketHeaderLegacyLegacy ( out , ver , legacySeq , ackSeq , ackMask , type , accumulator . GetLength ( ) , allowedExtras , state , callID ) ;
out . WriteBytes ( accumulator . GetBuffer ( ) , accumulator . GetLength ( ) ) ;
}
2020-03-25 21:38:07 +01:00
outArray . push_back ( std : : make_pair ( Buffer ( std : : move ( out ) ) , true ) ) ;
2020-03-21 21:33:51 +01:00
legacySeq + + ;
}
// Convert from mask to array
Array < Wrapped < Bytes > > extraECArray ;
2020-03-25 21:38:07 +01:00
if ( extraEC )
2020-03-21 21:33:51 +01:00
{
2020-03-25 21:38:07 +01:00
for ( auto & ecPacket : extraEC . v )
{
extraECArray . v . push_back ( std : : move ( ecPacket ) ) ;
}
2020-03-21 21:33:51 +01:00
}
2020-03-25 15:49:13 +01:00
if ( ver . peerVersion < 7 & & extraECArray )
2020-03-21 21:33:51 +01:00
{
2020-03-25 21:38:07 +01:00
LOGW ( " Serializing legacylegacy EC " ) ;
2020-03-21 21:33:51 +01:00
BufferOutputStream out ( 1500 ) ;
if ( ! ver . isLegacyLegacy ( ) )
{
writePacketHeaderLegacy ( out , ver , legacySeq , ackSeq , ackMask , PKT_STREAM_EC , allowedExtras ) ;
}
out . WriteByte ( streamId ) ;
2020-03-25 15:49:13 +01:00
out . WriteUInt32 ( ( seq - 1 ) * 60 ) ; // Account for seq starting at 1
2020-03-21 21:33:51 +01:00
out . Write ( extraECArray , ver ) ;
if ( ver . isLegacyLegacy ( ) )
{
BufferOutputStream accumulator ( 1500 ) ;
writePacketHeaderLegacyLegacy ( accumulator , ver , legacySeq , ackSeq , ackMask , PKT_STREAM_EC , out . GetLength ( ) , allowedExtras , state , callID ) ;
accumulator . WriteBytes ( out . GetBuffer ( ) , out . GetLength ( ) ) ;
2020-03-25 21:38:07 +01:00
outArray . push_back ( std : : make_pair ( Buffer ( std : : move ( accumulator ) ) , false ) ) ;
2020-03-21 21:33:51 +01:00
}
else
{
2020-03-25 21:38:07 +01:00
outArray . push_back ( std : : make_pair ( Buffer ( std : : move ( out ) ) , false ) ) ;
2020-03-21 21:33:51 +01:00
}
legacySeq + + ;
}
if ( data )
{
2020-03-25 21:38:07 +01:00
LOGW ( " Serializing legacy data len %u " , ( unsigned int ) data - > Length ( ) ) ;
2020-03-21 21:33:51 +01:00
BufferOutputStream out ( 1500 ) ;
if ( ! ver . isLegacyLegacy ( ) )
{
writePacketHeaderLegacy ( out , ver , legacySeq , ackSeq , ackMask , PKT_STREAM_DATA , allowedExtras ) ;
}
2020-03-25 15:49:13 +01:00
bool hasExtraFEC = ver . peerVersion > = 7 & & extraECArray ;
2020-03-24 21:59:49 +01:00
uint8_t flags = static_cast < uint8_t > ( data - > Length ( ) > 255 | | hasExtraFEC ? STREAM_DATA_FLAG_LEN16 : 0 ) ;
2020-03-21 21:33:51 +01:00
out . WriteByte ( flags | 1 ) ; // flags + streamID
if ( flags & STREAM_DATA_FLAG_LEN16 )
{
2020-03-25 15:49:13 +01:00
int16_t lenAndFlags = static_cast < int16_t > ( data - > Length ( ) ) ;
2020-03-21 21:33:51 +01:00
if ( hasExtraFEC )
lenAndFlags | = STREAM_DATA_XFLAG_EXTRA_FEC ;
out . WriteInt16 ( lenAndFlags ) ;
}
else
{
2020-03-24 21:59:49 +01:00
out . WriteByte ( static_cast < uint8_t > ( data - > Length ( ) ) ) ;
2020-03-21 21:33:51 +01:00
}
out . WriteInt32 ( seq * 60 ) ;
2020-03-24 21:59:49 +01:00
out . WriteBytes ( * data ) ;
2020-03-21 21:33:51 +01:00
//LOGE("SEND: For pts %u = seq %u, using seq %u", audioTimestampOut, audioTimestampOut/60 + 1, packetManager.getLocalSeq());
if ( hasExtraFEC )
{
out . Write ( extraECArray , ver ) ;
}
if ( ver . isLegacyLegacy ( ) )
{
BufferOutputStream accumulator ( 1500 ) ;
writePacketHeaderLegacyLegacy ( accumulator , ver , legacySeq , ackSeq , ackMask , PKT_STREAM_DATA , out . GetLength ( ) , allowedExtras , state , callID ) ;
accumulator . WriteBytes ( out . GetBuffer ( ) , out . GetLength ( ) ) ;
2020-03-25 21:38:07 +01:00
outArray . push_back ( std : : make_pair ( Buffer ( std : : move ( accumulator ) ) , false ) ) ;
2020-03-21 21:33:51 +01:00
}
else
{
2020-03-25 21:38:07 +01:00
outArray . push_back ( std : : make_pair ( Buffer ( std : : move ( out ) ) , false ) ) ;
2020-03-21 21:33:51 +01:00
}
legacySeq + + ;
}
2020-03-25 21:38:07 +01:00
if ( legacySeq = = originalLegacySeq ) // No data was serialized
2020-03-21 21:33:51 +01:00
{
2020-03-25 21:38:07 +01:00
LOGW ( " Serializing legacy NOP packet " ) ;
2020-03-21 21:33:51 +01:00
BufferOutputStream out ( 1500 ) ;
if ( ver . peerVersion > = 8 | | ( ! ver . peerVersion & & ver . connectionMaxLayer > = 92 ) )
{
writePacketHeaderLegacy ( out , ver , legacySeq , ackSeq , ackMask , PKT_NOP , allowedExtras ) ;
}
else
{
writePacketHeaderLegacyLegacy ( out , ver , legacySeq , ackSeq , ackMask , PKT_NOP , 0 , allowedExtras , state , callID ) ;
}
2020-03-25 21:38:07 +01:00
outArray . push_back ( std : : make_pair ( Buffer ( std : : move ( out ) ) , false ) ) ;
legacySeq + + ;
2020-03-21 21:33:51 +01:00
}
}
void Packet : : writePacketHeaderLegacy ( BufferOutputStream & out , const VersionInfo & ver , const uint32_t seq , const uint32_t ackSeq , const uint32_t ackMask , const unsigned char type , const std : : vector < Wrapped < Extra > > & extras )
{
out . WriteByte ( type ) ;
out . WriteInt32 ( ackSeq ) ;
out . WriteInt32 ( seq ) ;
out . WriteInt32 ( ackMask ) ;
unsigned char flags = extras . empty ( ) ? 0 : XPFLAG_HAS_EXTRA ;
if ( recvTS )
flags | = XPFLAG_HAS_RECV_TS ;
out . WriteByte ( flags ) ;
if ( ! extras . empty ( ) )
{
out . WriteByte ( static_cast < unsigned char > ( extras . size ( ) ) ) ;
for ( auto & x : extras )
{
LOGV ( " Writing extra into header: type %u " , x . getID ( ) ) ;
out . Write ( x , ver ) ;
}
}
if ( recvTS )
{
out . WriteUInt32 ( recvTS ) ;
}
}
bool Packet : : parseLegacyLegacy ( const BufferInputStream & in , unsigned char & type , uint32_t & ackId , uint32_t & pseq , uint32_t & acks , unsigned char & pflags , size_t & packetInnerLen , int peerVersion )
{
uint32_t tlid = in . ReadUInt32 ( ) ;
if ( tlid = = TLID_DECRYPTED_AUDIO_BLOCK )
{
in . ReadInt64 ( ) ; // random id
uint32_t randLen = in . ReadTlLength ( ) ;
in . Seek ( in . GetOffset ( ) + randLen + pad4 ( randLen ) ) ;
uint32_t flags = in . ReadUInt32 ( ) ;
type = ( unsigned char ) ( ( flags > > 24 ) & 0xFF ) ;
if ( ! ( flags & LEGACY_PFLAG_HAS_SEQ & & flags & LEGACY_PFLAG_HAS_RECENT_RECV ) )
{
LOGW ( " Received packet doesn't have LEGACY_PFLAG_HAS_SEQ, LEGACY_PFLAG_HAS_RECENT_RECV, or both " ) ;
return false ;
}
// These are all errors that weren't even used in the first place in newer protocols.
// Also, a call cannot possibly have a wrong call ID and correct encryption key (unless there's some shady legacy stuff that's going on, but for now I won't even consider it).
/*
if ( flags & LEGACY_PFLAG_HAS_CALL_ID )
{
unsigned char pktCallID [ 16 ] ;
in . ReadBytes ( pktCallID , 16 ) ;
if ( memcmp ( pktCallID , callID , 16 ) ! = 0 )
{
LOGW ( " Received packet has wrong call id " ) ;
// These are all errors that weren't even used in the first place in newer protocols
//lastError = ERROR_UNKNOWN;
//SetState(STATE_FAILED);
return false ;
}
} */
ackId = in . ReadUInt32 ( ) ;
pseq = in . ReadUInt32 ( ) ;
acks = in . ReadUInt32 ( ) ;
if ( flags & LEGACY_PFLAG_HAS_PROTO )
{
uint32_t proto = in . ReadUInt32 ( ) ;
if ( proto ! = PROTOCOL_NAME )
{
LOGW ( " Received packet uses wrong protocol " ) ;
// These are all errors that weren't even used in the first place in newer protocols
//lastError = ERROR_INCOMPATIBLE;
//SetState(STATE_FAILED);
return false ;
}
}
if ( flags & LEGACY_PFLAG_HAS_EXTRA )
{
uint32_t extraLen = in . ReadTlLength ( ) ;
in . Seek ( in . GetOffset ( ) + extraLen + pad4 ( extraLen ) ) ;
}
if ( flags & LEGACY_PFLAG_HAS_DATA )
{
packetInnerLen = in . ReadTlLength ( ) ;
}
pflags = 0 ;
}
else if ( tlid = = TLID_SIMPLE_AUDIO_BLOCK )
{
in . ReadInt64 ( ) ; // random id
uint32_t randLen = in . ReadTlLength ( ) ;
in . Seek ( in . GetOffset ( ) + randLen + pad4 ( randLen ) ) ;
packetInnerLen = in . ReadTlLength ( ) ;
type = in . ReadByte ( ) ;
ackId = in . ReadUInt32 ( ) ;
pseq = in . ReadUInt32 ( ) ;
acks = in . ReadUInt32 ( ) ;
if ( peerVersion > = 6 )
pflags = in . ReadByte ( ) ;
else
pflags = 0 ;
}
else
{
LOGW ( " Received a packet of unknown type %08X " , tlid ) ;
return false ;
}
return true ;
}
void Packet : : writePacketHeaderLegacyLegacy ( BufferOutputStream & out , const VersionInfo & ver , const uint32_t pseq , const uint32_t ackSeq , const uint32_t ackMask , const unsigned char type , const uint32_t length , const std : : vector < Wrapped < Extra > > & extras , const int state , const unsigned char * callID )
{
out . WriteInt32 ( state = = STATE_WAIT_INIT | | state = = STATE_WAIT_INIT_ACK ? TLID_DECRYPTED_AUDIO_BLOCK : TLID_SIMPLE_AUDIO_BLOCK ) ;
int64_t randomID ;
VoIPController : : crypto . rand_bytes ( ( uint8_t * ) & randomID , 8 ) ;
out . WriteInt64 ( randomID ) ;
unsigned char randBytes [ 7 ] ;
VoIPController : : crypto . rand_bytes ( randBytes , 7 ) ;
out . WriteByte ( 7 ) ;
out . WriteBytes ( randBytes , 7 ) ;
2020-01-27 16:02:59 +01:00
if ( state = = STATE_WAIT_INIT | | state = = STATE_WAIT_INIT_ACK )
2020-01-25 20:45:43 +01:00
{
2020-03-15 19:43:35 +01:00
uint32_t pflags = LEGACY_PFLAG_HAS_RECENT_RECV | LEGACY_PFLAG_HAS_SEQ ;
2020-01-27 16:02:59 +01:00
if ( length > 0 )
2020-03-15 19:43:35 +01:00
pflags | = LEGACY_PFLAG_HAS_DATA ;
2020-01-27 16:02:59 +01:00
if ( state = = STATE_WAIT_INIT | | state = = STATE_WAIT_INIT_ACK )
{
2020-03-15 19:43:35 +01:00
pflags | = LEGACY_PFLAG_HAS_CALL_ID | LEGACY_PFLAG_HAS_PROTO ;
2020-01-27 16:02:59 +01:00
}
pflags | = ( ( uint32_t ) type ) < < 24 ;
2020-03-21 21:33:51 +01:00
out . WriteInt32 ( pflags ) ;
2020-01-27 16:02:59 +01:00
2020-03-15 19:43:35 +01:00
if ( pflags & LEGACY_PFLAG_HAS_CALL_ID )
2020-01-27 16:02:59 +01:00
{
2020-03-21 21:33:51 +01:00
out . WriteBytes ( callID , 16 ) ;
2020-01-27 16:02:59 +01:00
}
2020-03-21 21:33:51 +01:00
out . WriteInt32 ( ackSeq ) ;
out . WriteInt32 ( pseq ) ;
out . WriteInt32 ( ackMask ) ;
2020-03-15 19:43:35 +01:00
if ( pflags & LEGACY_PFLAG_HAS_PROTO )
2020-01-25 20:45:43 +01:00
{
2020-03-21 21:33:51 +01:00
out . WriteInt32 ( PROTOCOL_NAME ) ;
2020-01-27 16:02:59 +01:00
}
if ( length > 0 )
{
if ( length < = 253 )
2020-01-25 20:45:43 +01:00
{
2020-03-21 21:33:51 +01:00
out . WriteByte ( ( unsigned char ) length ) ;
2020-01-27 16:02:59 +01:00
}
else
{
2020-03-21 21:33:51 +01:00
out . WriteByte ( 254 ) ;
out . WriteByte ( ( unsigned char ) ( length & 0xFF ) ) ;
out . WriteByte ( ( unsigned char ) ( ( length > > 8 ) & 0xFF ) ) ;
out . WriteByte ( ( unsigned char ) ( ( length > > 16 ) & 0xFF ) ) ;
2020-01-27 16:02:59 +01:00
}
}
}
else
{
uint32_t lenWithHeader = length + 13 ;
if ( lenWithHeader > 0 )
{
if ( lenWithHeader < = 253 )
{
2020-03-21 21:33:51 +01:00
out . WriteByte ( ( unsigned char ) lenWithHeader ) ;
2020-01-27 16:02:59 +01:00
}
else
{
2020-03-21 21:33:51 +01:00
out . WriteByte ( 254 ) ;
out . WriteByte ( ( unsigned char ) ( lenWithHeader & 0xFF ) ) ;
out . WriteByte ( ( unsigned char ) ( ( lenWithHeader > > 8 ) & 0xFF ) ) ;
out . WriteByte ( ( unsigned char ) ( ( lenWithHeader > > 16 ) & 0xFF ) ) ;
2020-01-25 20:45:43 +01:00
}
}
2020-03-21 21:33:51 +01:00
out . WriteByte ( type ) ;
out . WriteInt32 ( ackSeq ) ;
out . WriteInt32 ( pseq ) ;
out . WriteInt32 ( ackMask ) ;
if ( ver . peerVersion > = 6 )
2020-01-25 20:45:43 +01:00
{
2020-03-21 21:33:51 +01:00
if ( extras . empty ( ) )
2020-01-27 16:02:59 +01:00
{
2020-03-21 21:33:51 +01:00
out . WriteByte ( 0 ) ;
2020-01-27 16:02:59 +01:00
}
else
{
2020-03-21 21:33:51 +01:00
out . WriteByte ( XPFLAG_HAS_EXTRA ) ;
out . WriteByte ( static_cast < unsigned char > ( extras . size ( ) ) ) ;
for ( auto & x : extras )
2020-01-27 16:02:59 +01:00
{
2020-03-21 21:33:51 +01:00
LOGV ( " Writing extra into header: type %u " , x . getID ( ) ) ;
out . Write ( x , ver ) ;
2020-01-27 16:02:59 +01:00
}
}
2020-01-25 20:45:43 +01:00
}
}
2020-01-27 16:02:59 +01:00
}