ICE client refactor: Each Interface knows what session owns it

Socket callback will be the interface pointer, which gives us
a little bit more context and makes a few things simpler.

(cherry picked from commit 60314c1606)
This commit is contained in:
Fletcher Dunn
2026-05-25 18:38:25 -07:00
parent b4592f126a
commit c6c752e5e4
2 changed files with 43 additions and 41 deletions
@@ -1303,43 +1303,23 @@ void CSteamNetworkingICESession::GatherInterfaces()
// the list was empty).
for ( const LocalAddress_t &addr: vecAddrs )
{
std::unique_ptr<ICESessionInterface> pIntf = std::make_unique<ICESessionInterface>( *this, uNextPriority, addr.m_nPrefixLen );
SteamDatagramErrMsg errMsg;
SteamNetworkingIPAddr bindAddr = addr.m_addr;
IRawUDPSocket *pSock = OpenRawUDPSocket( CRecvPacketCallback( CSteamNetworkingICESession::StaticPacketReceived, this ), errMsg, &bindAddr, nullptr );
if ( pSock == nullptr )
pIntf->m_pSocket = OpenRawUDPSocket( CRecvPacketCallback( CSteamNetworkingICESession::StaticPacketReceived, pIntf.get() ), errMsg, &bindAddr, nullptr );
if ( pIntf->m_pSocket == nullptr )
{
SpewWarning( "Could not bind to %s, skipping interface. %s\n", SteamNetworkingIPAddrRender( addr.m_addr ).c_str(), errMsg );
continue;
}
m_vecInterfaces.emplace_back( std::make_unique<ICESessionInterface>( uNextPriority, addr.m_nPrefixLen, pSock ) );
m_vecInterfaces.emplace_back( std::move( pIntf ) );
if ( uNextPriority > 0 )
--uNextPriority;
}
}
CSteamNetworkingSocketsSTUNRequest *CSteamNetworkingICESession::FindPendingRequestByTransactionID( const uint32 nTransactionID[3] ) const
{
auto fnMatches = [nTransactionID]( const CSteamNetworkingSocketsSTUNRequest *pRequest )
{
return pRequest != nullptr
&& pRequest->m_nTransactionID[0] == nTransactionID[0]
&& pRequest->m_nTransactionID[1] == nTransactionID[1]
&& pRequest->m_nTransactionID[2] == nTransactionID[2];
};
for ( const auto &pIntf : m_vecInterfaces )
if ( fnMatches( pIntf->m_pPendingSTUNRequest ) )
return pIntf->m_pPendingSTUNRequest;
for ( CSteamNetworkingSocketsSTUNRequest *pRequest : m_vecPendingPeerRequests )
if ( fnMatches( pRequest ) )
return pRequest;
return nullptr;
}
void CSteamNetworkingICESession::OnPacketReceived( const RecvPktInfo_t &info )
void CSteamNetworkingICESession::OnPacketReceived( const RecvPktInfo_t &info, ICESessionInterface *pInterface )
{
SteamNetworkingGlobalLock::AssertHeldByCurrentThread( "CSteamNetworkingICESession::OnPacketReceived" );
@@ -1351,7 +1331,27 @@ void CSteamNetworkingICESession::OnPacketReceived( const RecvPktInfo_t &info )
UnpackSTUNHeader( reinterpret_cast<const uint32 *>( info.m_pPkt ), &quickHeader );
if ( IsValidSTUNHeader( &quickHeader, info.m_cbPkt, nullptr ) && quickHeader.m_nMessageType != k_nSTUN_BindingRequest )
{
CSteamNetworkingSocketsSTUNRequest *pRequest = FindPendingRequestByTransactionID( quickHeader.m_nTransactionID );
CSteamNetworkingSocketsSTUNRequest *pRequest = pInterface->m_pPendingSTUNRequest;
if (
pRequest == nullptr
|| pRequest->m_nTransactionID[0] != quickHeader.m_nTransactionID[0]
|| pRequest->m_nTransactionID[1] != quickHeader.m_nTransactionID[1]
|| pRequest->m_nTransactionID[2] != quickHeader.m_nTransactionID[2]
) {
pRequest = nullptr;
for ( CSteamNetworkingSocketsSTUNRequest *p : m_vecPendingPeerRequests )
{
if (
p->m_pInterface == pInterface
&& p->m_nTransactionID[0] == quickHeader.m_nTransactionID[0]
&& p->m_nTransactionID[1] == quickHeader.m_nTransactionID[1]
&& p->m_nTransactionID[2] == quickHeader.m_nTransactionID[2]
) {
pRequest = p;
break;
}
}
}
if ( pRequest != nullptr )
{
pRequest->OnPacketReceived( info );
@@ -1414,14 +1414,13 @@ void CSteamNetworkingICESession::OnPacketReceived( const RecvPktInfo_t &info )
CUtlVector< STUNAttribute > outAttrs;
{
const SteamNetworkingIPAddr localAddr = info.m_pSock->m_boundAddr;
SpewMsg( "Incoming binding request from %s to %s.\n\n", SteamNetworkingIPAddrRender( fromAddr ).c_str(), SteamNetworkingIPAddrRender( localAddr ).c_str() );
SpewMsg( "Incoming binding request from %s to %s.\n\n", SteamNetworkingIPAddrRender( fromAddr ).c_str(), SteamNetworkingIPAddrRender( pInterface->m_pSocket->m_boundAddr ).c_str() );
ICECandidatePair *pThisPair = nullptr;
for ( ICECandidatePair *pPair : m_vecCandidatePairs )
{
if ( pPair->m_remoteCandidate.m_addr == fromAddr
&& pPair->m_localCandidate.m_pInterface->m_pSocket == info.m_pSock )
&& pPair->m_localCandidate.m_pInterface == pInterface )
{
pThisPair = pPair;
break;
@@ -1439,7 +1438,7 @@ void CSteamNetworkingICESession::OnPacketReceived( const RecvPktInfo_t &info )
ICELocalCandidate *pLocalCandidate = nullptr;
for ( ICELocalCandidate &c : m_vecCandidates )
{
if ( c.m_pInterface->m_pSocket == info.m_pSock )
if ( c.m_pInterface == pInterface )
{
pLocalCandidate = &c;
break;
@@ -1521,10 +1520,9 @@ void CSteamNetworkingICESession::OnPacketReceived( const RecvPktInfo_t &info )
}
}
void CSteamNetworkingICESession::StaticPacketReceived( const RecvPktInfo_t &info, CSteamNetworkingICESession *pContext )
void CSteamNetworkingICESession::StaticPacketReceived( const RecvPktInfo_t &info, ICESessionInterface *pContext )
{
if ( pContext != nullptr )
pContext->OnPacketReceived( info );
pContext->m_session.OnPacketReceived( info, pContext );
}
void CSteamNetworkingICESession::Think( SteamNetworkingMicroseconds usecNow )
@@ -14,11 +14,15 @@
namespace SteamNetworkingSocketsLib {
class CSteamNetworkingSocketsSTUNRequest;
class CSteamNetworkingICESessionCallbacks;
class CSteamNetworkingICESession;
/// Represents one local network interface used for ICE candidate gathering.
/// Owns its socket and tracks at most one in-flight server-reflexive STUN request.
struct ICESessionInterface
{
// The session that owns this interface.
CSteamNetworkingICESession &m_session;
// Local-preference component of the ICE priority formula
// (RFC 8445 §5.1.2). Assigned as a countdown from 65535 in
// enumeration order so the first adapter returned by the OS gets
@@ -31,17 +35,18 @@ namespace SteamNetworkingSocketsLib {
int m_nPrefixLen;
// Raw UDP socket bound to this interface for sending and receiving
// ICE traffic. Always non-NULL, owned by this object.
// ICE traffic. Null only transiently during construction before
// the socket is successfully opened. Owned by this object;
// m_pSocket->m_boundAddr is the local IP:port for this interface.
IRawUDPSocket * const m_pSocket;
IRawUDPSocket *m_pSocket;
// In-flight STUN bind request for server-reflexive discovery or
// keepalive, or null if none is active. At most one per interface.
CSteamNetworkingSocketsSTUNRequest *m_pPendingSTUNRequest = nullptr;
ICESessionInterface( uint32 p, int nPrefixLen, IRawUDPSocket *pSocket )
: m_nPriority( p ), m_nPrefixLen( nPrefixLen ), m_pSocket( pSocket ) {}
~ICESessionInterface() { m_pSocket->Close(); }
ICESessionInterface( CSteamNetworkingICESession &session, uint32 nPriority, int nPrefixLen )
: m_session( session ), m_nPriority( nPriority ), m_nPrefixLen( nPrefixLen ), m_pSocket( nullptr ) {}
~ICESessionInterface() { if ( m_pSocket ) m_pSocket->Close(); }
ICESessionInterface( const ICESessionInterface& ) = delete;
ICESessionInterface& operator=( const ICESessionInterface& ) = delete;
@@ -372,7 +377,6 @@ namespace SteamNetworkingSocketsLib {
// each Think() pass before the regular check list.
std_vector< ICECandidatePair* > m_vecTriggeredCheckQueue;
CSteamNetworkingSocketsSTUNRequest *FindPendingRequestByTransactionID( const uint32 nTransactionID[3] ) const;
void GatherInterfaces();
void UpdateHostCandidates();
void UpdateKeepalive( const ICELocalCandidate& c );
@@ -399,8 +403,8 @@ namespace SteamNetworkingSocketsLib {
void STUNRequestCallback_PeerConnectivityCheck( const RecvSTUNPktInfo_t &info );
static void StaticSTUNRequestCallback_PeerConnectivityCheck( const RecvSTUNPktInfo_t &info, CSteamNetworkingICESession* pContext );
void OnPacketReceived( const RecvPktInfo_t &info );
static void StaticPacketReceived( const RecvPktInfo_t &info, CSteamNetworkingICESession *pContext );
void OnPacketReceived( const RecvPktInfo_t &info, ICESessionInterface *pInterface );
static void StaticPacketReceived( const RecvPktInfo_t &info, ICESessionInterface *pContext );
};
class CSteamNetworkingICESessionCallbacks