Skip to content

Commit

Permalink
Sync up with work internally in the Steam code.
Browse files Browse the repository at this point in the history
* Interface changes:

Replaced all CSteamIDs with SteamNetworkingIdentity, which is an abstract concept.

Added IPv6 support.  This has not been tested at this time, but all the basics
are there and any issues should be small bugfixes.

Improved and standardized connection debug names.  You can set a debug name for a connection,
and the full debug string, which includes the Connection ID, transport-specific data, and
your name (if any) are printed consistently in logging messages and this name is also present
in SteamNetConnectionInfo_t.  Connection handles are now the same as the local ConnectionID
on the wire.  This makes debugging a lot easier.

GetListenSocketInfo renamed to GetListenSocketAddress and now actually does something.

Split out P2P and ordinary UDP listen sockets into two seperate objects.  This simplifies
the opensource code (since P2P is not support)

* Misc internal code cleanup:

Broke up CCrypto monolith, so that we can more easily and cleanly:
- Share what we really want to share with Steam.  Mainly some text parsing of keys, etc.
- Replace the actual crypto primitives with another provider (e.g. libsodium)

Delete a whole bunch of unused and messy cruft that was left when we ripped this out from Steam,
as well as code and messages specific to relayed connections (supported only on Steam)

Switch a bunch of maps to hashmaps instead of red/black tree maps.  The CUtlHashMap class comes
from Steam and is designed to scale to very large size (N in the millions), and if the table
needs to be rehashed, the cost is amortized instead of triggering a large cost all at once.
This functionality is not needed.  Nor do we need stable handles, so it would be better to use
a table based on open addressing.  That would be a small optimization and also allow us to
get rid of bitstring.*, which unfortunately got added as a result of this change.

Added standalone IPv6 address parsing files: ipv6text.*.  These are plain C and do not have
any dependencies, and could be split out, since they are independenctly useful and, unlike
all of our other utility routes (e.g. tier0, tier1, etc), actually worthy of being used
outside of Valve.
  • Loading branch information
zpostfacto committed Jan 3, 2019
1 parent 145199a commit d07b7b2
Show file tree
Hide file tree
Showing 54 changed files with 6,350 additions and 9,079 deletions.
File renamed without changes.
File renamed without changes.
34 changes: 20 additions & 14 deletions include/steam/steamtypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,20 +90,20 @@ typedef unsigned int uintp;
# define CLANG_ATTR(ATTR)

This comment has been minimized.

Copy link
@rlabrecque

rlabrecque Jan 3, 2019

Can you guys add the STEAM_ prefix to this too? 🙏

This comment has been minimized.

Copy link
@zpostfacto

zpostfacto Jan 3, 2019

Author Contributor

Sure thing.

#endif

