mirror of
https://github.com/ValveSoftware/GameNetworkingSockets.git
synced 2026-05-29 16:20:34 +00:00
Improvements to ICE error handling
Change how CSteamNetworkConnectionBase::GuessTimeoutReason defaults are set. Just set them directly in CSteamNetworkConnectionBase::ConnectionTimedOut. What we were doing previously was a bit convoluted. Add logic to actually attempt to classify ICE failure.
This commit is contained in:
@@ -285,19 +285,25 @@ message CMsgSteamNetworkingP2PRendezvous
|
||||
};
|
||||
|
||||
// A summary of what happened in an ICE session, for analytics
|
||||
message CMsgSteamNetworkingSocketsICESessionSummary
|
||||
message CMsgSteamNetworkingICESessionSummary
|
||||
{
|
||||
// What was the overall outcome of ICE?
|
||||
// Should always be set. Will be zero if
|
||||
// ICE succeeded
|
||||
optional uint32 failure_reason_code = 7; // ESteamNetConnectionEnd (or special internal value), if we failed in some way
|
||||
|
||||
// What types of candidates were we able to gather?
|
||||
// Should always be present
|
||||
optional uint32 local_candidate_types = 1;
|
||||
// Should always be present if this message is sent
|
||||
optional uint32 local_candidate_types = 1; // k_EICECandidate_xxx
|
||||
|
||||
// What types of candidates did we receive from peer?
|
||||
optional uint32 remote_candidate_types = 2;
|
||||
optional uint32 remote_candidate_types = 2; // k_EICECandidate_xxx
|
||||
|
||||
// Initial route type, and ping, when when we first pierced NAT.
|
||||
// Will not be present if we never pierced NAT
|
||||
optional uint32 initial_route_kind = 3; // ESteamNetTransportKind
|
||||
optional uint32 initial_ping = 4;
|
||||
optional uint32 nat_traversal_ms = 5; // How long did it take to get a NAT traversal result (either success or failure)
|
||||
};
|
||||
|
||||
// Do not remove this comment due to a bug on the Mac OS X protobuf compiler
|
||||
|
||||
@@ -2805,10 +2805,32 @@ void CSteamNetworkConnectionBase::ConnectionTimedOut( SteamNetworkingMicrosecond
|
||||
ESteamNetConnectionEnd nReasonCode;
|
||||
ConnectionEndDebugMsg msg;
|
||||
|
||||
// Set some generic defaults using our base class version, so
|
||||
// this function will work even if the derived class forgets to
|
||||
// call the base class.
|
||||
CSteamNetworkConnectionBase::GuessTimeoutReason( nReasonCode, msg, usecNow );
|
||||
// Set some generic defaults.
|
||||
nReasonCode = k_ESteamNetConnectionEnd_Misc_Timeout;
|
||||
switch ( GetState() )
|
||||
{
|
||||
case k_ESteamNetworkingConnectionState_Connecting:
|
||||
// Should use this more specific reason code at somepoint, when I add an API to get localized error messages
|
||||
//if ( !m_bConnectionInitiatedRemotely && m_statsEndToEnd.m_usecTimeLastRecv == 0 )
|
||||
//{
|
||||
// nReasonCode = k_ESteamNetConnectionEnd_Misc_ServerNeverReplied;
|
||||
// V_strcpy_safe( msg, "" );
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
V_strcpy_safe( msg, "Timed out attempting to connect" );
|
||||
//}
|
||||
break;
|
||||
|
||||
case k_ESteamNetworkingConnectionState_FindingRoute:
|
||||
nReasonCode = k_ESteamNetConnectionEnd_Misc_P2P_Rendezvous;
|
||||
V_strcpy_safe( msg, "Timed out attempting to negotiate rendezvous" );
|
||||
break;
|
||||
|
||||
default:
|
||||
V_strcpy_safe( msg, "Connection dropped" );
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if connection has a more enlightened understanding of what's wrong
|
||||
GuessTimeoutReason( nReasonCode, msg, usecNow );
|
||||
@@ -2819,23 +2841,7 @@ void CSteamNetworkConnectionBase::ConnectionTimedOut( SteamNetworkingMicrosecond
|
||||
|
||||
void CSteamNetworkConnectionBase::GuessTimeoutReason( ESteamNetConnectionEnd &nReasonCode, ConnectionEndDebugMsg &msg, SteamNetworkingMicroseconds usecNow )
|
||||
{
|
||||
NOTE_UNUSED( usecNow );
|
||||
|
||||
nReasonCode = k_ESteamNetConnectionEnd_Misc_Timeout;
|
||||
switch ( GetState() )
|
||||
{
|
||||
case k_ESteamNetworkingConnectionState_Connecting:
|
||||
V_strcpy_safe( msg, "Timed out attempting to connect" );
|
||||
break;
|
||||
|
||||
case k_ESteamNetworkingConnectionState_FindingRoute:
|
||||
V_strcpy_safe( msg, "Timed out attempting to negotiate rendezvous" );
|
||||
break;
|
||||
|
||||
default:
|
||||
V_strcpy_safe( msg, "Connection dropped" );
|
||||
break;
|
||||
}
|
||||
// No enlightenments at base class
|
||||
}
|
||||
|
||||
void CSteamNetworkConnectionBase::UpdateSpeeds( int nTXSpeed, int nRXSpeed )
|
||||
|
||||
@@ -95,6 +95,7 @@ CSteamNetworkConnectionP2P::CSteamNetworkConnectionP2P( CSteamNetworkingSockets
|
||||
m_nRemoteVirtualPort = -1;
|
||||
m_idxMapIncomingP2PConnections = -1;
|
||||
m_pSignaling = nullptr;
|
||||
m_usecWhenStartedFindingRoute = 0;
|
||||
m_usecNextEvaluateTransport = k_nThinkTime_ASAP;
|
||||
m_bTransportSticky = false;
|
||||
|
||||
@@ -111,7 +112,6 @@ CSteamNetworkConnectionP2P::CSteamNetworkConnectionP2P( CSteamNetworkingSockets
|
||||
#ifdef STEAMNETWORKINGSOCKETS_ENABLE_ICE
|
||||
m_pTransportICE = nullptr;
|
||||
m_pTransportICEPendingDelete = nullptr;
|
||||
m_nICECloseCode = 0;
|
||||
m_szICECloseMsg[ 0 ] = '\0';
|
||||
#endif
|
||||
}
|
||||
@@ -249,7 +249,7 @@ void CSteamNetworkConnectionP2P::CheckInitICE()
|
||||
Assert( !m_pTransportICEPendingDelete );
|
||||
|
||||
// Did we already fail?
|
||||
if ( m_nICECloseCode != 0 )
|
||||
if ( GetICEFailureCode() != 0 )
|
||||
return;
|
||||
|
||||
int P2P_Transport_ICE_Enable = m_connectionConfig.m_P2P_Transport_ICE_Enable.Get();
|
||||
@@ -301,7 +301,7 @@ void CSteamNetworkConnectionP2P::CheckInitICE()
|
||||
#endif
|
||||
if ( !g_SteamNetworkingSockets_CreateICESessionFunc )
|
||||
{
|
||||
ICEFailed( k_nICECloseCode_Local_FailedInit, "No ICE session factory" );
|
||||
ICEFailed( k_ESteamNetConnectionEnd_Misc_InternalError, "No ICE session factory" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -321,10 +321,144 @@ void CSteamNetworkConnectionP2P::CheckInitICE()
|
||||
|
||||
// If we're still all good, then add it to the list of options
|
||||
if ( m_pTransportICE )
|
||||
{
|
||||
m_vecAvailableTransports.push_back( m_pTransportICE );
|
||||
|
||||
// Set a field in the ice session summary message,
|
||||
// which is how we will remember that we did attempt to use ICE
|
||||
Assert( !m_msgICESessionSummary.has_local_candidate_types() );
|
||||
m_msgICESessionSummary.set_local_candidate_types( 0 );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void CSteamNetworkConnectionP2P::EnsureICEFailureReasonSet( SteamNetworkingMicroseconds usecNow )
|
||||
{
|
||||
#ifdef STEAMNETWORKINGSOCKETS_ENABLE_ICE
|
||||
|
||||
// Already have a reason?
|
||||
if ( m_msgICESessionSummary.has_failure_reason_code() )
|
||||
return;
|
||||
|
||||
// If we never tried ICE, then there's no "failure"!
|
||||
if ( !m_msgICESessionSummary.has_local_candidate_types() )
|
||||
return;
|
||||
|
||||
// Classify failure, and make it permanent
|
||||
ESteamNetConnectionEnd nReasonCode;
|
||||
GuessICEFailureReason( nReasonCode, m_szICECloseMsg, usecNow );
|
||||
m_msgICESessionSummary.set_failure_reason_code( nReasonCode );
|
||||
int nSeverity = ( nReasonCode != 0 && nReasonCode != k_nICECloseCode_Aborted ) ? k_ESteamNetworkingSocketsDebugOutputType_Msg : k_ESteamNetworkingSocketsDebugOutputType_Verbose;
|
||||
SpewTypeGroup( nSeverity, LogLevel_P2PRendezvous(), "[%s] Guessed ICE failure to be %d: %s\n",
|
||||
GetDescription(), nReasonCode, m_szICECloseMsg );
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef STEAMNETWORKINGSOCKETS_ENABLE_ICE
|
||||
void CSteamNetworkConnectionP2P::GuessICEFailureReason( ESteamNetConnectionEnd &nReasonCode, ConnectionEndDebugMsg &msg, SteamNetworkingMicroseconds usecNow )
|
||||
{
|
||||
// Already have a reason?
|
||||
if ( m_msgICESessionSummary.has_failure_reason_code() )
|
||||
{
|
||||
nReasonCode = ESteamNetConnectionEnd( m_msgICESessionSummary.failure_reason_code() );
|
||||
V_strcpy_safe( msg, m_szICECloseMsg );
|
||||
return;
|
||||
}
|
||||
|
||||
// This should not be called if we never even tried
|
||||
Assert( m_msgICESessionSummary.has_local_candidate_types() );
|
||||
|
||||
// This ought to be called before we cleanup and destroy the info we need
|
||||
Assert( m_pTransportICE );
|
||||
|
||||
// If we are connected right now, then there is no problem!
|
||||
if ( m_pTransportICE && !m_pTransportICE->m_bNeedToConfirmEndToEndConnectivity )
|
||||
{
|
||||
nReasonCode = k_ESteamNetConnectionEnd_Invalid;
|
||||
V_strcpy_safe( msg, "OK" );
|
||||
return;
|
||||
}
|
||||
|
||||
// Did we ever pierce NAT? If so, then we just dropped connection.
|
||||
if ( m_msgICESessionSummary.has_nat_traversal_ms() )
|
||||
{
|
||||
nReasonCode = k_ESteamNetConnectionEnd_Misc_Timeout;
|
||||
V_strcpy_safe( msg, "ICE connection dropped after successful negotiation" );
|
||||
return;
|
||||
}
|
||||
|
||||
// OK, looks like we never pierced NAT. Try to figure out why.
|
||||
const int nAllowedTypes = m_pTransportICE ? m_pTransportICE->m_nAllowedCandidateTypes : 0;
|
||||
const int nGatheredTypes = m_msgICESessionSummary.local_candidate_types();
|
||||
const int nFailedToGatherTypes = nAllowedTypes & ~nGatheredTypes;
|
||||
const int nRemoteTypes = m_msgICESessionSummary.remote_candidate_types();
|
||||
|
||||
// Terminated prematurely? Presumably the higher level code hs a reason,
|
||||
// and so this will only be used for analytics.
|
||||
if ( m_usecWhenStartedFindingRoute == 0 || m_usecWhenStartedFindingRoute+5*k_nMillion > usecNow )
|
||||
{
|
||||
nReasonCode = ESteamNetConnectionEnd( k_nICECloseCode_Aborted );
|
||||
V_strcpy_safe( msg, "NAT traversal aborted" );
|
||||
return;
|
||||
}
|
||||
|
||||
// Problem on our end?
|
||||
if ( nFailedToGatherTypes & (k_EICECandidate_Any_HostPrivate|k_EICECandidate_Any_HostPublic) )
|
||||
{
|
||||
// We should always be able to collect these sorts of candidates!
|
||||
nReasonCode = k_ESteamNetConnectionEnd_Misc_InternalError;
|
||||
V_strcpy_safe( msg, "Never gathered *any* host candidates?" );
|
||||
return;
|
||||
}
|
||||
|
||||
// Never received *any* candidates from them?
|
||||
if ( nRemoteTypes == 0 )
|
||||
{
|
||||
nReasonCode = k_ESteamNetConnectionEnd_Misc_Generic;
|
||||
V_strcpy_safe( msg, "Never received any remote candidates" );
|
||||
return;
|
||||
}
|
||||
|
||||
// We failed to STUN?
|
||||
if ( !( nGatheredTypes & k_EICECandidate_Any_Reflexive ) )
|
||||
{
|
||||
if ( m_connectionConfig.m_P2P_STUN_ServerList.Get().empty() )
|
||||
{
|
||||
nReasonCode = k_ESteamNetConnectionEnd_Misc_InternalError;
|
||||
V_strcpy_safe( msg, "No configured STUN servers" );
|
||||
return;
|
||||
}
|
||||
nReasonCode = k_ESteamNetConnectionEnd_Local_P2P_ICE_NoPublicAddresses;
|
||||
V_strcpy_safe( msg, "Failed to determine our public address via STUN" );
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME - we should probably handle this as a special case. TURN candidates
|
||||
// should basically always work
|
||||
//if ( (nAllowedTypes|nGatheredTypes) | k_EICECandidate_Any_Relay )
|
||||
//{
|
||||
//}
|
||||
|
||||
// Any candidates from remote host that we really ought to have been able to talk to?
|
||||
if ( !(nRemoteTypes & ( k_EICECandidate_IPv4_HostPublic|k_EICECandidate_Any_Reflexive|k_EICECandidate_Any_Relay) ) )
|
||||
{
|
||||
nReasonCode = k_ESteamNetConnectionEnd_Remote_P2P_ICE_NoPublicAddresses;
|
||||
V_strcpy_safe( msg, "No public or relay candidates from remote host" );
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: in theory, we could haveIPv4 vs IPv6 capabilities mismatch. In practice
|
||||
// does that ever happen?
|
||||
|
||||
// OK, both sides shared reflexive candidates, but we still failed? This is probably
|
||||
// a firewall thing
|
||||
nReasonCode = k_ESteamNetConnectionEnd_Misc_P2P_NAT_Firewall;
|
||||
V_strcpy_safe( msg, "NAT traversal failed" );
|
||||
}
|
||||
#endif
|
||||
|
||||
void CSteamNetworkConnectionP2P::CheckCleanupICE()
|
||||
{
|
||||
#ifdef STEAMNETWORKINGSOCKETS_ENABLE_ICE
|
||||
@@ -364,39 +498,29 @@ void CSteamNetworkConnectionP2P::DestroyICENow()
|
||||
}
|
||||
|
||||
#ifdef STEAMNETWORKINGSOCKETS_ENABLE_ICE
|
||||
|
||||
void CSteamNetworkConnectionP2P::ICEFailed( int nReasonCode, const char *pszReason )
|
||||
{
|
||||
SteamDatagramTransportLock::AssertHeldByCurrentThread();
|
||||
|
||||
// Remember reason code, if we didn't already set one
|
||||
if ( m_nICECloseCode == 0 )
|
||||
if ( GetICEFailureCode() == 0 )
|
||||
{
|
||||
SpewMsgGroup( LogLevel_P2PRendezvous(), "[%s] ICE failed %d %s\n", GetDescription(), nReasonCode, pszReason );
|
||||
m_nICECloseCode = nReasonCode;
|
||||
m_msgICESessionSummary.set_failure_reason_code( nReasonCode );
|
||||
V_strcpy_safe( m_szICECloseMsg, pszReason );
|
||||
}
|
||||
|
||||
QueueDestroyICE();
|
||||
}
|
||||
|
||||
void CSteamNetworkConnectionP2P::QueueDestroyICE()
|
||||
{
|
||||
if ( !m_pTransportICE )
|
||||
return;
|
||||
|
||||
// Queue for deletion
|
||||
if ( !m_pTransportICEPendingDelete )
|
||||
{
|
||||
m_pTransportICEPendingDelete = m_pTransportICE;
|
||||
m_pTransportICE = nullptr;
|
||||
|
||||
// Make sure we clean ourselves up as soon as it is safe to do so
|
||||
SetNextThinkTimeASAP();
|
||||
}
|
||||
|
||||
// Make sure we clean ourselves up as soon as it is safe to do so
|
||||
SetNextThinkTimeASAP();
|
||||
}
|
||||
|
||||
#endif // #ifdef STEAMNETWORKINGSOCKETS_ENABLE_ICE
|
||||
#endif
|
||||
|
||||
void CSteamNetworkConnectionP2P::FreeResources()
|
||||
{
|
||||
@@ -490,19 +614,32 @@ void CSteamNetworkConnectionP2P::TransportEndToEndConnectivityChanged( CConnecti
|
||||
// Schedule us to wake up immediately and deal with it.
|
||||
m_usecNextEvaluateTransport = k_nThinkTime_ASAP;
|
||||
SetNextThinkTimeASAP();
|
||||
|
||||
// Check if this is the first time ICE was successful
|
||||
#ifdef STEAMNETWORKINGSOCKETS_ENABLE_ICE
|
||||
if ( !pTransport->m_bNeedToConfirmEndToEndConnectivity && pTransport == m_pTransportICE && !m_msgICESessionSummary.has_nat_traversal_ms() )
|
||||
{
|
||||
if ( m_usecWhenStartedFindingRoute == 0 )
|
||||
{
|
||||
AssertMsg1( false, "[%s] We are confirming end-to-end connectivity, but usecWhenStartedFindingRoute == 0", GetDescription() );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_msgICESessionSummary.set_nat_traversal_ms( ( usecNow - m_usecWhenStartedFindingRoute + 500 ) / 1000 );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CSteamNetworkConnectionP2P::ConnectionStateChanged( ESteamNetworkingConnectionState eOldState )
|
||||
{
|
||||
SteamNetworkingMicroseconds usecNow = SteamNetworkingSockets_GetLocalTimestamp();
|
||||
|
||||
// NOTE: Do not call base class, because it it going to
|
||||
// call TransportConnectionStateChanged on whatever transport is active.
|
||||
// We don't want that here.
|
||||
|
||||
// Inform transports
|
||||
for ( CConnectionTransportP2PBase *pTransportP2P: m_vecAvailableTransports )
|
||||
pTransportP2P->m_pSelfAsConnectionTransport->TransportConnectionStateChanged( eOldState );
|
||||
|
||||
// Reset timer to evaluate transport at certain times
|
||||
// Take action at certain transitions
|
||||
switch ( GetState() )
|
||||
{
|
||||
case k_ESteamNetworkingConnectionState_Dead:
|
||||
@@ -513,17 +650,26 @@ void CSteamNetworkConnectionP2P::ConnectionStateChanged( ESteamNetworkingConnect
|
||||
|
||||
case k_ESteamNetworkingConnectionState_ClosedByPeer:
|
||||
case k_ESteamNetworkingConnectionState_FinWait:
|
||||
EnsureICEFailureReasonSet( usecNow );
|
||||
break;
|
||||
|
||||
case k_ESteamNetworkingConnectionState_Linger:
|
||||
break;
|
||||
|
||||
case k_ESteamNetworkingConnectionState_ProblemDetectedLocally:
|
||||
EnsureICEFailureReasonSet( usecNow );
|
||||
|
||||
// If we fail during these states, send a signal to Steam, for analytics
|
||||
if ( eOldState == k_ESteamNetworkingConnectionState_Connecting || eOldState == k_ESteamNetworkingConnectionState_FindingRoute )
|
||||
SendConnectionClosedSignal( SteamNetworkingSockets_GetLocalTimestamp() );
|
||||
SendConnectionClosedSignal( usecNow );
|
||||
break;
|
||||
|
||||
case k_ESteamNetworkingConnectionState_FindingRoute:
|
||||
m_usecWhenStartedFindingRoute = usecNow;
|
||||
// |
|
||||
// |
|
||||
// V
|
||||
// FALLTHROUGH
|
||||
case k_ESteamNetworkingConnectionState_Connecting:
|
||||
m_bTransportSticky = false; // Not sure how we could have set this flag, but make sure and clear it
|
||||
// |
|
||||
@@ -540,6 +686,10 @@ void CSteamNetworkConnectionP2P::ConnectionStateChanged( ESteamNetworkingConnect
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Inform transports
|
||||
for ( CConnectionTransportP2PBase *pTransportP2P: m_vecAvailableTransports )
|
||||
pTransportP2P->m_pSelfAsConnectionTransport->TransportConnectionStateChanged( eOldState );
|
||||
}
|
||||
|
||||
void CSteamNetworkConnectionP2P::ThinkConnection( SteamNetworkingMicroseconds usecNow )
|
||||
@@ -1080,15 +1230,8 @@ bool CSteamNetworkConnectionP2P::ProcessSignal( const CMsgSteamNetworkingP2PRend
|
||||
#endif
|
||||
|
||||
#ifdef STEAMNETWORKINGSOCKETS_ENABLE_ICE
|
||||
if ( m_pTransportICE && !msg.ice_enabled() )
|
||||
{
|
||||
// The lack of any message at all (even an empty one) means that they
|
||||
// will not support ICE, so we can destroy our transport
|
||||
SpewMsgGroup( LogLevel_P2PRendezvous(), "[%s] Destroying ICE transport, peer rendezvous indicates they will not use it\n", GetDescription() );
|
||||
m_nICECloseCode = k_nICECloseCode_Remote_NotEnabled;
|
||||
V_strcpy_safe( m_szICECloseMsg, "Peer sent signal without ice_enabled set" );
|
||||
DestroyICENow();
|
||||
}
|
||||
if ( !msg.ice_enabled() )
|
||||
ICEFailed( k_nICECloseCode_Remote_NotEnabled, "Peer sent signal without ice_enabled set" );
|
||||
#endif
|
||||
|
||||
// Check for acking reliable messages
|
||||
@@ -1140,7 +1283,7 @@ bool CSteamNetworkConnectionP2P::ProcessSignal( const CMsgSteamNetworkingP2PRend
|
||||
{
|
||||
m_pTransportICE->RecvRendezvous( reliable_msg.ice(), usecNow );
|
||||
}
|
||||
else if ( GetState() == k_ESteamNetworkingConnectionState_Connecting && m_nICECloseCode == 0 )
|
||||
else if ( GetState() == k_ESteamNetworkingConnectionState_Connecting && GetICEFailureCode() == 0 )
|
||||
{
|
||||
m_vecPendingICEMessages.push_back( reliable_msg.ice() );
|
||||
}
|
||||
@@ -1767,15 +1910,6 @@ bool CSteamNetworkingSockets::ReceivedP2PCustomSignal( const void *pMsg, int cbM
|
||||
// They accepted the request already.
|
||||
break;
|
||||
}
|
||||
|
||||
// Remember if peer has ICE enabled
|
||||
#ifdef STEAMNETWORKINGSOCKETS_ENABLE_ICE
|
||||
if ( !msg.ice_enabled() )
|
||||
{
|
||||
pConn->m_nICECloseCode = k_nICECloseCode_Remote_NotEnabled;
|
||||
V_strcpy_safe( pConn->m_szICECloseMsg, "Peer did not enable ICE" );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Stop suppressing state change notifications
|
||||
|
||||
@@ -30,7 +30,7 @@ constexpr int k_nP2P_TransportOverride_ICE = 2;
|
||||
|
||||
constexpr int k_nICECloseCode_Local_NotCompiled = k_ESteamNetConnectionEnd_Local_Max;
|
||||
constexpr int k_nICECloseCode_Local_UserNotEnabled = k_ESteamNetConnectionEnd_Local_Max-1;
|
||||
constexpr int k_nICECloseCode_Local_FailedInit = k_ESteamNetConnectionEnd_Local_Max-2;
|
||||
constexpr int k_nICECloseCode_Aborted = k_ESteamNetConnectionEnd_Local_Max-2;
|
||||
constexpr int k_nICECloseCode_Remote_NotEnabled = k_ESteamNetConnectionEnd_Remote_Max;
|
||||
|
||||
// A really terrible ping score, but one that we can do some math with without overflowing
|
||||
@@ -212,20 +212,22 @@ public:
|
||||
// m_pTransportICE. Then it will be deleted at a safe time.
|
||||
CConnectionTransportP2PICE *m_pTransportICEPendingDelete;
|
||||
|
||||
// Failure reason for ICE, if any. (0 if no failure yet.)
|
||||
int m_nICECloseCode;
|
||||
char m_szICECloseMsg[ k_cchSteamNetworkingMaxConnectionCloseReason ];
|
||||
|
||||
// When we receive a connection from peer, we need to wait for the app
|
||||
// to accept it. During that time we may need to pend any ICE messages
|
||||
std::vector<CMsgICERendezvous> m_vecPendingICEMessages;
|
||||
|
||||
CMsgSteamNetworkingSocketsICESessionSummary m_msgICESessionSummary;
|
||||
// Summary of connection. Note in particular that the failure reason (if any)
|
||||
// is here.
|
||||
CMsgSteamNetworkingICESessionSummary m_msgICESessionSummary;
|
||||
|
||||
// Detailed failure reason string.
|
||||
ConnectionEndDebugMsg m_szICECloseMsg;
|
||||
|
||||
void ICEFailed( int nReasonCode, const char *pszReason );
|
||||
void QueueDestroyICE();
|
||||
inline int GetICEFailureCode() const { return m_msgICESessionSummary.failure_reason_code(); }
|
||||
void GuessICEFailureReason( ESteamNetConnectionEnd &nReasonCode, ConnectionEndDebugMsg &msg, SteamNetworkingMicroseconds usecNow );
|
||||
#else
|
||||
static constexpr int m_nICECloseCode = k_nICECloseCode_Local_NotCompiled;
|
||||
inline int GetICEFailureCode() const { return k_nICECloseCode_Local_NotCompiled; }
|
||||
#endif
|
||||
|
||||
/// Sometimes it's nice to have all existing options in a list
|
||||
@@ -254,10 +256,15 @@ public:
|
||||
// Check if we pended ICE deletion, then do so now
|
||||
void CheckCleanupICE();
|
||||
|
||||
// If we don't already have a failure code for ice, set one now.
|
||||
void EnsureICEFailureReasonSet( SteamNetworkingMicroseconds usecNow );
|
||||
|
||||
//
|
||||
// Transport evaluation and selection
|
||||
//
|
||||
|
||||
SteamNetworkingMicroseconds m_usecWhenStartedFindingRoute;
|
||||
|
||||
SteamNetworkingMicroseconds m_usecNextEvaluateTransport;
|
||||
|
||||
/// True if we should be "sticky" to the current transport.
|
||||
|
||||
@@ -26,8 +26,7 @@ CConnectionTransportP2PICE::CConnectionTransportP2PICE( CSteamNetworkConnectionP
|
||||
, CConnectionTransportP2PBase( "ICE", this, this )
|
||||
, m_pICESession( nullptr )
|
||||
{
|
||||
//m_eCurrentRouteLocalCandidateType = k_EICECandidate_Invalid;
|
||||
//m_eCurrentRouteRemoteCandidateType = k_EICECandidate_Invalid;
|
||||
m_nAllowedCandidateTypes = 0;
|
||||
m_eCurrentRouteKind = k_ESteamNetTransport_Unknown;
|
||||
m_currentRouteRemoteAddress.Clear();
|
||||
}
|
||||
@@ -114,11 +113,19 @@ void CConnectionTransportP2PICE::Init()
|
||||
// Set role
|
||||
cfg.m_eRole = Connection().IsControllingAgent() ? k_EICERole_Controlling : k_EICERole_Controlled;
|
||||
|
||||
// Get the stun server list
|
||||
const int P2P_Transport_ICE_Enable = m_connection.m_connectionConfig.m_P2P_Transport_ICE_Enable.Get();
|
||||
|
||||
m_nAllowedCandidateTypes = 0;
|
||||
if ( P2P_Transport_ICE_Enable & k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_Private )
|
||||
m_nAllowedCandidateTypes |= k_EICECandidate_Any_HostPrivate;
|
||||
|
||||
// Get the STUN server list
|
||||
std::vector<std::string> vecStunServers;
|
||||
std::vector<const char *> vecStunServersPsz;
|
||||
if ( m_connection.m_connectionConfig.m_P2P_Transport_ICE_Enable.Get() & k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_Public )
|
||||
if ( P2P_Transport_ICE_Enable & k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_Public )
|
||||
{
|
||||
m_nAllowedCandidateTypes |= k_EICECandidate_Any_HostPublic;
|
||||
|
||||
SpewVerboseGroup( LogLevel_P2PRendezvous(), "[%s] Using STUN server list: %s\n", ConnectionDescription(), m_connection.m_connectionConfig.m_P2P_STUN_ServerList.Get().c_str() );
|
||||
{
|
||||
CUtlVectorAutoPurge<char *> tempStunServers;
|
||||
@@ -144,6 +151,25 @@ void CConnectionTransportP2PICE::Init()
|
||||
cfg.m_nStunServers = len( vecStunServersPsz );
|
||||
cfg.m_pStunServers = vecStunServersPsz.data();
|
||||
|
||||
// Get the TURN server list
|
||||
if ( P2P_Transport_ICE_Enable & k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_Relay )
|
||||
{
|
||||
// FIXME
|
||||
}
|
||||
|
||||
if ( cfg.m_nStunServers > 0 )
|
||||
m_nAllowedCandidateTypes |= k_EICECandidate_Any_Reflexive;
|
||||
if ( cfg.m_nTurnServers > 0 )
|
||||
m_nAllowedCandidateTypes |= k_EICECandidate_Any_Relay;
|
||||
cfg.m_nCandidateTypes = m_nAllowedCandidateTypes;
|
||||
|
||||
// No candidates possible?
|
||||
if ( m_nAllowedCandidateTypes == 0 )
|
||||
{
|
||||
Connection().ICEFailed( k_nICECloseCode_Local_UserNotEnabled, "No local candidate types are allowed by user settings and configured servers" );
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the session
|
||||
m_pICESession = (*g_SteamNetworkingSockets_CreateICESessionFunc)( cfg, this, ICESESSION_INTERFACE_VERSION );
|
||||
if ( !m_pICESession )
|
||||
@@ -339,8 +365,7 @@ bool CConnectionTransportP2PICE::SendPacketGather( int nChunks, const iovec *pCh
|
||||
if ( nChunks == 1 )
|
||||
{
|
||||
Assert( (int)pChunks->iov_len == cbSendTotal );
|
||||
SendPacket( pChunks->iov_base, pChunks->iov_len );
|
||||
return false;
|
||||
return SendPacket( pChunks->iov_base, pChunks->iov_len );
|
||||
}
|
||||
if ( cbSendTotal > k_cbSteamNetworkingSocketsMaxUDPMsgLen )
|
||||
{
|
||||
@@ -391,7 +416,7 @@ void CConnectionTransportP2PICE::RecvValidUDPDataPacket( UDPRecvPacketContext_t
|
||||
if ( !ctx.m_pStatsIn || !( ctx.m_pStatsIn->flags() & ctx.m_pStatsIn->NOT_PRIMARY_TRANSPORT_E2E ) )
|
||||
Connection().SetPeerSelectedTransport( this );
|
||||
P2PTransportTrackRecvEndToEndPacket( ctx.m_usecNow );
|
||||
if ( m_bNeedToConfirmEndToEndConnectivity )
|
||||
if ( m_bNeedToConfirmEndToEndConnectivity && BCanSendEndToEndData() )
|
||||
P2PTransportEndToEndConnectivityConfirmed( ctx.m_usecNow );
|
||||
}
|
||||
|
||||
@@ -465,7 +490,7 @@ void CConnectionTransportP2PICE::RouteOrWritableStateChanged()
|
||||
|
||||
Connection().TransportEndToEndConnectivityChanged( this, usecNow );
|
||||
|
||||
CMsgSteamNetworkingSocketsICESessionSummary &ice_summary = Connection().m_msgICESessionSummary;
|
||||
CMsgSteamNetworkingICESessionSummary &ice_summary = Connection().m_msgICESessionSummary;
|
||||
if (
|
||||
ConnectionState() == k_ESteamNetworkingConnectionState_FindingRoute
|
||||
|| !ice_summary.has_initial_ping()
|
||||
@@ -555,7 +580,7 @@ void CConnectionTransportP2PICE::OnLocalCandidateGathered( EICECandidateType eTy
|
||||
virtual void RunTransportP2PICE( CConnectionTransportP2PICE *pTransport )
|
||||
{
|
||||
CSteamNetworkConnectionP2P &conn = pTransport->Connection();
|
||||
CMsgSteamNetworkingSocketsICESessionSummary &sum = conn.m_msgICESessionSummary;
|
||||
CMsgSteamNetworkingICESessionSummary &sum = conn.m_msgICESessionSummary;
|
||||
sum.set_local_candidate_types( sum.local_candidate_types() | eType );
|
||||
pTransport->Connection().QueueSignalReliableMessage( std::move(msg), "LocalCandidateAdded" );
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ public:
|
||||
//EICECandidateType m_eCurrentRouteRemoteCandidateType;
|
||||
SteamNetworkingIPAddr m_currentRouteRemoteAddress;
|
||||
ESteamNetTransportKind m_eCurrentRouteKind;
|
||||
int m_nAllowedCandidateTypes; // k_EICECandidate_xxx
|
||||
|
||||
private:
|
||||
IICESession *m_pICESession;
|
||||
|
||||
Reference in New Issue
Block a user