2019-04-14 00:21:56 +08:00
//====== Copyright Valve Corporation, All rights reserved. ====================
//
// Purpose: misc networking utilities
//
//=============================================================================
# ifndef ISTEAMNETWORKINGUTILS
# define ISTEAMNETWORKINGUTILS
# ifdef STEAM_WIN32
# pragma once
# endif
# include <stdint.h>
# include "steamnetworkingtypes.h"
struct SteamDatagramRelayAuthTicket ;
2019-07-28 21:02:09 +08:00
struct SteamRelayNetworkStatus_t ;
2019-04-14 00:21:56 +08:00
//-----------------------------------------------------------------------------
/// Misc networking utilities for checking the local networking environment
/// and estimating pings.
class ISteamNetworkingUtils
{
public :
2019-12-10 01:49:55 +08:00
//
// Efficient message sending
//
/// Allocate and initialize a message object. Usually the reason
/// you call this is to pass it to ISteamNetworkingSockets::SendMessages.
/// The returned object will have all of the relevant fields cleared to zero.
///
/// Optionally you can also request that this system allocate space to
/// hold the payload itself. If cbAllocateBuffer is nonzero, the system
/// will allocate memory to hold a payload of at least cbAllocateBuffer bytes.
/// m_pData will point to the allocated buffer, m_cbSize will be set to the
/// size, and m_pfnFreeData will be set to the proper function to free up
/// the buffer.
///
/// If cbAllocateBuffer=0, then no buffer is allocated. m_pData will be NULL,
/// m_cbSize will be zero, and m_pfnFreeData will be NULL. You will need to
/// set each of these.
virtual SteamNetworkingMessage_t * AllocateMessage ( int cbAllocateBuffer ) = 0 ;
//
// Access to Steam Datagram Relay (SDR) network
//
2019-04-14 00:21:56 +08:00
# ifdef STEAMNETWORKINGSOCKETS_ENABLE_SDR
//
2019-07-28 21:02:09 +08:00
// Initialization and status check
2019-04-14 00:21:56 +08:00
//
2020-03-26 01:43:23 +08:00
/// If you know that you are going to be using the relay network (for example,
/// because you anticipate making P2P connections), call this to initialize the
/// relay network. If you do not call this, the initialization will
/// be delayed until the first time you use a feature that requires access
/// to the relay network, which will delay that first access.
///
/// You can also call this to force a retry if the previous attempt has failed.
/// Performing any action that requires access to the relay network will also
/// trigger a retry, and so calling this function is never strictly necessary,
/// but it can be useful to call it a program launch time, if access to the
/// relay network is anticipated.
2019-04-14 00:21:56 +08:00
///
2019-07-28 21:02:09 +08:00
/// Use GetRelayNetworkStatus or listen for SteamRelayNetworkStatus_t
/// callbacks to know when initialization has completed.
2019-04-14 00:21:56 +08:00
/// Typically initialization completes in a few seconds.
///
2019-07-28 21:02:09 +08:00
/// Note: dedicated servers hosted in known data centers 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
2019-04-14 00:21:56 +08:00
/// a "client" and this should be called.
2019-07-28 21:02:09 +08:00
inline void InitRelayNetworkAccess ( ) ;
/// Fetch current status of the relay network.
///
/// SteamRelayNetworkStatus_t is also a callback. It will be triggered on
/// both the user and gameserver interfaces any time the status changes, or
/// ping measurement starts or stops.
///
/// SteamRelayNetworkStatus_t::m_eAvail is returned. If you want
/// more details, you can pass a non-NULL value.
virtual ESteamNetworkingAvailability GetRelayNetworkStatus ( SteamRelayNetworkStatus_t * pDetails ) = 0 ;
2019-04-14 00:21:56 +08:00
//
// "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.
2019-07-28 21:02:09 +08:00
// We have a separate library you can use on your app's matchmaking/coordinating
// server to manipulate these objects. (See steamdatagram_gamecoordinator.h)
2019-04-14 00:21:56 +08:00
/// 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
2019-07-28 21:02:09 +08:00
/// you call this very soon after calling InitRelayNetworkAccess,
2019-04-14 00:21:56 +08:00
/// 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 ;
/// 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.)
2019-07-28 21:02:09 +08:00
///
/// You can use GetRelayNetworkStatus or listen for SteamRelayNetworkStatus_t
/// to know when ping measurement completes.
2019-04-14 00:21:56 +08:00
virtual bool CheckPingDataUpToDate ( float flMaxAgeSeconds ) = 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.
///
2020-06-15 04:04:43 +08:00
/// The value here controls the detail level for most messages. You can control the
/// detail level for various subsystems (perhaps only for certain connections) by
/// adjusting the configuration values k_ESteamNetworkingConfig_LogLevel_Xxxxx.
///
2019-04-14 00:21:56 +08:00
/// Except when debugging, you should only use k_ESteamNetworkingSocketsDebugOutputType_Msg
/// or k_ESteamNetworkingSocketsDebugOutputType_Warning. For best performance, do NOT
2019-12-10 01:49:55 +08:00
/// request a high detail level and then filter out messages in your callback. This incurs
/// all of the expense of formatting the messages, which are then discarded. Setting a high
/// priority value (low numeric value) here allows the library to avoid doing this work.
2019-04-14 00:21:56 +08:00
///
/// 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!
2019-12-10 01:49:55 +08:00
/// - pArg: Value to set it to. You can pass NULL to remove a non-global setting at this scope,
2019-04-14 00:21:56 +08:00
/// 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 ;
2019-12-10 01:49:55 +08:00
/// Set a configuration value, using a struct to pass the value.
/// (This is just a convenience shortcut; see below for the implementation and
/// a little insight into how SteamNetworkingConfigValue_t is used when
/// setting config options during listen socket and connection creation.)
bool SetConfigValueStruct ( const SteamNetworkingConfigValue_t & opt , ESteamNetworkingConfigScope eScopeType , intptr_t scopeObj ) ;
2019-04-14 00:21:56 +08:00
/// 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.
2019-12-10 01:49:55 +08:00
///
/// See k_ESteamNetworkingConfig_EnumerateDevVars for some more info about "dev" variables,
/// which are usually excluded from the set of variables enumerated using this function.
2019-04-14 00:21:56 +08:00
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
} ;
2019-12-10 01:49:55 +08:00
# define STEAMNETWORKINGUTILS_INTERFACE_VERSION "SteamNetworkingUtils003"
2019-04-14 00:21:56 +08:00
// Global accessor.
# ifdef STEAMNETWORKINGSOCKETS_STANDALONELIB
// Standalone lib
STEAMNETWORKINGSOCKETS_INTERFACE ISteamNetworkingUtils * SteamNetworkingUtils_Lib ( ) ;
inline ISteamNetworkingUtils * SteamNetworkingUtils ( ) { return SteamNetworkingUtils_Lib ( ) ; }
# else
# ifdef NETWORKSOCKETS_DLL
# define SteamNetworkingUtils() SteamNetworkingUtilsX()
# endif
// Steamworks SDK
inline ISteamNetworkingUtils * SteamNetworkingUtils ( ) ;
2019-12-10 01:49:55 +08:00
STEAM_DEFINE_INTERFACE_ACCESSOR ( ISteamNetworkingUtils * , SteamNetworkingUtils ,
/* Prefer user version of the interface. But if it isn't found, then use
gameserver one . Yes , this is a completely terrible hack */
SteamInternal_FindOrCreateUserInterface ( 0 , STEAMNETWORKINGUTILS_INTERFACE_VERSION ) ?
SteamInternal_FindOrCreateUserInterface ( 0 , STEAMNETWORKINGUTILS_INTERFACE_VERSION ) :
2020-03-26 01:43:23 +08:00
SteamInternal_FindOrCreateGameServerInterface ( 0 , STEAMNETWORKINGUTILS_INTERFACE_VERSION ) ,
" global " ,
STEAMNETWORKINGUTILS_INTERFACE_VERSION
2019-12-10 01:49:55 +08:00
)
2019-04-14 00:21:56 +08:00
# endif
2019-07-28 21:02:09 +08:00
/// A struct used to describe our readiness to use the relay network.
/// To do this we first need to fetch the network configuration,
/// which describes what POPs are available.
struct SteamRelayNetworkStatus_t
{
enum { k_iCallback = k_iSteamNetworkingUtilsCallbacks + 1 } ;
/// Summary status. When this is "current", initialization has
/// completed. Anything else means you are not ready yet, or
/// there is a significant problem.
ESteamNetworkingAvailability m_eAvail ;
/// Nonzero if latency measurement is in progress (or pending,
/// awaiting a prerequisite).
int m_bPingMeasurementInProgress ;
/// Status obtaining the network config. This is a prerequisite
/// for relay network access.
///
/// Failure to obtain the network config almost always indicates
/// a problem with the local internet connection.
ESteamNetworkingAvailability m_eAvailNetworkConfig ;
/// Current ability to communicate with ANY relay. Note that
/// the complete failure to communicate with any relays almost
/// always indicates a problem with the local Internet connection.
/// (However, just because you can reach a single relay doesn't
/// mean that the local connection is in perfect health.)
ESteamNetworkingAvailability m_eAvailAnyRelay ;
/// Non-localized English language status. For diagnostic/debugging
/// purposes only.
char m_debugMsg [ 256 ] ;
} ;
2020-06-15 04:04:43 +08:00
/// Utility class for printing a SteamNetworkingIdentity.
/// E.g. printf( "Identity is '%s'\n", SteamNetworkingIdentityRender( identity ).c_str() );
struct SteamNetworkingIdentityRender
{
SteamNetworkingIdentityRender ( const SteamNetworkingIdentity & x ) { x . ToString ( buf , sizeof ( buf ) ) ; }
inline const char * c_str ( ) const { return buf ; }
private :
char buf [ SteamNetworkingIdentity : : k_cchMaxString ] ;
} ;
/// Utility class for printing a SteamNetworkingIPAddrRender.
struct SteamNetworkingIPAddrRender
{
SteamNetworkingIPAddrRender ( const SteamNetworkingIPAddr & x , bool bWithPort = true ) { x . ToString ( buf , sizeof ( buf ) , bWithPort ) ; }
inline const char * c_str ( ) const { return buf ; }
private :
char buf [ SteamNetworkingIPAddr : : k_cchMaxString ] ;
} ;
2019-07-28 21:02:09 +08:00
2019-04-14 00:21:56 +08:00
///////////////////////////////////////////////////////////////////////////////
//
// Internal stuff
# ifdef STEAMNETWORKINGSOCKETS_ENABLE_SDR
2019-07-28 21:02:09 +08:00
inline void ISteamNetworkingUtils : : InitRelayNetworkAccess ( ) { CheckPingDataUpToDate ( 1e10 f ) ; }
2019-04-14 00:21:56 +08:00
# 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 ) ; }
2019-12-10 01:49:55 +08:00
inline bool ISteamNetworkingUtils : : SetConfigValueStruct ( const SteamNetworkingConfigValue_t & opt , ESteamNetworkingConfigScope eScopeType , intptr_t scopeObj )
{
// Locate the argument. Strings are a special case, since the
// "value" (the whole string buffer) doesn't fit in the struct
const void * pVal = ( opt . m_eDataType = = k_ESteamNetworkingConfig_String ) ? ( const void * ) opt . m_val . m_string : ( const void * ) & opt . m_val ;
return SetConfigValue ( opt . m_eValue , eScopeType , scopeObj , opt . m_eDataType , pVal ) ;
}
2019-04-14 00:21:56 +08:00
2019-07-28 21:02:09 +08:00
# if !defined( STEAMNETWORKINGSOCKETS_STATIC_LINK ) && defined( STEAMNETWORKINGSOCKETS_STEAMCLIENT )
2019-04-14 00:21:56 +08:00
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
# ifdef NETWORKSOCKETS_DLL
# undef SteamNetworkingUtils
# endif
# endif // ISTEAMNETWORKINGUTILS