mirror of
https://github.com/danog/libtgvoip.git
synced 2024-11-30 04:39:03 +01:00
Finishing implementation of legacy serialization
This commit is contained in:
parent
5f7606049c
commit
eb3bc4e5b3
@ -11,6 +11,8 @@ bool Packet::parse(const BufferInputStream &in, const VersionInfo &ver)
|
|||||||
return parseLegacy(in, ver);
|
return parseLegacy(in, ver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t length;
|
||||||
|
uint8_t flags;
|
||||||
bool res = in.TryRead(seq) &&
|
bool res = in.TryRead(seq) &&
|
||||||
in.TryRead(ackSeq) &&
|
in.TryRead(ackSeq) &&
|
||||||
in.TryRead(ackMask) &&
|
in.TryRead(ackMask) &&
|
||||||
@ -21,7 +23,8 @@ bool Packet::parse(const BufferInputStream &in, const VersionInfo &ver)
|
|||||||
streamId = flags & 3;
|
streamId = flags & 3;
|
||||||
flags >>= 2;
|
flags >>= 2;
|
||||||
|
|
||||||
uint16_t length;
|
if (streamId == StreamId::Extended && !in.TryRead(streamId))
|
||||||
|
return false;
|
||||||
if (!(flags & Flags::Len16 ? in.TryRead(length) : in.TryReadCompat<uint8_t>(length)))
|
if (!(flags & Flags::Len16 ? in.TryRead(length) : in.TryReadCompat<uint8_t>(length)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -42,234 +45,51 @@ bool Packet::parse(const BufferInputStream &in, const VersionInfo &ver)
|
|||||||
|
|
||||||
if ((flags & Flags::RecvTS) && !in.TryRead(recvTS))
|
if ((flags & Flags::RecvTS) && !in.TryRead(recvTS))
|
||||||
return false;
|
return false;
|
||||||
if ((flags & Flags::ExtraFEC) && !in.TryRead(extraEC, ver))
|
if ((flags & Flags::ExtraEC) && !in.TryRead(extraEC, ver))
|
||||||
return false;
|
return false;
|
||||||
if ((flags & Flags::ExtraSignaling) && !in.TryRead(extraSignaling, ver))
|
if ((flags & Flags::ExtraSignaling) && !in.TryRead(extraSignaling, ver))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Packet::parseLegacy(const BufferInputStream &in, const VersionInfo &ver)
|
void Packet::serialize(BufferOutputStream &out, const VersionInfo &ver) const
|
||||||
{
|
{
|
||||||
// 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
|
if (!ver.isNew() || legacy)
|
||||||
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;
|
|
||||||
if (ver.peerVersion >= 8)
|
|
||||||
{
|
{
|
||||||
if (!(
|
return serializeLegacy(out, ver);
|
||||||
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))
|
uint8_t shortStreamId = streamId > StreamId::Extended ? StreamId::Extended : streamId;
|
||||||
{
|
uint8_t flags = 0;
|
||||||
if (!extra->parse(in, ver))
|
if (data.Length() > 0xFF || eFlags)
|
||||||
return false;
|
flags |= Flags::Len16;
|
||||||
|
if (recvTS)
|
||||||
|
flags |= Flags::RecvTS;
|
||||||
|
if (extraEC)
|
||||||
|
flags |= Flags::ExtraEC;
|
||||||
|
if (extraSignaling)
|
||||||
|
flags |= Flags::ExtraSignaling;
|
||||||
|
|
||||||
extraSignaling.v.push_back(Wrapped<Extra>(std::move(extra)));
|
out.WriteUInt32(seq);
|
||||||
streamId = 0;
|
out.WriteUInt32(ackSeq);
|
||||||
}
|
out.WriteUInt32(ackMask);
|
||||||
else if (type == PKT_STREAM_EC)
|
out.WriteByte(shortStreamId | (flags << 2));
|
||||||
{
|
|
||||||
if (ver.peerVersion < 7)
|
|
||||||
{
|
|
||||||
uint8_t count;
|
|
||||||
if (!(in.TryRead(streamId) && in.TryRead(seq) && in.TryRead(count)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
seq /= 60; // Constant frame duration
|
if (shortStreamId == StreamId::Extended)
|
||||||
|
out.WriteByte(streamId);
|
||||||
|
|
||||||
for (uint8_t i = 0; i < std::min(count, uint8_t{8}); i++)
|
if (flags & Flags::Len16)
|
||||||
{
|
out.WriteUInt16(data.Length() | (eFlags << 11));
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
packet->data = Buffer(len & 0x7FF);
|
|
||||||
if (!in.TryRead(packet->data))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
size_t packetInnerLen = 0;
|
|
||||||
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
|
else
|
||||||
{
|
out.WriteByte(data.Length());
|
||||||
LOGW("Received a packet of unknown type %08X", tlid);
|
|
||||||
|
|
||||||
return false;
|
if (flags & Flags::RecvTS)
|
||||||
}
|
out.WriteUInt32(recvTS);
|
||||||
return true;
|
if (flags & Flags::ExtraEC)
|
||||||
}
|
out.Write(extraEC, ver);
|
||||||
|
if (flags & Flags::ExtraSignaling)
|
||||||
|
out.Write(extraSignaling, ver);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "PacketStructsLegacy.cpp"
|
@ -19,14 +19,16 @@ private:
|
|||||||
bool parseLegacy(const BufferInputStream &in, const VersionInfo &ver);
|
bool parseLegacy(const BufferInputStream &in, const VersionInfo &ver);
|
||||||
bool parseLegacyLegacy(const BufferInputStream &in, unsigned char &type, uint32_t &ackId, uint32_t &pseq, uint32_t &acks, unsigned char &pflags, size_t &packetInnerLen, int peerVersion);
|
bool parseLegacyLegacy(const BufferInputStream &in, unsigned char &type, uint32_t &ackId, uint32_t &pseq, uint32_t &acks, unsigned char &pflags, size_t &packetInnerLen, int peerVersion);
|
||||||
|
|
||||||
|
void serializeLegacy(BufferOutputStream &out, const VersionInfo &ver) const;
|
||||||
|
void serializeLegacyLegacy(BufferOutputStream &out, uint32_t pseq, uint32_t acks, unsigned char type, uint32_t length) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum Flags : uint8_t
|
enum Flags : uint8_t
|
||||||
{
|
{
|
||||||
Len16 = 1,
|
Len16 = 1,
|
||||||
RecvTS = 2,
|
RecvTS = 2,
|
||||||
ExtraFEC = 4,
|
ExtraEC = 4,
|
||||||
ExtraSignaling = 8
|
ExtraSignaling = 8
|
||||||
|
|
||||||
};
|
};
|
||||||
enum EFlags : uint8_t
|
enum EFlags : uint8_t
|
||||||
{
|
{
|
||||||
@ -34,6 +36,14 @@ public:
|
|||||||
Keyframe = 2
|
Keyframe = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum StreamId : uint8_t
|
||||||
|
{
|
||||||
|
Signaling = 0,
|
||||||
|
Audio = 1,
|
||||||
|
Video = 2,
|
||||||
|
Extended = 3
|
||||||
|
};
|
||||||
|
|
||||||
bool legacy = false;
|
bool legacy = false;
|
||||||
uint32_t legacySeq = 0;
|
uint32_t legacySeq = 0;
|
||||||
|
|
||||||
@ -42,7 +52,6 @@ public:
|
|||||||
uint32_t ackMask = 0;
|
uint32_t ackMask = 0;
|
||||||
|
|
||||||
uint8_t streamId = 0;
|
uint8_t streamId = 0;
|
||||||
uint8_t flags = 0;
|
|
||||||
uint8_t eFlags = 0;
|
uint8_t eFlags = 0;
|
||||||
|
|
||||||
uint8_t fragmentIndex = 0;
|
uint8_t fragmentIndex = 0;
|
||||||
@ -55,8 +64,13 @@ public:
|
|||||||
Mask<Wrapped<Bytes>> extraEC;
|
Mask<Wrapped<Bytes>> extraEC;
|
||||||
Array<Wrapped<Extra>> extraSignaling;
|
Array<Wrapped<Extra>> extraSignaling;
|
||||||
|
|
||||||
// Ugly backwards compatibility hacks
|
// Ugly backwards compatibility hack
|
||||||
std::vector<Packet> otherPackets;
|
std::vector<Packet> otherPackets;
|
||||||
|
|
||||||
|
public:
|
||||||
|
operator bool() {
|
||||||
|
return data || extraEC || extraSignaling || seq;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Legacy stuff
|
// Legacy stuff
|
||||||
|
374
controller/protocol/PacketStructsLegacy.cpp
Normal file
374
controller/protocol/PacketStructsLegacy.cpp
Normal file
@ -0,0 +1,374 @@
|
|||||||
|
#include "PacketStructs.h"
|
||||||
|
#include "../PrivateDefines.cpp"
|
||||||
|
|
||||||
|
using namespace tgvoip;
|
||||||
|
|
||||||
|
bool Packet::parseLegacy(const BufferInputStream &in, const VersionInfo &ver)
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
if (ver.peerVersion >= 8)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
packet->data = Buffer(len & 0x7FF);
|
||||||
|
if (!in.TryRead(packet->data))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Packet::serializeLegacy(BufferOutputStream &out, const VersionInfo &ver) const
|
||||||
|
{
|
||||||
|
uint8_t type = PKT_NOP;
|
||||||
|
for (const auto &extra : extraSignaling) {
|
||||||
|
|
||||||
|
}
|
||||||
|
if (ver.peerVersion >= 8 || (!ver.peerVersion && ver.connectionMaxLayer >= 92))
|
||||||
|
{
|
||||||
|
out.WriteByte(pkt.type);
|
||||||
|
out.WriteInt32(manager.getLastRemoteSeq());
|
||||||
|
out.WriteInt32(pkt.seq);
|
||||||
|
out.WriteInt32(acks);
|
||||||
|
|
||||||
|
unsigned char flags = currentExtras.empty() ? 0 : XPFLAG_HAS_EXTRA;
|
||||||
|
|
||||||
|
shared_ptr<Stream> videoStream = GetStreamByType(STREAM_TYPE_VIDEO, false);
|
||||||
|
if (peerVersion >= 9 && videoStream && videoStream->enabled)
|
||||||
|
flags |= XPFLAG_HAS_RECV_TS;
|
||||||
|
|
||||||
|
if (peerVersion >= PROTOCOL_RELIABLE && manager.getTransportId() != 0xFF)
|
||||||
|
flags |= XPFLAG_HAS_TRANSPORT_ID;
|
||||||
|
|
||||||
|
out.WriteByte(flags);
|
||||||
|
|
||||||
|
if (!currentExtras.empty())
|
||||||
|
{
|
||||||
|
out.WriteByte(static_cast<unsigned char>(currentExtras.size()));
|
||||||
|
for (auto &x : currentExtras)
|
||||||
|
{
|
||||||
|
//LOGV("Writing extra into header: type %u, length %d", x.type, int(x.data.Length()));
|
||||||
|
assert(x.data.Length() <= 254);
|
||||||
|
out.WriteByte(static_cast<unsigned char>(x.data.Length() + 1));
|
||||||
|
out.WriteByte(x.type);
|
||||||
|
out.WriteBytes(*x.data, x.data.Length());
|
||||||
|
if (x.firstContainingSeq == 0)
|
||||||
|
x.firstContainingSeq = pkt.seq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (peerVersion >= 9 && videoStream && videoStream->enabled)
|
||||||
|
{
|
||||||
|
out.WriteUInt32((lastRecvPacketTime - connectionInitTime) * 1000.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
size_t packetInnerLen = 0;
|
||||||
|
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::serializeLegacyLegacy(BufferOutputStream &out, uint32_t pseq, uint32_t acks, unsigned char type, uint32_t length) const
|
||||||
|
{
|
||||||
|
if (state == STATE_WAIT_INIT || state == STATE_WAIT_INIT_ACK)
|
||||||
|
{
|
||||||
|
out.WriteInt32(TLID_DECRYPTED_AUDIO_BLOCK);
|
||||||
|
int64_t randomID;
|
||||||
|
crypto.rand_bytes((uint8_t *)&randomID, 8);
|
||||||
|
out.WriteInt64(randomID);
|
||||||
|
unsigned char randBytes[7];
|
||||||
|
crypto.rand_bytes(randBytes, 7);
|
||||||
|
out.WriteByte(7);
|
||||||
|
out.WriteBytes(randBytes, 7);
|
||||||
|
uint32_t pflags = LEGACY_PFLAG_HAS_RECENT_RECV | LEGACY_PFLAG_HAS_SEQ;
|
||||||
|
if (length > 0)
|
||||||
|
pflags |= LEGACY_PFLAG_HAS_DATA;
|
||||||
|
if (state == STATE_WAIT_INIT || state == STATE_WAIT_INIT_ACK)
|
||||||
|
{
|
||||||
|
pflags |= LEGACY_PFLAG_HAS_CALL_ID | LEGACY_PFLAG_HAS_PROTO;
|
||||||
|
}
|
||||||
|
pflags |= ((uint32_t)type) << 24;
|
||||||
|
out.WriteInt32(pflags);
|
||||||
|
|
||||||
|
if (pflags & LEGACY_PFLAG_HAS_CALL_ID)
|
||||||
|
{
|
||||||
|
out.WriteBytes(callID, 16);
|
||||||
|
}
|
||||||
|
out.WriteInt32(packetManager.getLastRemoteSeq());
|
||||||
|
out.WriteInt32(pseq);
|
||||||
|
out.WriteInt32(acks);
|
||||||
|
if (pflags & LEGACY_PFLAG_HAS_PROTO)
|
||||||
|
{
|
||||||
|
out.WriteInt32(PROTOCOL_NAME);
|
||||||
|
}
|
||||||
|
if (length > 0)
|
||||||
|
{
|
||||||
|
if (length <= 253)
|
||||||
|
{
|
||||||
|
out.WriteByte((unsigned char)length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out.WriteByte(254);
|
||||||
|
out.WriteByte((unsigned char)(length & 0xFF));
|
||||||
|
out.WriteByte((unsigned char)((length >> 8) & 0xFF));
|
||||||
|
out.WriteByte((unsigned char)((length >> 16) & 0xFF));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out.WriteInt32(TLID_SIMPLE_AUDIO_BLOCK);
|
||||||
|
int64_t randomID;
|
||||||
|
crypto.rand_bytes((uint8_t *)&randomID, 8);
|
||||||
|
out.WriteInt64(randomID);
|
||||||
|
unsigned char randBytes[7];
|
||||||
|
crypto.rand_bytes(randBytes, 7);
|
||||||
|
out.WriteByte(7);
|
||||||
|
out.WriteBytes(randBytes, 7);
|
||||||
|
uint32_t lenWithHeader = length + 13;
|
||||||
|
if (lenWithHeader > 0)
|
||||||
|
{
|
||||||
|
if (lenWithHeader <= 253)
|
||||||
|
{
|
||||||
|
out.WriteByte((unsigned char)lenWithHeader);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out.WriteByte(254);
|
||||||
|
out.WriteByte((unsigned char)(lenWithHeader & 0xFF));
|
||||||
|
out.WriteByte((unsigned char)((lenWithHeader >> 8) & 0xFF));
|
||||||
|
out.WriteByte((unsigned char)((lenWithHeader >> 16) & 0xFF));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.WriteByte(type);
|
||||||
|
out.WriteInt32(packetManager.getLastRemoteSeq());
|
||||||
|
out.WriteInt32(pseq);
|
||||||
|
out.WriteInt32(acks);
|
||||||
|
if (peerVersion >= 6)
|
||||||
|
{
|
||||||
|
if (currentExtras.empty())
|
||||||
|
{
|
||||||
|
out.WriteByte(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out.WriteByte(XPFLAG_HAS_EXTRA);
|
||||||
|
out.WriteByte(static_cast<unsigned char>(currentExtras.size()));
|
||||||
|
for (vector<UnacknowledgedExtraData>::iterator x = currentExtras.begin(); x != currentExtras.end(); ++x)
|
||||||
|
{
|
||||||
|
LOGV("Writing extra into header: type %u, length %d", x->type, int(x->data.Length()));
|
||||||
|
assert(x->data.Length() <= 254);
|
||||||
|
out.WriteByte(static_cast<unsigned char>(x->data.Length() + 1));
|
||||||
|
out.WriteByte(x->type);
|
||||||
|
out.WriteBytes(*x->data, x->data.Length());
|
||||||
|
if (x->firstContainingSeq == 0)
|
||||||
|
x->firstContainingSeq = pseq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -57,7 +57,7 @@ std::shared_ptr<Extra> Extra::choose(const BufferInputStream &in, const VersionI
|
|||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
std::shared_ptr<Extra> Extra::chooseFromType(int type)
|
std::shared_ptr<Extra> Extra::chooseFromType(uint8_t type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
@ -64,16 +64,42 @@ struct Mask : public Serializable, SingleChoice<Mask<T>>
|
|||||||
uint8_t mask = 0;
|
uint8_t mask = 0;
|
||||||
for (auto i = 0; i < sizeof(mask); i++)
|
for (auto i = 0; i < sizeof(mask); i++)
|
||||||
{
|
{
|
||||||
if (v[i]) {
|
if (v[i])
|
||||||
|
{
|
||||||
mask |= 1 << i;
|
mask |= 1 << i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.WriteByte(mask);
|
out.WriteByte(mask);
|
||||||
for (const auto &data : v) {
|
for (const auto &data : v)
|
||||||
|
{
|
||||||
out.Write(v, data);
|
out.Write(v, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
typename std::array<T, 8>::iterator begin()
|
||||||
|
{
|
||||||
|
return v.begin();
|
||||||
|
}
|
||||||
|
typename std::array<T, 8>::iterator end()
|
||||||
|
{
|
||||||
|
return v.end();
|
||||||
|
}
|
||||||
|
typename std::array<T, 8>::const_iterator cbegin()
|
||||||
|
{
|
||||||
|
return v.cbegin();
|
||||||
|
}
|
||||||
|
typename std::array<T, 8>::const_iterator cend()
|
||||||
|
{
|
||||||
|
return v.cend();
|
||||||
|
}
|
||||||
|
operator bool() const
|
||||||
|
{
|
||||||
|
for (const auto &data : v)
|
||||||
|
{
|
||||||
|
if (data)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
std::array<T, 8> v{};
|
std::array<T, 8> v{};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -107,15 +133,34 @@ struct Array : public Serializable, SingleChoice<Array<T>>
|
|||||||
data.serialize(out, ver);
|
data.serialize(out, ver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
typename std::vector<T>::iterator begin()
|
||||||
|
{
|
||||||
|
return v.begin();
|
||||||
|
}
|
||||||
|
typename std::vector<T>::iterator end()
|
||||||
|
{
|
||||||
|
return v.end();
|
||||||
|
}
|
||||||
|
typename std::vector<T>::const_iterator cbegin()
|
||||||
|
{
|
||||||
|
return v.cbegin();
|
||||||
|
}
|
||||||
|
typename std::vector<T>::const_iterator cend()
|
||||||
|
{
|
||||||
|
return v.cend();
|
||||||
|
}
|
||||||
|
operator bool() const
|
||||||
|
{
|
||||||
|
return !v.empty();
|
||||||
|
}
|
||||||
std::vector<T> v;
|
std::vector<T> v;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
struct Wrapped : public Serializable, SingleChoice<Wrapped<T>>
|
struct Wrapped : public Serializable, SingleChoice<Wrapped<T>>
|
||||||
{
|
{
|
||||||
Wrapped(std::shared_ptr<T> &&_d) : d(_d) {};
|
Wrapped(std::shared_ptr<T> &&_d) : d(_d){};
|
||||||
Wrapped(std::shared_ptr<T> &_d) : d(_d) {};
|
Wrapped(std::shared_ptr<T> &_d) : d(_d){};
|
||||||
Wrapped() = default;
|
Wrapped() = default;
|
||||||
|
|
||||||
bool parse(const BufferInputStream &in, const VersionInfo &ver) override
|
bool parse(const BufferInputStream &in, const VersionInfo &ver) override
|
||||||
@ -136,6 +181,10 @@ struct Wrapped : public Serializable, SingleChoice<Wrapped<T>>
|
|||||||
out.WriteByte(len);
|
out.WriteByte(len);
|
||||||
out.Advance(len);
|
out.Advance(len);
|
||||||
}
|
}
|
||||||
|
operator bool() const
|
||||||
|
{
|
||||||
|
return d && *d;
|
||||||
|
}
|
||||||
std::shared_ptr<T> d;
|
std::shared_ptr<T> d;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -238,6 +238,10 @@ public:
|
|||||||
{
|
{
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
operator bool() const
|
||||||
|
{
|
||||||
|
return length;
|
||||||
|
}
|
||||||
void CopyFromOtherBuffer(const Buffer &other, size_t count, size_t srcOffset = 0, size_t dstOffset = 0)
|
void CopyFromOtherBuffer(const Buffer &other, size_t count, size_t srcOffset = 0, size_t dstOffset = 0)
|
||||||
{
|
{
|
||||||
if (!other.data)
|
if (!other.data)
|
||||||
|
Loading…
Reference in New Issue
Block a user