mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +00:00
205 lines
7.3 KiB
C++
205 lines
7.3 KiB
C++
#include "Endpoint.h"
|
|
|
|
#include "rtc_base/buffer.h"
|
|
#include "rtc_base/byte_buffer.h"
|
|
|
|
#include <memory>
|
|
#include <queue>
|
|
|
|
EndpointBase::EndpointBase(LayerBase *layer, Type type)
|
|
: type(type)
|
|
, layer(layer)
|
|
, in_buffer(std::make_unique<rtc::ByteBufferReader>(nullptr, 0))
|
|
, in_remains(0) {}
|
|
|
|
void EndpointBase::RecvPacket(rtc::AsyncPacketSocket *, const char *data, size_t len,
|
|
const rtc::SocketAddress& remote_addr, const int64_t& packet_time_us) {
|
|
if (in_buffer && in_buffer->Length() > 0) {
|
|
rtc::Buffer tmp(in_buffer->Data(), in_buffer->Length() + len);
|
|
memcpy(tmp.data() + in_buffer->Length(), data, len);
|
|
in_buffer = std::make_unique<rtc::ByteBufferReader>(reinterpret_cast<const char *>(tmp.data()), tmp.size());
|
|
} else
|
|
in_buffer = std::make_unique<rtc::ByteBufferReader>(data, len);
|
|
}
|
|
|
|
EndpointUdp::EndpointUdp(const rtc::SocketAddress& addr, rtc::AsyncPacketSocket *socket, LayerBase *layer, Type type)
|
|
: EndpointBase(layer, type)
|
|
, address(addr)
|
|
, socket(socket) {}
|
|
|
|
void EndpointUdp::SendPacket(const uint8_t *data, size_t size) {
|
|
socket->SendTo(data, size, address, packet_options);
|
|
}
|
|
|
|
EndpointTcp::EndpointTcp(std::unique_ptr<rtc::AsyncPacketSocket> socket, LayerBase *layer, Type type)
|
|
: EndpointBase(layer, type)
|
|
, address(socket->GetRemoteAddress())
|
|
, socket(nullptr) {
|
|
Reconnect(std::move(socket));
|
|
}
|
|
|
|
void EndpointTcp::Reconnect(std::unique_ptr<rtc::AsyncPacketSocket> socket_) {
|
|
socket = std::move(socket_);
|
|
socket->SignalReadPacket.connect(dynamic_cast<EndpointBase *>(this), &EndpointTcp::RecvPacket);
|
|
socket->SignalReadyToSend.connect(this, &EndpointTcp::Ready);
|
|
socket->SignalClose.connect(this, &EndpointTcp::Close);
|
|
}
|
|
|
|
void EndpointTcp::SendPacket(const uint8_t *data, size_t size) {
|
|
socket->Send(data, size, packet_options);
|
|
}
|
|
|
|
Relay::Relay(const PeerTag& peer_tag_) : peer_tag() {
|
|
memcpy(peer_tag, peer_tag_, sizeof(PeerTag));
|
|
}
|
|
|
|
bool Relay::CheckPacket(rtc::ByteBufferReader *packet) {
|
|
if (packet->Length() >= 16 && memcmp(peer_tag, packet->Data(), 16) == 0) {
|
|
packet->Consume(16);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
const rtc::Buffer& Relay::PreparePacket(const rtc::Buffer& packet) {
|
|
buffer.Clear();
|
|
if (!packet.empty()) {
|
|
buffer.AppendData(peer_tag, 16);
|
|
buffer.AppendData(packet);
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
EndpointRelayObfuscatedTcp::EndpointRelayObfuscatedTcp(std::unique_ptr<rtc::AsyncPacketSocket> socket,
|
|
const PeerTag& peer_tag, LayerBase *layer)
|
|
: Relay(peer_tag)
|
|
, EndpointTcp(std::move(socket), layer, Type::RelayObfuscatedTcp)
|
|
, recvState()
|
|
, sendState() {}
|
|
|
|
void EndpointRelayObfuscatedTcp::Ready(rtc::AsyncPacketSocket *) {
|
|
unsigned char buf[64];
|
|
layer->GenerateTCPO2States(buf, &recvState, &sendState);
|
|
EndpointTcp::SendPacket(buf, 64);
|
|
SignalMessage(message::Connected(), this);
|
|
}
|
|
|
|
void EndpointRelayObfuscatedTcp::Close(rtc::AsyncPacketSocket *, int) {
|
|
SignalMessage(message::Disconnected(), this);
|
|
}
|
|
|
|
void EndpointRelayObfuscatedTcp::RecvPacket(rtc::AsyncPacketSocket *socket, const char *data, size_t packet_len,
|
|
const rtc::SocketAddress& remote_addr, const int64_t& packet_time_us) {
|
|
EndpointBase::RecvPacket(socket, data, packet_len, remote_addr, packet_time_us);
|
|
do {
|
|
if (in_remains > in_buffer->Length())
|
|
break;
|
|
if (in_remains > 0 && CheckPacket(in_buffer.get())) {
|
|
auto msg = layer->DecodePacket(*in_buffer);
|
|
if (msg)
|
|
SignalMessage(*msg, this);
|
|
}
|
|
|
|
unsigned char len1;
|
|
size_t packetLen = 0;
|
|
if (!in_buffer->ReadUInt8(&len1))
|
|
break;
|
|
layer->EncryptForTCPO2(&len1, 1, &recvState);
|
|
if (len1 < 0x7F) {
|
|
packetLen = (size_t) len1 * 4;
|
|
} else {
|
|
unsigned char len2[3];
|
|
if (!in_buffer->ReadBytes(reinterpret_cast<char *>(&len2), 3)) {
|
|
SignalMessage(message::PacketIncorrect(), this);
|
|
return;
|
|
}
|
|
layer->EncryptForTCPO2(len2, 3, &recvState);
|
|
packetLen = ((size_t) len2[0] | ((size_t) len2[1] << 8) | ((size_t) len2[2] << 16)) * 4;
|
|
}
|
|
|
|
in_remains = packetLen;
|
|
if (packetLen > in_buffer->Length()) {
|
|
in_remains = packetLen;
|
|
break;
|
|
}
|
|
} while (true);
|
|
}
|
|
|
|
void EndpointRelayObfuscatedTcp::SendMessage(const message::Base& msg_base) {
|
|
if (socket->GetState() == rtc::AsyncPacketSocket::State::STATE_CLOSED)
|
|
return;
|
|
const rtc::Buffer& out = PreparePacket(layer->EncodePacket(&msg_base));
|
|
if (!out.empty())
|
|
SendPacket(out.data(), out.size());
|
|
}
|
|
|
|
void EndpointRelayObfuscatedTcp::SendPacket(const uint8_t *data, size_t size) {
|
|
rtc::ByteBufferWriter out;
|
|
size_t len = size / 4;
|
|
if (len < 0x7F) {
|
|
out.WriteUInt8(len);
|
|
} else {
|
|
out.WriteUInt8(0x7F);
|
|
out.WriteUInt8(len & 0xFF);
|
|
out.WriteUInt8((len >> 8) & 0xFF);
|
|
out.WriteUInt8((len >> 16) & 0xFF);
|
|
}
|
|
out.WriteBytes(reinterpret_cast<const char *>(data), size);
|
|
layer->EncryptForTCPO2(reinterpret_cast<unsigned char *>(out.ReserveWriteBuffer(0)),
|
|
out.Length(), &sendState);
|
|
EndpointTcp::SendPacket(reinterpret_cast<const uint8_t *>(out.Data()), out.Length());
|
|
}
|
|
|
|
EndpointRelayUdp::EndpointRelayUdp(const rtc::SocketAddress& addr, const PeerTag& peer_tag,
|
|
rtc::AsyncPacketSocket *socket, LayerBase *layer)
|
|
: Relay(peer_tag)
|
|
, EndpointUdp(addr, socket, layer, Type::RelayUdp) {}
|
|
|
|
void EndpointRelayUdp::SendMessage(const message::Base& msg_base) {
|
|
const rtc::Buffer& out = PreparePacket(layer->EncodePacket(&msg_base));
|
|
if (!out.empty())
|
|
SendPacket(out.data(), out.size());
|
|
}
|
|
|
|
void EndpointRelayUdp::RecvPacket(rtc::AsyncPacketSocket *sock, const char *data, size_t len,
|
|
const rtc::SocketAddress& remote_addr, const int64_t& packet_time_us) {
|
|
bool glued;
|
|
bool processed = false;
|
|
do {
|
|
EndpointBase::RecvPacket(sock, data, len, remote_addr, packet_time_us);
|
|
glued = in_buffer->Length() > len;
|
|
std::unique_ptr<message::Base> msg;
|
|
while (CheckPacket(in_buffer.get()) && (msg = layer->DecodePacket(*in_buffer))) {
|
|
processed = true;
|
|
SignalMessage(*msg, this);
|
|
}
|
|
if (!processed)
|
|
in_buffer = std::make_unique<rtc::ByteBufferReader>(nullptr, 0);
|
|
} while (!processed && glued);
|
|
}
|
|
|
|
EndpointP2p::EndpointP2p(const rtc::SocketAddress& addr, rtc::AsyncPacketSocket *socket, LayerBase *layer)
|
|
: EndpointUdp(addr, socket, layer, Type::P2p) {}
|
|
|
|
void EndpointP2p::SendMessage(const message::Base& msg_base) {
|
|
rtc::Buffer out = layer->EncodePacket(&msg_base);
|
|
if (!out.empty())
|
|
SendPacket(out.data(), out.size());
|
|
}
|
|
|
|
void EndpointP2p::RecvPacket(rtc::AsyncPacketSocket *sock, const char *data, size_t len,
|
|
const rtc::SocketAddress& remote_addr, const int64_t& packet_time_us) {
|
|
bool glued;
|
|
bool processed = false;
|
|
do {
|
|
EndpointBase::RecvPacket(sock, data, len, remote_addr, packet_time_us);
|
|
glued = in_buffer->Length() > len;
|
|
while (auto msg = layer->DecodePacket(*in_buffer)) {
|
|
processed = true;
|
|
SignalMessage(*msg, this);
|
|
}
|
|
if (!processed)
|
|
in_buffer = std::make_unique<rtc::ByteBufferReader>(nullptr, 0);
|
|
} while (!processed && glued);
|
|
}
|