mirror of
https://github.com/rlabrecque/SteamworksSDK.git
synced 2026-10-10 01:23:04 +08:00
v1.44
This commit is contained in:
@@ -0,0 +1,489 @@
|
||||
//====== Copyright Valve Corporation, All rights reserved. ====================
|
||||
//
|
||||
// Networking API similar to Berkeley sockets, but for games.
|
||||
// - connection-oriented API (like TCP, not UDP)
|
||||
// - but unlike TCP, it's message-oriented, not stream-oriented
|
||||
// - mix of reliable and unreliable messages
|
||||
// - fragmentation and reassembly
|
||||
// - Supports connectivity over plain UDPv4
|
||||
// - Also supports SDR ("Steam Datagram Relay") connections, which are
|
||||
// addressed by SteamID. There is a "P2P" use case and also a "hosted
|
||||
// dedicated server" use case.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef ISTEAMNETWORKINGSOCKETS
|
||||
#define ISTEAMNETWORKINGSOCKETS
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "steamnetworkingtypes.h"
|
||||
|
||||
class ISteamNetworkingSocketsCallbacks;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Lower level networking interface that more closely mirrors the standard
|
||||
/// Berkeley sockets model. Sockets are hard! You should probably only use
|
||||
/// this interface under the existing circumstances:
|
||||
///
|
||||
/// - You have an existing socket-based codebase you want to port, or coexist with.
|
||||
/// - You want to be able to connect based on IP address, rather than (just) Steam ID.
|
||||
/// - You need low-level control of bandwidth utilization, when to drop packets, etc.
|
||||
///
|
||||
/// Note that neither of the terms "connection" and "socket" will correspond
|
||||
/// one-to-one with an underlying UDP socket. An attempt has been made to
|
||||
/// keep the semantics as similar to the standard socket model when appropriate,
|
||||
/// but some deviations do exist.
|
||||
class ISteamNetworkingSockets
|
||||
{
|
||||
public:
|
||||
|
||||
/// Creates a "server" socket that listens for clients to connect to by
|
||||
/// calling ConnectByIPAddress, over ordinary UDP (IPv4 or IPv6)
|
||||
///
|
||||
/// You must select a specific local port to listen on and set it
|
||||
/// the port field of the local address.
|
||||
///
|
||||
/// Usually you wil set the IP portion of the address to zero, (SteamNetworkingIPAddr::Clear()).
|
||||
/// This means that you will not bind to any particular local interface. In addition,
|
||||
/// if possible the socket will be bound in "dual stack" mode, which means that it can
|
||||
/// accept both IPv4 and IPv6 clients. If you wish to bind a particular interface, then
|
||||
/// set the local address to the appropriate IPv4 or IPv6 IP.
|
||||
///
|
||||
/// When a client attempts to connect, a SteamNetConnectionStatusChangedCallback_t
|
||||
/// will be posted. The connection will be in the connecting state.
|
||||
virtual HSteamListenSocket CreateListenSocketIP( const SteamNetworkingIPAddr &localAddress ) = 0;
|
||||
|
||||
/// Creates a connection and begins talking to a "server" over UDP at the
|
||||
/// given IPv4 or IPv6 address. The remote host must be listening with a
|
||||
/// matching call to CreateListenSocketIP on the specified port.
|
||||
///
|
||||
/// A SteamNetConnectionStatusChangedCallback_t callback will be triggered when we start
|
||||
/// connecting, and then another one on either timeout or successful connection.
|
||||
///
|
||||
/// If the server does not have any identity configured, then their network address
|
||||
/// will be the only identity in use. Or, the network host may provide a platform-specific
|
||||
/// identity with or without a valid certificate to authenticate that identity. (These
|
||||
/// details will be contained in the SteamNetConnectionStatusChangedCallback_t.) It's
|
||||
/// up to your application to decide whether to allow the connection.
|
||||
///
|
||||
/// By default, all connections will get basic encryption sufficient to prevent
|
||||
/// casual eavesdropping. But note that without certificates (or a shared secret
|
||||
/// distributed through some other out-of-band mechanism), you don't have any
|
||||
/// way of knowing who is actually on the other end, and thus are vulnerable to
|
||||
/// man-in-the-middle attacks.
|
||||
virtual HSteamNetConnection ConnectByIPAddress( const SteamNetworkingIPAddr &address ) = 0;
|
||||
|
||||
#ifdef STEAMNETWORKINGSOCKETS_ENABLE_SDR
|
||||
/// Like CreateListenSocketIP, but clients will connect using ConnectP2P
|
||||
///
|
||||
/// nVirtualPort specifies how clients can connect to this socket using
|
||||
/// ConnectP2P. It's very common for applications to only have one listening socket;
|
||||
/// in that case, use zero. If you need to open multiple listen sockets and have clients
|
||||
/// be able to connect to one or the other, then nVirtualPort should be a small integer (<1000)
|
||||
/// unique to each listen socket you create.
|
||||
///
|
||||
/// If you use this, you probably want to call ISteamNetworkingUtils::InitializeRelayNetworkAccess()
|
||||
/// when your app initializes
|
||||
virtual HSteamListenSocket CreateListenSocketP2P( int nVirtualPort ) = 0;
|
||||
|
||||
/// Begin connecting to a server that is identified using a platform-specific identifier.
|
||||
/// This requires some sort of third party rendezvous service, and will depend on the
|
||||
/// platform and what other libraries and services you are integrating with.
|
||||
///
|
||||
/// At the time of this writing, there is only one supported rendezvous service: Steam.
|
||||
/// Set the SteamID (whether "user" or "gameserver") and Steam will determine if the
|
||||
/// client is online and facilitate a relay connection. Note that all P2P connections on
|
||||
/// Steam are currently relayed.
|
||||
///
|
||||
/// If you use this, you probably want to call ISteamNetworkingUtils::InitializeRelayNetworkAccess()
|
||||
/// when your app initializes
|
||||
virtual HSteamNetConnection ConnectP2P( const SteamNetworkingIdentity &identityRemote, int nVirtualPort ) = 0;
|
||||
#endif
|
||||
|
||||
/// Accept an incoming connection that has been received on a listen socket.
|
||||
///
|
||||
/// When a connection attempt is received (perhaps after a few basic handshake
|
||||
/// packets have been exchanged to prevent trivial spoofing), a connection interface
|
||||
/// object is created in the k_ESteamNetworkingConnectionState_Connecting state
|
||||
/// and a SteamNetConnectionStatusChangedCallback_t is posted. At this point, your
|
||||
/// application MUST either accept or close the connection. (It may not ignore it.)
|
||||
/// Accepting the connection will transition it either into the connected state,
|
||||
/// or the finding route state, depending on the connection type.
|
||||
///
|
||||
/// You should take action within a second or two, because accepting the connection is
|
||||
/// what actually sends the reply notifying the client that they are connected. If you
|
||||
/// delay taking action, from the client's perspective it is the same as the network
|
||||
/// being unresponsive, and the client may timeout the connection attempt. In other
|
||||
/// words, the client cannot distinguish between a delay caused by network problems
|
||||
/// and a delay caused by the application.
|
||||
///
|
||||
/// This means that if your application goes for more than a few seconds without
|
||||
/// processing callbacks (for example, while loading a map), then there is a chance
|
||||
/// that a client may attempt to connect in that interval and fail due to timeout.
|
||||
///
|
||||
/// If the application does not respond to the connection attempt in a timely manner,
|
||||
/// and we stop receiving communication from the client, the connection attempt will
|
||||
/// be timed out locally, transitioning the connection to the
|
||||
/// k_ESteamNetworkingConnectionState_ProblemDetectedLocally state. The client may also
|
||||
/// close the connection before it is accepted, and a transition to the
|
||||
/// k_ESteamNetworkingConnectionState_ClosedByPeer is also possible depending the exact
|
||||
/// sequence of events.
|
||||
///
|
||||
/// Returns k_EResultInvalidParam if the handle is invalid.
|
||||
/// Returns k_EResultInvalidState if the connection is not in the appropriate state.
|
||||
/// (Remember that the connection state could change in between the time that the
|
||||
/// notification being posted to the queue and when it is received by the application.)
|
||||
virtual EResult AcceptConnection( HSteamNetConnection hConn ) = 0;
|
||||
|
||||
/// Disconnects from the remote host and invalidates the connection handle.
|
||||
/// Any unread data on the connection is discarded.
|
||||
///
|
||||
/// nReason is an application defined code that will be received on the other
|
||||
/// end and recorded (when possible) in backend analytics. The value should
|
||||
/// come from a restricted range. (See ESteamNetConnectionEnd.) If you don't need
|
||||
/// to communicate any information to the remote host, and do not want analytics to
|
||||
/// be able to distinguish "normal" connection terminations from "exceptional" ones,
|
||||
/// You may pass zero, in which case the generic value of
|
||||
/// k_ESteamNetConnectionEnd_App_Generic will be used.
|
||||
///
|
||||
/// pszDebug is an optional human-readable diagnostic string that will be received
|
||||
/// by the remote host and recorded (when possible) in backend analytics.
|
||||
///
|
||||
/// If you wish to put the socket into a "linger" state, where an attempt is made to
|
||||
/// flush any remaining sent data, use bEnableLinger=true. Otherwise reliable data
|
||||
/// is not flushed.
|
||||
///
|
||||
/// If the connection has already ended and you are just freeing up the
|
||||
/// connection interface, the reason code, debug string, and linger flag are
|
||||
/// ignored.
|
||||
virtual bool CloseConnection( HSteamNetConnection hPeer, int nReason, const char *pszDebug, bool bEnableLinger ) = 0;
|
||||
|
||||
/// Destroy a listen socket. All the connections that were accepting on the listen
|
||||
/// socket are closed ungracefully.
|
||||
virtual bool CloseListenSocket( HSteamListenSocket hSocket ) = 0;
|
||||
|
||||
/// Set connection user data. the data is returned in the following places
|
||||
/// - You can query it using GetConnectionUserData.
|
||||
/// - The SteamNetworkingmessage_t structure.
|
||||
/// - The SteamNetConnectionInfo_t structure. (Which is a member of SteamNetConnectionStatusChangedCallback_t.)
|
||||
///
|
||||
/// Returns false if the handle is invalid.
|
||||
virtual bool SetConnectionUserData( HSteamNetConnection hPeer, int64 nUserData ) = 0;
|
||||
|
||||
/// Fetch connection user data. Returns -1 if handle is invalid
|
||||
/// or if you haven't set any userdata on the connection.
|
||||
virtual int64 GetConnectionUserData( HSteamNetConnection hPeer ) = 0;
|
||||
|
||||
/// Set a name for the connection, used mostly for debugging
|
||||
virtual void SetConnectionName( HSteamNetConnection hPeer, const char *pszName ) = 0;
|
||||
|
||||
/// Fetch connection name. Returns false if handle is invalid
|
||||
virtual bool GetConnectionName( HSteamNetConnection hPeer, char *pszName, int nMaxLen ) = 0;
|
||||
|
||||
/// Send a message to the remote host on the specified connection.
|
||||
///
|
||||
/// nSendFlags determines the delivery guarantees that will be provided,
|
||||
/// when data should be buffered, etc. E.g. k_nSteamNetworkingSend_Unreliable
|
||||
///
|
||||
/// Note that the semantics we use for messages are not precisely
|
||||
/// the same as the semantics of a standard "stream" socket.
|
||||
/// (SOCK_STREAM) For an ordinary stream socket, the boundaries
|
||||
/// between chunks are not considered relevant, and the sizes of
|
||||
/// the chunks of data written will not necessarily match up to
|
||||
/// the sizes of the chunks that are returned by the reads on
|
||||
/// the other end. The remote host might read a partial chunk,
|
||||
/// or chunks might be coalesced. For the message semantics
|
||||
/// used here, however, the sizes WILL match. Each send call
|
||||
/// will match a successful read call on the remote host
|
||||
/// one-for-one. If you are porting existing stream-oriented
|
||||
/// code to the semantics of reliable messages, your code should
|
||||
/// work the same, since reliable message semantics are more
|
||||
/// strict than stream semantics. The only caveat is related to
|
||||
/// performance: there is per-message overhead to retain the
|
||||
/// message sizes, and so if your code sends many small chunks
|
||||
/// of data, performance will suffer. Any code based on stream
|
||||
/// sockets that does not write excessively small chunks will
|
||||
/// work without any changes.
|
||||
///
|
||||
/// Returns:
|
||||
/// - k_EResultInvalidParam: invalid connection handle, or the individual message is too big.
|
||||
/// (See k_cbMaxSteamNetworkingSocketsMessageSizeSend)
|
||||
/// - k_EResultInvalidState: connection is in an invalid state
|
||||
/// - k_EResultNoConnection: connection has ended
|
||||
/// - k_EResultIgnored: You used k_nSteamNetworkingSend_NoDelay, and the message was dropped because
|
||||
/// we were not ready to send it.
|
||||
/// - k_EResultLimitExceeded: there was already too much data queued to be sent.
|
||||
/// (See k_ESteamNetworkingConfig_SendBufferSize)
|
||||
virtual EResult SendMessageToConnection( HSteamNetConnection hConn, const void *pData, uint32 cbData, int nSendFlags ) = 0;
|
||||
|
||||
/// Flush any messages waiting on the Nagle timer and send them
|
||||
/// at the next transmission opportunity (often that means right now).
|
||||
///
|
||||
/// If Nagle is enabled (it's on by default) then when calling
|
||||
/// SendMessageToConnection the message will be buffered, up to the Nagle time
|
||||
/// before being sent, to merge small messages into the same packet.
|
||||
/// (See k_ESteamNetworkingConfig_NagleTime)
|
||||
///
|
||||
/// Returns:
|
||||
/// k_EResultInvalidParam: invalid connection handle
|
||||
/// k_EResultInvalidState: connection is in an invalid state
|
||||
/// k_EResultNoConnection: connection has ended
|
||||
/// k_EResultIgnored: We weren't (yet) connected, so this operation has no effect.
|
||||
virtual EResult FlushMessagesOnConnection( HSteamNetConnection hConn ) = 0;
|
||||
|
||||
/// Fetch the next available message(s) from the connection, if any.
|
||||
/// Returns the number of messages returned into your array, up to nMaxMessages.
|
||||
/// If the connection handle is invalid, -1 is returned.
|
||||
///
|
||||
/// The order of the messages returned in the array is relevant.
|
||||
/// Reliable messages will be received in the order they were sent (and with the
|
||||
/// same sizes --- see SendMessageToConnection for on this subtle difference from a stream socket).
|
||||
///
|
||||
/// Unreliable messages may be dropped, or delivered out of order withrespect to
|
||||
/// each other or with respect to reliable messages. The same unreliable message
|
||||
/// may be received multiple times.
|
||||
///
|
||||
/// If any messages are returned, you MUST call SteamNetworkingMessage_t::Release() on each
|
||||
/// of them free up resources after you are done. It is safe to keep the object alive for
|
||||
/// a little while (put it into some queue, etc), and you may call Release() from any thread.
|
||||
virtual int ReceiveMessagesOnConnection( HSteamNetConnection hConn, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages ) = 0;
|
||||
|
||||
/// Same as ReceiveMessagesOnConnection, but will return the next message available
|
||||
/// on any connection that was accepted through the specified listen socket. Examine
|
||||
/// SteamNetworkingMessage_t::m_conn to know which client connection.
|
||||
///
|
||||
/// Delivery order of messages among different clients is not defined. They may
|
||||
/// be returned in an order different from what they were actually received. (Delivery
|
||||
/// order of messages from the same client is well defined, and thus the order of the
|
||||
/// messages is relevant!)
|
||||
virtual int ReceiveMessagesOnListenSocket( HSteamListenSocket hSocket, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages ) = 0;
|
||||
|
||||
/// Returns basic information about the high-level state of the connection.
|
||||
virtual bool GetConnectionInfo( HSteamNetConnection hConn, SteamNetConnectionInfo_t *pInfo ) = 0;
|
||||
|
||||
/// Returns a small set of information about the real-time state of the connection
|
||||
/// Returns false if the connection handle is invalid, or the connection has ended.
|
||||
virtual bool GetQuickConnectionStatus( HSteamNetConnection hConn, SteamNetworkingQuickConnectionStatus *pStats ) = 0;
|
||||
|
||||
/// Returns detailed connection stats in text format. Useful
|
||||
/// for dumping to a log, etc.
|
||||
///
|
||||
/// Returns:
|
||||
/// -1 failure (bad connection handle)
|
||||
/// 0 OK, your buffer was filled in and '\0'-terminated
|
||||
/// >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.
|
||||
virtual int GetDetailedConnectionStatus( HSteamNetConnection hConn, char *pszBuf, int cbBuf ) = 0;
|
||||
|
||||
/// Returns local IP and port that a listen socket created using CreateListenSocketIP is bound to.
|
||||
///
|
||||
/// An IPv6 address of ::0 means "any IPv4 or IPv6"
|
||||
/// An IPv6 address of ::ffff:0000:0000 means "any IPv4"
|
||||
virtual bool GetListenSocketAddress( HSteamListenSocket hSocket, SteamNetworkingIPAddr *address ) = 0;
|
||||
|
||||
/// Create a pair of connections that are talking to each other, e.g. a loopback connection.
|
||||
/// This is very useful for testing, or so that your client/server code can work the same
|
||||
/// even when you are running a local "server".
|
||||
///
|
||||
/// The two connections will immediately be placed into the connected state, and no callbacks
|
||||
/// will be posted immediately. After this, if you close either connection, the other connection
|
||||
/// will receive a callback, exactly as if they were communicating over the network. You must
|
||||
/// close *both* sides in order to fully clean up the resources!
|
||||
///
|
||||
/// By default, internal buffers are used, completely bypassing the network, the chopping up of
|
||||
/// messages into packets, encryption, copying the payload, etc. This means that loopback
|
||||
/// packets, by default, will not simulate lag or loss. Passing true for bUseNetworkLoopback will
|
||||
/// cause the socket pair to send packets through the local network loopback device (127.0.0.1)
|
||||
/// on ephemeral ports. Fake lag and loss are supported in this case, and CPU time is expended
|
||||
/// to encrypt and decrypt.
|
||||
///
|
||||
/// If you wish to assign a specific identity to either connection, you may pass a particular
|
||||
/// identity. Otherwise, if you pass nullptr, the respective connection will assume a generic
|
||||
/// "localhost" identity. If you use real network loopback, this might be translated to the
|
||||
/// actual bound loopback port. Otherwise, the port will be zero.
|
||||
virtual bool CreateSocketPair( HSteamNetConnection *pOutConnection1, HSteamNetConnection *pOutConnection2, bool bUseNetworkLoopback, const SteamNetworkingIdentity *pIdentity1, const SteamNetworkingIdentity *pIdentity2 ) = 0;
|
||||
|
||||
/// Get the identity assigned to this interface.
|
||||
/// E.g. on Steam, this is the user's SteamID, or for the gameserver interface, the SteamID assigned
|
||||
/// to the gameserver. Returns false and sets the result to an invalid identity if we don't know
|
||||
/// our identity yet. (E.g. GameServer has not logged in. On Steam, the user will know their SteamID
|
||||
/// even if they are not signed into Steam.)
|
||||
virtual bool GetIdentity( SteamNetworkingIdentity *pIdentity ) = 0;
|
||||
|
||||
#ifdef STEAMNETWORKINGSOCKETS_ENABLE_SDR
|
||||
|
||||
//
|
||||
// Clients connecting to dedicated servers hosted in a data center,
|
||||
// using central-authority-granted tickets.
|
||||
//
|
||||
|
||||
/// Call this when you receive a ticket from your backend / matchmaking system. Puts the
|
||||
/// ticket into a persistent cache, and optionally returns the parsed ticket.
|
||||
///
|
||||
/// See stamdatagram_ticketgen.h for more details.
|
||||
virtual bool ReceivedRelayAuthTicket( const void *pvTicket, int cbTicket, SteamDatagramRelayAuthTicket *pOutParsedTicket ) = 0;
|
||||
|
||||
/// Search cache for a ticket to talk to the server on the specified virtual port.
|
||||
/// If found, returns the number of seconds until the ticket expires, and optionally
|
||||
/// the complete cracked ticket. Returns 0 if we don't have a ticket.
|
||||
///
|
||||
/// Typically this is useful just to confirm that you have a ticket, before you
|
||||
/// call ConnectToHostedDedicatedServer to connect to the server.
|
||||
virtual int FindRelayAuthTicketForServer( const SteamNetworkingIdentity &identityGameServer, int nVirtualPort, SteamDatagramRelayAuthTicket *pOutParsedTicket ) = 0;
|
||||
|
||||
/// Client call to connect to a server hosted in a Valve data center, on the specified virtual
|
||||
/// port. You must have placed a ticket for this server into the cache, or else this connect attempt will fail!
|
||||
///
|
||||
/// You may wonder why tickets are stored in a cache, instead of simply being passed as an argument
|
||||
/// here. The reason is to make reconnection to a gameserver robust, even if the client computer loses
|
||||
/// connection to Steam or the central backend, or the app is restarted or crashes, etc.
|
||||
///
|
||||
/// If you use this, you probably want to call ISteamNetworkingUtils::InitializeRelayNetworkAccess()
|
||||
/// when your app initializes
|
||||
virtual HSteamNetConnection ConnectToHostedDedicatedServer( const SteamNetworkingIdentity &identityTarget, int nVirtualPort ) = 0;
|
||||
|
||||
//
|
||||
// Servers hosted in Valve data centers
|
||||
//
|
||||
|
||||
/// Returns the value of the SDR_LISTEN_PORT environment variable. This
|
||||
/// is the UDP server your server will be listening on. This will
|
||||
/// configured automatically for you in production environments. (You
|
||||
/// should set it yourself for testing.)
|
||||
virtual uint16 GetHostedDedicatedServerPort() = 0;
|
||||
|
||||
/// If you are running in a production data center, this will return the data
|
||||
/// center code. Returns 0 otherwise.
|
||||
virtual SteamNetworkingPOPID GetHostedDedicatedServerPOPID() = 0;
|
||||
|
||||
/// Return info about the hosted server. You will need to send this information to your
|
||||
/// backend, and put it in tickets, so that the relays will know how to forward traffic from
|
||||
/// clients to your server. See SteamDatagramRelayAuthTicket for more info.
|
||||
///
|
||||
/// NOTE ABOUT DEVELOPMENT ENVIRONMENTS:
|
||||
/// In production in our data centers, these parameters are configured via environment variables.
|
||||
/// In development, the only one you need to set is SDR_LISTEN_PORT, which is the local port you
|
||||
/// want to listen on. Furthermore, if you are running your server behind a corporate firewall,
|
||||
/// you probably will not be able to put the routing information returned by this function into
|
||||
/// tickets. Instead, it should be a public internet address that the relays can use to send
|
||||
/// data to your server. So you might just end up hardcoding a public address and setup port
|
||||
/// forwarding on your corporate firewall. In that case, the port you put into the ticket
|
||||
/// needs to be the public-facing port opened on your firewall, if it is different from the
|
||||
/// actual server port.
|
||||
///
|
||||
/// This function will fail if SteamDatagramServer_Init has not been called.
|
||||
///
|
||||
/// Returns false if the SDR_LISTEN_PORT environment variable is not set.
|
||||
virtual bool GetHostedDedicatedServerAddress( SteamDatagramHostedAddress *pRouting ) = 0;
|
||||
|
||||
/// Create a listen socket on the specified virtual port. The physical UDP port to use
|
||||
/// will be determined by the SDR_LISTEN_PORT environment variable. If a UDP port is not
|
||||
/// configured, this call will fail.
|
||||
///
|
||||
/// Note that this call MUST be made through the SteamGameServerNetworkingSockets() interface
|
||||
virtual HSteamListenSocket CreateHostedDedicatedServerListenSocket( int nVirtualPort ) = 0;
|
||||
|
||||
#endif // #ifndef STEAMNETWORKINGSOCKETS_ENABLE_SDR
|
||||
|
||||
// Invoke all callbacks queued for this interface.
|
||||
// On Steam, callbacks are dispatched via the ordinary Steamworks callbacks mechanism.
|
||||
// So if you have code that is also targeting Steam, you should call this at about the
|
||||
// same time you would call SteamAPI_RunCallbacks and SteamGameServer_RunCallbacks.
|
||||
#ifdef STEAMNETWORKINGSOCKETS_STANDALONELIB
|
||||
virtual void RunCallbacks( ISteamNetworkingSocketsCallbacks *pCallbacks ) = 0;
|
||||
#endif
|
||||
protected:
|
||||
~ISteamNetworkingSockets(); // Silence some warnings
|
||||
};
|
||||
#define STEAMNETWORKINGSOCKETS_INTERFACE_VERSION "SteamNetworkingSockets002"
|
||||
|
||||
extern "C" {
|
||||
|
||||
// Global accessor.
|
||||
#if defined( STEAMNETWORKINGSOCKETS_PARTNER )
|
||||
|
||||
// Standalone lib. Use different symbol name, so that we can dynamically switch between steamclient.dll
|
||||
// and the standalone lib
|
||||
STEAMNETWORKINGSOCKETS_INTERFACE ISteamNetworkingSockets *SteamNetworkingSockets_Lib();
|
||||
STEAMNETWORKINGSOCKETS_INTERFACE ISteamNetworkingSockets *SteamGameServerNetworkingSockets_Lib();
|
||||
inline ISteamNetworkingSockets *SteamNetworkingSockets() { return SteamNetworkingSockets_Lib(); }
|
||||
inline ISteamNetworkingSockets *SteamGameServerNetworkingSockets() { return SteamGameServerNetworkingSockets_Lib(); }
|
||||
|
||||
#elif defined( STEAMNETWORKINGSOCKETS_OPENSOURCE )
|
||||
|
||||
// Opensource GameNetworkingSockets
|
||||
STEAMNETWORKINGSOCKETS_INTERFACE ISteamNetworkingSockets *SteamNetworkingSockets();
|
||||
|
||||
#else
|
||||
|
||||
// Steamworks SDK
|
||||
inline ISteamNetworkingSockets *SteamNetworkingSockets();
|
||||
STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamNetworkingSockets *, SteamNetworkingSockets, STEAMNETWORKINGSOCKETS_INTERFACE_VERSION );
|
||||
inline ISteamNetworkingSockets *SteamGameServerNetworkingSockets();
|
||||
STEAM_DEFINE_GAMESERVER_INTERFACE_ACCESSOR( ISteamNetworkingSockets *, SteamGameServerNetworkingSockets, STEAMNETWORKINGSOCKETS_INTERFACE_VERSION );
|
||||
#endif
|
||||
|
||||
/// Callback struct used to notify when a connection has changed state
|
||||
#if defined( VALVE_CALLBACK_PACK_SMALL )
|
||||
#pragma pack( push, 4 )
|
||||
#elif defined( VALVE_CALLBACK_PACK_LARGE )
|
||||
#pragma pack( push, 8 )
|
||||
#else
|
||||
#error "Must define VALVE_CALLBACK_PACK_SMALL or VALVE_CALLBACK_PACK_LARGE"
|
||||
#endif
|
||||
|
||||
/// This callback is posted whenever a connection is created, destroyed, or changes state.
|
||||
/// The m_info field will contain a complete description of the connection at the time the
|
||||
/// change occurred and the callback was posted. In particular, m_eState will have the
|
||||
/// new connection state.
|
||||
///
|
||||
/// You will usually need to listen for this callback to know when:
|
||||
/// - A new connection arrives on a listen socket.
|
||||
/// m_info.m_hListenSocket will be set, m_eOldState = k_ESteamNetworkingConnectionState_None,
|
||||
/// and m_info.m_eState = k_ESteamNetworkingConnectionState_Connecting.
|
||||
/// See ISteamNetworkigSockets::AcceptConnection.
|
||||
/// - A connection you initiated has been accepted by the remote host.
|
||||
/// m_eOldState = k_ESteamNetworkingConnectionState_Connecting, and
|
||||
/// m_info.m_eState = k_ESteamNetworkingConnectionState_Connected.
|
||||
/// Some connections might transition to k_ESteamNetworkingConnectionState_FindingRoute first.
|
||||
/// - A connection has been actively rejected or closed by the remote host.
|
||||
/// m_eOldState = k_ESteamNetworkingConnectionState_Connecting or k_ESteamNetworkingConnectionState_Connected,
|
||||
/// and m_info.m_eState = k_ESteamNetworkingConnectionState_ClosedByPeer. m_info.m_eEndReason
|
||||
/// and m_info.m_szEndDebug will have for more details.
|
||||
/// NOTE: upon receiving this callback, you must still destroy the connection using
|
||||
/// ISteamNetworkingSockets::CloseConnection to free up local resources. (The details
|
||||
/// passed to the function are not used in this case, since the connection is already closed.)
|
||||
/// - A problem was detected with the connection, and it has been closed by the local host.
|
||||
/// The most common failure is timeout, but other configuration or authentication failures
|
||||
/// can cause this. m_eOldState = k_ESteamNetworkingConnectionState_Connecting or
|
||||
/// k_ESteamNetworkingConnectionState_Connected, and m_info.m_eState = k_ESteamNetworkingConnectionState_ProblemDetectedLocally.
|
||||
/// m_info.m_eEndReason and m_info.m_szEndDebug will have for more details.
|
||||
/// NOTE: upon receiving this callback, you must still destroy the connection using
|
||||
/// ISteamNetworkingSockets::CloseConnection to free up local resources. (The details
|
||||
/// passed to the function are not used in this case, since the connection is already closed.)
|
||||
///
|
||||
/// Remember that callbacks are posted to a queue, and networking connections can
|
||||
/// change at any time. It is possible that the connection has already changed
|
||||
/// state by the time you process this callback.
|
||||
///
|
||||
/// Also note that callbacks will be posted when connections are created and destroyed by your own API calls.
|
||||
struct SteamNetConnectionStatusChangedCallback_t
|
||||
{
|
||||
enum { k_iCallback = k_iSteamNetworkingSocketsCallbacks + 1 };
|
||||
|
||||
/// Connection handle
|
||||
HSteamNetConnection m_hConn;
|
||||
|
||||
/// Full connection info
|
||||
SteamNetConnectionInfo_t m_info;
|
||||
|
||||
/// Previous state. (Current state is in m_info.m_eState)
|
||||
ESteamNetworkingConnectionState m_eOldState;
|
||||
};
|
||||
#pragma pack( pop )
|
||||
|
||||
}
|
||||
|
||||
#endif // ISTEAMNETWORKINGSOCKETS
|
||||
@@ -0,0 +1,302 @@
|
||||
//====== Copyright Valve Corporation, All rights reserved. ====================
|
||||
//
|
||||
// Purpose: misc networking utilities
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef ISTEAMNETWORKINGUTILS
|
||||
#define ISTEAMNETWORKINGUTILS
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "steamnetworkingtypes.h"
|
||||
struct SteamDatagramRelayAuthTicket;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Misc networking utilities for checking the local networking environment
|
||||
/// and estimating pings.
|
||||
class ISteamNetworkingUtils
|
||||
{
|
||||
public:
|
||||
#ifdef STEAMNETWORKINGSOCKETS_ENABLE_SDR
|
||||
|
||||
//
|
||||
// Initialization
|
||||
//
|
||||
|
||||
/// If you know that you are going to be using the relay network, call
|
||||
/// this to initialize the relay network or check if that initialization
|
||||
/// has completed. If you do not call this, the initialization will
|
||||
/// happen the first time you use a feature that requires access to the
|
||||
/// relay network, and that use will be delayed.
|
||||
///
|
||||
/// Returns true if initialization has completed successfully.
|
||||
/// (It will probably return false on the first call.)
|
||||
///
|
||||
/// Typically initialization completes in a few seconds.
|
||||
///
|
||||
/// Note: dedicated servers hosted with Valve do *not* need to call
|
||||
/// this, since they do not make routing decisions. However, if the
|
||||
/// dedicated server will be using P2P functionality, it will act as
|
||||
/// a "client" and this should be called.
|
||||
inline bool InitializeRelayNetworkAccess();
|
||||
|
||||
//
|
||||
// "Ping location" functions
|
||||
//
|
||||
// We use the ping times to the valve relays deployed worldwide to
|
||||
// generate a "marker" that describes the location of an Internet host.
|
||||
// Given two such markers, we can estimate the network latency between
|
||||
// two hosts, without sending any packets. The estimate is based on the
|
||||
// optimal route that is found through the Valve network. If you are
|
||||
// using the Valve network to carry the traffic, then this is precisely
|
||||
// the ping you want. If you are not, then the ping time will probably
|
||||
// still be a reasonable estimate.
|
||||
//
|
||||
// This is extremely useful to select peers for matchmaking!
|
||||
//
|
||||
// The markers can also be converted to a string, so they can be transmitted.
|
||||
// We have a separate library you can use on your backend to manipulate
|
||||
// these objects. (See steamdatagram_ticketgen.h)
|
||||
|
||||
/// Return location info for the current host. Returns the approximate
|
||||
/// age of the data, in seconds, or -1 if no data is available.
|
||||
///
|
||||
/// It takes a few seconds to initialize access to the relay network. If
|
||||
/// you call this very soon after calling InitializeRelayNetworkAccess,
|
||||
/// the data may not be available yet.
|
||||
///
|
||||
/// This always return the most up-to-date information we have available
|
||||
/// right now, even if we are in the middle of re-calculating ping times.
|
||||
virtual float GetLocalPingLocation( SteamNetworkPingLocation_t &result ) = 0;
|
||||
|
||||
/// Estimate the round-trip latency between two arbitrary locations, in
|
||||
/// milliseconds. This is a conservative estimate, based on routing through
|
||||
/// the relay network. For most basic relayed connections, this ping time
|
||||
/// will be pretty accurate, since it will be based on the route likely to
|
||||
/// be actually used.
|
||||
///
|
||||
/// If a direct IP route is used (perhaps via NAT traversal), then the route
|
||||
/// will be different, and the ping time might be better. Or it might actually
|
||||
/// be a bit worse! Standard IP routing is frequently suboptimal!
|
||||
///
|
||||
/// But even in this case, the estimate obtained using this method is a
|
||||
/// reasonable upper bound on the ping time. (Also it has the advantage
|
||||
/// of returning immediately and not sending any packets.)
|
||||
///
|
||||
/// In a few cases we might not able to estimate the route. In this case
|
||||
/// a negative value is returned. k_nSteamNetworkingPing_Failed means
|
||||
/// the reason was because of some networking difficulty. (Failure to
|
||||
/// ping, etc) k_nSteamNetworkingPing_Unknown is returned if we cannot
|
||||
/// currently answer the question for some other reason.
|
||||
///
|
||||
/// Do you need to be able to do this from a backend/matchmaking server?
|
||||
/// You are looking for the "ticketgen" library.
|
||||
virtual int EstimatePingTimeBetweenTwoLocations( const SteamNetworkPingLocation_t &location1, const SteamNetworkPingLocation_t &location2 ) = 0;
|
||||
|
||||
/// Same as EstimatePingTime, but assumes that one location is the local host.
|
||||
/// This is a bit faster, especially if you need to calculate a bunch of
|
||||
/// these in a loop to find the fastest one.
|
||||
///
|
||||
/// In rare cases this might return a slightly different estimate than combining
|
||||
/// GetLocalPingLocation with EstimatePingTimeBetweenTwoLocations. That's because
|
||||
/// this function uses a slightly more complete set of information about what
|
||||
/// route would be taken.
|
||||
virtual int EstimatePingTimeFromLocalHost( const SteamNetworkPingLocation_t &remoteLocation ) = 0;
|
||||
|
||||
/// Convert a ping location into a text format suitable for sending over the wire.
|
||||
/// The format is a compact and human readable. However, it is subject to change
|
||||
/// so please do not parse it yourself. Your buffer must be at least
|
||||
/// k_cchMaxSteamNetworkingPingLocationString bytes.
|
||||
virtual void ConvertPingLocationToString( const SteamNetworkPingLocation_t &location, char *pszBuf, int cchBufSize ) = 0;
|
||||
|
||||
/// Parse back SteamNetworkPingLocation_t string. Returns false if we couldn't understand
|
||||
/// the string.
|
||||
virtual bool ParsePingLocationString( const char *pszString, SteamNetworkPingLocation_t &result ) = 0;
|
||||
|
||||
//
|
||||
// Initialization / ping measurement status
|
||||
//
|
||||
|
||||
/// Check if the ping data of sufficient recency is available, and if
|
||||
/// it's too old, start refreshing it.
|
||||
///
|
||||
/// Please only call this function when you *really* do need to force an
|
||||
/// immediate refresh of the data. (For example, in response to a specific
|
||||
/// user input to refresh this information.) Don't call it "just in case",
|
||||
/// before every connection, etc. That will cause extra traffic to be sent
|
||||
/// for no benefit. The library will automatically refresh the information
|
||||
/// as needed.
|
||||
///
|
||||
/// Returns true if sufficiently recent data is already available.
|
||||
///
|
||||
/// Returns false if sufficiently recent data is not available. In this
|
||||
/// case, ping measurement is initiated, if it is not already active.
|
||||
/// (You cannot restart a measurement already in progress.)
|
||||
virtual bool CheckPingDataUpToDate( float flMaxAgeSeconds ) = 0;
|
||||
|
||||
/// Return true if we are taking ping measurements to update our ping
|
||||
/// location or select optimal routing. Ping measurement typically takes
|
||||
/// a few seconds, perhaps up to 10 seconds.
|
||||
virtual bool IsPingMeasurementInProgress() = 0;
|
||||
|
||||
//
|
||||
// List of Valve data centers, and ping times to them. This might
|
||||
// be useful to you if you are use our hosting, or just need to measure
|
||||
// latency to a cloud data center where we are running relays.
|
||||
//
|
||||
|
||||
/// Fetch ping time of best available relayed route from this host to
|
||||
/// the specified data center.
|
||||
virtual int GetPingToDataCenter( SteamNetworkingPOPID popID, SteamNetworkingPOPID *pViaRelayPoP ) = 0;
|
||||
|
||||
/// Get *direct* ping time to the relays at the data center.
|
||||
virtual int GetDirectPingToPOP( SteamNetworkingPOPID popID ) = 0;
|
||||
|
||||
/// Get number of network points of presence in the config
|
||||
virtual int GetPOPCount() = 0;
|
||||
|
||||
/// Get list of all POP IDs. Returns the number of entries that were filled into
|
||||
/// your list.
|
||||
virtual int GetPOPList( SteamNetworkingPOPID *list, int nListSz ) = 0;
|
||||
#endif // #ifdef STEAMNETWORKINGSOCKETS_ENABLE_SDR
|
||||
|
||||
//
|
||||
// Misc
|
||||
//
|
||||
|
||||
/// Fetch current timestamp. This timer has the following properties:
|
||||
///
|
||||
/// - Monotonicity is guaranteed.
|
||||
/// - The initial value will be at least 24*3600*30*1e6, i.e. about
|
||||
/// 30 days worth of microseconds. In this way, the timestamp value of
|
||||
/// 0 will always be at least "30 days ago". Also, negative numbers
|
||||
/// will never be returned.
|
||||
/// - Wraparound / overflow is not a practical concern.
|
||||
///
|
||||
/// If you are running under the debugger and stop the process, the clock
|
||||
/// might not advance the full wall clock time that has elapsed between
|
||||
/// calls. If the process is not blocked from normal operation, the
|
||||
/// timestamp values will track wall clock time, even if you don't call
|
||||
/// the function frequently.
|
||||
///
|
||||
/// The value is only meaningful for this run of the process. Don't compare
|
||||
/// it to values obtained on another computer, or other runs of the same process.
|
||||
virtual SteamNetworkingMicroseconds GetLocalTimestamp() = 0;
|
||||
|
||||
/// Set a function to receive network-related information that is useful for debugging.
|
||||
/// This can be very useful during development, but it can also be useful for troubleshooting
|
||||
/// problems with tech savvy end users. If you have a console or other log that customers
|
||||
/// can examine, these log messages can often be helpful to troubleshoot network issues.
|
||||
/// (Especially any warning/error messages.)
|
||||
///
|
||||
/// The detail level indicates what message to invoke your callback on. Lower numeric
|
||||
/// value means more important, and the value you pass is the lowest priority (highest
|
||||
/// numeric value) you wish to receive callbacks for.
|
||||
///
|
||||
/// Except when debugging, you should only use k_ESteamNetworkingSocketsDebugOutputType_Msg
|
||||
/// or k_ESteamNetworkingSocketsDebugOutputType_Warning. For best performance, do NOT
|
||||
/// request a high detail level and then filter out messages in your callback. Instead,
|
||||
/// call function function to adjust the desired level of detail.
|
||||
///
|
||||
/// IMPORTANT: This may be called from a service thread, while we own a mutex, etc.
|
||||
/// Your output function must be threadsafe and fast! Do not make any other
|
||||
/// Steamworks calls from within the handler.
|
||||
virtual void SetDebugOutputFunction( ESteamNetworkingSocketsDebugOutputType eDetailLevel, FSteamNetworkingSocketsDebugOutput pfnFunc ) = 0;
|
||||
|
||||
//
|
||||
// Set and get configuration values, see ESteamNetworkingConfigValue for individual descriptions.
|
||||
//
|
||||
|
||||
// Shortcuts for common cases. (Implemented as inline functions below)
|
||||
bool SetGlobalConfigValueInt32( ESteamNetworkingConfigValue eValue, int32 val );
|
||||
bool SetGlobalConfigValueFloat( ESteamNetworkingConfigValue eValue, float val );
|
||||
bool SetGlobalConfigValueString( ESteamNetworkingConfigValue eValue, const char *val );
|
||||
bool SetConnectionConfigValueInt32( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, int32 val );
|
||||
bool SetConnectionConfigValueFloat( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, float val );
|
||||
bool SetConnectionConfigValueString( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, const char *val );
|
||||
|
||||
/// Set a configuration value.
|
||||
/// - eValue: which value is being set
|
||||
/// - eScope: Onto what type of object are you applying the setting?
|
||||
/// - scopeArg: Which object you want to change? (Ignored for global scope). E.g. connection handle, listen socket handle, interface pointer, etc.
|
||||
/// - eDataType: What type of data is in the buffer at pValue? This must match the type of the variable exactly!
|
||||
/// - pArg: Value to set it to. You can pass NULL to remove a non-global sett at this scope,
|
||||
/// causing the value for that object to use global defaults. Or at global scope, passing NULL
|
||||
/// will reset any custom value and restore it to the system default.
|
||||
/// NOTE: When setting callback functions, do not pass the function pointer directly.
|
||||
/// Your argument should be a pointer to a function pointer.
|
||||
virtual bool SetConfigValue( ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigScope eScopeType, intptr_t scopeObj,
|
||||
ESteamNetworkingConfigDataType eDataType, const void *pArg ) = 0;
|
||||
|
||||
/// Get a configuration value.
|
||||
/// - eValue: which value to fetch
|
||||
/// - eScopeType: query setting on what type of object
|
||||
/// - eScopeArg: the object to query the setting for
|
||||
/// - pOutDataType: If non-NULL, the data type of the value is returned.
|
||||
/// - pResult: Where to put the result. Pass NULL to query the required buffer size. (k_ESteamNetworkingGetConfigValue_BufferTooSmall will be returned.)
|
||||
/// - cbResult: IN: the size of your buffer. OUT: the number of bytes filled in or required.
|
||||
virtual ESteamNetworkingGetConfigValueResult GetConfigValue( ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigScope eScopeType, intptr_t scopeObj,
|
||||
ESteamNetworkingConfigDataType *pOutDataType, void *pResult, size_t *cbResult ) = 0;
|
||||
|
||||
/// Returns info about a configuration value. Returns false if the value does not exist.
|
||||
/// pOutNextValue can be used to iterate through all of the known configuration values.
|
||||
/// (Use GetFirstConfigValue() to begin the iteration, will be k_ESteamNetworkingConfig_Invalid on the last value)
|
||||
/// Any of the output parameters can be NULL if you do not need that information.
|
||||
virtual bool GetConfigValueInfo( ESteamNetworkingConfigValue eValue, const char **pOutName, ESteamNetworkingConfigDataType *pOutDataType, ESteamNetworkingConfigScope *pOutScope, ESteamNetworkingConfigValue *pOutNextValue ) = 0;
|
||||
|
||||
/// Return the lowest numbered configuration value available in the current environment.
|
||||
virtual ESteamNetworkingConfigValue GetFirstConfigValue() = 0;
|
||||
|
||||
// String conversions. You'll usually access these using the respective
|
||||
// inline methods.
|
||||
virtual void SteamNetworkingIPAddr_ToString( const SteamNetworkingIPAddr &addr, char *buf, size_t cbBuf, bool bWithPort ) = 0;
|
||||
virtual bool SteamNetworkingIPAddr_ParseString( SteamNetworkingIPAddr *pAddr, const char *pszStr ) = 0;
|
||||
virtual void SteamNetworkingIdentity_ToString( const SteamNetworkingIdentity &identity, char *buf, size_t cbBuf ) = 0;
|
||||
virtual bool SteamNetworkingIdentity_ParseString( SteamNetworkingIdentity *pIdentity, const char *pszStr ) = 0;
|
||||
|
||||
protected:
|
||||
~ISteamNetworkingUtils(); // Silence some warnings
|
||||
};
|
||||
#define STEAMNETWORKINGUTILS_INTERFACE_VERSION "SteamNetworkingUtils001"
|
||||
|
||||
// Global accessor.
|
||||
#ifdef STEAMNETWORKINGSOCKETS_STANDALONELIB
|
||||
|
||||
// Standalone lib
|
||||
STEAMNETWORKINGSOCKETS_INTERFACE ISteamNetworkingUtils *SteamNetworkingUtils_Lib();
|
||||
inline ISteamNetworkingUtils *SteamNetworkingUtils() { return SteamNetworkingUtils_Lib(); }
|
||||
|
||||
#else
|
||||
|
||||
// Steamworks SDK
|
||||
inline ISteamNetworkingUtils *SteamNetworkingUtils();
|
||||
STEAM_DEFINE_INTERFACE_ACCESSOR( ISteamNetworkingUtils *, SteamNetworkingUtils, SteamInternal_FindOrCreateUserInterface( 0, STEAMNETWORKINGUTILS_INTERFACE_VERSION ) );
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Internal stuff
|
||||
|
||||
#ifdef STEAMNETWORKINGSOCKETS_ENABLE_SDR
|
||||
inline bool ISteamNetworkingUtils::InitializeRelayNetworkAccess() { return CheckPingDataUpToDate( 1e10f ); }
|
||||
#endif
|
||||
|
||||
inline bool ISteamNetworkingUtils::SetGlobalConfigValueInt32( ESteamNetworkingConfigValue eValue, int32 val ) { return SetConfigValue( eValue, k_ESteamNetworkingConfig_Global, 0, k_ESteamNetworkingConfig_Int32, &val ); }
|
||||
inline bool ISteamNetworkingUtils::SetGlobalConfigValueFloat( ESteamNetworkingConfigValue eValue, float val ) { return SetConfigValue( eValue, k_ESteamNetworkingConfig_Global, 0, k_ESteamNetworkingConfig_Float, &val ); }
|
||||
inline bool ISteamNetworkingUtils::SetGlobalConfigValueString( ESteamNetworkingConfigValue eValue, const char *val ) { return SetConfigValue( eValue, k_ESteamNetworkingConfig_Global, 0, k_ESteamNetworkingConfig_String, val ); }
|
||||
inline bool ISteamNetworkingUtils::SetConnectionConfigValueInt32( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, int32 val ) { return SetConfigValue( eValue, k_ESteamNetworkingConfig_Connection, hConn, k_ESteamNetworkingConfig_Int32, &val ); }
|
||||
inline bool ISteamNetworkingUtils::SetConnectionConfigValueFloat( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, float val ) { return SetConfigValue( eValue, k_ESteamNetworkingConfig_Connection, hConn, k_ESteamNetworkingConfig_Float, &val ); }
|
||||
inline bool ISteamNetworkingUtils::SetConnectionConfigValueString( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, const char *val ) { return SetConfigValue( eValue, k_ESteamNetworkingConfig_Connection, hConn, k_ESteamNetworkingConfig_String, val ); }
|
||||
|
||||
#if !defined( STEAMNETWORKINGSOCKETS_STATIC_LINK ) && defined( STEAMNETWORKINGSOCKETS_STEAM )
|
||||
inline void SteamNetworkingIPAddr::ToString( char *buf, size_t cbBuf, bool bWithPort ) const { SteamNetworkingUtils()->SteamNetworkingIPAddr_ToString( *this, buf, cbBuf, bWithPort ); }
|
||||
inline bool SteamNetworkingIPAddr::ParseString( const char *pszStr ) { return SteamNetworkingUtils()->SteamNetworkingIPAddr_ParseString( this, pszStr ); }
|
||||
inline void SteamNetworkingIdentity::ToString( char *buf, size_t cbBuf ) const { SteamNetworkingUtils()->SteamNetworkingIdentity_ToString( *this, buf, cbBuf ); }
|
||||
inline bool SteamNetworkingIdentity::ParseString( const char *pszStr ) { return SteamNetworkingUtils()->SteamNetworkingIdentity_ParseString( this, pszStr ); }
|
||||
#endif
|
||||
|
||||
#endif // ISTEAMNETWORKINGUTILS
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,69 @@
|
||||
//====== Copyright Valve Corporation, All rights reserved. ====================
|
||||
//
|
||||
// Backend functions to generate authorization tickets for steam datagram
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef STEAMDATAGRAM_TICKETGEN_H
|
||||
#define STEAMDATAGRAM_TICKETGEN_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
// Import some common stuff that is useful by both the client
|
||||
// and the backend ticket-generating authority.
|
||||
#include "steamdatagram_tickets.h"
|
||||
|
||||
#if defined( STEAMDATAGRAM_TICKETGEN_FOREXPORT )
|
||||
#define STEAMDATAGRAM_TICKET_INTERFACE DLL_EXPORT
|
||||
#elif defined( STEAMNETWORKINGSOCKETS_STATIC_LINK )
|
||||
#define STEAMDATAGRAM_TICKET_INTERFACE extern "C"
|
||||
#else
|
||||
#define STEAMDATAGRAM_TICKET_INTERFACE DLL_IMPORT
|
||||
#endif
|
||||
|
||||
struct SteamDatagramSignedTicketBlob
|
||||
{
|
||||
int m_sz;
|
||||
uint8 m_blob[ k_cbSteamDatagramMaxSerializedTicket ];
|
||||
};
|
||||
|
||||
/// Initialize ticket generation with an Ed25519 private key.
|
||||
/// See: https://ed25519.cr.yp.to/
|
||||
///
|
||||
/// Input buffer will be securely wiped.
|
||||
///
|
||||
/// You can generate an Ed25519 key using OpenSSH: ssh-keygen -t ed25519
|
||||
/// Or with our cert tool: steamnetworkingsockets_certtool gen_keypair
|
||||
///
|
||||
/// The private key should be a PEM-like block of text
|
||||
/// ("-----BEGIN OPENSSH PRIVATE KEY-----").
|
||||
/// Private keys encrypted with a password are not supported.
|
||||
///
|
||||
/// In order for signatures using this key to be accepted by the relay network,
|
||||
/// you need to send your public key to Valve. This key should be on a single line
|
||||
/// of text that begins with "ssh-ed25519". (The format used in the .ssh/authorized_keys
|
||||
/// file.)
|
||||
STEAMDATAGRAM_TICKET_INTERFACE bool SteamDatagram_InitTicketGenerator_Ed25519( void *pvPrivateKey, size_t cbPrivateKey );
|
||||
|
||||
/// Serialize the specified auth ticket and attach a signature.
|
||||
/// Returns false if you did something stupid like forgot to load a key.
|
||||
/// Will also fail if your ticket is too big. (Probably because you
|
||||
/// added too many extra fields.)
|
||||
///
|
||||
/// The resulting blob should be sent to the client, who will put it in
|
||||
/// their ticket cache using ISteamNetworkingSockets::ReceivedRelayAuthTicket
|
||||
STEAMDATAGRAM_TICKET_INTERFACE bool SteamDatagram_SerializeAndSignTicket( const SteamDatagramRelayAuthTicket &ticket, SteamDatagramSignedTicketBlob &outBlob, SteamNetworkingErrMsg &errMsg );
|
||||
|
||||
//
|
||||
// Some ping-related tools that don't have anything to do with tickets.
|
||||
// But it's something that a backend might find useful, so we're putting it in this library for now.
|
||||
//
|
||||
|
||||
/// Parse location string. Returns true on success
|
||||
STEAMDATAGRAM_TICKET_INTERFACE bool SteamDatagram_ParsePingLocation( const char *pszString, SteamNetworkPingLocation_t &outLocation );
|
||||
|
||||
/// Estimate ping time between two locations.
|
||||
STEAMDATAGRAM_TICKET_INTERFACE int SteamDatagram_EstimatePingBetweenTwoLocations( const SteamNetworkPingLocation_t &location1, const SteamNetworkPingLocation_t &location2 );
|
||||
|
||||
#endif // STEAMDATAGRAM_TICKETGEN_H
|
||||
@@ -0,0 +1,247 @@
|
||||
//====== Copyright Valve Corporation, All rights reserved. ====================
|
||||
//
|
||||
// Types and utilities for handling steam datagram tickets. These are
|
||||
// useful for both the client and the backend ticket generating authority.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef STEAMDATAGRAM_TICKETS_H
|
||||
#define STEAMDATAGRAM_TICKETS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef assert
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include "steamnetworkingtypes.h"
|
||||
|
||||
#if defined( VALVE_CALLBACK_PACK_SMALL )
|
||||
#pragma pack( push, 4 )
|
||||
#elif defined( VALVE_CALLBACK_PACK_LARGE )
|
||||
#pragma pack( push, 8 )
|
||||
#else
|
||||
#error "Must define VALVE_CALLBACK_PACK_SMALL or VALVE_CALLBACK_PACK_LARGE"
|
||||
#endif
|
||||
|
||||
/// Max length of serialized auth ticket. This is important so that we
|
||||
/// can ensure that we always fit into a single UDP datagram (along with
|
||||
/// other certs and signatures) and keep the implementation simple.
|
||||
const size_t k_cbSteamDatagramMaxSerializedTicket = 512;
|
||||
|
||||
/// Network-routable identifier for a service. This is an intentionally
|
||||
/// opaque byte blob. The relays know how to use this to forward it on
|
||||
/// to the intended destination, but otherwise clients really should not
|
||||
/// need to know what's inside. (Indeed, we don't really want them to
|
||||
/// know, as it could reveal information useful to an attacker.)
|
||||
#ifndef IS_STEAMDATAGRAMROUTER
|
||||
struct SteamDatagramHostedAddress
|
||||
{
|
||||
|
||||
// Size of data blob.
|
||||
int m_cbSize;
|
||||
|
||||
// Opaque data
|
||||
char m_data[ 128 ];
|
||||
|
||||
// Reset to empty state
|
||||
void Clear() { memset( this, 0, sizeof(*this) ); }
|
||||
|
||||
// Parse the data center out of the blob.
|
||||
SteamNetworkingPOPID GetPopID() const { return CalculateSteamNetworkingPOPIDFromString( m_data ); }
|
||||
|
||||
/// Set a dummy routing blob with a hardcoded IP:port. You should only use
|
||||
/// this in a dev environment, since the address is in plaintext!
|
||||
/// In production this information should come from the server,
|
||||
/// using ISteamNetworkingSockets::GetHostedDedicatedServerAddress
|
||||
void SetDevAddress( uint32 nIP, uint16 nPort, SteamNetworkingPOPID popid = 0 )
|
||||
{
|
||||
GetSteamNetworkingLocationPOPStringFromID( popid, m_data );
|
||||
m_cbSize = 4;
|
||||
m_data[m_cbSize++] = 1;
|
||||
m_data[m_cbSize++] = 1;
|
||||
m_data[m_cbSize++] = char(nPort);
|
||||
m_data[m_cbSize++] = char(nPort>>8);
|
||||
m_data[m_cbSize++] = char(nIP);
|
||||
m_data[m_cbSize++] = char(nIP>>8);
|
||||
m_data[m_cbSize++] = char(nIP>>16);
|
||||
m_data[m_cbSize++] = char(nIP>>24);
|
||||
}
|
||||
|
||||
/// Convert to/from std::string (or anything that acts like it).
|
||||
/// Useful for interfacing with google protobuf. It's a template
|
||||
/// mainly so that we don't have to include <string> in the header.
|
||||
/// Note: by "string", we don't mean that it's text. Ut's a binary
|
||||
/// blob, and it might have zeros in it. (std::string can handle that.)
|
||||
template <typename T> bool SetFromStdString( const T &str )
|
||||
{
|
||||
if ( str.length() >= sizeof(m_data) )
|
||||
{
|
||||
m_cbSize = 0;
|
||||
return false;
|
||||
}
|
||||
m_cbSize = (int)str.length();
|
||||
memcpy( m_data, str.c_str(), m_cbSize );
|
||||
return true;
|
||||
}
|
||||
template <typename T> void GetAsStdString( T *str ) const
|
||||
{
|
||||
str->assign( m_data, m_cbSize );
|
||||
}
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
/// Ticket used to gain access to the relay network.
|
||||
struct SteamDatagramRelayAuthTicket
|
||||
{
|
||||
SteamDatagramRelayAuthTicket() { Clear(); }
|
||||
|
||||
/// Reset all fields
|
||||
void Clear() { memset( this, 0, sizeof(*this) ); m_nRestrictToVirtualPort = -1; }
|
||||
|
||||
/// Identity of the gameserver we want to talk to. This is required.
|
||||
SteamNetworkingIdentity m_identityGameserver;
|
||||
|
||||
/// Identity of the person who was authorized. This is required.
|
||||
SteamNetworkingIdentity m_identityAuthorizedClient;
|
||||
|
||||
/// SteamID is authorized to send from a particular public IP. If this
|
||||
/// is 0, then the sender is not restricted to a particular IP.
|
||||
///
|
||||
/// Recommend to leave this set to zero.
|
||||
uint32 m_unPublicIP;
|
||||
|
||||
/// Time when the ticket expires. Recommended: take the current
|
||||
/// time and add 6 hours, or maybe a bit longer if your gameplay
|
||||
/// sessions are longer.
|
||||
///
|
||||
/// NOTE: relays may reject tickets with expiry times excessively
|
||||
/// far in the future, so contact us if you wish to use an expiry
|
||||
/// longer than, say, 24 hours.
|
||||
RTime32 m_rtimeTicketExpiry;
|
||||
|
||||
/// Routing information where the gameserver is listening for
|
||||
/// relayed traffic. You should fill this in when generating
|
||||
/// a ticket.
|
||||
///
|
||||
/// When generating tickets on your backend:
|
||||
/// - In production: The gameserver knows the proper routing
|
||||
/// information, so you need to call
|
||||
/// ISteamNetworkingSockets::GetHostedDedicatedServerAddress
|
||||
/// and send the info to your backend.
|
||||
/// - In development, you will need to provide public IP
|
||||
/// of the server using SteamDatagramServiceNetID::SetDevAddress.
|
||||
/// Relays need to be able to send UDP
|
||||
/// packets to this server. Since it's very likely that
|
||||
/// your server is behind a firewall/NAT, make sure that
|
||||
/// the address is the one that the outside world can use.
|
||||
/// The traffic from the relays will be "unsolicited", so
|
||||
/// stateful firewalls won't work -- you will probably have
|
||||
/// to set up an explicit port forward.
|
||||
/// On the client:
|
||||
/// - this field will always be blank.
|
||||
SteamDatagramHostedAddress m_routing;
|
||||
|
||||
/// App ID this is for. This is required, and should be the
|
||||
/// App ID the client is running. (Even if your gameserver
|
||||
/// uses a different App ID.)
|
||||
uint32 m_nAppID;
|
||||
|
||||
/// Restrict this ticket to be used for a particular virtual port?
|
||||
/// Set to -1 to allow any virtual port.
|
||||
///
|
||||
/// This is useful as a security measure, and also so the client will
|
||||
/// use the right ticket (which might have extra fields that are useful
|
||||
/// for proper analytics), if the client happens to have more than one
|
||||
/// appropriate ticket.
|
||||
///
|
||||
/// Note: if a client has more that one acceptable ticket, they will
|
||||
/// always use the one expiring the latest.
|
||||
int m_nRestrictToVirtualPort;
|
||||
|
||||
//
|
||||
// Extra fields.
|
||||
//
|
||||
// These are collected for backend analytics. For example, you might
|
||||
// send a MatchID so that all of the records for a particular match can
|
||||
// be located. Or send a game mode field so that you can compare
|
||||
// the network characteristics of different game modes.
|
||||
//
|
||||
// (At the time of this writing we don't have a way to expose the data
|
||||
// we collect to partners, but we hope to in the future so that you can
|
||||
// get visibility into network conditions.)
|
||||
//
|
||||
|
||||
struct ExtraField
|
||||
{
|
||||
enum EType
|
||||
{
|
||||
k_EType_String,
|
||||
k_EType_Int, // For most small integral values. Uses google protobuf sint64, so it's small on the wire. WARNING: In some places this value may be transmitted in JSON, in which case precision may be lost in backend analytics. Don't use this for an "identifier", use it for a scalar quantity.
|
||||
k_EType_Fixed64, // 64 arbitrary bits. This value is treated as an "identifier". In places where JSON format is used, it will be serialized as a string. No aggregation / analytics can be performed on this value.
|
||||
};
|
||||
int /* EType */ m_eType;
|
||||
char m_szName[28];
|
||||
|
||||
union {
|
||||
char m_szStringValue[128];
|
||||
int64 m_nIntValue;
|
||||
uint64 m_nFixed64Value;
|
||||
};
|
||||
};
|
||||
enum { k_nMaxExtraFields = 16 };
|
||||
int m_nExtraFields;
|
||||
ExtraField m_vecExtraFields[ k_nMaxExtraFields ];
|
||||
|
||||
/// Helper to add an extra field in a single call
|
||||
void AddExtraField_Int( const char *pszName, int64 val )
|
||||
{
|
||||
ExtraField *p = AddExtraField( pszName, ExtraField::k_EType_Int );
|
||||
if ( p )
|
||||
p->m_nIntValue = val;
|
||||
}
|
||||
void AddExtraField_Fixed64( const char *pszName, uint64 val )
|
||||
{
|
||||
ExtraField *p = AddExtraField( pszName, ExtraField::k_EType_Fixed64 );
|
||||
if ( p )
|
||||
p->m_nFixed64Value = val;
|
||||
}
|
||||
void AddExtraField_String( const char *pszName, const char *val )
|
||||
{
|
||||
ExtraField *p = AddExtraField( pszName, ExtraField::k_EType_String );
|
||||
if ( p )
|
||||
{
|
||||
size_t l = strlen( val );
|
||||
if ( l > sizeof(p->m_szStringValue)-1 )
|
||||
l = sizeof(p->m_szStringValue)-1;
|
||||
memcpy( p->m_szStringValue, val, l );
|
||||
p->m_szStringValue[l] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ExtraField *AddExtraField( const char *pszName, ExtraField::EType eType )
|
||||
{
|
||||
if ( m_nExtraFields >= k_nMaxExtraFields )
|
||||
{
|
||||
assert( false );
|
||||
return nullptr;
|
||||
}
|
||||
ExtraField *p = &m_vecExtraFields[ m_nExtraFields++ ];
|
||||
p->m_eType = eType;
|
||||
|
||||
size_t l = strlen( pszName );
|
||||
if ( l > sizeof(p->m_szName)-1 )
|
||||
l = sizeof(p->m_szName)-1;
|
||||
memcpy( p->m_szName, pszName, l );
|
||||
p->m_szName[l] = '\0';
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif // STEAMDATAGRAM_TICKETS_H
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user