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