The P2P Interface enables games implementing the Epic Online Services (EOS) SDK to set up and manage peer-to-peer (P2P) connections between users. This enables them to send and receive data between one another directly, typically for the purpose of a multiplayer game. Connections made with the EOS P2P Interface are only established between authenticated users, and are secure-by-default using DTLS, which provides two distinct advantages. First, the speed of handling P2P connections is significantly increased, in that EOS's authentication greatly reduces the need for connections to be re-negotiated. Second, the process of securely handling connections is itself greatly simplified for the SDK user, abstracting out the need for detailed network socket management and condensing most functions to what data needs to be sent and to whom.
Accessing the P2P Interface
In order to use the functions within the EOS P2P Interface, you must first obtain a valid EOS_HP2P
handle from the Platform Interface function EOS_Platform_GetP2PInterface
, as this handle is used in all P2P Interface functions. For more information about the Platform Interface and this function, you may refer to the page on the EOS Platform Interface.
Managing P2P Connections
The P2P Interface uses the struct EOS_P2P_SocketId
as a title-specified identifier for a connection between peers. Most P2P functions related to connections either require an EOS_P2P_SocketId
to associate with a connection request, or to return one in order to specify what connection a received connection request is associated with. EOS_P2P_SocketId
is comprised of the following parameters:
Parameter | Description |
---|---|
ApiVersion | A version field. This must be set to EOS_P2P_SOCKETID_API_LATEST . |
SocketName | A value used to vet all incoming connections from unknown peers in multiplayer games. A SocketName must contain 1-32 alpha-numeric, null-terminated characters. |
The SocketName
field can be a single value for all connections, or it can be a secret value known only to specific players in a multiplayer session. As accepted P2P connections expose a user's IP address to the peer that they are connecting to, it is important to not blindly accept any connection request.
A valid EOS_ProductUserId
is also usually required both for users to identify themselves when sending data, and to specify which user they wish to send data to.
All function parameters and their associated values in the P2P Interface are required unless explicitly marked as optional. This includes out-parameters, which the P2P Interface often uses to output data for asynchronous functions or event responses. If a function has a return type of EOS_EResult
and the return value is not EOS_Success
, then take note that any out-parameters that the function provides will be unset unless specified otherwise.
Requesting Connections
When a local user attempts to send information to a remote user, such as with the EOS_P2P_SendPacket
function, the P2P Interface will automatically make a request to open a connection between those two users, with an EOS_P2P_SocketId
acting as the identifier for that connection. The user sending the information automatically accepts their own request for that SocketId, while the user receiving the information must accept it, usually by listening for the incoming connection request and using the EOS_P2P_AcceptConnection
function.
All operations requiring an open P2P connection can be used to both request and accept a P2P connection if one is not already open. For example, EOS_P2P_AcceptConnection
can be used to request a P2P connection with a remote user, and EOS_P2P_SendPacket
can be used to accept a remote user's P2P connection request if one has already been made for the Socket Id that the local user is trying to use to send information. This effectively means that it is possible to use EOS_P2P_AcceptConnection
to pre-emptively accept the next connection request made with a given SocketId.
If multiple connections are open with a particular user, only the first connection must be negotiated. This greatly increases the speed at which data may be received with subsequent connection requests.
Receiving Connection Request Notifications
When a user receives a connection request, a notify event is fired to all bound Peer Connection Request Handlers.
To listen for connection requests with a new Peer Connection Request Handler, use EOS_P2P_AddNotifyPeerConnectionRequest
to bind a function that you would like to use as a response to incoming connection requests. The EOS_P2P_AddNotifyPeerConnectionRequest
function takes the following parameters:
Parameter | Description |
---|---|
Handle | A valid EOS_HP2P handle received from the Platform Interface. |
Options | A pointer to an EOS_P2P_AddNotifyPeerConnectionRequestOptions struct. |
ClientData (Optional) | Pointer to data that will be returned to the caller when the event fires. |
ConnectionRequestHandler | A function that will act as your Peer Connection Request Handler, responding to incoming connection requests. This function must take a pointer to an EOS_P2P_OnIncomingConnectionRequestInfo struct as a parameter. |
The EOS_P2P_AddNotifyPeerConnectionRequestOptions
struct is comprised of the following parameters:
Parameter | Description |
---|---|
ApiVersion | A version field. Set to EOS_P2P_ADDNOTIFYPEERCONNECTIONREQUEST_API_LATEST |
LocalUserId | Set to the ID of the local user that is listening for incoming connection request. |
SocketId (Optional) | Pointer to a valid EOS_P2P_SocketId struct that you would like to use to filter connection requests. |
The EOS_P2P_AddNotifyPeerConnectionRequest
function will return either a valid EOS_NotificationId
on success, or the value EOS_INVALID_NOTIFICATIONID
on failure.
You can remove a Peer Connection Request Handler with the EOS_P2P_RemoveNotifyPeerConnectionRequest
function, which requires the following parameters:
Parameter | Description |
---|---|
Handle | A valid EOS_HP2P handle received from the Platform Interface. |
NotificationId | A valid EOS_NotificationId returned from EOS_P2P_AddNotifyPeerConnectionRequest , used to identify the peer connection request handler you wish to remove. |
Accepting Connections
The EOS_P2P_AcceptConnection
function can be used to accept a connection that has been requested, or to start a new connection request. Both users must accept a connection for a given SocketId before the connection can be established and used to send data. The user attempting to open a connection has to call EOS_P2P_AcceptConnection
, if bDisableAutoAcceptConnection
is set to EOS_TRUE
.
To call the EOS_P2P_AcceptConnection
function, you must provide the following parameters:
Parameter | Description |
---|---|
Handle | A valid EOS_HP2P handle received from the Platform Interface. |
Options | A pointer to an EOS_P2P_AcceptConnectionOptions struct. |
The EOS_P2P_AcceptConnectionOptions
struct contains the following parameters:
Parameter | Description |
---|---|
ApiVersion | Set to EOS_P2P_ACCEPTCONNECTION_API_LATEST |
LocalUserId | Set to the EOS_ProductUserId of the local user that is accepting the connection. |
RemoteUserId | Set to the EOS_ProductUserId of the remote user that the local user wants to connect to. |
SocketId | Pointer to a valid EOS_P2P_SocketId struct that you would like to accept a connection for. |
The EOS_P2P_AcceptConnection
function will return a value of EOS_InvalidParameters
if any of the supplied input was invalid. It will return EOS_Success
if the supplied information was valid, signifying that the connection was locally accepted and will be able to send data when the remote user accepts the connection as well. Calling EOS_P2P_AcceptConnection
multiple times before a Connection Closed event fires will have no effect.
Closing Connections
The EOS_P2P_CloseConnection
function can be used to reject a connection that has been requested, or to close a connection that was previously accepted with a specific user. If all connections with a specific user are closed, the backing socket connection will also be destroyed soon after. The EOS_P2P_CloseConnection
function requires the following parameters:
Parameter | Description |
---|---|
Handle | A valid EOS_HP2P handle received from the Platform Interface. |
Options | A pointer to an EOS_P2P_CloseConnectionOptions struct. |
The EOS_P2P_CloseConnectionOptions
struct contains the following parameters:
Parameter | Description |
---|---|
ApiVersion | Set to EOS_P2P_CLOSECONNECTION_API_LATEST . |
LocalUserId | Set to the EOS_ProductUserId of the local user that is closing or rejecting the connection. |
RemoteUserId | Set to the EOS_ProductUserId of the remote user whose connection is being closed or rejected. |
SocketId | Pointer to a valid EOS_P2P_SocketId struct you would like to close or reject a connection on. |
The EOS_P2P_CloseConnection
function will return either a value of EOS_InvalidParameters
, signifying that the supplied input for the function was invalid, or it will return a value of EOS_Success
, in which case the supplied input was valid and the connection will be closed or the connection request will be silently rejected.
The EOS_P2P_CloseConnections
function can be used to close or reject all connections on a specific SocketId, rather than a connection from a specific user. This could be used at the end of a session to drop all related connections for that session. The EOS_P2P_CloseConnections
function requires the following parameters:
Parameter | Description |
---|---|
Handle | A valid EOS_HP2P handle received from the Platform Interface. |
Options | Pointer to an EOS_P2P_CloseConnectionsOptions struct. |
The EOS_P2P_CloseConnectionsOptions
struct contains the following parameters:
Parameter | Description |
---|---|
ApiVersion | Set to EOS_P2P_CLOSECONNECTIONS_API_LATEST |
LocalUserId | Set to the EOS_ProductUserId of the local user that is closing all connections with the requested SocketId. |
SocketId | Pointer to a valid EOS_P2P_SocketId struct that you would like to close all connections on. |
The function will return a result of EOS_InvalidParameters
if any of the supplied input was invalid, or it will return EOS_Success
if the supplied information was valid and all the connections with the specified SocketId
were successfully closed.
Receiving Connection Closed Notifications
When an open or pending connection closes, a Connection Closed Event will fire, notifying the application and permitting it to respond. To create a handler for Connection Closed Events, use the EOS_P2P_AddNotifyPeerConnectionClosed
function, which requires the following parameters:
Parameter | Description |
---|---|
Handle | A valid EOS_HP2P handle received from the Platform Interface. |
Options | Pointer to a EOS_P2P_AddNotifyPeerConnectionClosedOptions struct. |
ClientData (Optional) | Pointer to data that will be returned to the caller when the event fires. |
ConnectionClosedHandler | A function that will be called when the Connection Closed Event fires. This function must take a pointer to an EOS_P2P_OnRemoteConnectionClosedInfo struct passed as a parameter. |
The EOS_P2P_AddNotifyPeerConnectionClosedOptions
struct contains the following parameters:
Parameter | Description |
---|---|
ApiVersion | Set to EOS_P2P_ADDNOTIFYPEERCONNECTIONCLOSED_API_LATEST . |
LocalUserId | Set to the EOS_ProductUserId of the local user that is listening for connections to close. |
SocketId (Optional) | Pointer to a valid EOS_P2P_SocketId struct that you would like to filter connection closed events on. |
The EOS_P2P_AddNotifyPeerConnectionClosed
function returns an EOS_NotificationId
that can be used to identify the Connection Closed Event Handler.
You can remove a Connection Closed Event Handler by calling the function EOS_P2P_RemoveNotifyPeerConnectionClosed
, which takes the following parameters:
Parameter | Description |
---|---|
Handle | A valid EOS_HP2P handle received from the Platform Interface. |
NotificationId | A valid EOS_NotificationId returned from EOS_P2P_AddNotifyPeerConnectionClosed . |
Sending and Receiving Data Through P2P Connections
Once a P2P Connection is successfully established, users may send and receive data through it.
Sending Data
The EOS_P2P_SendPacket
function will securely send a packet to another user. If there is already an open connection to that peer, it will be sent immediately. If there is not an open connection, then a request for a new connection will be made. The EOS_P2P_SendPacket
function takes the following parameters:
Parameter | Description |
---|---|
Handle | A valid EOS_HP2P handle received from the Platform Interface. |
Options | A pointer to a EOS_P2P_SendPacketOptions struct. |
The EOS_P2P_SendPacketOptions
struct contains the following parameters:
Parameter | Description |
---|---|
ApiVersion | Set to EOS_P2P_SENDPACKET_API_LATEST . |
LocalUserId | Set to the EOS_ProductUserId of the local user that is sending the packet. |
RemoteUserId | Set to the EOS_ProductUserId of the remote user to send the packet to. |
SocketId | Pointer to a valid EOS_P2P_SocketId . |
Channel | Set to the channel to send this data on. |
DataLengthBytes | Set to the amount of bytes to send from Data . |
Data | Pointer to the start of the buffer of data to send DataLengthBytes from. |
bAllowDelayedDelivery | If we do not have an established connection and this is false, the packet will be silently dropped. Otherwise the packet will be queued until the connection has been opened or until the connection is closed using EOS_P2P_CloseConnection or EOS_P2P_CloseConnections . |
Reliability | Sets the reliability of the delivery of this packet. The reliability can be EOS_PR_UnreliableUnordered , EOS_PR_ReliableUnordered , or EOS_PR_ReliableOrdered . |
bDisableAutoAcceptConnection | If this is true , EOS_P2P_SendPacket does not automatically establish a connection with the RemoteUserId , and therefore you must make explicit calls to EOS_P2P_AcceptConnection first, whenever the connection is closed. If this is false , EOS_P2P_SendPacket automatically accepts and starts the connection any time it is called, as long as the connection is not already open. |
This function will return either EOS_InvalidParameters
if any of the supplied input is invalid, or EOS_Success
if the supplied information was valid and could be sent. Note that a return of Success only denotes that the packet can be successfully sent, not whether or not it is successfully delivered. Successful delivery is not guaranteed, as data is sent unreliably.
Receiving Data
The P2P Interface queues packets that a user receives internally, awaiting a call to the EOS_P2P_ReceivePacket
function in order to remove it from the queue and store its data in a buffer. This function takes the following parameters:
Parameter | Description |
---|---|
Handle | A valid EOS_HP2P handle received from the Platform Interface. |
Options | A pointer to a valid EOS_P2P_ReceivePacketOptions struct. |
OutPeerId | A pointer to an EOS_ProductUserId value to write out who sent this packet. |
OutSocketId | A pointer to an EOS_P2P_SocketId struct to write the associated SocketId data into. |
OutChannel | A pointer to a uint8_t to write the associated Channel for this packet. |
OutData | A pointer to a buffer that will have the data from the received packet written to it. This buffer must be the size of MaxDataSizeBytes in the Options for this function. |
OutBytesWritten | A pointer to a uint32_t , which will record the number of bytes written to OutData . |
The EOS_P2P_ReceivePacketOptions
struct contains the following parameters:
Parameter | Description |
---|---|
ApiVersion | A version field. Set to EOS_P2P_RECEIVEPACKET_API_LATEST |
LocalUserId | Set to the EOS_ProductUserId of the local user that is requesting the received packet. |
MaxDataSizeBytes | The maximum amount of bytes that can be written to the OutData buffer safely. |
RequestedChannel (Optional) | If set, only packets belonging to this channel will be received. |
The function will return EOS_InvalidParameters
if any of the input parameters were invalid. It will return EOS_Success
if the packet and its associated data is copied into all of the out-paramters successfully, and it will return EOS_NotFound
if there are no packets available to fulfill the request. It is important to note that the out-parameters will only be written to if the function returns a value of EOS_Success
.
EOS_P2P_ReceivePacketOptions
requires you to specify the amount of data that can be safely written to the buffer with MaxDataSizeBytes
, in addition to specifying the buffer itself with OutData
. If the provided buffer is too small to fit the next packet, the data will be silently truncated to the provided buffer's length. It is possible to discard a packet's data entirely by providing a buffer of NULL
in OutData
, with a size of 0 in MaxDataSizeBytes
. It is also possible to safely use a buffer of EOS_P2P_MAX_PACKET_SIZE
to store the data from a packet, but it is recommended to call EOS_P2P_GetNextReceivedPacketSize
to retrieve the exact size of the packet data before calling EOS_P2P_ReceivePacket
. The EOS_P2P_MAX_PACKET_SIZE
is 1170 because of DTLS/SCTP/UDP packet overhead.
It is recommended to call EOS_P2P_RecievePacket
often to prevent the internal packet queue from filling up. If the internal packet queue is full, incoming packets will be lost rather than received.
Determining Packet Size
EOS_P2P_GetNextReceivedPacketSize
retrieves size in bytes of the next packet in the internal queue without removing it from the queue, and it takes the following parameters:
Parameter | Description |
---|---|
Handle | A valid EOS_HP2P handle received from the Platform Interface. |
Options | Pointer to a EOS_P2P_GetNextReceivedPacketSizeOptions struct. |
OutPacketSizeBytes | A pointer to a uint32_t that can store the size of the next packet for the user calling the function. |
The EOS_P2P_GetNextReceivedPacketSizeOptions
struct contains the following parameters:
Parameter | Description |
---|---|
ApiVersion | Set to EOS_P2P_GETNEXTRECEIVEDPACKETSIZE_API_LATEST |
LocalUserId | Set to the EOS_ProductUserId of the local user that is requesting the size of the next packet. |
RequestedChannel (Optional) | If set, only the size of the next packet belonging to this channel will be returned. |
This function will return a value of EOS_InvalidParameters
if any of the input parameters are invalid, or a value of EOS_Success
if the packet data size was copied to OutPacketSizeBytes
successfully. If no data is available, the function will return a value of EOS_NotFound
instead.
Determining NAT Type
While the P2P Interface will attempt NAT-traversal, it is not always possible to receive incoming connections when one or more peers has a restrictive NAT. In these cases a relay is required, which will be used automatically in case of NAT-traversal failure. To help determine if the user can easily connect to peers, the P2P Interface can query the local user's NAT Type in relation to the internet. This is represented by EOS_ENATType
, which can take the following values:
Value | Description |
---|---|
EOS_NAT_Unknown | The NAT Type is either currently unknown or we are otherwise unable to accurately determine it. |
EOS_NAT_Open | All types of peers should be able to directly connect to you. |
EOS_NAT_Moderate | You can directly connect to other Moderate and Open peers without the use of relay servers. |
EOS_NAT_Strict | You can directly connect only to Open peers without the use of relay servers. |
The EOS_P2P_QueryNATType
function can asynchronously determine the NAT Type of the current connection. It does this by sending multiple packets of data to remote servers, and those servers respond back with what IP and Ports the local application used. Note that additional calls to EOS_P2P_QueryNATType
while a request is already in progress will be grouped into that first request, and will not start new requests. EOS_P2P_QueryNATType
takes the following parameters:
Parameter | Description |
---|---|
Handle | A valid EOS_HP2P handle received from the Platform Interface. |
Options | A pointer to an EOS_P2P_QueryNATTypeOptions struct. |
ClientData (Optional) | Pointer to data that will be returned to the caller when the query finishes. |
NATTypeQueriedHandler | Pointer to a function to call when the query finishes. |
The EOS_P2P_QueryNATTypeOptions
struct contains the following parameters:
Parameter | Description |
---|---|
ApiVersion | A version field. Set to EOS_P2P_QUERYNATTYPE_API_LATEST . |
Because the NAT Type query is asynchronous, this function does not return a value directly. Instead, it outputs the user's NAT Type through a NAT Type Queried Handler, a function that is registered to occur when the query finishes. In some cases this query will be unable to determine the user's NAT Type, and will instead return a value of EOS_NAT_Unknown
.
When EOS_P2P_QueryNATType
completes, the value of the user's NAT Type is cached, and you can instead call the function EOS_P2P_GetNATType
to return that value immediately. This will only return successfully if EOS_P2P_QueryNATType
has completed at least once. To call the EOS_P2P_GetNATType
function, you must provide the following parameters:
Parameter | Description |
---|---|
Handle | A valid EOS_HP2P handle received from the Platform Interface. |
Options | Pointer to an EOS_P2P_GetNATTypeOptions struct. |
OutNATType | Pointer to an EOS_ENATType object to set to the cached value that was previously queried by EOS_P2P_QueryNATType . |
The EOS_P2P_GetNATTypeOptions
struct contains the following parameters:
Parameter | Description |
---|---|
ApiVersion | Set to EOS_P2P_GETNATTYPE_API_LATEST . |
The EOS_P2P_GetNATType
function will return EOS_Success
if EOS_P2P_QueryNATType
was successfully called in the past. It will return EOS_NotFound
if EOS_P2P_QueryNATType
has not been called before, or if it has not been completed.