#define METHOD_DESC(DESC) CLANG_ATTR( "desc:" #DESC ";" )
#define IGNOREATTR() CLANG_ATTR( "ignore" )
#define OUT_STRUCT() CLANG_ATTR( "out_struct: ;" )
#define OUT_STRING() CLANG_ATTR( "out_string: ;" )
#define OUT_ARRAY_CALL(COUNTER,FUNCTION,PARAMS) CLANG_ATTR( "out_array_call:" #COUNTER "," #FUNCTION "," #PARAMS ";" )
#define OUT_ARRAY_COUNT(COUNTER, DESC) CLANG_ATTR( "out_array_count:" #COUNTER ";desc:" #DESC )
#define ARRAY_COUNT(COUNTER) CLANG_ATTR( "array_count:" #COUNTER ";" )
#define ARRAY_COUNT_D(COUNTER, DESC) CLANG_ATTR( "array_count:" #COUNTER ";desc:" #DESC )
#define BUFFER_COUNT(COUNTER) CLANG_ATTR( "buffer_count:" #COUNTER ";" )
#define OUT_BUFFER_COUNT(COUNTER) CLANG_ATTR( "out_buffer_count:" #COUNTER ";" )
#define OUT_STRING_COUNT(COUNTER) CLANG_ATTR( "out_string_count:" #COUNTER ";" )
#define DESC(DESC) CLANG_ATTR("desc:" #DESC ";")
#define CALL_RESULT(RESULT_TYPE) CLANG_ATTR("callresult:" #RESULT_TYPE ";")
#define CALL_BACK(RESULT_TYPE) CLANG_ATTR("callback:" #RESULT_TYPE ";")
#define STEAM_METHOD_DESC(DESC) CLANG_ATTR( "desc:" #DESC ";" )
#define STEAM_IGNOREATTR() CLANG_ATTR( "ignore" )
#define STEAM_OUT_STRUCT() CLANG_ATTR( "out_struct: ;" )
#define STEAM_OUT_STRING() CLANG_ATTR( "out_string: ;" )
#define STEAM_OUT_ARRAY_CALL(COUNTER,FUNCTION,PARAMS) CLANG_ATTR( "out_array_call:" #COUNTER "," #FUNCTION "," #PARAMS ";" )
#define STEAM_OUT_ARRAY_COUNT(COUNTER, DESC) CLANG_ATTR( "out_array_count:" #COUNTER ";desc:" #DESC )
#define STEAM_ARRAY_COUNT(COUNTER) CLANG_ATTR( "array_count:" #COUNTER ";" )
#define STEAM_ARRAY_COUNT_D(COUNTER, DESC) CLANG_ATTR( "array_count:" #COUNTER ";desc:" #DESC )
#define STEAM_BUFFER_COUNT(COUNTER) CLANG_ATTR( "buffer_count:" #COUNTER ";" )
#define STEAM_OUT_BUFFER_COUNT(COUNTER) CLANG_ATTR( "out_buffer_count:" #COUNTER ";" )
#define STEAM_OUT_STRING_COUNT(COUNTER) CLANG_ATTR( "out_string_count:" #COUNTER ";" )
#define STEAM_DESC(DESC) CLANG_ATTR("desc:" #DESC ";")
#define STEAM_CALL_RESULT(RESULT_TYPE) CLANG_ATTR("callresult:" #RESULT_TYPE ";")
#define STEAM_CALL_BACK(RESULT_TYPE) CLANG_ATTR("callback:" #RESULT_TYPE ";")

const int k_cubSaltSize = 8;
typedef uint8 Salt_t[ k_cubSaltSize ];
Expand Down Expand Up @@ -176,6 +176,12 @@ const PartnerId_t k_uPartnerIdInvalid = 0;
typedef uint64 ManifestId_t;
const ManifestId_t k_uManifestIdInvalid = 0;

// ID for cafe sites
typedef uint64 SiteId_t;
const SiteId_t k_ulSiteIdInvalid = 0;

// Party Beacon ID
typedef uint64 PartyBeaconID_t;
const PartyBeaconID_t k_ulPartyBeaconIdInvalid = 0;

