This repository has been archived on 2024-06-13. You can view files and clone it, but cannot push or open issues or pull requests.
2020-08-04 13:13:01 -04:00

372 lines
18 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: interface to steam managing network connections between game clients
// & servers
//
//=============================================================================
#ifndef ISTEAMNETWORKING
#define ISTEAMNETWORKING
#ifdef _WIN32
#pragma once
#endif
#include "steamclientpublic.h"
#include "steamtypes.h"
// list of possible errors returned by SendP2PPacket() API
// these will be posted in the P2PSessionConnectFail_t callback
enum EP2PSessionError {
k_EP2PSessionErrorNone = 0,
k_EP2PSessionErrorNotRunningApp = 1, // target is not running the same game
k_EP2PSessionErrorNoRightsToApp =
2, // local user doesn't own the app that is running
k_EP2PSessionErrorDestinationNotLoggedIn =
3, // target user isn't connected to Steam
k_EP2PSessionErrorTimeout =
4, // target isn't responding, perhaps not calling
// AcceptP2PSessionWithUser() corporate firewalls can also block
// this (NAT traversal is not firewall traversal) make sure that UDP
// ports 3478, 4379, and 4380 are open in an outbound direction
k_EP2PSessionErrorMax = 5
};
// SendP2PPacket() send types
// Typically k_EP2PSendUnreliable is what you want for UDP-like packets,
// k_EP2PSendReliable for TCP-like packets
enum EP2PSend {
// Basic UDP send. Packets can't be bigger than 1200 bytes (your typical MTU
// size). Can be lost, or arrive out of order (rare). The sending API does
// have some knowledge of the underlying connection, so if there is no
// NAT-traversal accomplished or there is a recognized adjustment happening
// on the connection, the packet will be batched until the connection is
// open again.
k_EP2PSendUnreliable = 0,
// As above, but if the underlying p2p connection isn't yet established the
// packet will just be thrown away. Using this on the first packet sent to a
// remote host almost guarantees the packet will be dropped. This is only
// really useful for kinds of data that should never buffer up, i.e. voice
// payload packets
k_EP2PSendUnreliableNoDelay = 1,
// Reliable message send. Can send up to 1MB of data in a single message.
// Does fragmentation/re-assembly of messages under the hood, as well as a
// sliding window for efficient sends of large chunks of data.
k_EP2PSendReliable = 2,
// As above, but applies the Nagle algorithm to the send - sends will
// accumulate until the current MTU size (typically ~1200 bytes, but can
// change) or ~200ms has passed (Nagle algorithm). Useful if you want to
// send a set of smaller messages but have the coalesced into a single
// packet Since the reliable stream is all ordered, you can do several small
// message sends with k_EP2PSendReliableWithBuffering and then do a normal
// k_EP2PSendReliable to force all the buffered data to be sent.
k_EP2PSendReliableWithBuffering = 3,
};
// connection state to a specified user, returned by GetP2PSessionState()
// this is under-the-hood info about what's going on with a SendP2PPacket(),
// shouldn't be needed except for debuggin
#if defined(VALVE_CALLBACK_PACK_SMALL)
#pragma pack(push, 4)
#elif defined(VALVE_CALLBACK_PACK_LARGE)
#pragma pack(push, 8)
#else
#error isteamclient.h must be included
#endif
struct P2PSessionState_t {
uint8 m_bConnectionActive; // true if we've got an active open connection
uint8 m_bConnecting; // true if we're currently trying to establish a
// connection
uint8 m_eP2PSessionError; // last error recorded (see enum above)
uint8 m_bUsingRelay; // true if it's going through a relay server (TURN)
int32 m_nBytesQueuedForSend;
int32 m_nPacketsQueuedForSend;
uint32
m_nRemoteIP; // potential IP:Port of remote host. Could be TURN server.
uint16 m_nRemotePort; // Only exists for compatibility with older
// authentication api's
};
#pragma pack(pop)
// handle to a socket
typedef uint32 SNetSocket_t; // CreateP2PConnectionSocket()
typedef uint32 SNetListenSocket_t; // CreateListenSocket()
// connection progress indicators, used by CreateP2PConnectionSocket()
enum ESNetSocketState {
k_ESNetSocketStateInvalid = 0,
// communication is valid
k_ESNetSocketStateConnected = 1,
// states while establishing a connection
k_ESNetSocketStateInitiated =
10, // the connection state machine has started
// p2p connections
k_ESNetSocketStateLocalCandidatesFound =
11, // we've found our local IP info
k_ESNetSocketStateReceivedRemoteCandidates =
12, // we've received information from the remote machine, via the
// Steam back-end, about their IP info
// direct connections
k_ESNetSocketStateChallengeHandshake =
15, // we've received a challenge packet from the server
// failure states
k_ESNetSocketStateDisconnecting =
21, // the API shut it down, and we're in the process of telling the
// other end
k_ESNetSocketStateLocalDisconnect =
22, // the API shut it down, and we've completed shutdown
k_ESNetSocketStateTimeoutDuringConnect =
23, // we timed out while trying to creating the connection
k_ESNetSocketStateRemoteEndDisconnected =
24, // the remote end has disconnected from us
k_ESNetSocketStateConnectionBroken =
25, // connection has been broken; either the other end has disappeared
// or our local network connection has broke
};
// describes how the socket is currently connected
enum ESNetSocketConnectionType {
k_ESNetSocketConnectionTypeNotConnected = 0,
k_ESNetSocketConnectionTypeUDP = 1,
k_ESNetSocketConnectionTypeUDPRelay = 2,
};
//-----------------------------------------------------------------------------
// Purpose: Functions for making connections and sending data between clients,
// traversing NAT's where possible
//-----------------------------------------------------------------------------
class ISteamNetworking {
public:
////////////////////////////////////////////////////////////////////////////////////////////
// Session-less connection functions
// automatically establishes NAT-traversing or Relay server connections
// Sends a P2P packet to the specified user
// UDP-like, unreliable and a max packet size of 1200 bytes
// the first packet send may be delayed as the NAT-traversal code runs
// if we can't get through to the user, an error will be posted via the
// callback P2PSessionConnectFail_t see EP2PSend enum above for the
// descriptions of the different ways of sending packets
//
// nChannel is a routing number you can use to help route message to
// different systems - you'll have to call ReadP2PPacket() with the
// same channel number in order to retrieve the data on the other end using
// different channels to talk to the same user will still use the same
// underlying p2p connection, saving on resources
virtual bool SendP2PPacket(CSteamID steamIDRemote, const void *pubData,
uint32 cubData, EP2PSend eP2PSendType,
int nChannel = 0) = 0;
// returns true if any data is available for read, and the amount of data
// that will need to be read
virtual bool IsP2PPacketAvailable(uint32 *pcubMsgSize,
int nChannel = 0) = 0;
// reads in a packet that has been sent from another user via
// SendP2PPacket() returns the size of the message and the steamID of the
// user who sent it in the last two parameters if the buffer passed in is
// too small, the message will be truncated this call is not blocking, and
// will return false if no data is available
virtual bool ReadP2PPacket(void *pubDest, uint32 cubDest,
uint32 *pcubMsgSize, CSteamID *psteamIDRemote,
int nChannel = 0) = 0;
// AcceptP2PSessionWithUser() should only be called in response to a
// P2PSessionRequest_t callback P2PSessionRequest_t will be posted if
// another user tries to send you a packet that you haven't talked to yet if
// you don't want to talk to the user, just ignore the request if the user
// continues to send you packets, another P2PSessionRequest_t will be posted
// periodically this may be called multiple times for a single user (if
// you've called SendP2PPacket() on the other user, this implicitly accepts
// the session request)
virtual bool AcceptP2PSessionWithUser(CSteamID steamIDRemote) = 0;
// call CloseP2PSessionWithUser() when you're done talking to a user, will
// free up resources under-the-hood if the remote user tries to send data to
// you again, another P2PSessionRequest_t callback will be posted
virtual bool CloseP2PSessionWithUser(CSteamID steamIDRemote) = 0;
// call CloseP2PChannelWithUser() when you're done talking to a user on a
// specific channel. Once all channels open channels to a user have been
// closed, the open session to the user will be closed and new data from
// this user will trigger a P2PSessionRequest_t callback
virtual bool CloseP2PChannelWithUser(CSteamID steamIDRemote,
int nChannel) = 0;
// fills out P2PSessionState_t structure with details about the underlying
// connection to the user should only needed for debugging purposes returns
// false if no connection exists to the specified user
virtual bool GetP2PSessionState(CSteamID steamIDRemote,
P2PSessionState_t *pConnectionState) = 0;
// Allow P2P connections to fall back to being relayed through the Steam
// servers if a direct connection or NAT-traversal cannot be established.
// Only applies to connections created after setting this value, or to
// existing connections that need to automatically reconnect after this
// value is set.
//
// P2P packet relay is allowed by default
virtual bool AllowP2PPacketRelay(bool bAllow) = 0;
////////////////////////////////////////////////////////////////////////////////////////////
// LISTEN / CONNECT style interface functions
//
// This is an older set of functions designed around the Berkeley TCP
// sockets model it's preferential that you use the above P2P functions,
// they're more robust and these older functions will be removed eventually
//
////////////////////////////////////////////////////////////////////////////////////////////
// creates a socket and listens others to connect
// will trigger a SocketStatusCallback_t callback on another client
// connecting nVirtualP2PPort is the unique ID that the client will connect
// to, in case you have multiple ports
// this can usually just be 0 unless you want multiple sets of
//connections
// unIP is the local IP address to bind to
// pass in 0 if you just want the default local IP
// unPort is the port to use
// pass in 0 if you don't want users to be able to connect via IP/Port,
//but expect to be always peer-to-peer connections only
virtual SNetListenSocket_t CreateListenSocket(
int nVirtualP2PPort, uint32 nIP, uint16 nPort,
bool bAllowUseOfPacketRelay) = 0;
// creates a socket and begin connection to a remote destination
// can connect via a known steamID (client or game server), or directly to
// an IP on success will trigger a SocketStatusCallback_t callback on
// failure or timeout will trigger a SocketStatusCallback_t callback with a
// failure code in m_eSNetSocketState
virtual SNetSocket_t CreateP2PConnectionSocket(
CSteamID steamIDTarget, int nVirtualPort, int nTimeoutSec,
bool bAllowUseOfPacketRelay) = 0;
virtual SNetSocket_t CreateConnectionSocket(uint32 nIP, uint16 nPort,
int nTimeoutSec) = 0;
// disconnects the connection to the socket, if any, and invalidates the
// handle any unread data on the socket will be thrown away if
// bNotifyRemoteEnd is set, socket will not be completely destroyed until
// the remote end acknowledges the disconnect
virtual bool DestroySocket(SNetSocket_t hSocket, bool bNotifyRemoteEnd) = 0;
// destroying a listen socket will automatically kill all the regular
// sockets generated from it
virtual bool DestroyListenSocket(SNetListenSocket_t hSocket,
bool bNotifyRemoteEnd) = 0;
// sending data
// must be a handle to a connected socket
// data is all sent via UDP, and thus send sizes are limited to 1200 bytes;
// after this, many routers will start dropping packets use the reliable
// flag with caution; although the resend rate is pretty aggressive, it can
// still cause stalls in receiving data (like TCP)
virtual bool SendDataOnSocket(SNetSocket_t hSocket, void *pubData,
uint32 cubData, bool bReliable) = 0;
// receiving data
// returns false if there is no data remaining
// fills out *pcubMsgSize with the size of the next message, in bytes
virtual bool IsDataAvailableOnSocket(SNetSocket_t hSocket,
uint32 *pcubMsgSize) = 0;
// fills in pubDest with the contents of the message
// messages are always complete, of the same size as was sent (i.e.
// packetized, not streaming) if *pcubMsgSize < cubDest, only partial data
// is written returns false if no data is available
virtual bool RetrieveDataFromSocket(SNetSocket_t hSocket, void *pubDest,
uint32 cubDest,
uint32 *pcubMsgSize) = 0;
// checks for data from any socket that has been connected off this listen
// socket returns false if there is no data remaining fills out *pcubMsgSize
// with the size of the next message, in bytes fills out *phSocket with the
// socket that data is available on
virtual bool IsDataAvailable(SNetListenSocket_t hListenSocket,
uint32 *pcubMsgSize,
SNetSocket_t *phSocket) = 0;
// retrieves data from any socket that has been connected off this listen
// socket fills in pubDest with the contents of the message messages are
// always complete, of the same size as was sent (i.e. packetized, not
// streaming) if *pcubMsgSize < cubDest, only partial data is written
// returns false if no data is available
// fills out *phSocket with the socket that data is available on
virtual bool RetrieveData(SNetListenSocket_t hListenSocket, void *pubDest,
uint32 cubDest, uint32 *pcubMsgSize,
SNetSocket_t *phSocket) = 0;
// returns information about the specified socket, filling out the contents
// of the pointers
virtual bool GetSocketInfo(SNetSocket_t hSocket, CSteamID *pSteamIDRemote,
int *peSocketStatus, uint32 *punIPRemote,
uint16 *punPortRemote) = 0;
// returns which local port the listen socket is bound to
// *pnIP and *pnPort will be 0 if the socket is set to listen for P2P
// connections only
virtual bool GetListenSocketInfo(SNetListenSocket_t hListenSocket,
uint32 *pnIP, uint16 *pnPort) = 0;
// returns true to describe how the socket ended up connecting
virtual ESNetSocketConnectionType GetSocketConnectionType(
SNetSocket_t hSocket) = 0;
// max packet size, in bytes
virtual int GetMaxPacketSize(SNetSocket_t hSocket) = 0;
};
#define STEAMNETWORKING_INTERFACE_VERSION "SteamNetworking005"
// callbacks
#if defined(VALVE_CALLBACK_PACK_SMALL)
#pragma pack(push, 4)
#elif defined(VALVE_CALLBACK_PACK_LARGE)
#pragma pack(push, 8)
#else
#error isteamclient.h must be included
#endif
// callback notification - a user wants to talk to us over the P2P channel via
// the SendP2PPacket() API in response, a call to AcceptP2PPacketsFromUser()
// needs to be made, if you want to talk with them
struct P2PSessionRequest_t {
enum { k_iCallback = k_iSteamNetworkingCallbacks + 2 };
CSteamID m_steamIDRemote; // user who wants to talk to us
};
// callback notification - packets can't get through to the specified user via
// the SendP2PPacket() API all packets queued packets unsent at this point will
// be dropped further attempts to send will retry making the connection (but
// will be dropped if we fail again)
struct P2PSessionConnectFail_t {
enum { k_iCallback = k_iSteamNetworkingCallbacks + 3 };
CSteamID m_steamIDRemote; // user we were sending packets to
uint8 m_eP2PSessionError; // EP2PSessionError indicating why we're having
// trouble
};
// callback notification - status of a socket has changed
// used as part of the CreateListenSocket() / CreateP2PConnectionSocket()
struct SocketStatusCallback_t {
enum { k_iCallback = k_iSteamNetworkingCallbacks + 1 };
SNetSocket_t
m_hSocket; // the socket used to send/receive data to the remote host
SNetListenSocket_t
m_hListenSocket; // this is the server socket that we were listening
// on; NULL if this was an outgoing connection
CSteamID
m_steamIDRemote; // remote steamID we have connected to, if it has one
int m_eSNetSocketState; // socket state, ESNetSocketState
};
#pragma pack(pop)
#endif // ISTEAMNETWORKING