1112 lines
74 KiB
C#
1112 lines
74 KiB
C#
#define STEAMNETWORKINGSOCKETS_ENABLE_SDR
|
|
// This file is provided under The MIT License as part of Steamworks.NET.
|
|
// Copyright (c) 2013-2022 Riley Labrecque
|
|
// Please see the included LICENSE.txt for additional information.
|
|
|
|
// This file is automatically generated.
|
|
// Changes to this file will be reverted when you update Steamworks.NET
|
|
|
|
#if !(UNITY_STANDALONE_WIN || UNITY_STANDALONE_LINUX || UNITY_STANDALONE_OSX || STEAMWORKS_WIN || STEAMWORKS_LIN_OSX)
|
|
#define DISABLESTEAMWORKS
|
|
#endif
|
|
|
|
#if !DISABLESTEAMWORKS
|
|
|
|
using System.Runtime.InteropServices;
|
|
using IntPtr = System.IntPtr;
|
|
|
|
namespace Steamworks {
|
|
public static class SteamGameServerNetworkingSockets {
|
|
/// <summary>
|
|
/// <para>/ Creates a "server" socket that listens for clients to connect to by</para>
|
|
/// <para>/ calling ConnectByIPAddress, over ordinary UDP (IPv4 or IPv6)</para>
|
|
/// <para>/</para>
|
|
/// <para>/ You must select a specific local port to listen on and set it</para>
|
|
/// <para>/ the port field of the local address.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Usually you will set the IP portion of the address to zero (SteamNetworkingIPAddr::Clear()).</para>
|
|
/// <para>/ This means that you will not bind to any particular local interface (i.e. the same</para>
|
|
/// <para>/ as INADDR_ANY in plain socket code). Furthermore, if possible the socket will be bound</para>
|
|
/// <para>/ in "dual stack" mode, which means that it can accept both IPv4 and IPv6 client connections.</para>
|
|
/// <para>/ If you really do wish to bind a particular interface, then set the local address to the</para>
|
|
/// <para>/ appropriate IPv4 or IPv6 IP.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ If you need to set any initial config options, pass them here. See</para>
|
|
/// <para>/ SteamNetworkingConfigValue_t for more about why this is preferable to</para>
|
|
/// <para>/ setting the options "immediately" after creation.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ When a client attempts to connect, a SteamNetConnectionStatusChangedCallback_t</para>
|
|
/// <para>/ will be posted. The connection will be in the connecting state.</para>
|
|
/// </summary>
|
|
public static HSteamListenSocket CreateListenSocketIP(ref SteamNetworkingIPAddr localAddress, int nOptions, SteamNetworkingConfigValue_t[] pOptions) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return (HSteamListenSocket)NativeMethods.ISteamNetworkingSockets_CreateListenSocketIP(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), ref localAddress, nOptions, pOptions);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Creates a connection and begins talking to a "server" over UDP at the</para>
|
|
/// <para>/ given IPv4 or IPv6 address. The remote host must be listening with a</para>
|
|
/// <para>/ matching call to CreateListenSocketIP on the specified port.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ A SteamNetConnectionStatusChangedCallback_t callback will be triggered when we start</para>
|
|
/// <para>/ connecting, and then another one on either timeout or successful connection.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ If the server does not have any identity configured, then their network address</para>
|
|
/// <para>/ will be the only identity in use. Or, the network host may provide a platform-specific</para>
|
|
/// <para>/ identity with or without a valid certificate to authenticate that identity. (These</para>
|
|
/// <para>/ details will be contained in the SteamNetConnectionStatusChangedCallback_t.) It's</para>
|
|
/// <para>/ up to your application to decide whether to allow the connection.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ By default, all connections will get basic encryption sufficient to prevent</para>
|
|
/// <para>/ casual eavesdropping. But note that without certificates (or a shared secret</para>
|
|
/// <para>/ distributed through some other out-of-band mechanism), you don't have any</para>
|
|
/// <para>/ way of knowing who is actually on the other end, and thus are vulnerable to</para>
|
|
/// <para>/ man-in-the-middle attacks.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ If you need to set any initial config options, pass them here. See</para>
|
|
/// <para>/ SteamNetworkingConfigValue_t for more about why this is preferable to</para>
|
|
/// <para>/ setting the options "immediately" after creation.</para>
|
|
/// </summary>
|
|
public static HSteamNetConnection ConnectByIPAddress(ref SteamNetworkingIPAddr address, int nOptions, SteamNetworkingConfigValue_t[] pOptions) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return (HSteamNetConnection)NativeMethods.ISteamNetworkingSockets_ConnectByIPAddress(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), ref address, nOptions, pOptions);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Like CreateListenSocketIP, but clients will connect using ConnectP2P.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ nLocalVirtualPort specifies how clients can connect to this socket using</para>
|
|
/// <para>/ ConnectP2P. It's very common for applications to only have one listening socket;</para>
|
|
/// <para>/ in that case, use zero. If you need to open multiple listen sockets and have clients</para>
|
|
/// <para>/ be able to connect to one or the other, then nLocalVirtualPort should be a small</para>
|
|
/// <para>/ integer (<1000) unique to each listen socket you create.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ If you use this, you probably want to call ISteamNetworkingUtils::InitRelayNetworkAccess()</para>
|
|
/// <para>/ when your app initializes.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ If you are listening on a dedicated servers in known data center,</para>
|
|
/// <para>/ then you can listen using this function instead of CreateHostedDedicatedServerListenSocket,</para>
|
|
/// <para>/ to allow clients to connect without a ticket. Any user that owns</para>
|
|
/// <para>/ the app and is signed into Steam will be able to attempt to connect to</para>
|
|
/// <para>/ your server. Also, a connection attempt may require the client to</para>
|
|
/// <para>/ be connected to Steam, which is one more moving part that may fail. When</para>
|
|
/// <para>/ tickets are used, then once a ticket is obtained, a client can connect to</para>
|
|
/// <para>/ your server even if they got disconnected from Steam or Steam is offline.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ If you need to set any initial config options, pass them here. See</para>
|
|
/// <para>/ SteamNetworkingConfigValue_t for more about why this is preferable to</para>
|
|
/// <para>/ setting the options "immediately" after creation.</para>
|
|
/// </summary>
|
|
public static HSteamListenSocket CreateListenSocketP2P(int nLocalVirtualPort, int nOptions, SteamNetworkingConfigValue_t[] pOptions) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return (HSteamListenSocket)NativeMethods.ISteamNetworkingSockets_CreateListenSocketP2P(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), nLocalVirtualPort, nOptions, pOptions);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Begin connecting to a peer that is identified using a platform-specific identifier.</para>
|
|
/// <para>/ This uses the default rendezvous service, which depends on the platform and library</para>
|
|
/// <para>/ configuration. (E.g. on Steam, it goes through the steam backend.)</para>
|
|
/// <para>/</para>
|
|
/// <para>/ If you need to set any initial config options, pass them here. See</para>
|
|
/// <para>/ SteamNetworkingConfigValue_t for more about why this is preferable to</para>
|
|
/// <para>/ setting the options "immediately" after creation.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ To use your own signaling service, see:</para>
|
|
/// <para>/ - ConnectP2PCustomSignaling</para>
|
|
/// <para>/ - k_ESteamNetworkingConfig_Callback_CreateConnectionSignaling</para>
|
|
/// </summary>
|
|
public static HSteamNetConnection ConnectP2P(ref SteamNetworkingIdentity identityRemote, int nRemoteVirtualPort, int nOptions, SteamNetworkingConfigValue_t[] pOptions) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return (HSteamNetConnection)NativeMethods.ISteamNetworkingSockets_ConnectP2P(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), ref identityRemote, nRemoteVirtualPort, nOptions, pOptions);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Accept an incoming connection that has been received on a listen socket.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ When a connection attempt is received (perhaps after a few basic handshake</para>
|
|
/// <para>/ packets have been exchanged to prevent trivial spoofing), a connection interface</para>
|
|
/// <para>/ object is created in the k_ESteamNetworkingConnectionState_Connecting state</para>
|
|
/// <para>/ and a SteamNetConnectionStatusChangedCallback_t is posted. At this point, your</para>
|
|
/// <para>/ application MUST either accept or close the connection. (It may not ignore it.)</para>
|
|
/// <para>/ Accepting the connection will transition it either into the connected state,</para>
|
|
/// <para>/ or the finding route state, depending on the connection type.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ You should take action within a second or two, because accepting the connection is</para>
|
|
/// <para>/ what actually sends the reply notifying the client that they are connected. If you</para>
|
|
/// <para>/ delay taking action, from the client's perspective it is the same as the network</para>
|
|
/// <para>/ being unresponsive, and the client may timeout the connection attempt. In other</para>
|
|
/// <para>/ words, the client cannot distinguish between a delay caused by network problems</para>
|
|
/// <para>/ and a delay caused by the application.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ This means that if your application goes for more than a few seconds without</para>
|
|
/// <para>/ processing callbacks (for example, while loading a map), then there is a chance</para>
|
|
/// <para>/ that a client may attempt to connect in that interval and fail due to timeout.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ If the application does not respond to the connection attempt in a timely manner,</para>
|
|
/// <para>/ and we stop receiving communication from the client, the connection attempt will</para>
|
|
/// <para>/ be timed out locally, transitioning the connection to the</para>
|
|
/// <para>/ k_ESteamNetworkingConnectionState_ProblemDetectedLocally state. The client may also</para>
|
|
/// <para>/ close the connection before it is accepted, and a transition to the</para>
|
|
/// <para>/ k_ESteamNetworkingConnectionState_ClosedByPeer is also possible depending the exact</para>
|
|
/// <para>/ sequence of events.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Returns k_EResultInvalidParam if the handle is invalid.</para>
|
|
/// <para>/ Returns k_EResultInvalidState if the connection is not in the appropriate state.</para>
|
|
/// <para>/ (Remember that the connection state could change in between the time that the</para>
|
|
/// <para>/ notification being posted to the queue and when it is received by the application.)</para>
|
|
/// <para>/</para>
|
|
/// <para>/ A note about connection configuration options. If you need to set any configuration</para>
|
|
/// <para>/ options that are common to all connections accepted through a particular listen</para>
|
|
/// <para>/ socket, consider setting the options on the listen socket, since such options are</para>
|
|
/// <para>/ inherited automatically. If you really do need to set options that are connection</para>
|
|
/// <para>/ specific, it is safe to set them on the connection before accepting the connection.</para>
|
|
/// </summary>
|
|
public static EResult AcceptConnection(HSteamNetConnection hConn) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_AcceptConnection(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), hConn);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Disconnects from the remote host and invalidates the connection handle.</para>
|
|
/// <para>/ Any unread data on the connection is discarded.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ nReason is an application defined code that will be received on the other</para>
|
|
/// <para>/ end and recorded (when possible) in backend analytics. The value should</para>
|
|
/// <para>/ come from a restricted range. (See ESteamNetConnectionEnd.) If you don't need</para>
|
|
/// <para>/ to communicate any information to the remote host, and do not want analytics to</para>
|
|
/// <para>/ be able to distinguish "normal" connection terminations from "exceptional" ones,</para>
|
|
/// <para>/ You may pass zero, in which case the generic value of</para>
|
|
/// <para>/ k_ESteamNetConnectionEnd_App_Generic will be used.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ pszDebug is an optional human-readable diagnostic string that will be received</para>
|
|
/// <para>/ by the remote host and recorded (when possible) in backend analytics.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ If you wish to put the socket into a "linger" state, where an attempt is made to</para>
|
|
/// <para>/ flush any remaining sent data, use bEnableLinger=true. Otherwise reliable data</para>
|
|
/// <para>/ is not flushed.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ If the connection has already ended and you are just freeing up the</para>
|
|
/// <para>/ connection interface, the reason code, debug string, and linger flag are</para>
|
|
/// <para>/ ignored.</para>
|
|
/// </summary>
|
|
public static bool CloseConnection(HSteamNetConnection hPeer, int nReason, string pszDebug, bool bEnableLinger) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
using (var pszDebug2 = new InteropHelp.UTF8StringHandle(pszDebug)) {
|
|
return NativeMethods.ISteamNetworkingSockets_CloseConnection(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), hPeer, nReason, pszDebug2, bEnableLinger);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Destroy a listen socket. All the connections that were accepting on the listen</para>
|
|
/// <para>/ socket are closed ungracefully.</para>
|
|
/// </summary>
|
|
public static bool CloseListenSocket(HSteamListenSocket hSocket) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_CloseListenSocket(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), hSocket);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Set connection user data. the data is returned in the following places</para>
|
|
/// <para>/ - You can query it using GetConnectionUserData.</para>
|
|
/// <para>/ - The SteamNetworkingmessage_t structure.</para>
|
|
/// <para>/ - The SteamNetConnectionInfo_t structure.</para>
|
|
/// <para>/ (Which is a member of SteamNetConnectionStatusChangedCallback_t -- but see WARNINGS below!!!!)</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Do you need to set this atomically when the connection is created?</para>
|
|
/// <para>/ See k_ESteamNetworkingConfig_ConnectionUserData.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ WARNING: Be *very careful* when using the value provided in callbacks structs.</para>
|
|
/// <para>/ Callbacks are queued, and the value that you will receive in your</para>
|
|
/// <para>/ callback is the userdata that was effective at the time the callback</para>
|
|
/// <para>/ was queued. There are subtle race conditions that can hapen if you</para>
|
|
/// <para>/ don't understand this!</para>
|
|
/// <para>/</para>
|
|
/// <para>/ If any incoming messages for this connection are queued, the userdata</para>
|
|
/// <para>/ field is updated, so that when when you receive messages (e.g. with</para>
|
|
/// <para>/ ReceiveMessagesOnConnection), they will always have the very latest</para>
|
|
/// <para>/ userdata. So the tricky race conditions that can happen with callbacks</para>
|
|
/// <para>/ do not apply to retrieving messages.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Returns false if the handle is invalid.</para>
|
|
/// </summary>
|
|
public static bool SetConnectionUserData(HSteamNetConnection hPeer, long nUserData) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_SetConnectionUserData(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), hPeer, nUserData);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Fetch connection user data. Returns -1 if handle is invalid</para>
|
|
/// <para>/ or if you haven't set any userdata on the connection.</para>
|
|
/// </summary>
|
|
public static long GetConnectionUserData(HSteamNetConnection hPeer) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_GetConnectionUserData(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), hPeer);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Set a name for the connection, used mostly for debugging</para>
|
|
/// </summary>
|
|
public static void SetConnectionName(HSteamNetConnection hPeer, string pszName) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
using (var pszName2 = new InteropHelp.UTF8StringHandle(pszName)) {
|
|
NativeMethods.ISteamNetworkingSockets_SetConnectionName(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), hPeer, pszName2);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Fetch connection name. Returns false if handle is invalid</para>
|
|
/// </summary>
|
|
public static bool GetConnectionName(HSteamNetConnection hPeer, out string pszName, int nMaxLen) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
IntPtr pszName2 = Marshal.AllocHGlobal(nMaxLen);
|
|
bool ret = NativeMethods.ISteamNetworkingSockets_GetConnectionName(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), hPeer, pszName2, nMaxLen);
|
|
pszName = ret ? InteropHelp.PtrToStringUTF8(pszName2) : null;
|
|
Marshal.FreeHGlobal(pszName2);
|
|
return ret;
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Send a message to the remote host on the specified connection.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ nSendFlags determines the delivery guarantees that will be provided,</para>
|
|
/// <para>/ when data should be buffered, etc. E.g. k_nSteamNetworkingSend_Unreliable</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Note that the semantics we use for messages are not precisely</para>
|
|
/// <para>/ the same as the semantics of a standard "stream" socket.</para>
|
|
/// <para>/ (SOCK_STREAM) For an ordinary stream socket, the boundaries</para>
|
|
/// <para>/ between chunks are not considered relevant, and the sizes of</para>
|
|
/// <para>/ the chunks of data written will not necessarily match up to</para>
|
|
/// <para>/ the sizes of the chunks that are returned by the reads on</para>
|
|
/// <para>/ the other end. The remote host might read a partial chunk,</para>
|
|
/// <para>/ or chunks might be coalesced. For the message semantics</para>
|
|
/// <para>/ used here, however, the sizes WILL match. Each send call</para>
|
|
/// <para>/ will match a successful read call on the remote host</para>
|
|
/// <para>/ one-for-one. If you are porting existing stream-oriented</para>
|
|
/// <para>/ code to the semantics of reliable messages, your code should</para>
|
|
/// <para>/ work the same, since reliable message semantics are more</para>
|
|
/// <para>/ strict than stream semantics. The only caveat is related to</para>
|
|
/// <para>/ performance: there is per-message overhead to retain the</para>
|
|
/// <para>/ message sizes, and so if your code sends many small chunks</para>
|
|
/// <para>/ of data, performance will suffer. Any code based on stream</para>
|
|
/// <para>/ sockets that does not write excessively small chunks will</para>
|
|
/// <para>/ work without any changes.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ The pOutMessageNumber is an optional pointer to receive the</para>
|
|
/// <para>/ message number assigned to the message, if sending was successful.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Returns:</para>
|
|
/// <para>/ - k_EResultInvalidParam: invalid connection handle, or the individual message is too big.</para>
|
|
/// <para>/ (See k_cbMaxSteamNetworkingSocketsMessageSizeSend)</para>
|
|
/// <para>/ - k_EResultInvalidState: connection is in an invalid state</para>
|
|
/// <para>/ - k_EResultNoConnection: connection has ended</para>
|
|
/// <para>/ - k_EResultIgnored: You used k_nSteamNetworkingSend_NoDelay, and the message was dropped because</para>
|
|
/// <para>/ we were not ready to send it.</para>
|
|
/// <para>/ - k_EResultLimitExceeded: there was already too much data queued to be sent.</para>
|
|
/// <para>/ (See k_ESteamNetworkingConfig_SendBufferSize)</para>
|
|
/// </summary>
|
|
public static EResult SendMessageToConnection(HSteamNetConnection hConn, IntPtr pData, uint cbData, int nSendFlags, out long pOutMessageNumber) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_SendMessageToConnection(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), hConn, pData, cbData, nSendFlags, out pOutMessageNumber);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Send one or more messages without copying the message payload.</para>
|
|
/// <para>/ This is the most efficient way to send messages. To use this</para>
|
|
/// <para>/ function, you must first allocate a message object using</para>
|
|
/// <para>/ ISteamNetworkingUtils::AllocateMessage. (Do not declare one</para>
|
|
/// <para>/ on the stack or allocate your own.)</para>
|
|
/// <para>/</para>
|
|
/// <para>/ You should fill in the message payload. You can either let</para>
|
|
/// <para>/ it allocate the buffer for you and then fill in the payload,</para>
|
|
/// <para>/ or if you already have a buffer allocated, you can just point</para>
|
|
/// <para>/ m_pData at your buffer and set the callback to the appropriate function</para>
|
|
/// <para>/ to free it. Note that if you use your own buffer, it MUST remain valid</para>
|
|
/// <para>/ until the callback is executed. And also note that your callback can be</para>
|
|
/// <para>/ invoked at any time from any thread (perhaps even before SendMessages</para>
|
|
/// <para>/ returns!), so it MUST be fast and threadsafe.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ You MUST also fill in:</para>
|
|
/// <para>/ - m_conn - the handle of the connection to send the message to</para>
|
|
/// <para>/ - m_nFlags - bitmask of k_nSteamNetworkingSend_xxx flags.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ All other fields are currently reserved and should not be modified.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ The library will take ownership of the message structures. They may</para>
|
|
/// <para>/ be modified or become invalid at any time, so you must not read them</para>
|
|
/// <para>/ after passing them to this function.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ pOutMessageNumberOrResult is an optional array that will receive,</para>
|
|
/// <para>/ for each message, the message number that was assigned to the message</para>
|
|
/// <para>/ if sending was successful. If sending failed, then a negative EResult</para>
|
|
/// <para>/ value is placed into the array. For example, the array will hold</para>
|
|
/// <para>/ -k_EResultInvalidState if the connection was in an invalid state.</para>
|
|
/// <para>/ See ISteamNetworkingSockets::SendMessageToConnection for possible</para>
|
|
/// <para>/ failure codes.</para>
|
|
/// </summary>
|
|
public static void SendMessages(int nMessages, SteamNetworkingMessage_t[] pMessages, long[] pOutMessageNumberOrResult) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
NativeMethods.ISteamNetworkingSockets_SendMessages(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), nMessages, pMessages, pOutMessageNumberOrResult);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Flush any messages waiting on the Nagle timer and send them</para>
|
|
/// <para>/ at the next transmission opportunity (often that means right now).</para>
|
|
/// <para>/</para>
|
|
/// <para>/ If Nagle is enabled (it's on by default) then when calling</para>
|
|
/// <para>/ SendMessageToConnection the message will be buffered, up to the Nagle time</para>
|
|
/// <para>/ before being sent, to merge small messages into the same packet.</para>
|
|
/// <para>/ (See k_ESteamNetworkingConfig_NagleTime)</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Returns:</para>
|
|
/// <para>/ k_EResultInvalidParam: invalid connection handle</para>
|
|
/// <para>/ k_EResultInvalidState: connection is in an invalid state</para>
|
|
/// <para>/ k_EResultNoConnection: connection has ended</para>
|
|
/// <para>/ k_EResultIgnored: We weren't (yet) connected, so this operation has no effect.</para>
|
|
/// </summary>
|
|
public static EResult FlushMessagesOnConnection(HSteamNetConnection hConn) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_FlushMessagesOnConnection(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), hConn);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Fetch the next available message(s) from the connection, if any.</para>
|
|
/// <para>/ Returns the number of messages returned into your array, up to nMaxMessages.</para>
|
|
/// <para>/ If the connection handle is invalid, -1 is returned.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ The order of the messages returned in the array is relevant.</para>
|
|
/// <para>/ Reliable messages will be received in the order they were sent (and with the</para>
|
|
/// <para>/ same sizes --- see SendMessageToConnection for on this subtle difference from a stream socket).</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Unreliable messages may be dropped, or delivered out of order with respect to</para>
|
|
/// <para>/ each other or with respect to reliable messages. The same unreliable message</para>
|
|
/// <para>/ may be received multiple times.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ If any messages are returned, you MUST call SteamNetworkingMessage_t::Release() on each</para>
|
|
/// <para>/ of them free up resources after you are done. It is safe to keep the object alive for</para>
|
|
/// <para>/ a little while (put it into some queue, etc), and you may call Release() from any thread.</para>
|
|
/// </summary>
|
|
public static int ReceiveMessagesOnConnection(HSteamNetConnection hConn, IntPtr[] ppOutMessages, int nMaxMessages) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_ReceiveMessagesOnConnection(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), hConn, ppOutMessages, nMaxMessages);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Returns basic information about the high-level state of the connection.</para>
|
|
/// </summary>
|
|
public static bool GetConnectionInfo(HSteamNetConnection hConn, out SteamNetConnectionInfo_t pInfo) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_GetConnectionInfo(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), hConn, out pInfo);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Returns a small set of information about the real-time state of the connection</para>
|
|
/// <para>/ and the queue status of each lane.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ - pStatus may be NULL if the information is not desired. (E.g. you are only interested</para>
|
|
/// <para>/ in the lane information.)</para>
|
|
/// <para>/ - On entry, nLanes specifies the length of the pLanes array. This may be 0</para>
|
|
/// <para>/ if you do not wish to receive any lane data. It's OK for this to be smaller than</para>
|
|
/// <para>/ the total number of configured lanes.</para>
|
|
/// <para>/ - pLanes points to an array that will receive lane-specific info. It can be NULL</para>
|
|
/// <para>/ if this is not needed.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Return value:</para>
|
|
/// <para>/ - k_EResultNoConnection - connection handle is invalid or connection has been closed.</para>
|
|
/// <para>/ - k_EResultInvalidParam - nLanes is bad</para>
|
|
/// </summary>
|
|
public static EResult GetConnectionRealTimeStatus(HSteamNetConnection hConn, ref SteamNetConnectionRealTimeStatus_t pStatus, int nLanes, ref SteamNetConnectionRealTimeLaneStatus_t pLanes) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_GetConnectionRealTimeStatus(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), hConn, ref pStatus, nLanes, ref pLanes);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Returns detailed connection stats in text format. Useful</para>
|
|
/// <para>/ for dumping to a log, etc.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Returns:</para>
|
|
/// <para>/ -1 failure (bad connection handle)</para>
|
|
/// <para>/ 0 OK, your buffer was filled in and '\0'-terminated</para>
|
|
/// <para>/ >0 Your buffer was either nullptr, or it was too small and the text got truncated.</para>
|
|
/// <para>/ Try again with a buffer of at least N bytes.</para>
|
|
/// </summary>
|
|
public static int GetDetailedConnectionStatus(HSteamNetConnection hConn, out string pszBuf, int cbBuf) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
IntPtr pszBuf2 = Marshal.AllocHGlobal(cbBuf);
|
|
int ret = NativeMethods.ISteamNetworkingSockets_GetDetailedConnectionStatus(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), hConn, pszBuf2, cbBuf);
|
|
pszBuf = ret != -1 ? InteropHelp.PtrToStringUTF8(pszBuf2) : null;
|
|
Marshal.FreeHGlobal(pszBuf2);
|
|
return ret;
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Returns local IP and port that a listen socket created using CreateListenSocketIP is bound to.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ An IPv6 address of ::0 means "any IPv4 or IPv6"</para>
|
|
/// <para>/ An IPv6 address of ::ffff:0000:0000 means "any IPv4"</para>
|
|
/// </summary>
|
|
public static bool GetListenSocketAddress(HSteamListenSocket hSocket, out SteamNetworkingIPAddr address) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_GetListenSocketAddress(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), hSocket, out address);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Create a pair of connections that are talking to each other, e.g. a loopback connection.</para>
|
|
/// <para>/ This is very useful for testing, or so that your client/server code can work the same</para>
|
|
/// <para>/ even when you are running a local "server".</para>
|
|
/// <para>/</para>
|
|
/// <para>/ The two connections will immediately be placed into the connected state, and no callbacks</para>
|
|
/// <para>/ will be posted immediately. After this, if you close either connection, the other connection</para>
|
|
/// <para>/ will receive a callback, exactly as if they were communicating over the network. You must</para>
|
|
/// <para>/ close *both* sides in order to fully clean up the resources!</para>
|
|
/// <para>/</para>
|
|
/// <para>/ By default, internal buffers are used, completely bypassing the network, the chopping up of</para>
|
|
/// <para>/ messages into packets, encryption, copying the payload, etc. This means that loopback</para>
|
|
/// <para>/ packets, by default, will not simulate lag or loss. Passing true for bUseNetworkLoopback will</para>
|
|
/// <para>/ cause the socket pair to send packets through the local network loopback device (127.0.0.1)</para>
|
|
/// <para>/ on ephemeral ports. Fake lag and loss are supported in this case, and CPU time is expended</para>
|
|
/// <para>/ to encrypt and decrypt.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ If you wish to assign a specific identity to either connection, you may pass a particular</para>
|
|
/// <para>/ identity. Otherwise, if you pass nullptr, the respective connection will assume a generic</para>
|
|
/// <para>/ "localhost" identity. If you use real network loopback, this might be translated to the</para>
|
|
/// <para>/ actual bound loopback port. Otherwise, the port will be zero.</para>
|
|
/// </summary>
|
|
public static bool CreateSocketPair(out HSteamNetConnection pOutConnection1, out HSteamNetConnection pOutConnection2, bool bUseNetworkLoopback, ref SteamNetworkingIdentity pIdentity1, ref SteamNetworkingIdentity pIdentity2) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_CreateSocketPair(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), out pOutConnection1, out pOutConnection2, bUseNetworkLoopback, ref pIdentity1, ref pIdentity2);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Configure multiple outbound messages streams ("lanes") on a connection, and</para>
|
|
/// <para>/ control head-of-line blocking between them. Messages within a given lane</para>
|
|
/// <para>/ are always sent in the order they are queued, but messages from different</para>
|
|
/// <para>/ lanes may be sent out of order. Each lane has its own message number</para>
|
|
/// <para>/ sequence. The first message sent on each lane will be assigned the number 1.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Each lane has a "priority". Lower priority lanes will only be processed</para>
|
|
/// <para>/ when all higher-priority lanes are empty. The magnitudes of the priority</para>
|
|
/// <para>/ values are not relevant, only their sort order. Higher numeric values</para>
|
|
/// <para>/ take priority over lower numeric values.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Each lane also is assigned a weight, which controls the approximate proportion</para>
|
|
/// <para>/ of the bandwidth that will be consumed by the lane, relative to other lanes</para>
|
|
/// <para>/ of the same priority. (This is assuming the lane stays busy. An idle lane</para>
|
|
/// <para>/ does not build up "credits" to be be spent once a message is queued.)</para>
|
|
/// <para>/ This value is only meaningful as a proportion, relative to other lanes with</para>
|
|
/// <para>/ the same priority. For lanes with different priorities, the strict priority</para>
|
|
/// <para>/ order will prevail, and their weights relative to each other are not relevant.</para>
|
|
/// <para>/ Thus, if a lane has a unique priority value, the weight value for that lane is</para>
|
|
/// <para>/ not relevant.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Example: 3 lanes, with priorities [ 0, 10, 10 ] and weights [ (NA), 20, 5 ].</para>
|
|
/// <para>/ Messages sent on the first will always be sent first, before messages in the</para>
|
|
/// <para>/ other two lanes. Its weight value is irrelevant, since there are no other</para>
|
|
/// <para>/ lanes with priority=0. The other two lanes will share bandwidth, with the second</para>
|
|
/// <para>/ and third lanes sharing bandwidth using a ratio of approximately 4:1.</para>
|
|
/// <para>/ (The weights [ NA, 4, 1 ] would be equivalent.)</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Notes:</para>
|
|
/// <para>/ - At the time of this writing, some code has performance cost that is linear</para>
|
|
/// <para>/ in the number of lanes, so keep the number of lanes to an absolute minimum.</para>
|
|
/// <para>/ 3 or so is fine; >8 is a lot. The max number of lanes on Steam is 255,</para>
|
|
/// <para>/ which is a very large number and not recommended! If you are compiling this</para>
|
|
/// <para>/ library from source, see STEAMNETWORKINGSOCKETS_MAX_LANES.)</para>
|
|
/// <para>/ - Lane priority values may be any int. Their absolute value is not relevant,</para>
|
|
/// <para>/ only the order matters.</para>
|
|
/// <para>/ - Weights must be positive, and due to implementation details, they are restricted</para>
|
|
/// <para>/ to 16-bit values. The absolute magnitudes don't matter, just the proportions.</para>
|
|
/// <para>/ - Messages sent on a lane index other than 0 have a small overhead on the wire,</para>
|
|
/// <para>/ so for maximum wire efficiency, lane 0 should be the "most common" lane, regardless</para>
|
|
/// <para>/ of priorities or weights.</para>
|
|
/// <para>/ - A connection has a single lane by default. Calling this function with</para>
|
|
/// <para>/ nNumLanes=1 is legal, but pointless, since the priority and weight values are</para>
|
|
/// <para>/ irrelevant in that case.</para>
|
|
/// <para>/ - You may reconfigure connection lanes at any time, however reducing the number of</para>
|
|
/// <para>/ lanes is not allowed.</para>
|
|
/// <para>/ - Reconfiguring lanes might restart any bandwidth sharing balancing. Usually you</para>
|
|
/// <para>/ will call this function once, near the start of the connection, perhaps after</para>
|
|
/// <para>/ exchanging a few messages.</para>
|
|
/// <para>/ - To assign all lanes the same priority, you may use pLanePriorities=NULL.</para>
|
|
/// <para>/ - If you wish all lanes with the same priority to share bandwidth equally (or</para>
|
|
/// <para>/ if no two lanes have the same priority value, and thus priority values are</para>
|
|
/// <para>/ irrelevant), you may use pLaneWeights=NULL</para>
|
|
/// <para>/ - Priorities and weights determine the order that messages are SENT on the wire.</para>
|
|
/// <para>/ There are NO GUARANTEES on the order that messages are RECEIVED! Due to packet</para>
|
|
/// <para>/ loss, out-of-order delivery, and subtle details of packet serialization, messages</para>
|
|
/// <para>/ might still be received slightly out-of-order! The *only* strong guarantee is that</para>
|
|
/// <para>/ *reliable* messages on the *same lane* will be delivered in the order they are sent.</para>
|
|
/// <para>/ - Each host configures the lanes for the packets they send; the lanes for the flow</para>
|
|
/// <para>/ in one direction are completely unrelated to the lanes in the opposite direction.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Return value:</para>
|
|
/// <para>/ - k_EResultNoConnection - bad hConn</para>
|
|
/// <para>/ - k_EResultInvalidParam - Invalid number of lanes, bad weights, or you tried to reduce the number of lanes</para>
|
|
/// <para>/ - k_EResultInvalidState - Connection is already dead, etc</para>
|
|
/// <para>/</para>
|
|
/// <para>/ See also:</para>
|
|
/// <para>/ SteamNetworkingMessage_t::m_idxLane</para>
|
|
/// </summary>
|
|
public static EResult ConfigureConnectionLanes(HSteamNetConnection hConn, int nNumLanes, out int pLanePriorities, out ushort pLaneWeights) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_ConfigureConnectionLanes(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), hConn, nNumLanes, out pLanePriorities, out pLaneWeights);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para> Identity and authentication</para>
|
|
/// <para>/ Get the identity assigned to this interface.</para>
|
|
/// <para>/ E.g. on Steam, this is the user's SteamID, or for the gameserver interface, the SteamID assigned</para>
|
|
/// <para>/ to the gameserver. Returns false and sets the result to an invalid identity if we don't know</para>
|
|
/// <para>/ our identity yet. (E.g. GameServer has not logged in. On Steam, the user will know their SteamID</para>
|
|
/// <para>/ even if they are not signed into Steam.)</para>
|
|
/// </summary>
|
|
public static bool GetIdentity(out SteamNetworkingIdentity pIdentity) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_GetIdentity(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), out pIdentity);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Indicate our desire to be ready participate in authenticated communications.</para>
|
|
/// <para>/ If we are currently not ready, then steps will be taken to obtain the necessary</para>
|
|
/// <para>/ certificates. (This includes a certificate for us, as well as any CA certificates</para>
|
|
/// <para>/ needed to authenticate peers.)</para>
|
|
/// <para>/</para>
|
|
/// <para>/ You can call this at program init time if you know that you are going to</para>
|
|
/// <para>/ be making authenticated connections, so that we will be ready immediately when</para>
|
|
/// <para>/ those connections are attempted. (Note that essentially all connections require</para>
|
|
/// <para>/ authentication, with the exception of ordinary UDP connections with authentication</para>
|
|
/// <para>/ disabled using k_ESteamNetworkingConfig_IP_AllowWithoutAuth.) If you don't call</para>
|
|
/// <para>/ this function, we will wait until a feature is utilized that that necessitates</para>
|
|
/// <para>/ these resources.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ You can also call this function to force a retry, if failure has occurred.</para>
|
|
/// <para>/ Once we make an attempt and fail, we will not automatically retry.</para>
|
|
/// <para>/ In this respect, the behavior of the system after trying and failing is the same</para>
|
|
/// <para>/ as before the first attempt: attempting authenticated communication or calling</para>
|
|
/// <para>/ this function will call the system to attempt to acquire the necessary resources.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ You can use GetAuthenticationStatus or listen for SteamNetAuthenticationStatus_t</para>
|
|
/// <para>/ to monitor the status.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Returns the current value that would be returned from GetAuthenticationStatus.</para>
|
|
/// </summary>
|
|
public static ESteamNetworkingAvailability InitAuthentication() {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_InitAuthentication(CSteamGameServerAPIContext.GetSteamNetworkingSockets());
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Query our readiness to participate in authenticated communications. A</para>
|
|
/// <para>/ SteamNetAuthenticationStatus_t callback is posted any time this status changes,</para>
|
|
/// <para>/ but you can use this function to query it at any time.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ The value of SteamNetAuthenticationStatus_t::m_eAvail is returned. If you only</para>
|
|
/// <para>/ want this high level status, you can pass NULL for pDetails. If you want further</para>
|
|
/// <para>/ details, pass non-NULL to receive them.</para>
|
|
/// </summary>
|
|
public static ESteamNetworkingAvailability GetAuthenticationStatus(out SteamNetAuthenticationStatus_t pDetails) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_GetAuthenticationStatus(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), out pDetails);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para> Poll groups. A poll group is a set of connections that can be polled efficiently.</para>
|
|
/// <para> (In our API, to "poll" a connection means to retrieve all pending messages. We</para>
|
|
/// <para> actually don't have an API to "poll" the connection *state*, like BSD sockets.)</para>
|
|
/// <para>/ Create a new poll group.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ You should destroy the poll group when you are done using DestroyPollGroup</para>
|
|
/// </summary>
|
|
public static HSteamNetPollGroup CreatePollGroup() {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return (HSteamNetPollGroup)NativeMethods.ISteamNetworkingSockets_CreatePollGroup(CSteamGameServerAPIContext.GetSteamNetworkingSockets());
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Destroy a poll group created with CreatePollGroup().</para>
|
|
/// <para>/</para>
|
|
/// <para>/ If there are any connections in the poll group, they are removed from the group,</para>
|
|
/// <para>/ and left in a state where they are not part of any poll group.</para>
|
|
/// <para>/ Returns false if passed an invalid poll group handle.</para>
|
|
/// </summary>
|
|
public static bool DestroyPollGroup(HSteamNetPollGroup hPollGroup) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_DestroyPollGroup(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), hPollGroup);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Assign a connection to a poll group. Note that a connection may only belong to a</para>
|
|
/// <para>/ single poll group. Adding a connection to a poll group implicitly removes it from</para>
|
|
/// <para>/ any other poll group it is in.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ You can pass k_HSteamNetPollGroup_Invalid to remove a connection from its current</para>
|
|
/// <para>/ poll group without adding it to a new poll group.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ If there are received messages currently pending on the connection, an attempt</para>
|
|
/// <para>/ is made to add them to the queue of messages for the poll group in approximately</para>
|
|
/// <para>/ the order that would have applied if the connection was already part of the poll</para>
|
|
/// <para>/ group at the time that the messages were received.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Returns false if the connection handle is invalid, or if the poll group handle</para>
|
|
/// <para>/ is invalid (and not k_HSteamNetPollGroup_Invalid).</para>
|
|
/// </summary>
|
|
public static bool SetConnectionPollGroup(HSteamNetConnection hConn, HSteamNetPollGroup hPollGroup) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_SetConnectionPollGroup(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), hConn, hPollGroup);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Same as ReceiveMessagesOnConnection, but will return the next messages available</para>
|
|
/// <para>/ on any connection in the poll group. Examine SteamNetworkingMessage_t::m_conn</para>
|
|
/// <para>/ to know which connection. (SteamNetworkingMessage_t::m_nConnUserData might also</para>
|
|
/// <para>/ be useful.)</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Delivery order of messages among different connections will usually match the</para>
|
|
/// <para>/ order that the last packet was received which completed the message. But this</para>
|
|
/// <para>/ is not a strong guarantee, especially for packets received right as a connection</para>
|
|
/// <para>/ is being assigned to poll group.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Delivery order of messages on the same connection is well defined and the</para>
|
|
/// <para>/ same guarantees are present as mentioned in ReceiveMessagesOnConnection.</para>
|
|
/// <para>/ (But the messages are not grouped by connection, so they will not necessarily</para>
|
|
/// <para>/ appear consecutively in the list; they may be interleaved with messages for</para>
|
|
/// <para>/ other connections.)</para>
|
|
/// </summary>
|
|
public static int ReceiveMessagesOnPollGroup(HSteamNetPollGroup hPollGroup, IntPtr[] ppOutMessages, int nMaxMessages) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_ReceiveMessagesOnPollGroup(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), hPollGroup, ppOutMessages, nMaxMessages);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para> Clients connecting to dedicated servers hosted in a data center,</para>
|
|
/// <para> using tickets issued by your game coordinator. If you are not</para>
|
|
/// <para> issuing your own tickets to restrict who can attempt to connect</para>
|
|
/// <para> to your server, then you won't use these functions.</para>
|
|
/// <para>/ Call this when you receive a ticket from your backend / matchmaking system. Puts the</para>
|
|
/// <para>/ ticket into a persistent cache, and optionally returns the parsed ticket.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ See stamdatagram_ticketgen.h for more details.</para>
|
|
/// </summary>
|
|
public static bool ReceivedRelayAuthTicket(IntPtr pvTicket, int cbTicket, out SteamDatagramRelayAuthTicket pOutParsedTicket) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_ReceivedRelayAuthTicket(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), pvTicket, cbTicket, out pOutParsedTicket);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Search cache for a ticket to talk to the server on the specified virtual port.</para>
|
|
/// <para>/ If found, returns the number of seconds until the ticket expires, and optionally</para>
|
|
/// <para>/ the complete cracked ticket. Returns 0 if we don't have a ticket.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Typically this is useful just to confirm that you have a ticket, before you</para>
|
|
/// <para>/ call ConnectToHostedDedicatedServer to connect to the server.</para>
|
|
/// </summary>
|
|
public static int FindRelayAuthTicketForServer(ref SteamNetworkingIdentity identityGameServer, int nRemoteVirtualPort, out SteamDatagramRelayAuthTicket pOutParsedTicket) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_FindRelayAuthTicketForServer(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), ref identityGameServer, nRemoteVirtualPort, out pOutParsedTicket);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Client call to connect to a server hosted in a Valve data center, on the specified virtual</para>
|
|
/// <para>/ port. You must have placed a ticket for this server into the cache, or else this connect</para>
|
|
/// <para>/ attempt will fail! If you are not issuing your own tickets, then to connect to a dedicated</para>
|
|
/// <para>/ server via SDR in auto-ticket mode, use ConnectP2P. (The server must be configured to allow</para>
|
|
/// <para>/ this type of connection by listening using CreateListenSocketP2P.)</para>
|
|
/// <para>/</para>
|
|
/// <para>/ You may wonder why tickets are stored in a cache, instead of simply being passed as an argument</para>
|
|
/// <para>/ here. The reason is to make reconnection to a gameserver robust, even if the client computer loses</para>
|
|
/// <para>/ connection to Steam or the central backend, or the app is restarted or crashes, etc.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ If you use this, you probably want to call ISteamNetworkingUtils::InitRelayNetworkAccess()</para>
|
|
/// <para>/ when your app initializes</para>
|
|
/// <para>/</para>
|
|
/// <para>/ If you need to set any initial config options, pass them here. See</para>
|
|
/// <para>/ SteamNetworkingConfigValue_t for more about why this is preferable to</para>
|
|
/// <para>/ setting the options "immediately" after creation.</para>
|
|
/// </summary>
|
|
public static HSteamNetConnection ConnectToHostedDedicatedServer(ref SteamNetworkingIdentity identityTarget, int nRemoteVirtualPort, int nOptions, SteamNetworkingConfigValue_t[] pOptions) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return (HSteamNetConnection)NativeMethods.ISteamNetworkingSockets_ConnectToHostedDedicatedServer(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), ref identityTarget, nRemoteVirtualPort, nOptions, pOptions);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para> Servers hosted in data centers known to the Valve relay network</para>
|
|
/// <para>/ Returns the value of the SDR_LISTEN_PORT environment variable. This</para>
|
|
/// <para>/ is the UDP server your server will be listening on. This will</para>
|
|
/// <para>/ configured automatically for you in production environments.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ In development, you'll need to set it yourself. See</para>
|
|
/// <para>/ https://partner.steamgames.com/doc/api/ISteamNetworkingSockets</para>
|
|
/// <para>/ for more information on how to configure dev environments.</para>
|
|
/// </summary>
|
|
public static ushort GetHostedDedicatedServerPort() {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_GetHostedDedicatedServerPort(CSteamGameServerAPIContext.GetSteamNetworkingSockets());
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Returns 0 if SDR_LISTEN_PORT is not set. Otherwise, returns the data center the server</para>
|
|
/// <para>/ is running in. This will be k_SteamDatagramPOPID_dev in non-production environment.</para>
|
|
/// </summary>
|
|
public static SteamNetworkingPOPID GetHostedDedicatedServerPOPID() {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return (SteamNetworkingPOPID)NativeMethods.ISteamNetworkingSockets_GetHostedDedicatedServerPOPID(CSteamGameServerAPIContext.GetSteamNetworkingSockets());
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Return info about the hosted server. This contains the PoPID of the server,</para>
|
|
/// <para>/ and opaque routing information that can be used by the relays to send traffic</para>
|
|
/// <para>/ to your server.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ You will need to send this information to your backend, and put it in tickets,</para>
|
|
/// <para>/ so that the relays will know how to forward traffic from</para>
|
|
/// <para>/ clients to your server. See SteamDatagramRelayAuthTicket for more info.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Also, note that the routing information is contained in SteamDatagramGameCoordinatorServerLogin,</para>
|
|
/// <para>/ so if possible, it's preferred to use GetGameCoordinatorServerLogin to send this info</para>
|
|
/// <para>/ to your game coordinator service, and also login securely at the same time.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ On a successful exit, k_EResultOK is returned</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Unsuccessful exit:</para>
|
|
/// <para>/ - Something other than k_EResultOK is returned.</para>
|
|
/// <para>/ - k_EResultInvalidState: We are not configured to listen for SDR (SDR_LISTEN_SOCKET</para>
|
|
/// <para>/ is not set.)</para>
|
|
/// <para>/ - k_EResultPending: we do not (yet) have the authentication information needed.</para>
|
|
/// <para>/ (See GetAuthenticationStatus.) If you use environment variables to pre-fetch</para>
|
|
/// <para>/ the network config, this data should always be available immediately.</para>
|
|
/// <para>/ - A non-localized diagnostic debug message will be placed in m_data that describes</para>
|
|
/// <para>/ the cause of the failure.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ NOTE: The returned blob is not encrypted. Send it to your backend, but don't</para>
|
|
/// <para>/ directly share it with clients.</para>
|
|
/// </summary>
|
|
public static EResult GetHostedDedicatedServerAddress(out SteamDatagramHostedAddress pRouting) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_GetHostedDedicatedServerAddress(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), out pRouting);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Create a listen socket on the specified virtual port. The physical UDP port to use</para>
|
|
/// <para>/ will be determined by the SDR_LISTEN_PORT environment variable. If a UDP port is not</para>
|
|
/// <para>/ configured, this call will fail.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ This call MUST be made through the SteamGameServerNetworkingSockets() interface.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ This function should be used when you are using the ticket generator library</para>
|
|
/// <para>/ to issue your own tickets. Clients connecting to the server on this virtual</para>
|
|
/// <para>/ port will need a ticket, and they must connect using ConnectToHostedDedicatedServer.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ If you need to set any initial config options, pass them here. See</para>
|
|
/// <para>/ SteamNetworkingConfigValue_t for more about why this is preferable to</para>
|
|
/// <para>/ setting the options "immediately" after creation.</para>
|
|
/// </summary>
|
|
public static HSteamListenSocket CreateHostedDedicatedServerListenSocket(int nLocalVirtualPort, int nOptions, SteamNetworkingConfigValue_t[] pOptions) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return (HSteamListenSocket)NativeMethods.ISteamNetworkingSockets_CreateHostedDedicatedServerListenSocket(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), nLocalVirtualPort, nOptions, pOptions);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Generate an authentication blob that can be used to securely login with</para>
|
|
/// <para>/ your backend, using SteamDatagram_ParseHostedServerLogin. (See</para>
|
|
/// <para>/ steamdatagram_gamecoordinator.h)</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Before calling the function:</para>
|
|
/// <para>/ - Populate the app data in pLoginInfo (m_cbAppData and m_appData). You can leave</para>
|
|
/// <para>/ all other fields uninitialized.</para>
|
|
/// <para>/ - *pcbSignedBlob contains the size of the buffer at pBlob. (It should be</para>
|
|
/// <para>/ at least k_cbMaxSteamDatagramGameCoordinatorServerLoginSerialized.)</para>
|
|
/// <para>/</para>
|
|
/// <para>/ On a successful exit:</para>
|
|
/// <para>/ - k_EResultOK is returned</para>
|
|
/// <para>/ - All of the remaining fields of pLoginInfo will be filled out.</para>
|
|
/// <para>/ - *pcbSignedBlob contains the size of the serialized blob that has been</para>
|
|
/// <para>/ placed into pBlob.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Unsuccessful exit:</para>
|
|
/// <para>/ - Something other than k_EResultOK is returned.</para>
|
|
/// <para>/ - k_EResultNotLoggedOn: you are not logged in (yet)</para>
|
|
/// <para>/ - See GetHostedDedicatedServerAddress for more potential failure return values.</para>
|
|
/// <para>/ - A non-localized diagnostic debug message will be placed in pBlob that describes</para>
|
|
/// <para>/ the cause of the failure.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ This works by signing the contents of the SteamDatagramGameCoordinatorServerLogin</para>
|
|
/// <para>/ with the cert that is issued to this server. In dev environments, it's OK if you do</para>
|
|
/// <para>/ not have a cert. (You will need to enable insecure dev login in SteamDatagram_ParseHostedServerLogin.)</para>
|
|
/// <para>/ Otherwise, you will need a signed cert.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ NOTE: The routing blob returned here is not encrypted. Send it to your backend</para>
|
|
/// <para>/ and don't share it directly with clients.</para>
|
|
/// </summary>
|
|
public static EResult GetGameCoordinatorServerLogin(IntPtr pLoginInfo, out int pcbSignedBlob, IntPtr pBlob) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_GetGameCoordinatorServerLogin(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), pLoginInfo, out pcbSignedBlob, pBlob);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para> Relayed connections using custom signaling protocol</para>
|
|
/// <para> This is used if you have your own method of sending out-of-band</para>
|
|
/// <para> signaling / rendezvous messages through a mutually trusted channel.</para>
|
|
/// <para>/ Create a P2P "client" connection that does signaling over a custom</para>
|
|
/// <para>/ rendezvous/signaling channel.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ pSignaling points to a new object that you create just for this connection.</para>
|
|
/// <para>/ It must stay valid until Release() is called. Once you pass the</para>
|
|
/// <para>/ object to this function, it assumes ownership. Release() will be called</para>
|
|
/// <para>/ from within the function call if the call fails. Furthermore, until Release()</para>
|
|
/// <para>/ is called, you should be prepared for methods to be invoked on your</para>
|
|
/// <para>/ object from any thread! You need to make sure your object is threadsafe!</para>
|
|
/// <para>/ Furthermore, you should make sure that dispatching the methods is done</para>
|
|
/// <para>/ as quickly as possible.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ This function will immediately construct a connection in the "connecting"</para>
|
|
/// <para>/ state. Soon after (perhaps before this function returns, perhaps in another thread),</para>
|
|
/// <para>/ the connection will begin sending signaling messages by calling</para>
|
|
/// <para>/ ISteamNetworkingConnectionSignaling::SendSignal.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ When the remote peer accepts the connection (See</para>
|
|
/// <para>/ ISteamNetworkingSignalingRecvContext::OnConnectRequest),</para>
|
|
/// <para>/ it will begin sending signaling messages. When these messages are received,</para>
|
|
/// <para>/ you can pass them to the connection using ReceivedP2PCustomSignal.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ If you know the identity of the peer that you expect to be on the other end,</para>
|
|
/// <para>/ you can pass their identity to improve debug output or just detect bugs.</para>
|
|
/// <para>/ If you don't know their identity yet, you can pass NULL, and their</para>
|
|
/// <para>/ identity will be established in the connection handshake.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ If you use this, you probably want to call ISteamNetworkingUtils::InitRelayNetworkAccess()</para>
|
|
/// <para>/ when your app initializes</para>
|
|
/// <para>/</para>
|
|
/// <para>/ If you need to set any initial config options, pass them here. See</para>
|
|
/// <para>/ SteamNetworkingConfigValue_t for more about why this is preferable to</para>
|
|
/// <para>/ setting the options "immediately" after creation.</para>
|
|
/// </summary>
|
|
public static HSteamNetConnection ConnectP2PCustomSignaling(out ISteamNetworkingConnectionSignaling pSignaling, ref SteamNetworkingIdentity pPeerIdentity, int nRemoteVirtualPort, int nOptions, SteamNetworkingConfigValue_t[] pOptions) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return (HSteamNetConnection)NativeMethods.ISteamNetworkingSockets_ConnectP2PCustomSignaling(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), out pSignaling, ref pPeerIdentity, nRemoteVirtualPort, nOptions, pOptions);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Called when custom signaling has received a message. When your</para>
|
|
/// <para>/ signaling channel receives a message, it should save off whatever</para>
|
|
/// <para>/ routing information was in the envelope into the context object,</para>
|
|
/// <para>/ and then pass the payload to this function.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ A few different things can happen next, depending on the message:</para>
|
|
/// <para>/</para>
|
|
/// <para>/ - If the signal is associated with existing connection, it is dealt</para>
|
|
/// <para>/ with immediately. If any replies need to be sent, they will be</para>
|
|
/// <para>/ dispatched using the ISteamNetworkingConnectionSignaling</para>
|
|
/// <para>/ associated with the connection.</para>
|
|
/// <para>/ - If the message represents a connection request (and the request</para>
|
|
/// <para>/ is not redundant for an existing connection), a new connection</para>
|
|
/// <para>/ will be created, and ReceivedConnectRequest will be called on your</para>
|
|
/// <para>/ context object to determine how to proceed.</para>
|
|
/// <para>/ - Otherwise, the message is for a connection that does not</para>
|
|
/// <para>/ exist (anymore). In this case, we *may* call SendRejectionReply</para>
|
|
/// <para>/ on your context object.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ In any case, we will not save off pContext or access it after this</para>
|
|
/// <para>/ function returns.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Returns true if the message was parsed and dispatched without anything</para>
|
|
/// <para>/ unusual or suspicious happening. Returns false if there was some problem</para>
|
|
/// <para>/ with the message that prevented ordinary handling. (Debug output will</para>
|
|
/// <para>/ usually have more information.)</para>
|
|
/// <para>/</para>
|
|
/// <para>/ If you expect to be using relayed connections, then you probably want</para>
|
|
/// <para>/ to call ISteamNetworkingUtils::InitRelayNetworkAccess() when your app initializes</para>
|
|
/// </summary>
|
|
public static bool ReceivedP2PCustomSignal(IntPtr pMsg, int cbMsg, out ISteamNetworkingSignalingRecvContext pContext) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_ReceivedP2PCustomSignal(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), pMsg, cbMsg, out pContext);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para> Certificate provision by the application. On Steam, we normally handle all this automatically</para>
|
|
/// <para> and you will not need to use these advanced functions.</para>
|
|
/// <para>/ Get blob that describes a certificate request. You can send this to your game coordinator.</para>
|
|
/// <para>/ Upon entry, *pcbBlob should contain the size of the buffer. On successful exit, it will</para>
|
|
/// <para>/ return the number of bytes that were populated. You can pass pBlob=NULL to query for the required</para>
|
|
/// <para>/ size. (512 bytes is a conservative estimate.)</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Pass this blob to your game coordinator and call SteamDatagram_CreateCert.</para>
|
|
/// </summary>
|
|
public static bool GetCertificateRequest(out int pcbBlob, IntPtr pBlob, out SteamNetworkingErrMsg errMsg) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_GetCertificateRequest(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), out pcbBlob, pBlob, out errMsg);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Set the certificate. The certificate blob should be the output of</para>
|
|
/// <para>/ SteamDatagram_CreateCert.</para>
|
|
/// </summary>
|
|
public static bool SetCertificate(IntPtr pCertificate, int cbCertificate, out SteamNetworkingErrMsg errMsg) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_SetCertificate(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), pCertificate, cbCertificate, out errMsg);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Reset the identity associated with this instance.</para>
|
|
/// <para>/ Any open connections are closed. Any previous certificates, etc are discarded.</para>
|
|
/// <para>/ You can pass a specific identity that you want to use, or you can pass NULL,</para>
|
|
/// <para>/ in which case the identity will be invalid until you set it using SetCertificate</para>
|
|
/// <para>/</para>
|
|
/// <para>/ NOTE: This function is not actually supported on Steam! It is included</para>
|
|
/// <para>/ for use on other platforms where the active user can sign out and</para>
|
|
/// <para>/ a new user can sign in.</para>
|
|
/// </summary>
|
|
public static void ResetIdentity(ref SteamNetworkingIdentity pIdentity) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
NativeMethods.ISteamNetworkingSockets_ResetIdentity(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), ref pIdentity);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para> Misc</para>
|
|
/// <para>/ Invoke all callback functions queued for this interface.</para>
|
|
/// <para>/ See k_ESteamNetworkingConfig_Callback_ConnectionStatusChanged, etc</para>
|
|
/// <para>/</para>
|
|
/// <para>/ You don't need to call this if you are using Steam's callback dispatch</para>
|
|
/// <para>/ mechanism (SteamAPI_RunCallbacks and SteamGameserver_RunCallbacks).</para>
|
|
/// </summary>
|
|
public static void RunCallbacks() {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
NativeMethods.ISteamNetworkingSockets_RunCallbacks(CSteamGameServerAPIContext.GetSteamNetworkingSockets());
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para> "FakeIP" system.</para>
|
|
/// <para> A FakeIP is essentially a temporary, arbitrary identifier that</para>
|
|
/// <para> happens to be a valid IPv4 address. The purpose of this system is to make it</para>
|
|
/// <para> easy to integrate with existing code that identifies hosts using IPv4 addresses.</para>
|
|
/// <para> The FakeIP address will never actually be used to send or receive any packets</para>
|
|
/// <para> on the Internet, it is strictly an identifier.</para>
|
|
/// <para> FakeIP addresses are designed to (hopefully) pass through existing code as</para>
|
|
/// <para> transparently as possible, while conflicting with "real" addresses that might</para>
|
|
/// <para> be in use on networks (both the Internet and LANs) in the same code as little</para>
|
|
/// <para> as possible. At the time this comment is being written, they come from the</para>
|
|
/// <para> 169.254.0.0/16 range, and the port number will always be >1024. HOWEVER,</para>
|
|
/// <para> this is subject to change! Do not make assumptions about these addresses,</para>
|
|
/// <para> or your code might break in the future. In particular, you should use</para>
|
|
/// <para> functions such as ISteamNetworkingUtils::IsFakeIP to determine if an IP</para>
|
|
/// <para> address is a "fake" one used by this system.</para>
|
|
/// <para>/ Begin asynchronous process of allocating a fake IPv4 address that other</para>
|
|
/// <para>/ peers can use to contact us via P2P. IP addresses returned by this</para>
|
|
/// <para>/ function are globally unique for a given appid.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ nNumPorts is the numbers of ports you wish to reserve. This is useful</para>
|
|
/// <para>/ for the same reason that listening on multiple UDP ports is useful for</para>
|
|
/// <para>/ different types of traffic. Because these allocations come from a global</para>
|
|
/// <para>/ namespace, there is a relatively strict limit on the maximum number of</para>
|
|
/// <para>/ ports you may request. (At the time of this writing, the limit is 4.)</para>
|
|
/// <para>/ The Port assignments are *not* guaranteed to have any particular order</para>
|
|
/// <para>/ or relationship! Do *not* assume they are contiguous, even though that</para>
|
|
/// <para>/ may often occur in practice.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ Returns false if a request was already in progress, true if a new request</para>
|
|
/// <para>/ was started. A SteamNetworkingFakeIPResult_t will be posted when the request</para>
|
|
/// <para>/ completes.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ For gameservers, you *must* call this after initializing the SDK but before</para>
|
|
/// <para>/ beginning login. Steam needs to know in advance that FakeIP will be used.</para>
|
|
/// <para>/ Everywhere your public IP would normally appear (such as the server browser) will be</para>
|
|
/// <para>/ replaced by the FakeIP, and the fake port at index 0. The request is actually queued</para>
|
|
/// <para>/ until the logon completes, so you must not wait until the allocation completes</para>
|
|
/// <para>/ before logging in. Except for trivial failures that can be detected locally</para>
|
|
/// <para>/ (e.g. invalid parameter), a SteamNetworkingFakeIPResult_t callback (whether success or</para>
|
|
/// <para>/ failure) will not be posted until after we have logged in. Furthermore, it is assumed</para>
|
|
/// <para>/ that FakeIP allocation is essential for your application to function, and so failure</para>
|
|
/// <para>/ will not be reported until *several* retries have been attempted. This process may</para>
|
|
/// <para>/ last several minutes. It is *highly* recommended to treat failure as fatal.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ To communicate using a connection-oriented (TCP-style) API:</para>
|
|
/// <para>/ - Server creates a listen socket using CreateListenSocketP2PFakeIP</para>
|
|
/// <para>/ - Client connects using ConnectByIPAddress, passing in the FakeIP address.</para>
|
|
/// <para>/ - The connection will behave mostly like a P2P connection. The identities</para>
|
|
/// <para>/ that appear in SteamNetConnectionInfo_t will be the FakeIP identity until</para>
|
|
/// <para>/ we know the real identity. Then it will be the real identity. If the</para>
|
|
/// <para>/ SteamNetConnectionInfo_t::m_addrRemote is valid, it will be a real IPv4</para>
|
|
/// <para>/ address of a NAT-punched connection. Otherwise, it will not be valid.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ To communicate using an ad-hoc sendto/recv from (UDP-style) API,</para>
|
|
/// <para>/ use CreateFakeUDPPort.</para>
|
|
/// </summary>
|
|
public static bool BeginAsyncRequestFakeIP(int nNumPorts) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_BeginAsyncRequestFakeIP(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), nNumPorts);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Return info about the FakeIP and port(s) that we have been assigned,</para>
|
|
/// <para>/ if any. idxFirstPort is currently reserved and must be zero.</para>
|
|
/// <para>/ Make sure and check SteamNetworkingFakeIPResult_t::m_eResult</para>
|
|
/// </summary>
|
|
public static void GetFakeIP(int idxFirstPort, out SteamNetworkingFakeIPResult_t pInfo) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
NativeMethods.ISteamNetworkingSockets_GetFakeIP(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), idxFirstPort, out pInfo);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Create a listen socket that will listen for P2P connections sent</para>
|
|
/// <para>/ to our FakeIP. A peer can initiate connections to this listen</para>
|
|
/// <para>/ socket by calling ConnectByIPAddress.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ idxFakePort refers to the *index* of the fake port requested,</para>
|
|
/// <para>/ not the actual port number. For example, pass 0 to refer to the</para>
|
|
/// <para>/ first port in the reservation. You must call this only after calling</para>
|
|
/// <para>/ BeginAsyncRequestFakeIP. However, you do not need to wait for the</para>
|
|
/// <para>/ request to complete before creating the listen socket.</para>
|
|
/// </summary>
|
|
public static HSteamListenSocket CreateListenSocketP2PFakeIP(int idxFakePort, int nOptions, SteamNetworkingConfigValue_t[] pOptions) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return (HSteamListenSocket)NativeMethods.ISteamNetworkingSockets_CreateListenSocketP2PFakeIP(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), idxFakePort, nOptions, pOptions);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ If the connection was initiated using the "FakeIP" system, then we</para>
|
|
/// <para>/ we can get an IP address for the remote host. If the remote host had</para>
|
|
/// <para>/ a global FakeIP at the time the connection was established, this</para>
|
|
/// <para>/ function will return that global IP. Otherwise, a FakeIP that is</para>
|
|
/// <para>/ unique locally will be allocated from the local FakeIP address space,</para>
|
|
/// <para>/ and that will be returned.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ The allocation of local FakeIPs attempts to assign addresses in</para>
|
|
/// <para>/ a consistent manner. If multiple connections are made to the</para>
|
|
/// <para>/ same remote host, they *probably* will return the same FakeIP.</para>
|
|
/// <para>/ However, since the namespace is limited, this cannot be guaranteed.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ On failure, returns:</para>
|
|
/// <para>/ - k_EResultInvalidParam: invalid connection handle</para>
|
|
/// <para>/ - k_EResultIPNotFound: This connection wasn't made using FakeIP system</para>
|
|
/// </summary>
|
|
public static EResult GetRemoteFakeIPForConnection(HSteamNetConnection hConn, out SteamNetworkingIPAddr pOutAddr) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_GetRemoteFakeIPForConnection(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), hConn, out pOutAddr);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>/ Get an interface that can be used like a UDP port to send/receive</para>
|
|
/// <para>/ datagrams to a FakeIP address. This is intended to make it easy</para>
|
|
/// <para>/ to port existing UDP-based code to take advantage of SDR.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ idxFakeServerPort refers to the *index* of the port allocated using</para>
|
|
/// <para>/ BeginAsyncRequestFakeIP and is used to create "server" ports. You may</para>
|
|
/// <para>/ call this before the allocation has completed. However, any attempts</para>
|
|
/// <para>/ to send packets will fail until the allocation has succeeded. When</para>
|
|
/// <para>/ the peer receives packets sent from this interface, the from address</para>
|
|
/// <para>/ of the packet will be the globally-unique FakeIP. If you call this</para>
|
|
/// <para>/ function multiple times and pass the same (nonnegative) fake port index,</para>
|
|
/// <para>/ the same object will be returned, and this object is not reference counted.</para>
|
|
/// <para>/</para>
|
|
/// <para>/ To create a "client" port (e.g. the equivalent of an ephemeral UDP port)</para>
|
|
/// <para>/ pass -1. In this case, a distinct object will be returned for each call.</para>
|
|
/// <para>/ When the peer receives packets sent from this interface, the peer will</para>
|
|
/// <para>/ assign a FakeIP from its own locally-controlled namespace.</para>
|
|
/// </summary>
|
|
public static IntPtr CreateFakeUDPPort(int idxFakeServerPort) {
|
|
InteropHelp.TestIfAvailableGameServer();
|
|
return NativeMethods.ISteamNetworkingSockets_CreateFakeUDPPort(CSteamGameServerAPIContext.GetSteamNetworkingSockets(), idxFakeServerPort);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // !DISABLESTEAMWORKS
|