Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

330 lines
19 KiB

  1. //====== Copyright Valve Corporation, All rights reserved. ====================
  2. //
  3. // Purpose: A low level API similar to Berkeley socket, to send messages
  4. // between hosts over the Steam network and addressed using Steam IDs.
  5. //
  6. //=============================================================================
  7. #ifndef ISTEAMNETWORKINGSOCKETS
  8. #define ISTEAMNETWORKINGSOCKETS
  9. #ifdef _WIN32
  10. #pragma once
  11. #endif
  12. #include "steamnetworkingtypes.h"
  13. // #KLUDGE! This is so we don't have to link with steam_api.lib
  14. #include <steam/steam_api.h>
  15. #include <steam/steam_gameserver.h>
  16. //-----------------------------------------------------------------------------
  17. /// Lower level networking interface that more closely mirrors the standard
  18. /// Berkeley sockets model. Sockets are hard! You should probably only use
  19. /// this interface under the existing circumstances:
  20. ///
  21. /// - You have an existing socket-based codebase you want to port, or coexist with.
  22. /// - You want to be able to connect based on IP address, rather than (just) Steam ID.
  23. /// - You need low-level control of bandwidth utilization, when to drop packets, etc.
  24. ///
  25. /// Note that neither of the terms "connection" and "socket" will correspond
  26. /// one-to-one with an underlying UDP socket. An attempt has been made to
  27. /// keep the semantics as similar to the standard socket model when appropriate,
  28. /// but some deviations do exist.
  29. class ISteamSocketNetworking
  30. {
  31. public:
  32. /// Creates a "server" socket that listens for clients to connect to, either by calling
  33. /// ConnectSocketBySteamID or ConnectSocketByIPv4Address.
  34. ///
  35. /// nSteamConnectVirtualPort specifies how clients can connect to this socket using
  36. /// ConnectBySteamID. A negative value indicates that this functionality is
  37. /// disabled and clients must connect by IP address. It's very common for applications
  38. /// to only have one listening socket; in that case, use zero. If you need to open
  39. /// multiple listen sockets and have clients be able to connect to one or the other, then
  40. /// nSteamConnectVirtualPort should be a small integer constant unique to each listen socket
  41. /// you create.
  42. ///
  43. /// If you want clients to connect to you by your IPv4 addresses using
  44. /// ConnectByIPv4Address, then you must set nPort to be nonzero. Steam will
  45. /// bind a UDP socket to the specified local port, and clients will send packets using
  46. /// ordinary IP routing. It's up to you to take care of NAT, protecting your server
  47. /// from DoS, etc. If you don't need clients to connect to you by IP, then set nPort=0.
  48. /// Use nIP if you wish to bind to a particular local interface. Typically you will use 0,
  49. /// which means to listen on all interfaces, and accept the default outbound IP address.
  50. /// If nPort is zero, then nIP must also be zero.
  51. ///
  52. /// A SocketStatusCallback_t callback when another client attempts a connection.
  53. virtual HSteamListenSocket CreateListenSocket( int nSteamConnectVirtualPort, uint32 nIP, uint16 nPort ) = 0;
  54. /// Creates a connection and begins talking to a remote destination. The remote host
  55. /// must be listening with the appropriate call to CreateListenSocket.
  56. ///
  57. /// Use ConnectBySteamID to connect using the SteamID (client or game server) as the network address.
  58. /// Use ConnectByIPv4Address to connect by IP address.
  59. ///
  60. /// On success, a SocketStatusCallback_t callback is triggered.
  61. /// On failure or timeout, a SocketStatusCallback_t callback with a failure code in m_eSNetSocketState
  62. virtual HSteamNetConnection ConnectBySteamID( CSteamID steamIDTarget, int nVirtualPort, int nTimeoutSec ) = 0;
  63. virtual HSteamNetConnection ConnectByIPv4Address( uint32 nIP, uint16 nPort, int nTimeoutSec ) = 0;
  64. /// Accept an incoming connection that has been received on a listen socket.
  65. ///
  66. /// When a connection attempt is received (perhaps after a few basic handshake
  67. /// packets have been exchanged to prevent trivial spoofing), a connection interface
  68. /// object is created in the k_ESteamNetworkingConnectionState_Connecting state
  69. /// and a SteamNetConnectionStatusChangedCallback_t is posted. At this point, your
  70. /// application MUST either accept or close the connection. (It may not ignore it.)
  71. /// Accepting the connection will transition it into the connected state.
  72. ///
  73. /// You should take action within a few seconds, because accepting the connection is
  74. /// what actually sends the reply notifying the client that they are connected. If you
  75. /// delay taking action, from the client's perspective it is the same as the network
  76. /// being unresponsive, and the client may timeout the connection attempt. In other
  77. /// words, the client cannot distinguish between a delay caused by network problems
  78. /// and a delay caused by the application.
  79. ///
  80. /// This means that if your application goes for more than a few seconds without
  81. /// processing callbacks, then there is a chance that a client may attempt to connect
  82. /// in that interval, and timeout.
  83. ///
  84. /// If the application does not respond to the connection attempt in a timely manner,
  85. /// and we stop receiving communication from the client, the connection attempt will
  86. /// be timed out locally, transitioning the connection to the
  87. /// k_ESteamNetworkingConnectionState_ProblemDetectedLocally state. The client may also
  88. /// close the connection before it is accepted and a transition to the
  89. /// k_ESteamNetworkingConnectionState_ClosedByPeer is also possible.
  90. ///
  91. /// Returns k_EResultInvalidParam if the handle is invalid.
  92. /// Returns k_EResultInvalidState if the connection is not in the appropriate state.
  93. /// (Remember that the connection state could change in between the time that the
  94. /// notification being posted to the queue and when it is received by the application.)
  95. virtual EResult AcceptConnection( HSteamNetConnection hConn ) = 0;
  96. /// Disconnects from the remote host and invalidates the connection handle.
  97. /// Any unread data on the connection is discarded.
  98. ///
  99. /// nReason is an application defined code that will be received on the other
  100. /// end and recorded (when possible) in backend analytics. The value should
  101. /// come from a restricted range. (See ESteamNetConnectionEnd.) If you don't need
  102. /// to communicate any information to the remote host, and do not want analytics to
  103. /// be able to distinguish "normal" connection terminations from "exceptional" ones,
  104. /// You may pass zero, in which case the generic value of
  105. /// k_ESteamNetConnectionEnd_App_Generic will be used.
  106. ///
  107. /// pszDebug is an optional human-readable diagnostic string that will be received
  108. /// by the remote host and recorded (when possible) in backend analytics.
  109. ///
  110. /// If you wish to put the socket into a "linger" state, where an attempt is made to
  111. /// flush any remaining sent data, use bEnableLinger=true. Otherwise reliable data
  112. /// is not flushed.
  113. ///
  114. /// If the connection has already ended and you are just freeing up the
  115. /// connection interface, the reason code, debug string, and linger flag are
  116. /// ignored.
  117. virtual bool CloseConnection( HSteamNetConnection hPeer, int nReason, const char *pszDebug, bool bEnableLinger ) = 0;
  118. /// Destroy a listen socket, and all the client sockets generated by accepting connections
  119. /// on the listen socket.
  120. ///
  121. /// pszNotifyRemoteReason determines what cleanup actions are performed on the client
  122. /// sockets being destroyed. (See DestroySocket for more details.)
  123. ///
  124. /// Note that if cleanup is requested and you have requested the listen socket bound to a
  125. /// particular local port to facilitate direct UDP/IPv4 connections, then the underlying UDP
  126. /// socket must remain open until all clients have been cleaned up.
  127. virtual bool CloseListenSocket( HSteamListenSocket hSocket, const char *pszNotifyRemoteReason ) = 0;
  128. /// Set connection user data. Returns false if the handle is invalid.
  129. virtual bool SetConnectionUserData( HSteamNetConnection hPeer, int64 nUserData ) = 0;
  130. /// Fetch connection user data. Returns -1 if handle is invalid
  131. /// or if you haven't set any userdata on the connection.
  132. virtual int64 GetConnectionUserData( HSteamNetConnection hPeer ) = 0;
  133. /// Set a name for the connection, used mostly for debugging
  134. virtual void SetConnectionName( HSteamNetConnection hPeer, const char *pszName ) = 0;
  135. /// Fetch connection user data. Returns -1 if handle is invalid
  136. /// or if you haven't set any userdata on the connection.
  137. virtual void GetConnectionName( HSteamNetConnection hPeer, char *ppszName, int nMaxLen ) = 0;
  138. /// Send a message to the remote host on the connected socket.
  139. ///
  140. /// eSendType determines the delivery guarantees that will be provided,
  141. /// when data should be buffered, etc.
  142. ///
  143. /// Note that the semantics we use for messages are not precisely
  144. /// the same as the semantics of a standard "stream" socket.
  145. /// (SOCK_STREAM) For an ordinary stream socket, the boundaries
  146. /// between chunks are not considered relevant, and the sizes of
  147. /// the chunks of data written will not necessarily match up to
  148. /// the sizes of the chunks that are returned by the reads on
  149. /// the other end. The remote host might read a partial chunk,
  150. /// or chunks might be coalesced. For the message semantics
  151. /// used here, however, the sizes WILL match. Each send call
  152. /// will match a successful read call on the remote host
  153. /// one-for-one. If you are porting existing stream-oriented
  154. /// code to the semantics of reliable messages, your code should
  155. /// work the same, since reliable message semantics are more
  156. /// strict than stream semantics. The only caveat is related to
  157. /// performance: there is per-message overhead to retain the
  158. /// messages sizes, and so if your code sends many small chunks
  159. /// of data, performance will suffer. Any code based on stream
  160. /// sockets that does not write excessively small chunks will
  161. /// work without any changes.
  162. virtual EResult SendMessageToConnection( HSteamNetConnection hConn, const void *pData, uint32 cbData, ESteamNetworkingSendType eSendType ) = 0;
  163. /// Fetch the next available message(s) from the socket, if any.
  164. /// Returns the number of messages returned into your array, up to nMaxMessages.
  165. /// If the connection handle is invalid, -1 is returned.
  166. ///
  167. /// The order of the messages returned in the array is relevant.
  168. /// Reliable messages will be received in the order they were sent (and with the
  169. /// same sizes --- see SendMessageToConnection for on this subtle difference from a stream socket).
  170. ///
  171. /// FIXME - We're still debating the exact set of guarantees for unreliable, so this might change.
  172. /// Unreliable messages may not be received. The order of delivery of unreliable messages
  173. /// is NOT specified. They may be received out of order with respect to each other or
  174. /// reliable messages. They may be received multiple times!
  175. ///
  176. /// If any messages are returned, you MUST call Release() to each of them free up resources
  177. /// after you are done. It is safe to keep the object alive for a little while (put it
  178. /// into some queue, etc), and you may call Release() from any thread.
  179. virtual int ReceiveMessagesOnConnection( HSteamNetConnection hConn, ISteamNetworkingMessage **ppOutMessages, int nMaxMessages ) = 0;
  180. /// Same as ReceiveMessagesOnConnection, but will return the next message available
  181. /// on any client socket that was accepted through the specified listen socket. Use
  182. /// ISteamNetworkingMessage::GetConnection to know which client connection.
  183. ///
  184. /// Delivery order of messages among different clients is not defined. They may
  185. /// be returned in an order different from what they were actually received. (Delivery
  186. /// order of messages from the same client is well defined, and thus the order of the
  187. /// messages is relevant!)
  188. virtual int ReceiveMessagesOnListenSocket( HSteamListenSocket hSocket, ISteamNetworkingMessage **ppOutMessages, int nMaxMessages ) = 0;
  189. /// Returns information about the specified connection.
  190. virtual bool GetConnectionInfo( HSteamNetConnection hConn, SteamNetConnectionInfo_t *pInfo ) = 0;
  191. /// Returns brief set of connection status that you might want to display
  192. /// to the user in game.
  193. virtual bool GetQuickConnectionStatus( HSteamNetConnection hConn, SteamNetworkingQuickConnectionStatus *pStats ) = 0;
  194. /// Returns detailed connection stats in text format. Useful
  195. /// for dumping to a log, etc.
  196. ///
  197. /// Returns:
  198. /// -1 failure (bad connection handle)
  199. /// 0 OK, your buffer was filled in and '\0'-terminated
  200. /// >0 Your buffer was either nullptr, or it was too small and the text got truncated. Try again with a buffer of at least N bytes.
  201. virtual int GetDetailedConnectionStatus( HSteamNetConnection hConn, char *pszBuf, int cbBuf ) = 0;
  202. /// Returns information about the listen socket.
  203. ///
  204. /// *pnIP and *pnPort will be 0 if the socket is set to listen for connections based
  205. /// on SteamID only. If your listen socket accepts connections on IPv4, then both
  206. /// fields will return nonzero, even if you originally passed a zero IP. However,
  207. /// note that the address returned may be a private address (e.g. 10.0.0.x or 192.168.x.x),
  208. /// and may not be reachable by a general host on the Internet.
  209. virtual bool GetListenSocketInfo( HSteamListenSocket hSocket, uint32 *pnIP, uint16 *pnPort ) = 0;
  210. //
  211. // Special SDR connections involved with servers hosted in Valve data centers
  212. //
  213. virtual bool SetHostedDedicatedServerCertificate( const void *pCert, int cbCert, void *pPrivateKey, int cbPrivateKey ) = 0;
  214. virtual HSteamListenSocket CreateHostedDedicatedServerListenSocket( uint16 nPort ) = 0;
  215. virtual HSteamNetConnection ConnectToHostedDedicatedServer( CSteamID steamIDTarget ) = 0;
  216. //
  217. // Gets some debug text from the connection
  218. //
  219. virtual bool GetConnectionDebugText( HSteamNetConnection hConn, char *pOut, int nOutCCH ) = 0;
  220. //
  221. // Set and get configuration values, see ESteamNetworkingConfigurationValue for individual descriptions.
  222. //
  223. // Returns the value or -1 is eConfigValue is invalid
  224. virtual int32 GetConfigurationValue( ESteamNetworkingConfigurationValue eConfigValue ) = 0;
  225. // Returns true if successfully set
  226. virtual bool SetConfigurationValue( ESteamNetworkingConfigurationValue eConfigValue, int32 nValue ) = 0;
  227. // Return the name of an int configuration value, or NULL if config value isn't known
  228. virtual const char *GetConfigurationValueName( ESteamNetworkingConfigurationValue eConfigValue ) = 0;
  229. //
  230. // Set and get configuration strings, see ESteamNetworkingConfigurationString for individual descriptions.
  231. //
  232. // Get the configuration string, returns length of string needed if pDest is nullpr or destSize is 0
  233. // returns -1 if the eConfigValue is invalid
  234. virtual int32 GetConfigurationString( ESteamNetworkingConfigurationString eConfigString, char *pDest, int32 destSize ) = 0;
  235. virtual bool SetConfigurationString( ESteamNetworkingConfigurationString eConfigString, const char *pString ) = 0;
  236. // Return the name of a string configuration value, or NULL if config value isn't known
  237. virtual const char *GetConfigurationStringName( ESteamNetworkingConfigurationString eConfigString ) = 0;
  238. };
  239. #define STEAMSOCKETNETWORKING_VERSION "SteamSocketNetworking001"
  240. // Notification struct used to notify when a connection has changed state
  241. struct SteamNetConnectionStatusChangedCallback_t
  242. {
  243. HSteamNetConnection m_hConn; //< Connection handle
  244. SteamNetConnectionInfo_t m_info; //< Full connection info
  245. int m_eOldState; //< ESNetSocketState. (Current stats is in m_info)
  246. };
  247. // Temporary global accessor. This will be moved to steam_api.h
  248. STEAMDATAGRAMLIB_INTERFACE ISteamSocketNetworking *SteamSocketNetworking();
  249. typedef void * ( S_CALLTYPE *FSteamInternal_CreateInterface )( const char *);
  250. typedef void ( S_CALLTYPE *FSteamAPI_RegisterCallResult)( class CCallbackBase *pCallback, SteamAPICall_t hAPICall );
  251. typedef void ( S_CALLTYPE *FSteamAPI_UnregisterCallResult)( class CCallbackBase *pCallback, SteamAPICall_t hAPICall );
  252. /// !KLUDGE! Glue code that will go away when we move everything into
  253. /// the ISteamNetwork interfaces
  254. STEAMDATAGRAMLIB_INTERFACE void SteamDatagramClient_Internal_SteamAPIKludge( FSteamAPI_RegisterCallResult fnRegisterCallResult, FSteamAPI_UnregisterCallResult fnUnregisterCallResult );
  255. STEAMDATAGRAMLIB_INTERFACE bool SteamDatagramClient_Init_Internal( const char *pszCacheDirectory, /* ESteamDatagramPartner */ int ePartner, int iPartnerMask, SteamDatagramErrMsg &errMsg, ISteamClient *pClient, HSteamUser hSteamUser, HSteamPipe hSteamPipe );
  256. inline bool SteamDatagramClient_Init( const char *pszCacheDirectory, /* ESteamDatagramPartner */ int ePartner, int iPartnerMask, SteamDatagramErrMsg &errMsg )
  257. {
  258. SteamDatagramClient_Internal_SteamAPIKludge( &::SteamAPI_RegisterCallResult, &::SteamAPI_UnregisterCallResult );
  259. return SteamDatagramClient_Init_Internal( pszCacheDirectory, ePartner, iPartnerMask, errMsg, ::SteamClient(), ::SteamAPI_GetHSteamUser(), ::SteamAPI_GetHSteamPipe() );
  260. }
  261. /// Shutdown all clients and close all sockets
  262. STEAMDATAGRAMLIB_INTERFACE void SteamDatagramClient_Kill();
  263. /// Initialize the game server interface
  264. STEAMDATAGRAMLIB_INTERFACE bool SteamDatagramServer_Init_Internal( SteamDatagramErrMsg &errMsg, ISteamClient *pClient, HSteamUser hSteamUser, HSteamPipe hSteamPipe );
  265. // KLUDGE TF is using an old version of the SDK, which doesn't have this. TF doesn't need this, so just comment it out.
  266. // We'll need to upgrade the Steamworks SDK if we want to actually use SDR
  267. //inline bool SteamDatagramServer_Init( SteamDatagramErrMsg &errMsg )
  268. //{
  269. // SteamDatagramClient_Internal_SteamAPIKludge( &::SteamAPI_RegisterCallResult, &::SteamAPI_UnregisterCallResult );
  270. // return SteamDatagramServer_Init_Internal( errMsg, ::SteamGameServerClient(), ::SteamGameServer_GetHSteamUser(), ::SteamGameServer_GetHSteamPipe() );
  271. //}
  272. /// Shutdown the game server interface
  273. STEAMDATAGRAMLIB_INTERFACE void SteamDatagramServer_Kill( );
  274. // !KLUDGE! Check for connections that have changed status, and post callbacks.
  275. // This is temporary we can hook this up using the ordinary steam CCallback mechanism
  276. typedef void (*FSteamNetConnectionStatusChangedCallback)( SteamNetConnectionStatusChangedCallback_t *pInfo );
  277. STEAMDATAGRAMLIB_INTERFACE void Temp_DispatchsSteamNetConnectionStatusChangedCallbacks( FSteamNetConnectionStatusChangedCallback fnCallback );
  278. enum ESteamDatagramDebugOutputType
  279. {
  280. k_ESteamDatagramDebugOutputType_None,
  281. k_ESteamDatagramDebugOutputType_Error,
  282. k_ESteamDatagramDebugOutputType_Important, // Nothing is wrong, but this is an important notification
  283. k_ESteamDatagramDebugOutputType_Warning,
  284. k_ESteamDatagramDebugOutputType_Msg, // Recommended amount
  285. k_ESteamDatagramDebugOutputType_Verbose, // Quite a bit
  286. k_ESteamDatagramDebugOutputType_Debug, // Practically everything
  287. };
  288. /// Setup callback for debug output, and the desired verbosity you want.
  289. typedef void (*FSteamDatagramDebugOutput)( /* ESteamDatagramDebugOutputType */ int nType, const char *pszMsg );
  290. STEAMDATAGRAMLIB_INTERFACE void SteamDatagram_SetDebugOutputFunction( /* ESteamDatagramDebugOutputType */ int eDetailLevel, FSteamDatagramDebugOutput pfnFunc );
  291. #endif // ISTEAMNETWORKINGSOCKETS