goldberg_emulator/sdk_includes/steamdatagram_tickets.h

287 lines
9.7 KiB
C++

//====== 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 STEAM_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.)
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. It'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 );
}
};
/// 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 NULL;
}
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)
/// Max size of user data blob
const size_t k_cbMaxSteamDatagramGameCoordinatorServerLoginAppData = 2048;
/// Max size of serialized data blob
const size_t k_cbMaxSteamDatagramGameCoordinatorServerLoginSerialized = 4096;
/// Structure that describes a gameserver attempting to authenticate
/// with your central server allocator / matchmaking service ("game coordinator").
/// This is useful because the game coordinator needs to know:
///
/// - What data center is the gameserver running in?
/// - The routing blob of the gameserver
/// - Is the gameserver actually trusted?
///
/// Using this structure, you can securely communicate this information
/// to your server, and you can do this WITHOUT maintaining any
/// whitelists or tables of IP addresses.
///
/// See ISteamNetworkingSockets::GetGameCoordinatorServerLogin
struct SteamDatagramGameCoordinatorServerLogin
{
/// Server's identity
SteamNetworkingIdentity m_identity;
/// Routing info. Note that this includes the POPID
SteamDatagramHostedAddress m_routing;
/// AppID that the server thinks it is running
AppId_t m_nAppID;
/// Unix timestamp when this was generated
RTime32 m_rtime;
/// Size of application data
int m_cbAppData;
/// Application data. This is any additional information
/// that you need to identify the server not contained above.
/// (E.g. perhaps a public IP as seen by the coordinator service.)
char m_appData[ k_cbMaxSteamDatagramGameCoordinatorServerLoginAppData ];
};
#endif // STEAMDATAGRAM_TICKETS_H