1
0
mirror of https://github.com/danog/libtgvoip.git synced 2024-12-02 09:37:52 +01:00
libtgvoip/controller/protocol/Reflector.cpp
2020-03-16 16:07:13 +01:00

118 lines
4.6 KiB
C++

#include "../PrivateDefines.cpp"
using namespace tgvoip;
using namespace std;
bool VoIPController::parseRelayPacket(const BufferInputStream &in, Endpoint &srcEndpoint)
{
size_t offset = in.GetOffset();
if (!(in.ReadUInt64() == 0xFFFFFFFFFFFFFFFFLL && in.ReadUInt32() == 0xFFFFFFFF))
{
in.Seek(offset);
return false;
}
// UDP relay special request response
in.Seek(16 + 12);
uint32_t tlid = in.ReadUInt32();
if (tlid == TLID_UDP_REFLECTOR_SELF_INFO)
{
if (srcEndpoint.type == Endpoint::Type::UDP_RELAY && in.Remaining() >= 32)
{
int32_t date = in.ReadInt32();
int64_t queryID = in.ReadInt64();
unsigned char myIP[16];
in.ReadBytes(myIP, 16);
int32_t myPort = in.ReadInt32();
//udpConnectivityState=UDP_AVAILABLE;
double selfRTT = 0.0;
srcEndpoint.udpPongCount++;
srcEndpoint.totalUdpPingReplies++;
if (srcEndpoint.udpPingTimes.find(queryID) != srcEndpoint.udpPingTimes.end())
{
double sendTime = srcEndpoint.udpPingTimes[queryID];
srcEndpoint.udpPingTimes.erase(queryID);
srcEndpoint.selfRtts.Add(selfRTT = GetCurrentTime() - sendTime);
}
LOGV("Received UDP ping reply from %s:%d: date=%d, queryID=%ld, my IP=%s, my port=%d, selfRTT=%f", srcEndpoint.address.ToString().c_str(), srcEndpoint.port, date, (long int)queryID, NetworkAddress::IPv4(*reinterpret_cast<uint32_t *>(myIP + 12)).ToString().c_str(), myPort, selfRTT);
if (srcEndpoint.IsIPv6Only() && !didSendIPv6Endpoint)
{
NetworkAddress realAddr = NetworkAddress::IPv6(myIP);
if (realAddr == myIPv6)
{
LOGI("Public IPv6 matches local address");
useIPv6 = true;
if (allowP2p)
{
didSendIPv6Endpoint = true;
BufferOutputStream o(18);
o.WriteBytes(myIP, 16);
o.WriteInt16(udpSocket->GetLocalPort());
Buffer b(move(o));
SendExtra(b, EXTRA_TYPE_IPV6_ENDPOINT);
}
}
}
}
}
else if (tlid == TLID_UDP_REFLECTOR_PEER_INFO)
{
if (in.Remaining() >= 16)
{
uint32_t myAddr = in.ReadUInt32();
uint32_t myPort = in.ReadUInt32();
uint32_t peerAddr = in.ReadUInt32();
uint32_t peerPort = in.ReadUInt32();
constexpr int64_t p2pID = static_cast<int64_t>(FOURCC('P', '2', 'P', '4')) << 32;
constexpr int64_t lanID = static_cast<int64_t>(FOURCC('L', 'A', 'N', '4')) << 32;
if (currentEndpoint == p2pID || currentEndpoint == lanID)
currentEndpoint = preferredRelay;
if (endpoints.find(lanID) != endpoints.end())
{
MutexGuard m(endpointsMutex);
endpoints.erase(lanID);
}
unsigned char peerTag[16];
LOGW("Received reflector peer info, my=%s:%u, peer=%s:%u", NetworkAddress::IPv4(myAddr).ToString().c_str(), myPort, NetworkAddress::IPv4(peerAddr).ToString().c_str(), peerPort);
if (waitingForRelayPeerInfo)
{
Endpoint p2p(p2pID, (uint16_t)peerPort, NetworkAddress::IPv4(peerAddr), NetworkAddress::Empty(), Endpoint::Type::UDP_P2P_INET, peerTag);
{
MutexGuard m(endpointsMutex);
endpoints[p2pID] = p2p;
}
if (myAddr == peerAddr)
{
LOGW("Detected LAN");
NetworkAddress lanAddr = NetworkAddress::IPv4(0);
udpSocket->GetLocalInterfaceInfo(&lanAddr, NULL);
BufferOutputStream pkt(8);
pkt.WriteInt32(lanAddr.addr.ipv4);
pkt.WriteInt32(udpSocket->GetLocalPort());
if (peerVersion < 6)
{
SendPacketReliably(PKT_LAN_ENDPOINT, pkt.GetBuffer(), pkt.GetLength(), 0.5, 10);
}
else
{
Buffer buf(move(pkt));
SendExtra(buf, EXTRA_TYPE_LAN_ENDPOINT);
}
}
waitingForRelayPeerInfo = false;
}
}
}
else
{
LOGV("Received relay response with unknown tl id: 0x%08X", tlid);
}
return true;
}