372 lines
18 KiB
C++
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
|