1 //====== Copyright Valve Corporation, All rights reserved. ==================== 2 3 #ifndef CSTEAMNETWORKINGSOCKETS_H 4 #define CSTEAMNETWORKINGSOCKETS_H 5 #pragma once 6 7 #include <time.h> 8 #include <mutex> 9 #include <steam/isteamnetworkingsockets.h> 10 #include <steam/isteamnetworkingutils.h> 11 12 #if defined( STEAMNETWORKINGSOCKETS_STEAMCLIENT ) || defined( STEAMNETWORKINGSOCKETS_STREAMINGCLIENT ) 13 #include "../../common/steam/iclientnetworkingsockets.h" 14 #include "../../common/steam/iclientnetworkingutils.h" 15 #define ICLIENTNETWORKING_OVERRIDE override 16 #else 17 typedef ISteamNetworkingSockets IClientNetworkingSockets; 18 typedef ISteamNetworkingUtils IClientNetworkingUtils; 19 #define ICLIENTNETWORKING_OVERRIDE 20 #endif 21 22 #include "steamnetworkingsockets_connections.h" 23 24 namespace SteamNetworkingSocketsLib { 25 26 class CSteamNetworkingUtils; 27 class CSteamNetworkListenSocketP2P; 28 29 ///////////////////////////////////////////////////////////////////////////// 30 // 31 // Steam API interfaces 32 // 33 ///////////////////////////////////////////////////////////////////////////// 34 35 class CSteamNetworkingSockets : public IClientNetworkingSockets 36 { 37 public: 38 STEAMNETWORKINGSOCKETS_DECLARE_CLASS_OPERATOR_NEW 39 CSteamNetworkingSockets( CSteamNetworkingUtils *pSteamNetworkingUtils ); 40 41 CSteamNetworkingUtils *const m_pSteamNetworkingUtils; 42 CMsgSteamDatagramCertificateSigned m_msgSignedCert; 43 CMsgSteamDatagramCertificate m_msgCert; 44 CECSigningPrivateKey m_keyPrivateKey; 45 bool BCertHasIdentity() const; 46 virtual bool SetCertificateAndPrivateKey( const void *pCert, int cbCert, void *pPrivateKey, int cbPrivateKey ); 47 48 bool BHasAnyConnections() const; 49 bool BHasAnyListenSockets() const; BInitted()50 bool BInitted() const { return m_bHaveLowLevelRef; } 51 52 #ifdef STEAMNETWORKINGSOCKETS_OPENSOURCE 53 bool BInitGameNetworkingSockets( const SteamNetworkingIdentity *pIdentity, SteamDatagramErrMsg &errMsg ); CacheIdentity()54 void CacheIdentity() { m_identity.SetLocalHost(); } 55 #else 56 virtual void CacheIdentity() = 0; 57 #endif 58 59 /// Perform cleanup and self-destruct. Use this instead of 60 /// calling operator delete. This solves some complications 61 /// due to calling virtual functions from within destructor. 62 void Destroy(); 63 virtual void FreeResources(); 64 InternalGetIdentity()65 const SteamNetworkingIdentity &InternalGetIdentity() 66 { 67 if ( m_identity.IsInvalid() ) 68 CacheIdentity(); 69 return m_identity; 70 } 71 72 template <typename T> QueueCallback(const T & x,void * fnRegisteredFunctionPtr)73 void QueueCallback( const T& x, void *fnRegisteredFunctionPtr ) 74 { 75 InternalQueueCallback( T::k_iCallback, sizeof(T), &x, fnRegisteredFunctionPtr ); 76 } 77 78 // Implements ISteamNetworkingSockets 79 virtual HSteamListenSocket CreateListenSocketIP( const SteamNetworkingIPAddr &localAddress, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) override; 80 virtual HSteamNetConnection ConnectByIPAddress( const SteamNetworkingIPAddr &adress, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) override; 81 virtual HSteamListenSocket CreateListenSocketP2P( int nLocalVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) override; 82 virtual HSteamNetConnection ConnectP2P( const SteamNetworkingIdentity &identityRemote, int nRemoteVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) override; 83 virtual EResult AcceptConnection( HSteamNetConnection hConn ) override; 84 virtual bool CloseConnection( HSteamNetConnection hConn, int nReason, const char *pszDebug, bool bEnableLinger ) override; 85 virtual bool CloseListenSocket( HSteamListenSocket hSocket ) override; 86 virtual bool SetConnectionUserData( HSteamNetConnection hPeer, int64 nUserData ) override; 87 virtual int64 GetConnectionUserData( HSteamNetConnection hPeer ) override; 88 virtual void SetConnectionName( HSteamNetConnection hPeer, const char *pszName ) override; 89 virtual bool GetConnectionName( HSteamNetConnection hPeer, char *pszName, int nMaxLen ) override; 90 virtual EResult SendMessageToConnection( HSteamNetConnection hConn, const void *pData, uint32 cbData, int nSendFlags, int64 *pOutMessageNumber ) override; 91 virtual void SendMessages( int nMessages, SteamNetworkingMessage_t *const *pMessages, int64 *pOutMessageNumberOrResult ) override; 92 virtual EResult FlushMessagesOnConnection( HSteamNetConnection hConn ) override; 93 virtual int ReceiveMessagesOnConnection( HSteamNetConnection hConn, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages ) override; 94 virtual bool GetConnectionInfo( HSteamNetConnection hConn, SteamNetConnectionInfo_t *pInfo ) override; 95 virtual bool GetQuickConnectionStatus( HSteamNetConnection hConn, SteamNetworkingQuickConnectionStatus *pStats ) override; 96 virtual int GetDetailedConnectionStatus( HSteamNetConnection hConn, char *pszBuf, int cbBuf ) override; 97 virtual bool GetListenSocketAddress( HSteamListenSocket hSocket, SteamNetworkingIPAddr *pAddress ) override; 98 virtual bool CreateSocketPair( HSteamNetConnection *pOutConnection1, HSteamNetConnection *pOutConnection2, bool bUseNetworkLoopback, const SteamNetworkingIdentity *pIdentity1, const SteamNetworkingIdentity *pIdentity2 ) override; 99 virtual bool GetIdentity( SteamNetworkingIdentity *pIdentity ) override; 100 101 virtual HSteamNetPollGroup CreatePollGroup() override; 102 virtual bool DestroyPollGroup( HSteamNetPollGroup hPollGroup ) override; 103 virtual bool SetConnectionPollGroup( HSteamNetConnection hConn, HSteamNetPollGroup hPollGroup ) override; 104 virtual int ReceiveMessagesOnPollGroup( HSteamNetPollGroup hPollGroup, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages ) override; 105 virtual HSteamNetConnection ConnectP2PCustomSignaling( ISteamNetworkingConnectionSignaling *pSignaling, const SteamNetworkingIdentity *pPeerIdentity, int nVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) override; 106 virtual bool ReceivedP2PCustomSignal( const void *pMsg, int cbMsg, ISteamNetworkingSignalingRecvContext *pContext ) override; 107 virtual int GetP2P_Transport_ICE_Enable( const SteamNetworkingIdentity &identityRemote, int *pOutUserFlags ); 108 109 virtual bool GetCertificateRequest( int *pcbBlob, void *pBlob, SteamNetworkingErrMsg &errMsg ) override; 110 virtual bool SetCertificate( const void *pCertificate, int cbCertificate, SteamNetworkingErrMsg &errMsg ) override; 111 virtual void ResetIdentity( const SteamNetworkingIdentity *pIdentity ) override; 112 113 #ifdef STEAMNETWORKINGSOCKETS_STEAMCLIENT 114 virtual int ReceiveMessagesOnListenSocketLegacyPollGroup( HSteamListenSocket hSocket, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages ) override; TEST_EnableP2PLooopbackOptimization(bool flag)115 virtual void TEST_EnableP2PLooopbackOptimization( bool flag ) override { m_TEST_bEnableP2PLoopbackOptimization = flag; } 116 bool m_TEST_bEnableP2PLoopbackOptimization = true; 117 #else 118 static constexpr bool m_TEST_bEnableP2PLoopbackOptimization = true; 119 #endif 120 121 virtual void RunCallbacks() override; 122 123 /// Configuration options that will apply to all connections on this interface 124 ConnectionConfig m_connectionConfig; 125 126 /// List of existing CSteamNetworkingSockets instances. This is used, for example, 127 /// if we want to initiate a P2P connection to a local identity, we can instead 128 /// use a loopback connection. 129 static std::vector<CSteamNetworkingSockets *> s_vecSteamNetworkingSocketsInstances; 130 131 // P2P listen sockets 132 CUtlHashMap<int,CSteamNetworkListenSocketP2P *,std::equal_to<int>,std::hash<int>> m_mapListenSocketsByVirtualPort; 133 CSteamNetworkListenSocketP2P *InternalCreateListenSocketP2P( int nLocalVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ); 134 135 CSteamNetworkPollGroup *InternalCreatePollGroup( PollGroupScopeLock &scopeLock ); 136 137 // 138 // Authentication 139 // 140 141 #ifdef STEAMNETWORKINGSOCKETS_CAN_REQUEST_CERT 142 virtual bool BCertRequestInFlight() = 0; 143 144 ScheduledMethodThinker<CSteamNetworkingSockets> m_scheduleCheckRenewCert; 145 146 /// Platform-specific code to actually obtain a cert 147 virtual void BeginFetchCertAsync() = 0; 148 #else BCertRequestInFlight()149 inline bool BCertRequestInFlight() { return false; } 150 #endif 151 152 /// Called in any situation where we need to be able to authenticate, or anticipate 153 /// needing to be able to do so soon. If we don't have one right now, we will begin 154 /// taking action to obtain one 155 virtual void CheckAuthenticationPrerequisites( SteamNetworkingMicroseconds usecNow ); AuthenticationNeeded()156 void AuthenticationNeeded() { CheckAuthenticationPrerequisites( SteamNetworkingSockets_GetLocalTimestamp() ); } 157 158 virtual ESteamNetworkingAvailability InitAuthentication() override final; 159 virtual ESteamNetworkingAvailability GetAuthenticationStatus( SteamNetAuthenticationStatus_t *pAuthStatus ) override final; 160 int GetSecondsUntilCertExpiry() const; 161 162 // 163 // Default signaling 164 // 165 166 CSteamNetworkConnectionBase *InternalConnectP2PDefaultSignaling( 167 const SteamNetworkingIdentity &identityRemote, 168 int nRemoteVirtualPort, 169 int nOptions, const SteamNetworkingConfigValue_t *pOptions, 170 ConnectionScopeLock &scopeLock 171 ); 172 CSteamNetworkingMessages *GetSteamNetworkingMessages(); 173 CSteamNetworkingMessages *m_pSteamNetworkingMessages; 174 175 // Stubs if SDR not enabled 176 #ifndef STEAMNETWORKINGSOCKETS_ENABLE_SDR FindRelayAuthTicketForServer(const SteamNetworkingIdentity & identityGameServer,int nRemoteVirtualPort,SteamDatagramRelayAuthTicket * pOutParsedTicket)177 virtual int FindRelayAuthTicketForServer( const SteamNetworkingIdentity &identityGameServer, int nRemoteVirtualPort, SteamDatagramRelayAuthTicket *pOutParsedTicket ) override { return 0; } ConnectToHostedDedicatedServer(const SteamNetworkingIdentity & identityTarget,int nRemoteVirtualPort,int nOptions,const SteamNetworkingConfigValue_t * pOptions)178 virtual HSteamNetConnection ConnectToHostedDedicatedServer( const SteamNetworkingIdentity &identityTarget, int nRemoteVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) override { return k_HSteamNetConnection_Invalid; } GetHostedDedicatedServerPort()179 virtual uint16 GetHostedDedicatedServerPort() override { return 0; } GetHostedDedicatedServerPOPID()180 virtual SteamNetworkingPOPID GetHostedDedicatedServerPOPID() override { return 0; } GetHostedDedicatedServerAddress(SteamDatagramHostedAddress * pRouting)181 virtual EResult GetHostedDedicatedServerAddress( SteamDatagramHostedAddress *pRouting ) override { return k_EResultFail; } CreateHostedDedicatedServerListenSocket(int nLocalVirtualPort,int nOptions,const SteamNetworkingConfigValue_t * pOptions)182 virtual HSteamListenSocket CreateHostedDedicatedServerListenSocket( int nLocalVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) override { return k_HSteamNetConnection_Invalid; } ReceivedRelayAuthTicket(const void * pvTicket,int cbTicket,SteamDatagramRelayAuthTicket * pOutParsedTicket)183 virtual bool ReceivedRelayAuthTicket( const void *pvTicket, int cbTicket, SteamDatagramRelayAuthTicket *pOutParsedTicket ) override { return false; } GetGameCoordinatorServerLogin(SteamDatagramGameCoordinatorServerLogin * pLogin,int * pcbSignedBlob,void * pBlob)184 virtual EResult GetGameCoordinatorServerLogin( SteamDatagramGameCoordinatorServerLogin *pLogin, int *pcbSignedBlob, void *pBlob ) override { return k_EResultFail; } 185 #endif 186 187 protected: 188 189 /// Overall authentication status. Depends on the status of our cert, and the ability 190 /// to obtain the CA certs (from the network config) 191 SteamNetAuthenticationStatus_t m_AuthenticationStatus; 192 193 /// Set new status, dispatch callbacks if it actually changed 194 void SetAuthenticationStatus( const SteamNetAuthenticationStatus_t &newStatus ); 195 196 /// Current status of our attempt to get a certificate 197 bool m_bEverTriedToGetCert; 198 bool m_bEverGotCert; 199 SteamNetAuthenticationStatus_t m_CertStatus; 200 201 /// Set cert status, and then update m_AuthenticationStatus and 202 /// dispatch any callbacks as needed 203 void SetCertStatus( ESteamNetworkingAvailability eAvail, const char *pszFmt, ... ); 204 #ifdef STEAMNETWORKINGSOCKETS_CAN_REQUEST_CERT 205 void AsyncCertRequestFinished(); 206 void CertRequestFailed( ESteamNetworkingAvailability eCertAvail, ESteamNetConnectionEnd nConnectionEndReason, const char *pszMsg ); 207 #endif 208 209 /// Figure out the current authentication status. And if it has changed, send out callbacks 210 virtual void DeduceAuthenticationStatus(); 211 212 void InternalInitIdentity(); 213 void KillConnections(); 214 215 SteamNetworkingIdentity m_identity; 216 217 struct QueuedCallback 218 { 219 int nCallback; 220 void *fnCallback; 221 char data[ sizeof(SteamNetConnectionStatusChangedCallback_t) ]; // whatever the biggest callback struct we have is 222 }; 223 std_vector<QueuedCallback> m_vecPendingCallbacks; 224 ShortDurationLock m_mutexPendingCallbacks; 225 virtual void InternalQueueCallback( int nCallback, int cbCallback, const void *pvCallback, void *fnRegisteredFunctionPtr ); 226 227 bool m_bHaveLowLevelRef; 228 bool BInitLowLevel( SteamNetworkingErrMsg &errMsg ); 229 230 CSteamNetworkConnectionBase *InternalConnectP2P( 231 ISteamNetworkingConnectionSignaling *pSignaling, 232 const SteamNetworkingIdentity *pPeerIdentity, 233 int nRemoteVirtualPort, 234 int nOptions, const SteamNetworkingConfigValue_t *pOptions, 235 ConnectionScopeLock &scopeLock 236 ); 237 bool InternalReceivedP2PSignal( const void *pMsg, int cbMsg, ISteamNetworkingSignalingRecvContext *pContext, bool bDefaultPlatformSignaling ); 238 239 // Protected - use Destroy() 240 virtual ~CSteamNetworkingSockets(); 241 }; 242 243 class CSteamNetworkingUtils : public IClientNetworkingUtils 244 { 245 public: 246 STEAMNETWORKINGSOCKETS_DECLARE_CLASS_OPERATOR_NEW 247 virtual ~CSteamNetworkingUtils(); 248 249 virtual SteamNetworkingMessage_t *AllocateMessage( int cbAllocateBuffer ) override; 250 251 virtual SteamNetworkingMicroseconds GetLocalTimestamp() override; 252 virtual void SetDebugOutputFunction( ESteamNetworkingSocketsDebugOutputType eDetailLevel, FSteamNetworkingSocketsDebugOutput pfnFunc ) override; 253 254 virtual bool SetConfigValue( ESteamNetworkingConfigValue eValue, 255 ESteamNetworkingConfigScope eScopeType, intptr_t scopeObj, 256 ESteamNetworkingConfigDataType eDataType, const void *pValue ) override; 257 258 virtual ESteamNetworkingGetConfigValueResult GetConfigValue( 259 ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigScope eScopeType, 260 intptr_t scopeObj, ESteamNetworkingConfigDataType *pOutDataType, 261 void *pResult, size_t *cbResult ) override; 262 263 virtual bool GetConfigValueInfo( ESteamNetworkingConfigValue eValue, 264 const char **pOutName, ESteamNetworkingConfigDataType *pOutDataType, 265 ESteamNetworkingConfigScope *pOutScope, ESteamNetworkingConfigValue *pOutNextValue ) override; 266 267 virtual ESteamNetworkingConfigValue GetFirstConfigValue() override; 268 269 virtual void SteamNetworkingIPAddr_ToString( const SteamNetworkingIPAddr &addr, char *buf, size_t cbBuf, bool bWithPort ) override; 270 virtual bool SteamNetworkingIPAddr_ParseString( SteamNetworkingIPAddr *pAddr, const char *pszStr ) override; 271 virtual void SteamNetworkingIdentity_ToString( const SteamNetworkingIdentity &identity, char *buf, size_t cbBuf ) override; 272 virtual bool SteamNetworkingIdentity_ParseString( SteamNetworkingIdentity *pIdentity, const char *pszStr ) override; 273 274 virtual AppId_t GetAppID(); 275 SetAppID(AppId_t nAppID)276 void SetAppID( AppId_t nAppID ) 277 { 278 Assert( m_nAppID == 0 || m_nAppID == nAppID ); 279 m_nAppID = nAppID; 280 } 281 282 // Get current time of day, ideally from a source that 283 // doesn't depend on the user setting their local clock properly 284 virtual time_t GetTimeSecure(); 285 286 /// Get a string that describes what version this code is that is running. 287 /// (What branch it is, when it was compiled, etc.) 288 virtual const char *GetBuildString(); 289 virtual const char *GetPlatformString(); 290 291 // Reset this utils instance for testing 292 virtual void TEST_ResetSelf(); 293 294 // Post a connection update message to the OS diagnostics 295 #ifdef STEAMNETWORKINGSOCKETS_ENABLE_DIAGNOSTICSUI 296 virtual void PostConnectionStateUpdateForDiagnosticsUI( ESteamNetworkingConnectionState eOldState, CSteamNetworkConnectionBase *pConnection, SteamNetworkingMicroseconds usecNow ) = 0; 297 298 // Desired update interval for connections, outside of state changes. 299 // The default is zero, which means no updates, not even for state changes. 300 // Derived classes that override PostConnectionStateUpdateForDiagnosticsUI must set this. 301 SteamNetworkingMicroseconds m_usecConnectionUpdateFrequency = 0; 302 #else 303 static constexpr SteamNetworkingMicroseconds m_usecConnectionUpdateFrequency = 0; 304 #endif 305 306 // Stubs if SDR not enabled 307 #ifndef STEAMNETWORKINGSOCKETS_ENABLE_SDR GetRelayNetworkStatus(SteamRelayNetworkStatus_t * pDetails)308 virtual ESteamNetworkingAvailability GetRelayNetworkStatus( SteamRelayNetworkStatus_t *pDetails ) override 309 { 310 if ( pDetails ) 311 { 312 memset( pDetails, 0, sizeof(*pDetails) ); 313 pDetails->m_eAvail = k_ESteamNetworkingAvailability_CannotTry; 314 pDetails->m_eAvailAnyRelay = k_ESteamNetworkingAvailability_CannotTry; 315 pDetails->m_eAvailNetworkConfig = k_ESteamNetworkingAvailability_CannotTry; 316 } 317 return k_ESteamNetworkingAvailability_CannotTry; 318 } CheckPingDataUpToDate(float flMaxAgeSeconds)319 virtual bool CheckPingDataUpToDate( float flMaxAgeSeconds ) override { return false; } GetLocalPingLocation(SteamNetworkPingLocation_t & result)320 virtual float GetLocalPingLocation( SteamNetworkPingLocation_t &result ) override { return -1.0f; } EstimatePingTimeBetweenTwoLocations(const SteamNetworkPingLocation_t & location1,const SteamNetworkPingLocation_t & location2)321 virtual int EstimatePingTimeBetweenTwoLocations( const SteamNetworkPingLocation_t &location1, const SteamNetworkPingLocation_t &location2 ) override { return k_nSteamNetworkingPing_Unknown; } EstimatePingTimeFromLocalHost(const SteamNetworkPingLocation_t & remoteLocation)322 virtual int EstimatePingTimeFromLocalHost( const SteamNetworkPingLocation_t &remoteLocation ) override { return k_nSteamNetworkingPing_Unknown; } ConvertPingLocationToString(const SteamNetworkPingLocation_t & location,char * pszBuf,int cchBufSize)323 virtual void ConvertPingLocationToString( const SteamNetworkPingLocation_t &location, char *pszBuf, int cchBufSize ) override { if ( pszBuf ) *pszBuf = '\0'; } ParsePingLocationString(const char * pszString,SteamNetworkPingLocation_t & result)324 virtual bool ParsePingLocationString( const char *pszString, SteamNetworkPingLocation_t &result ) override { return false; } GetPingToDataCenter(SteamNetworkingPOPID popID,SteamNetworkingPOPID * pViaRelayPoP)325 virtual int GetPingToDataCenter( SteamNetworkingPOPID popID, SteamNetworkingPOPID *pViaRelayPoP ) override { return k_nSteamNetworkingPing_Unknown; } GetDirectPingToPOP(SteamNetworkingPOPID popID)326 virtual int GetDirectPingToPOP( SteamNetworkingPOPID popID ) override { return k_nSteamNetworkingPing_Unknown; } GetPOPCount()327 virtual int GetPOPCount() override { return 0; } GetPOPList(SteamNetworkingPOPID * list,int nListSz)328 virtual int GetPOPList( SteamNetworkingPOPID *list, int nListSz ) override { return 0; } 329 #endif 330 331 protected: 332 AppId_t m_nAppID = 0; 333 }; 334 335 } // namespace SteamNetworkingSocketsLib 336 337 #endif // CSTEAMNETWORKINGSOCKETS_H 338