#endif // STEAMTYPES_H
126 changes: 67 additions & 59 deletions include/steamnetworkingsockets/isteamnetworkingsockets.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,43 +47,61 @@ class ISteamNetworkingSockets
{
public:

/// Creates a "server" socket that listens for clients to connect to, either by calling
/// ConnectSocketBySteamID or ConnectSocketByIPv4Address.
///
/// nSteamConnectVirtualPort specifies how clients can connect to this socket using
/// ConnectBySteamID. A negative value indicates that this functionality is
/// disabled and clients must connect by IP address. 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
/// nSteamConnectVirtualPort should be a small integer constant unique to each listen socket
/// you create.
///
/// In the open-source version of this API, you must pass -1 for nSteamConnectVirtualPort
///
/// If you want clients to connect to you by your IPv4 addresses using
/// ConnectByIPv4Address, then you must set nPort to be nonzero. Steam will
/// bind a UDP socket to the specified local port, and clients will send packets using
/// ordinary IP routing. It's up to you to take care of NAT, protecting your server
/// from DoS, etc. If you don't need clients to connect to you by IP, then set nPort=0.
/// Use nIP if you wish to bind to a particular local interface. Typically you will use 0,
/// which means to listen on all interfaces, and accept the default outbound IP address.
/// If nPort is zero, then nIP must also be zero.
/// Creates a "server" socket that listens for clients to connect to by
/// calling ConnectByIPAddress, over order 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.
///
/// A SocketStatusCallback_t callback when another client attempts a connection.
virtual HSteamListenSocket CreateListenSocket( int nSteamConnectVirtualPort, uint32 nIP, uint16 nPort ) = 0;
virtual HSteamListenSocket CreateListenSocketIP( const SteamNetworkingIPAddr &localAddress ) = 0;

/// Creates a connection and begins talking to a remote destination. The remote host
/// must be listening with a matching call to CreateListenSocket.
/// 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 CreateListenSocket 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.
///
/// Use ConnectBySteamID to connect using the SteamID (client or game server) as the network address.
/// Use ConnectByIPv4Address to connect by IP address.
/// If the server does not have any identity configured, then heir 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.
///
/// A SteamNetConnectionStatusChangedCallback_t callback will be triggered when we start connecting,
/// and then another one on timeout or successful 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;

#ifndef STEAMNETWORKINGSOCKETS_OPENSOURCE
virtual HSteamNetConnection ConnectBySteamID( CSteamID steamIDTarget, int nVirtualPort ) = 0;
/// 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.
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.
virtual HSteamNetConnection ConnectP2P( const SteamNetworkingIdentity &identityRemote, int nVirtualPort ) = 0;
#endif
virtual HSteamNetConnection ConnectByIPv4Address( uint32 nIP, uint16 nPort ) = 0;

/// Accept an incoming connection that has been received on a listen socket.
///
Expand Down Expand Up @@ -143,16 +161,9 @@ class ISteamNetworkingSockets
/// ignored.
virtual bool CloseConnection( HSteamNetConnection hPeer, int nReason, const char *pszDebug, bool bEnableLinger ) = 0;

/// Destroy a listen socket, and all the client sockets generated by accepting connections
/// on the listen socket.
///
/// pszNotifyRemoteReason determines what cleanup actions are performed on the client
/// sockets being destroyed. (See DestroySocket for more details.)
///
/// Note that if cleanup is requested and you have requested the listen socket bound to a
/// particular local port to facilitate direct UDP/IPv4 connections, then the underlying UDP
/// socket must remain open until all clients have been cleaned up.
virtual bool CloseListenSocket( HSteamListenSocket hSocket, const char *pszNotifyRemoteReason ) = 0;
/// Destroy a listen socket. All the client sockets generated by accepting connections
/// on the listen socket are closed ungracefully.
virtual bool CloseListenSocket( HSteamListenSocket hSocket ) = 0;

/// Set connection user data. Returns false if the handle is invalid.
virtual bool SetConnectionUserData( HSteamNetConnection hPeer, int64 nUserData ) = 0;
Expand Down Expand Up @@ -187,15 +198,15 @@ class ISteamNetworkingSockets
/// 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
/// messages sizes, and so if your code sends many small chunks
/// 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.
virtual EResult SendMessageToConnection( HSteamNetConnection hConn, const void *pData, uint32 cbData, ESteamNetworkingSendType eSendType ) = 0;

/// If Nagle is enabled (its on by default) then when calling
/// SendMessageToConnection the message will be queued up the Nagle time
/// before being sent to merge small messages into the same packet.
/// 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.
///
/// Call this function to flush any queued messages and send them immediately
/// on the next transmission time (often that means right now).
Expand All @@ -209,10 +220,9 @@ class ISteamNetworkingSockets
/// 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).
///
/// FIXME - We're still debating the exact set of guarantees for unreliable, so this might change.
/// Unreliable messages may not be received. The order of delivery of unreliable messages
/// is NOT specified. They may be received out of order with respect to each other or
/// reliable messages. They may be received multiple times!
/// 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 Release() to each of them free up resources
/// after you are done. It is safe to keep the object alive for a little while (put it
Expand Down Expand Up @@ -242,17 +252,15 @@ class ISteamNetworkingSockets
/// 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.
/// >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 information about the listen socket.
/// Returns local IP and port that a listen socket created using CreateListenSocketIP is bound to.
///
/// *pnIP and *pnPort will be 0 if the socket is set to listen for connections based
/// on SteamID only. If your listen socket accepts connections on IPv4, then both
/// fields will return nonzero, even if you originally passed a zero IP. However,
/// note that the address returned may be a private address (e.g. 10.0.0.x or 192.168.x.x),
/// and may not be reachable by a general host on the Internet.
virtual bool GetListenSocketInfo( HSteamListenSocket hSocket, uint32 *pnIP, uint16 *pnPort ) = 0;
/// 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
Expand Down Expand Up @@ -292,15 +300,15 @@ class ISteamNetworkingSockets
///
/// Typically this is useful just to confirm that you have a ticket, before you
/// call ConnectToHostedDedicatedServer to connect to the server.
virtual int FindRelayAuthTicketForServer( CSteamID steamID, int nVirtualPort, SteamDatagramRelayAuthTicket *pOutParsedTicket ) = 0;
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 should have received a ticket for this server, or else this connect call 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.
virtual HSteamNetConnection ConnectToHostedDedicatedServer( CSteamID steamIDTarget, int nVirtualPort ) = 0;
virtual HSteamNetConnection ConnectToHostedDedicatedServer( const SteamNetworkingIdentity &identityTarget, int nVirtualPort ) = 0;

//
// Servers hosted in Valve data centers
Expand Down Expand Up @@ -408,7 +416,7 @@ STEAMNETWORKINGSOCKETS_INTERFACE void GameNetworkingSockets_Kill();
typedef void ( S_CALLTYPE *FSteamAPI_UnregisterCallback)( class CCallbackBase *pCallback );
typedef void ( S_CALLTYPE *FSteamAPI_RegisterCallResult)( class CCallbackBase *pCallback, SteamAPICall_t hAPICall );
typedef void ( S_CALLTYPE *FSteamAPI_UnregisterCallResult)( class CCallbackBase *pCallback, SteamAPICall_t hAPICall );
STEAMNETWORKINGSOCKETS_INTERFACE void SteamDatagramClient_SetPartner( const char *pszLauncher, int iLegcayPartnerMask ); // Call this before SteamDatagramClient_Init
STEAMNETWORKINGSOCKETS_INTERFACE void SteamDatagramClient_SetLauncher( const char *pszLauncher ); // Call this before SteamDatagramClient_Init
STEAMNETWORKINGSOCKETS_INTERFACE void SteamDatagramClient_Internal_SteamAPIKludge( FSteamAPI_RegisterCallback fnRegisterCallback, FSteamAPI_UnregisterCallback fnUnregisterCallback, FSteamAPI_RegisterCallResult fnRegisterCallResult, FSteamAPI_UnregisterCallResult fnUnregisterCallResult );
STEAMNETWORKINGSOCKETS_INTERFACE bool SteamDatagramClient_Init_InternalV6( SteamDatagramErrMsg &errMsg, FSteamInternal_CreateInterface fnCreateInterface, HSteamUser hSteamUser, HSteamPipe hSteamPipe );
STEAMNETWORKINGSOCKETS_INTERFACE bool SteamDatagramServer_Init_Internal( SteamDatagramErrMsg &errMsg, FSteamInternal_CreateInterface fnCreateInterface, HSteamUser hSteamUser, HSteamPipe hSteamPipe );
Expand Down

0 comments on commit d07b7b2

Please sign in to comment.