2022-05-15 19:59:17 +00:00
|
|
|
#include "network.h"
|
|
|
|
|
|
|
|
#include <base/log.h>
|
|
|
|
#include <base/system.h>
|
|
|
|
|
|
|
|
static int IndexFromNetType(int NetType)
|
|
|
|
{
|
|
|
|
switch(NetType)
|
|
|
|
{
|
|
|
|
case NETTYPE_IPV6:
|
|
|
|
return 0;
|
|
|
|
case NETTYPE_IPV4:
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *IndexToSystem(int Index)
|
|
|
|
{
|
|
|
|
switch(Index)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
return "stun/6";
|
|
|
|
case 1:
|
|
|
|
return "stun/4";
|
|
|
|
}
|
|
|
|
dbg_break();
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int RetryWaitSeconds(int NumUnsuccessfulTries)
|
|
|
|
{
|
|
|
|
return (1 << clamp(0, NumUnsuccessfulTries, 9));
|
|
|
|
}
|
|
|
|
|
|
|
|
CStun::CProtocol::CProtocol(int Index, NETSOCKET Socket) :
|
|
|
|
m_Index(Index),
|
|
|
|
m_Socket(Socket)
|
|
|
|
{
|
2022-05-21 22:39:52 +00:00
|
|
|
mem_zero(&m_StunServer, sizeof(NETADDR));
|
2022-05-15 19:59:17 +00:00
|
|
|
// Initialize `m_Stun` with random data.
|
|
|
|
unsigned char aBuf[32];
|
|
|
|
StunMessagePrepare(aBuf, sizeof(aBuf), &m_Stun);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CStun::CProtocol::FeedStunServer(NETADDR StunServer)
|
|
|
|
{
|
|
|
|
if(net_addr_comp(&m_StunServer, &StunServer) == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_HaveStunServer = true;
|
|
|
|
m_StunServer = StunServer;
|
|
|
|
m_NumUnsuccessfulTries = 0;
|
|
|
|
Refresh();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CStun::CProtocol::Refresh()
|
|
|
|
{
|
|
|
|
m_NextTry = time_get();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CStun::CProtocol::Update()
|
|
|
|
{
|
|
|
|
int64_t Now = time_get();
|
|
|
|
if(m_NextTry == -1 || Now < m_NextTry || !m_HaveStunServer)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_NextTry = Now + RetryWaitSeconds(m_NumUnsuccessfulTries) * time_freq();
|
|
|
|
m_NumUnsuccessfulTries += 1;
|
|
|
|
unsigned char aBuf[32];
|
|
|
|
int Size = StunMessagePrepare(aBuf, sizeof(aBuf), &m_Stun);
|
|
|
|
if(net_udp_send(m_Socket, &m_StunServer, aBuf, Size) == -1)
|
|
|
|
{
|
|
|
|
log_error(IndexToSystem(m_Index), "couldn't send stun request");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CStun::CProtocol::OnPacket(NETADDR Addr, unsigned char *pData, int DataSize)
|
|
|
|
{
|
|
|
|
if(m_NextTry < 0 || !m_HaveStunServer)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool Success;
|
|
|
|
NETADDR StunAddr;
|
|
|
|
if(StunMessageParse(pData, DataSize, &m_Stun, &Success, &StunAddr))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
int64_t Now = time_get();
|
|
|
|
int64_t Freq = time_freq();
|
|
|
|
m_LastResponse = Now;
|
|
|
|
if(!Success)
|
|
|
|
{
|
|
|
|
m_HaveAddr = false;
|
|
|
|
log_debug(IndexToSystem(m_Index), "got error response");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
m_NextTry = Now + 600 * Freq;
|
|
|
|
m_NumUnsuccessfulTries = -1;
|
|
|
|
m_HaveAddr = true;
|
|
|
|
m_Addr = StunAddr;
|
|
|
|
|
|
|
|
char aStunAddr[NETADDR_MAXSTRSIZE];
|
|
|
|
net_addr_str(&StunAddr, aStunAddr, sizeof(aStunAddr), true);
|
|
|
|
log_debug(IndexToSystem(m_Index), "got address: %s", aStunAddr);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
CONNECTIVITY CStun::CProtocol::GetConnectivity(NETADDR *pGlobalAddr)
|
|
|
|
{
|
|
|
|
if(!m_HaveStunServer)
|
|
|
|
{
|
|
|
|
return CONNECTIVITY::UNKNOWN;
|
|
|
|
}
|
|
|
|
int64_t Now = time_get();
|
|
|
|
int64_t Freq = time_freq();
|
|
|
|
bool HaveTriedALittle = m_NumUnsuccessfulTries >= 5 && (m_LastResponse == -1 || Now - m_LastResponse >= 30 * Freq);
|
|
|
|
if(m_LastResponse == -1 && !HaveTriedALittle)
|
|
|
|
{
|
|
|
|
return CONNECTIVITY::CHECKING;
|
|
|
|
}
|
|
|
|
else if(HaveTriedALittle)
|
|
|
|
{
|
|
|
|
return CONNECTIVITY::UNREACHABLE;
|
|
|
|
}
|
|
|
|
else if(!m_HaveAddr)
|
|
|
|
{
|
|
|
|
return CONNECTIVITY::REACHABLE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*pGlobalAddr = m_Addr;
|
|
|
|
return CONNECTIVITY::ADDRESS_KNOWN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CStun::CStun(NETSOCKET Socket) :
|
|
|
|
m_aProtocols{CProtocol(0, Socket), CProtocol(1, Socket)}
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void CStun::FeedStunServer(NETADDR StunServer)
|
|
|
|
{
|
|
|
|
int Index = IndexFromNetType(StunServer.type);
|
|
|
|
if(Index < 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_aProtocols[Index].FeedStunServer(StunServer);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CStun::Refresh()
|
|
|
|
{
|
|
|
|
for(auto &Protocol : m_aProtocols)
|
|
|
|
{
|
|
|
|
Protocol.Refresh();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CStun::Update()
|
|
|
|
{
|
|
|
|
for(auto &Protocol : m_aProtocols)
|
|
|
|
{
|
|
|
|
Protocol.Update();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CStun::OnPacket(NETADDR Addr, unsigned char *pData, int DataSize)
|
|
|
|
{
|
|
|
|
int Index = IndexFromNetType(Addr.type);
|
|
|
|
if(Index < 0)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return m_aProtocols[Index].OnPacket(Addr, pData, DataSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
CONNECTIVITY CStun::GetConnectivity(int NetType, NETADDR *pGlobalAddr)
|
|
|
|
{
|
|
|
|
int Index = IndexFromNetType(NetType);
|
|
|
|
dbg_assert(Index != -1, "invalid nettype");
|
|
|
|
return m_aProtocols[Index].GetConnectivity(pGlobalAddr);
|
|
|
|
}
|