1 /// Transcription of isteamnetworkingsockets.h to D.
2 ///
3 /// Copyright: Valve Corporation, all rights reserved
4 module steam_gns.sockets;
5 
6 import std.string;
7 
8 import steam_gns.misc;
9 import steam_gns.types;
10 import steam_gns.client_public;
11 
12 @nogc nothrow extern (C++) align(4):
13 
14 
15 // defines from steam_gns.types
16 version = STEAMNETWORKINGSOCKETS_STANDALONELIB;
17 
18 // Where are those defined‽
19 struct SteamDatagramRelayAuthTicket;
20 struct SteamDatagramHostedAddress;
21 struct SteamNetworkingFakeIPResult_t;
22 struct SteamDatagramGameCoordinatorServerLogin;
23 struct ISteamNetworkingConnectionSignaling;
24 struct ISteamNetworkingSignalingRecvContext;
25 struct ISteamNetworkingFakeUDPPort;
26 
27 /// Lower level networking API.
28 ///
29 /// - Connection-oriented API (like TCP, not UDP).  When sending and receiving
30 ///   messages, a connection handle is used.  (For a UDP-style interface, where
31 ///   the peer is identified by their address with each send/recv call, see
32 ///   ISteamNetworkingMessages.)  The typical pattern is for a "server" to "listen"
33 ///   on a "listen socket."  A "client" will "connect" to the server, and the
34 ///   server will "accept" the connection.  If you have a symmetric situation
35 ///   where either peer may initiate the connection and server/client roles are
36 ///   not clearly defined, check out k_ESteamNetworkingConfig_SymmetricConnect.
37 /// - But unlike TCP, it's message-oriented, not stream-oriented.
38 /// - Mix of reliable and unreliable messages
39 /// - Fragmentation and reassembly
40 /// - Supports connectivity over plain UDP
41 /// - Also supports SDR ("Steam Datagram Relay") connections, which are
42 ///   addressed by the identity of the peer.  There is a "P2P" use case and
43 ///   a "hosted dedicated server" use case.
44 ///
45 /// Note that neither of the terms "connection" nor "socket" necessarily correspond
46 /// one-to-one with an underlying UDP socket.  An attempt has been made to
47 /// keep the semantics as similar to the standard socket model when appropriate,
48 /// but some deviations do exist.
49 ///
50 /// See also: ISteamNetworkingMessages, the UDP-style interface.  This API might be
51 /// easier to use, especially when porting existing UDP code.
52 abstract class ISteamNetworkingSockets {
53 
54     /// Creates a "server" socket that listens for clients to connect to by
55     /// calling ConnectByIPAddress, over ordinary UDP (IPv4 or IPv6)
56     ///
57     /// You must select a specific local port to listen on and set it
58     /// the port field of the local address.
59     ///
60     /// Usually you will set the IP portion of the address to zero (SteamNetworkingIPAddr::Clear()).
61     /// This means that you will not bind to any particular local interface (i.e. the same
62     /// as INADDR_ANY in plain socket code).  Furthermore, if possible the socket will be bound
63     /// in "dual stack" mode, which means that it can accept both IPv4 and IPv6 client connections.
64     /// If you really do wish to bind a particular interface, then set the local address to the
65     /// appropriate IPv4 or IPv6 IP.
66     ///
67     /// If you need to set any initial config options, pass them here.  See
68     /// SteamNetworkingConfigValue_t for more about why this is preferable to
69     /// setting the options "immediately" after creation.
70     ///
71     /// When a client attempts to connect, a SteamNetConnectionStatusChangedCallback_t
72     /// will be posted.  The connection will be in the connecting state.
73     HSteamListenSocket CreateListenSocketIP(const ref SteamNetworkingIPAddr localAddress, int nOptions,
74     const SteamNetworkingConfigValue_t* pOptions);
75 
76     /// Creates a connection and begins talking to a "server" over UDP at the
77     /// given IPv4 or IPv6 address.  The remote host must be listening with a
78     /// matching call to CreateListenSocketIP on the specified port.
79     ///
80     /// A SteamNetConnectionStatusChangedCallback_t callback will be triggered when we start
81     /// connecting, and then another one on either timeout or successful connection.
82     ///
83     /// If the server does not have any identity configured, then their network address
84     /// will be the only identity in use.  Or, the network host may provide a platform-specific
85     /// identity with or without a valid certificate to authenticate that identity.  (These
86     /// details will be contained in the SteamNetConnectionStatusChangedCallback_t.)  It's
87     /// up to your application to decide whether to allow the connection.
88     ///
89     /// By default, all connections will get basic encryption sufficient to prevent
90     /// casual eavesdropping.  But note that without certificates (or a shared secret
91     /// distributed through some other out-of-band mechanism), you don't have any
92     /// way of knowing who is actually on the other end, and thus are vulnerable to
93     /// man-in-the-middle attacks.
94     ///
95     /// If you need to set any initial config options, pass them here.  See
96     /// SteamNetworkingConfigValue_t for more about why this is preferable to
97     /// setting the options "immediately" after creation.
98     HSteamNetConnection ConnectByIPAddress(const ref SteamNetworkingIPAddr address, int nOptions,
99     const SteamNetworkingConfigValue_t* pOptions);
100 
101     /// Like CreateListenSocketIP, but clients will connect using ConnectP2P.
102     ///
103     /// nLocalVirtualPort specifies how clients can connect to this socket using
104     /// ConnectP2P.  It's very common for applications to only have one listening socket;
105     /// in that case, use zero.  If you need to open multiple listen sockets and have clients
106     /// be able to connect to one or the other, then nLocalVirtualPort should be a small
107     /// integer (<1000) unique to each listen socket you create.
108     ///
109     /// If you use this, you probably want to call ISteamNetworkingUtils::InitRelayNetworkAccess()
110     /// when your app initializes.
111     ///
112     /// If you are listening on a dedicated servers in known data center,
113     /// then you can listen using this function instead of CreateHostedDedicatedServerListenSocket,
114     /// to allow clients to connect without a ticket.  Any user that owns
115     /// the app and is signed into Steam will be able to attempt to connect to
116     /// your server.  Also, a connection attempt may require the client to
117     /// be connected to Steam, which is one more moving part that may fail.  When
118     /// tickets are used, then once a ticket is obtained, a client can connect to
119     /// your server even if they got disconnected from Steam or Steam is offline.
120     ///
121     /// If you need to set any initial config options, pass them here.  See
122     /// SteamNetworkingConfigValue_t for more about why this is preferable to
123     /// setting the options "immediately" after creation.
124     HSteamListenSocket CreateListenSocketP2P(int nLocalVirtualPort, int nOptions,
125     const SteamNetworkingConfigValue_t* pOptions);
126 
127     /// Begin connecting to a peer that is identified using a platform-specific identifier.
128     /// This uses the default rendezvous service, which depends on the platform and library
129     /// configuration.  (E.g. on Steam, it goes through the steam backend.)
130     ///
131     /// If you need to set any initial config options, pass them here.  See
132     /// SteamNetworkingConfigValue_t for more about why this is preferable to
133     /// setting the options "immediately" after creation.
134     ///
135     /// To use your own signaling service, see:
136     /// - ConnectP2PCustomSignaling
137     /// - k_ESteamNetworkingConfig_Callback_CreateConnectionSignaling
138     HSteamNetConnection ConnectP2P(const ref SteamNetworkingIdentity identityRemote, int nRemoteVirtualPort,
139     int nOptions, const SteamNetworkingConfigValue_t* pOptions);
140 
141     /// Accept an incoming connection that has been received on a listen socket.
142     ///
143     /// When a connection attempt is received (perhaps after a few basic handshake
144     /// packets have been exchanged to prevent trivial spoofing), a connection interface
145     /// object is created in the k_ESteamNetworkingConnectionState_Connecting state
146     /// and a SteamNetConnectionStatusChangedCallback_t is posted.  At this point, your
147     /// application MUST either accept or close the connection.  (It may not ignore it.)
148     /// Accepting the connection will transition it either into the connected state,
149     /// or the finding route state, depending on the connection type.
150     ///
151     /// You should take action within a second or two, because accepting the connection is
152     /// what actually sends the reply notifying the client that they are connected.  If you
153     /// delay taking action, from the client's perspective it is the same as the network
154     /// being unresponsive, and the client may timeout the connection attempt.  In other
155     /// words, the client cannot distinguish between a delay caused by network problems
156     /// and a delay caused by the application.
157     ///
158     /// This means that if your application goes for more than a few seconds without
159     /// processing callbacks (for example, while loading a map), then there is a chance
160     /// that a client may attempt to connect in that interval and fail due to timeout.
161     ///
162     /// If the application does not respond to the connection attempt in a timely manner,
163     /// and we stop receiving communication from the client, the connection attempt will
164     /// be timed out locally, transitioning the connection to the
165     /// k_ESteamNetworkingConnectionState_ProblemDetectedLocally state.  The client may also
166     /// close the connection before it is accepted, and a transition to the
167     /// k_ESteamNetworkingConnectionState_ClosedByPeer is also possible depending the exact
168     /// sequence of events.
169     ///
170     /// Returns k_EResultInvalidParam if the handle is invalid.
171     /// Returns k_EResultInvalidState if the connection is not in the appropriate state.
172     /// (Remember that the connection state could change in between the time that the
173     /// notification being posted to the queue and when it is received by the application.)
174     ///
175     /// A note about connection configuration options.  If you need to set any configuration
176     /// options that are common to all connections accepted through a particular listen
177     /// socket, consider setting the options on the listen socket, since such options are
178     /// inherited automatically.  If you really do need to set options that are connection
179     /// specific, it is safe to set them on the connection before accepting the connection.
180     EResult AcceptConnection(HSteamNetConnection hConn);
181 
182     /// Disconnects from the remote host and invalidates the connection handle.
183     /// Any unread data on the connection is discarded.
184     ///
185     /// nReason is an application defined code that will be received on the other
186     /// end and recorded (when possible) in backend analytics.  The value should
187     /// come from a restricted range.  (See ESteamNetConnectionEnd.)  If you don't need
188     /// to communicate any information to the remote host, and do not want analytics to
189     /// be able to distinguish "normal" connection terminations from "exceptional" ones,
190     /// You may pass zero, in which case the generic value of
191     /// k_ESteamNetConnectionEnd_App_Generic will be used.
192     ///
193     /// pszDebug is an optional human-readable diagnostic string that will be received
194     /// by the remote host and recorded (when possible) in backend analytics.
195     ///
196     /// If you wish to put the socket into a "linger" state, where an attempt is made to
197     /// flush any remaining sent data, use bEnableLinger=true.  Otherwise reliable data
198     /// is not flushed.
199     ///
200     /// If the connection has already ended and you are just freeing up the
201     /// connection interface, the reason code, debug string, and linger flag are
202     /// ignored.
203     bool CloseConnection(HSteamNetConnection hPeer, int nReason, const char* pszDebug, bool bEnableLinger);
204 
205     /// Destroy a listen socket.  All the connections that were accepting on the listen
206     /// socket are closed ungracefully.
207     bool CloseListenSocket(HSteamListenSocket hSocket);
208 
209     /// Set connection user data.  the data is returned in the following places
210     /// - You can query it using GetConnectionUserData.
211     /// - The SteamNetworkingmessage_t structure.
212     /// - The SteamNetConnectionInfo_t structure.
213     ///   (Which is a member of SteamNetConnectionStatusChangedCallback_t -- but see WARNINGS below!!!!)
214     ///
215     /// Do you need to set this atomically when the connection is created?
216     /// See k_ESteamNetworkingConfig_ConnectionUserData.
217     ///
218     /// WARNING: Be *very careful* when using the value provided in callbacks structs.
219     /// Callbacks are queued, and the value that you will receive in your
220     /// callback is the userdata that was effective at the time the callback
221     /// was queued.  There are subtle race conditions that can happen if you
222     /// don't understand this!
223     ///
224     /// If any incoming messages for this connection are queued, the userdata
225     /// field is updated, so that when when you receive messages (e.g. with
226     /// ReceiveMessagesOnConnection), they will always have the very latest
227     /// userdata.  So the tricky race conditions that can happen with callbacks
228     /// do not apply to retrieving messages.
229     ///
230     /// Returns false if the handle is invalid.
231     bool SetConnectionUserData(HSteamNetConnection hPeer, long nUserData);
232 
233     /// Fetch connection user data.  Returns -1 if handle is invalid
234     /// or if you haven't set any userdata on the connection.
235     long GetConnectionUserData(HSteamNetConnection hPeer);
236 
237     /// Set a name for the connection, used mostly for debugging
238     void SetConnectionName(HSteamNetConnection hPeer, const char *pszName);
239 
240     /// Fetch connection name.  Returns false if handle is invalid
241     bool GetConnectionName(HSteamNetConnection hPeer, char *pszName, int nMaxLen);
242 
243     /// Send a message to the remote host on the specified connection.
244     ///
245     /// nSendFlags determines the delivery guarantees that will be provided,
246     /// when data should be buffered, etc.  E.g. k_nSteamNetworkingSend_Unreliable
247     ///
248     /// Note that the semantics we use for messages are not precisely
249     /// the same as the semantics of a standard "stream" socket.
250     /// (SOCK_STREAM)  For an ordinary stream socket, the boundaries
251     /// between chunks are not considered relevant, and the sizes of
252     /// the chunks of data written will not necessarily match up to
253     /// the sizes of the chunks that are returned by the reads on
254     /// the other end.  The remote host might read a partial chunk,
255     /// or chunks might be coalesced.  For the message semantics
256     /// used here, however, the sizes WILL match.  Each send call
257     /// will match a successful read call on the remote host
258     /// one-for-one.  If you are porting existing stream-oriented
259     /// code to the semantics of reliable messages, your code should
260     /// work the same, since reliable message semantics are more
261     /// strict than stream semantics.  The only caveat is related to
262     /// performance: there is per-message overhead to retain the
263     /// message sizes, and so if your code sends many small chunks
264     /// of data, performance will suffer. Any code based on stream
265     /// sockets that does not write excessively small chunks will
266     /// work without any changes.
267     ///
268     /// The pOutMessageNumber is an optional pointer to receive the
269     /// message number assigned to the message, if sending was successful.
270     ///
271     /// Returns:
272     /// - k_EResultInvalidParam: invalid connection handle, or the individual message is too big.
273     ///   (See k_cbMaxSteamNetworkingSocketsMessageSizeSend)
274     /// - k_EResultInvalidState: connection is in an invalid state
275     /// - k_EResultNoConnection: connection has ended
276     /// - k_EResultIgnored: You used k_nSteamNetworkingSend_NoDelay, and the message was dropped because
277     ///   we were not ready to send it.
278     /// - k_EResultLimitExceeded: there was already too much data queued to be sent.
279     ///   (See k_ESteamNetworkingConfig_SendBufferSize)
280     EResult SendMessageToConnection(HSteamNetConnection hConn, const void* pData, uint cbData, int nSendFlags,
281     long* pOutMessageNumber);
282 
283     /// Send one or more messages without copying the message payload.
284     /// This is the most efficient way to send messages. To use this
285     /// function, you must first allocate a message object using
286     /// ISteamNetworkingUtils::AllocateMessage.  (Do not declare one
287     /// on the stack or allocate your own.)
288     ///
289     /// You should fill in the message payload.  You can either let
290     /// it allocate the buffer for you and then fill in the payload,
291     /// or if you already have a buffer allocated, you can just point
292     /// m_pData at your buffer and set the callback to the appropriate function
293     /// to free it.  Note that if you use your own buffer, it MUST remain valid
294     /// until the callback is executed.  And also note that your callback can be
295     /// invoked at any time from any thread (perhaps even before SendMessages
296     /// returns!), so it MUST be fast and threadsafe.
297     ///
298     /// You MUST also fill in:
299     /// - m_conn - the handle of the connection to send the message to
300     /// - m_nFlags - bitmask of k_nSteamNetworkingSend_xxx flags.
301     ///
302     /// All other fields are currently reserved and should not be modified.
303     ///
304     /// The library will take ownership of the message structures.  They may
305     /// be modified or become invalid at any time, so you must not read them
306     /// after passing them to this function.
307     ///
308     /// pOutMessageNumberOrResult is an optional array that will receive,
309     /// for each message, the message number that was assigned to the message
310     /// if sending was successful.  If sending failed, then a negative EResult
311     /// value is placed into the array.  For example, the array will hold
312     /// -k_EResultInvalidState if the connection was in an invalid state.
313     /// See ISteamNetworkingSockets::SendMessageToConnection for possible
314     /// failure codes.
315     void SendMessages(int nMessages, const(SteamNetworkingMessage_t*)* pMessages, long* pOutMessageNumberOrResult);
316 
317     /// Flush any messages waiting on the Nagle timer and send them
318     /// at the next transmission opportunity (often that means right now).
319     ///
320     /// If Nagle is enabled (it's on by default) then when calling
321     /// SendMessageToConnection the message will be buffered, up to the Nagle time
322     /// before being sent, to merge small messages into the same packet.
323     /// (See k_ESteamNetworkingConfig_NagleTime)
324     ///
325     /// Returns:
326     /// k_EResultInvalidParam: invalid connection handle
327     /// k_EResultInvalidState: connection is in an invalid state
328     /// k_EResultNoConnection: connection has ended
329     /// k_EResultIgnored: We weren't (yet) connected, so this operation has no effect.
330     EResult FlushMessagesOnConnection(HSteamNetConnection hConn);
331 
332     /// Fetch the next available message(s) from the connection, if any.
333     /// Returns the number of messages returned into your array, up to nMaxMessages.
334     /// If the connection handle is invalid, -1 is returned.
335     ///
336     /// The order of the messages returned in the array is relevant.
337     /// Reliable messages will be received in the order they were sent (and with the
338     /// same sizes --- see SendMessageToConnection for on this subtle difference from a stream socket).
339     ///
340     /// Unreliable messages may be dropped, or delivered out of order with respect to
341     /// each other or with respect to reliable messages.  The same unreliable message
342     /// may be received multiple times.
343     ///
344     /// If any messages are returned, you MUST call SteamNetworkingMessage_t::Release() on each
345     /// of them free up resources after you are done.  It is safe to keep the object alive for
346     /// a little while (put it into some queue, etc), and you may call Release() from any thread.
347     int ReceiveMessagesOnConnection(HSteamNetConnection hConn, SteamNetworkingMessage_t** ppOutMessages,
348     int nMaxMessages);
349 
350     /// Returns basic information about the high-level state of the connection.
351     bool GetConnectionInfo(HSteamNetConnection hConn, SteamNetConnectionInfo_t* pInfo);
352 
353     /// Returns a small set of information about the real-time state of the connection
354     /// and the queue status of each lane.
355     ///
356     /// - pStatus may be NULL if the information is not desired.  (E.g. you are only interested
357     ///   in the lane information.)
358     /// - On entry, nLanes specifies the length of the pLanes array.  This may be 0
359     ///   if you do not wish to receive any lane data.  It's OK for this to be smaller than
360     ///   the total number of configured lanes.
361     /// - pLanes points to an array that will receive lane-specific info.  It can be NULL
362     ///   if this is not needed.
363     ///
364     /// Return value:
365     /// - k_EResultNoConnection - connection handle is invalid or connection has been closed.
366     /// - k_EResultInvalidParam - nLanes is bad
367     EResult GetConnectionRealTimeStatus(HSteamNetConnection hConn, SteamNetConnectionRealTimeStatus_t* pStatus,
368                int nLanes, SteamNetConnectionRealTimeLaneStatus_t* pLanes );
369 
370     /// Returns detailed connection stats in text format.  Useful
371     /// for dumping to a log, etc.
372     ///
373     /// Returns:
374     /// -1 failure (bad connection handle)
375     /// 0 OK, your buffer was filled in and '\0'-terminated
376     /// >0 Your buffer was either nullptr, or it was too small and the text got truncated.
377     ///    Try again with a buffer of at least N bytes.
378     int GetDetailedConnectionStatus(HSteamNetConnection hConn, char* pszBuf, int cbBuf);
379 
380     /// Returns local IP and port that a listen socket created using CreateListenSocketIP is bound to.
381     ///
382     /// An IPv6 address of ::0 means "any IPv4 or IPv6"
383     /// An IPv6 address of ::ffff:0000:0000 means "any IPv4"
384     bool GetListenSocketAddress(HSteamListenSocket hSocket, SteamNetworkingIPAddr* address);
385 
386     /// Create a pair of connections that are talking to each other, e.g. a loopback connection.
387     /// This is very useful for testing, or so that your client/server code can work the same
388     /// even when you are running a local "server".
389     ///
390     /// The two connections will immediately be placed into the connected state, and no callbacks
391     /// will be posted immediately.  After this, if you close either connection, the other connection
392     /// will receive a callback, exactly as if they were communicating over the network.  You must
393     /// close *both* sides in order to fully clean up the resources!
394     ///
395     /// By default, internal buffers are used, completely bypassing the network, the chopping up of
396     /// messages into packets, encryption, copying the payload, etc.  This means that loopback
397     /// packets, by default, will not simulate lag or loss.  Passing true for bUseNetworkLoopback will
398     /// cause the socket pair to send packets through the local network loopback device (127.0.0.1)
399     /// on ephemeral ports.  Fake lag and loss are supported in this case, and CPU time is expended
400     /// to encrypt and decrypt.
401     ///
402     /// If you wish to assign a specific identity to either connection, you may pass a particular
403     /// identity.  Otherwise, if you pass nullptr, the respective connection will assume a generic
404     /// "localhost" identity.  If you use real network loopback, this might be translated to the
405     /// actual bound loopback port.  Otherwise, the port will be zero.
406     bool CreateSocketPair(HSteamNetConnection* pOutConnection1, HSteamNetConnection* pOutConnection2,
407     bool bUseNetworkLoopback, const SteamNetworkingIdentity* pIdentity1, const SteamNetworkingIdentity* pIdentity2);
408 
409     /// Configure multiple outbound messages streams ("lanes") on a connection, and
410     /// control head-of-line blocking between them.  Messages within a given lane
411     /// are always sent in the order they are queued, but messages from different
412     /// lanes may be sent out of order.  Each lane has its own message number
413     /// sequence.  The first message sent on each lane will be assigned the number 1.
414     ///
415     /// Each lane has a "priority".  Lanes with higher numeric values will only be processed
416     /// when all lanes with lower number values are empty.  The magnitudes of the priority
417     /// values are not relevant, only their sort order.
418     ///
419     /// Each lane also is assigned a weight, which controls the approximate proportion
420     /// of the bandwidth that will be consumed by the lane, relative to other lanes
421     /// of the same priority.  (This is assuming the lane stays busy.  An idle lane
422     /// does not build up "credits" to be be spent once a message is queued.)
423     /// This value is only meaningful as a proportion, relative to other lanes with
424     /// the same priority.  For lanes with different priorities, the strict priority
425     /// order will prevail, and their weights relative to each other are not relevant.
426     /// Thus, if a lane has a unique priority value, the weight value for that lane is
427     /// not relevant.
428     ///
429     /// Example: 3 lanes, with priorities [ 0, 10, 10 ] and weights [ (NA), 20, 5 ].
430     /// Messages sent on the first will always be sent first, before messages in the
431     /// other two lanes.  Its weight value is irrelevant, since there are no other
432     /// lanes with priority=0.  The other two lanes will share bandwidth, with the second
433     /// and third lanes sharing bandwidth using a ratio of approximately 4:1.
434     /// (The weights [ NA, 4, 1 ] would be equivalent.)
435     ///
436     /// Notes:
437     /// - At the time of this writing, some code has performance cost that is linear
438     ///   in the number of lanes, so keep the number of lanes to an absolute minimum.
439     ///   3 or so is fine; >8 is a lot.  The max number of lanes on Steam is 255,
440     ///   which is a very large number and not recommended!  If you are compiling this
441     ///   library from source, see STEAMNETWORKINGSOCKETS_MAX_LANES.)
442     /// - Lane priority values may be any int.  Their absolute value is not relevant,
443     ///   only the order matters.
444     /// - Weights must be positive, and due to implementation details, they are restricted
445     ///   to 16-bit values.  The absolute magnitudes don't matter, just the proportions.
446     /// - Messages sent on a lane index other than 0 have a small overhead on the wire,
447     ///   so for maximum wire efficiency, lane 0 should be the "most common" lane, regardless
448     ///   of priorities or weights.
449     /// - A connection has a single lane by default.  Calling this function with
450     ///   nNumLanes=1 is legal, but pointless, since the priority and weight values are
451     ///   irrelevant in that case.
452     /// - You may reconfigure connection lanes at any time, however reducing the number of
453     ///   lanes is not allowed.
454     /// - Reconfiguring lanes might restart any bandwidth sharing balancing.  Usually you
455     ///   will call this function once, near the start of the connection, perhaps after
456     ///   exchanging a few messages.
457     /// - To assign all lanes the same priority, you may use pLanePriorities=NULL.
458     /// - If you wish all lanes with the same priority to share bandwidth equally (or
459     ///   if no two lanes have the same priority value, and thus priority values are
460     ///   irrelevant), you may use pLaneWeights=NULL
461     /// - Priorities and weights determine the order that messages are SENT on the wire.
462     ///   There are NO GUARANTEES on the order that messages are RECEIVED!  Due to packet
463     ///   loss, out-of-order delivery, and subtle details of packet serialization, messages
464     ///   might still be received slightly out-of-order!  The *only* strong guarantee is that
465     ///   *reliable* messages on the *same lane* will be delivered in the order they are sent.
466     /// - Each host configures the lanes for the packets they send; the lanes for the flow
467     ///   in one direction are completely unrelated to the lanes in the opposite direction.
468     ///
469     /// Return value:
470     /// - k_EResultNoConnection - bad hConn
471     /// - k_EResultInvalidParam - Invalid number of lanes, bad weights, or you tried to reduce the number of lanes
472     /// - k_EResultInvalidState - Connection is already dead, etc
473     ///
474     /// See also:
475     /// SteamNetworkingMessage_t::m_idxLane
476     EResult ConfigureConnectionLanes(HSteamNetConnection hConn, int nNumLanes, const int* pLanePriorities, const ushort* pLaneWeights);
477 
478     //
479     // Identity and authentication
480     //
481 
482     /// Get the identity assigned to this interface.
483     /// E.g. on Steam, this is the user's SteamID, or for the gameserver interface, the SteamID assigned
484     /// to the gameserver.  Returns false and sets the result to an invalid identity if we don't know
485     /// our identity yet.  (E.g. GameServer has not logged in.  On Steam, the user will know their SteamID
486     /// even if they are not signed into Steam.)
487     bool GetIdentity(SteamNetworkingIdentity* pIdentity);
488 
489     /// Indicate our desire to be ready participate in authenticated communications.
490     /// If we are currently not ready, then steps will be taken to obtain the necessary
491     /// certificates.   (This includes a certificate for us, as well as any CA certificates
492     /// needed to authenticate peers.)
493     ///
494     /// You can call this at program init time if you know that you are going to
495     /// be making authenticated connections, so that we will be ready immediately when
496     /// those connections are attempted.  (Note that essentially all connections require
497     /// authentication, with the exception of ordinary UDP connections with authentication
498     /// disabled using k_ESteamNetworkingConfig_IP_AllowWithoutAuth.)  If you don't call
499     /// this function, we will wait until a feature is utilized that that necessitates
500     /// these resources.
501     ///
502     /// You can also call this function to force a retry, if failure has occurred.
503     /// Once we make an attempt and fail, we will not automatically retry.
504     /// In this respect, the behavior of the system after trying and failing is the same
505     /// as before the first attempt: attempting authenticated communication or calling
506     /// this function will call the system to attempt to acquire the necessary resources.
507     ///
508     /// You can use GetAuthenticationStatus or listen for SteamNetAuthenticationStatus_t
509     /// to monitor the status.
510     ///
511     /// Returns the current value that would be returned from GetAuthenticationStatus.
512     ESteamNetworkingAvailability InitAuthentication();
513 
514     /// Query our readiness to participate in authenticated communications.  A
515     /// SteamNetAuthenticationStatus_t callback is posted any time this status changes,
516     /// but you can use this function to query it at any time.
517     ///
518     /// The value of SteamNetAuthenticationStatus_t::m_eAvail is returned.  If you only
519     /// want this high level status, you can pass NULL for pDetails.  If you want further
520     /// details, pass non-NULL to receive them.
521     ESteamNetworkingAvailability GetAuthenticationStatus(SteamNetAuthenticationStatus_t* pDetails);
522 
523     //
524     // Poll groups.  A poll group is a set of connections that can be polled efficiently.
525     // (In our API, to "poll" a connection means to retrieve all pending messages.  We
526     // actually don't have an API to "poll" the connection *state*, like BSD sockets.)
527     //
528 
529     /// Create a new poll group.
530     ///
531     /// You should destroy the poll group when you are done using DestroyPollGroup
532     HSteamNetPollGroup CreatePollGroup();
533 
534     /// Destroy a poll group created with CreatePollGroup().
535     ///
536     /// If there are any connections in the poll group, they are removed from the group,
537     /// and left in a state where they are not part of any poll group.
538     /// Returns false if passed an invalid poll group handle.
539     bool DestroyPollGroup(HSteamNetPollGroup hPollGroup);
540 
541     /// Assign a connection to a poll group.  Note that a connection may only belong to a
542     /// single poll group.  Adding a connection to a poll group implicitly removes it from
543     /// any other poll group it is in.
544     ///
545     /// You can pass k_HSteamNetPollGroup_Invalid to remove a connection from its current
546     /// poll group without adding it to a new poll group.
547     ///
548     /// If there are received messages currently pending on the connection, an attempt
549     /// is made to add them to the queue of messages for the poll group in approximately
550     /// the order that would have applied if the connection was already part of the poll
551     /// group at the time that the messages were received.
552     ///
553     /// Returns false if the connection handle is invalid, or if the poll group handle
554     /// is invalid (and not k_HSteamNetPollGroup_Invalid).
555     bool SetConnectionPollGroup(HSteamNetConnection hConn, HSteamNetPollGroup hPollGroup);
556 
557     /// Same as ReceiveMessagesOnConnection, but will return the next messages available
558     /// on any connection in the poll group.  Examine SteamNetworkingMessage_t::m_conn
559     /// to know which connection.  (SteamNetworkingMessage_t::m_nConnUserData might also
560     /// be useful.)
561     ///
562     /// Delivery order of messages among different connections will usually match the
563     /// order that the last packet was received which completed the message.  But this
564     /// is not a strong guarantee, especially for packets received right as a connection
565     /// is being assigned to poll group.
566     ///
567     /// Delivery order of messages on the same connection is well defined and the
568     /// same guarantees are present as mentioned in ReceiveMessagesOnConnection.
569     /// (But the messages are not grouped by connection, so they will not necessarily
570     /// appear consecutively in the list; they may be interleaved with messages for
571     /// other connections.)
572     int ReceiveMessagesOnPollGroup(HSteamNetPollGroup hPollGroup, SteamNetworkingMessage_t** ppOutMessages,
573     int nMaxMessages);
574 
575     //
576     // Clients connecting to dedicated servers hosted in a data center,
577     // using tickets issued by your game coordinator.  If you are not
578     // issuing your own tickets to restrict who can attempt to connect
579     // to your server, then you won't use these functions.
580     //
581 
582     /// Call this when you receive a ticket from your backend / matchmaking system.  Puts the
583     /// ticket into a persistent cache, and optionally returns the parsed ticket.
584     ///
585     /// See stamdatagram_ticketgen.h for more details.
586     bool ReceivedRelayAuthTicket(const void* pvTicket, int cbTicket, SteamDatagramRelayAuthTicket* pOutParsedTicket);
587 
588     /// Search cache for a ticket to talk to the server on the specified virtual port.
589     /// If found, returns the number of seconds until the ticket expires, and optionally
590     /// the complete cracked ticket.  Returns 0 if we don't have a ticket.
591     ///
592     /// Typically this is useful just to confirm that you have a ticket, before you
593     /// call ConnectToHostedDedicatedServer to connect to the server.
594     int FindRelayAuthTicketForServer(const ref SteamNetworkingIdentity identityGameServer, int nRemoteVirtualPort,
595     SteamDatagramRelayAuthTicket* pOutParsedTicket);
596 
597     /// Client call to connect to a server hosted in a Valve data center, on the specified virtual
598     /// port.  You must have placed a ticket for this server into the cache, or else this connect
599     /// attempt will fail!  If you are not issuing your own tickets, then to connect to a dedicated
600     /// server via SDR in auto-ticket mode, use ConnectP2P.  (The server must be configured to allow
601     /// this type of connection by listening using CreateListenSocketP2P.)
602     ///
603     /// You may wonder why tickets are stored in a cache, instead of simply being passed as an argument
604     /// here.  The reason is to make reconnection to a gameserver robust, even if the client computer loses
605     /// connection to Steam or the central backend, or the app is restarted or crashes, etc.
606     ///
607     /// If you use this, you probably want to call ISteamNetworkingUtils::InitRelayNetworkAccess()
608     /// when your app initializes
609     ///
610     /// If you need to set any initial config options, pass them here.  See
611     /// SteamNetworkingConfigValue_t for more about why this is preferable to
612     /// setting the options "immediately" after creation.
613     HSteamNetConnection ConnectToHostedDedicatedServer(const ref SteamNetworkingIdentity identityTarget,
614     int nRemoteVirtualPort, int nOptions, const SteamNetworkingConfigValue_t* pOptions);
615 
616     //
617     // Servers hosted in data centers known to the Valve relay network
618     //
619 
620     /// Returns the value of the SDR_LISTEN_PORT environment variable.  This
621     /// is the UDP server your server will be listening on.  This will
622     /// configured automatically for you in production environments.
623     ///
624     /// In development, you'll need to set it yourself.  See
625     /// https://partner.steamgames.com/doc/api/ISteamNetworkingSockets
626     /// for more information on how to configure dev environments.
627     ushort GetHostedDedicatedServerPort();
628 
629     /// Returns 0 if SDR_LISTEN_PORT is not set.  Otherwise, returns the data center the server
630     /// is running in.  This will be k_SteamDatagramPOPID_dev in non-production environment.
631     SteamNetworkingPOPID GetHostedDedicatedServerPOPID();
632 
633     /// Return info about the hosted server.  This contains the PoPID of the server,
634     /// and opaque routing information that can be used by the relays to send traffic
635     /// to your server.
636     ///
637     /// You will need to send this information to your backend, and put it in tickets,
638     /// so that the relays will know how to forward traffic from
639     /// clients to your server.  See SteamDatagramRelayAuthTicket for more info.
640     ///
641     /// Also, note that the routing information is contained in SteamDatagramGameCoordinatorServerLogin,
642     /// so if possible, it's preferred to use GetGameCoordinatorServerLogin to send this info
643     /// to your game coordinator service, and also login securely at the same time.
644     ///
645     /// On a successful exit, k_EResultOK is returned
646     ///
647     /// Unsuccessful exit:
648     /// - Something other than k_EResultOK is returned.
649     /// - k_EResultInvalidState: We are not configured to listen for SDR (SDR_LISTEN_SOCKET
650     ///   is not set.)
651     /// - k_EResultPending: we do not (yet) have the authentication information needed.
652     ///   (See GetAuthenticationStatus.)  If you use environment variables to pre-fetch
653     ///   the network config, this data should always be available immediately.
654     /// - A non-localized diagnostic debug message will be placed in m_data that describes
655     ///   the cause of the failure.
656     ///
657     /// NOTE: The returned blob is not encrypted.  Send it to your backend, but don't
658     ///       directly share it with clients.
659     EResult GetHostedDedicatedServerAddress(SteamDatagramHostedAddress* pRouting);
660 
661     /// Create a listen socket on the specified virtual port.  The physical UDP port to use
662     /// will be determined by the SDR_LISTEN_PORT environment variable.  If a UDP port is not
663     /// configured, this call will fail.
664     ///
665     /// This call MUST be made through the SteamGameServerNetworkingSockets() interface.
666     ///
667     /// This function should be used when you are using the ticket generator library
668     /// to issue your own tickets.  Clients connecting to the server on this virtual
669     /// port will need a ticket, and they must connect using ConnectToHostedDedicatedServer.
670     ///
671     /// If you need to set any initial config options, pass them here.  See
672     /// SteamNetworkingConfigValue_t for more about why this is preferable to
673     /// setting the options "immediately" after creation.
674     HSteamListenSocket CreateHostedDedicatedServerListenSocket(int nLocalVirtualPort, int nOptions,
675     const SteamNetworkingConfigValue_t* pOptions);
676 
677     /// Generate an authentication blob that can be used to securely login with
678     /// your backend, using SteamDatagram_ParseHostedServerLogin.  (See
679     /// steamdatagram_gamecoordinator.h)
680     ///
681     /// Before calling the function:
682     /// - Populate the app data in pLoginInfo (m_cbAppData and m_appData).  You can leave
683     ///   all other fields uninitialized.
684     /// - *pcbSignedBlob contains the size of the buffer at pBlob.  (It should be
685     ///   at least k_cbMaxSteamDatagramGameCoordinatorServerLoginSerialized.)
686     ///
687     /// On a successful exit:
688     /// - k_EResultOK is returned
689     /// - All of the remaining fields of pLoginInfo will be filled out.
690     /// - *pcbSignedBlob contains the size of the serialized blob that has been
691     ///   placed into pBlob.
692     ///
693     /// Unsuccessful exit:
694     /// - Something other than k_EResultOK is returned.
695     /// - k_EResultNotLoggedOn: you are not logged in (yet)
696     /// - See GetHostedDedicatedServerAddress for more potential failure return values.
697     /// - A non-localized diagnostic debug message will be placed in pBlob that describes
698     ///   the cause of the failure.
699     ///
700     /// This works by signing the contents of the SteamDatagramGameCoordinatorServerLogin
701     /// with the cert that is issued to this server.  In dev environments, it's OK if you do
702     /// not have a cert.  (You will need to enable insecure dev login in SteamDatagram_ParseHostedServerLogin.)
703     /// Otherwise, you will need a signed cert.
704     ///
705     /// NOTE: The routing blob returned here is not encrypted.  Send it to your backend
706     ///       and don't share it directly with clients.
707     EResult GetGameCoordinatorServerLogin(SteamDatagramGameCoordinatorServerLogin* pLoginInfo, int* pcbSignedBlob,
708     void* pBlob);
709 
710 
711     //
712     // Relayed connections using custom signaling protocol
713     //
714     // This is used if you have your own method of sending out-of-band
715     // signaling / rendezvous messages through a mutually trusted channel.
716     //
717 
718     /// Create a P2P "client" connection that does signaling over a custom
719     /// rendezvous/signaling channel.
720     ///
721     /// pSignaling points to a new object that you create just for this connection.
722     /// It must stay valid until Release() is called.  Once you pass the
723     /// object to this function, it assumes ownership.  Release() will be called
724     /// from within the function call if the call fails.  Furthermore, until Release()
725     /// is called, you should be prepared for methods to be invoked on your
726     /// object from any thread!  You need to make sure your object is threadsafe!
727     /// Furthermore, you should make sure that dispatching the methods is done
728     /// as quickly as possible.
729     ///
730     /// This function will immediately construct a connection in the "connecting"
731     /// state.  Soon after (perhaps before this function returns, perhaps in another thread),
732     /// the connection will begin sending signaling messages by calling
733     /// ISteamNetworkingConnectionSignaling::SendSignal.
734     ///
735     /// When the remote peer accepts the connection (See
736     /// ISteamNetworkingSignalingRecvContext::OnConnectRequest),
737     /// it will begin sending signaling messages.  When these messages are received,
738     /// you can pass them to the connection using ReceivedP2PCustomSignal.
739     ///
740     /// If you know the identity of the peer that you expect to be on the other end,
741     /// you can pass their identity to improve debug output or just detect bugs.
742     /// If you don't know their identity yet, you can pass NULL, and their
743     /// identity will be established in the connection handshake.
744     ///
745     /// If you use this, you probably want to call ISteamNetworkingUtils::InitRelayNetworkAccess()
746     /// when your app initializes
747     ///
748     /// If you need to set any initial config options, pass them here.  See
749     /// SteamNetworkingConfigValue_t for more about why this is preferable to
750     /// setting the options "immediately" after creation.
751     HSteamNetConnection ConnectP2PCustomSignaling(ISteamNetworkingConnectionSignaling* pSignaling,
752     const SteamNetworkingIdentity* pPeerIdentity, int nRemoteVirtualPort, int nOptions,
753     const SteamNetworkingConfigValue_t* pOptions);
754 
755     /// Called when custom signaling has received a message.  When your
756     /// signaling channel receives a message, it should save off whatever
757     /// routing information was in the envelope into the context object,
758     /// and then pass the payload to this function.
759     ///
760     /// A few different things can happen next, depending on the message:
761     ///
762     /// - If the signal is associated with existing connection, it is dealt
763     ///   with immediately.  If any replies need to be sent, they will be
764     ///   dispatched using the ISteamNetworkingConnectionSignaling
765     ///   associated with the connection.
766     /// - If the message represents a connection request (and the request
767     ///   is not redundant for an existing connection), a new connection
768     ///   will be created, and ReceivedConnectRequest will be called on your
769     ///   context object to determine how to proceed.
770     /// - Otherwise, the message is for a connection that does not
771     ///   exist (anymore).  In this case, we *may* call SendRejectionReply
772     ///   on your context object.
773     ///
774     /// In any case, we will not save off pContext or access it after this
775     /// function returns.
776     ///
777     /// Returns true if the message was parsed and dispatched without anything
778     /// unusual or suspicious happening.  Returns false if there was some problem
779     /// with the message that prevented ordinary handling.  (Debug output will
780     /// usually have more information.)
781     ///
782     /// If you expect to be using relayed connections, then you probably want
783     /// to call ISteamNetworkingUtils::InitRelayNetworkAccess() when your app initializes
784     bool ReceivedP2PCustomSignal(const void* pMsg, int cbMsg, ISteamNetworkingSignalingRecvContext* pContext);
785 
786     //
787     // Certificate provision by the application.  On Steam, we normally handle all this automatically
788     // and you will not need to use these advanced functions.
789     //
790 
791     /// Get blob that describes a certificate request.  You can send this to your game coordinator.
792     /// Upon entry, *pcbBlob should contain the size of the buffer.  On successful exit, it will
793     /// return the number of bytes that were populated.  You can pass pBlob=NULL to query for the required
794     /// size.  (512 bytes is a conservative estimate.)
795     ///
796     /// Pass this blob to your game coordinator and call SteamDatagram_CreateCert.
797     bool GetCertificateRequest(int* pcbBlob, void* pBlob, SteamNetworkingErrMsg* errMsg);
798 
799     /// Set the certificate.  The certificate blob should be the output of
800     /// SteamDatagram_CreateCert.
801     bool SetCertificate(const void* pCertificate, int cbCertificate, SteamNetworkingErrMsg* errMsg);
802 
803     /// Reset the identity associated with this instance.
804     /// Any open connections are closed.  Any previous certificates, etc are discarded.
805     /// You can pass a specific identity that you want to use, or you can pass NULL,
806     /// in which case the identity will be invalid until you set it using SetCertificate
807     ///
808     /// NOTE: This function is not actually supported on Steam!  It is included
809     ///       for use on other platforms where the active user can sign out and
810     ///       a new user can sign in.
811     void ResetIdentity(const SteamNetworkingIdentity* pIdentity);
812 
813     //
814     // Misc
815     //
816 
817     /// Invoke all callback functions queued for this interface.
818     /// See k_ESteamNetworkingConfig_Callback_ConnectionStatusChanged, etc
819     ///
820     /// You don't need to call this if you are using Steam's callback dispatch
821     /// mechanism (SteamAPI_RunCallbacks and SteamGameserver_RunCallbacks).
822     void RunCallbacks();
823 
824     //
825     // "FakeIP" system.
826     //
827     // A FakeIP is essentially a temporary, arbitrary identifier that
828     // happens to be a valid IPv4 address.  The purpose of this system is to make it
829     // easy to integrate with existing code that identifies hosts using IPv4 addresses.
830     // The FakeIP address will never actually be used to send or receive any packets
831     // on the Internet, it is strictly an identifier.
832     //
833     // FakeIP addresses are designed to (hopefully) pass through existing code as
834     // transparently as possible, while conflicting with "real" addresses that might
835     // be in use on networks (both the Internet and LANs) in the same code as little
836     // as possible.  At the time this comment is being written, they come from the
837     // 169.254.0.0/16 range, and the port number will always be >1024.  HOWEVER,
838     // this is subject to change!  Do not make assumptions about these addresses,
839     // or your code might break in the future.  In particular, you should use
840     // functions such as  ISteamNetworkingUtils::IsFakeIP to determine if an IP
841     // address is a "fake" one used by this system.
842     //
843 
844     /// Begin asynchronous process of allocating a fake IPv4 address that other
845     /// peers can use to contact us via P2P.  IP addresses returned by this
846     /// function are globally unique for a given appid.
847     ///
848     /// nNumPorts is the numbers of ports you wish to reserve.  This is useful
849     /// for the same reason that listening on multiple UDP ports is useful for
850     /// different types of traffic.  Because these allocations come from a global
851     /// namespace, there is a relatively strict limit on the maximum number of
852     /// ports you may request.  (At the time of this writing, the limit is 4.)
853     /// The Port assignments are *not* guaranteed to have any particular order
854     /// or relationship!  Do *not* assume they are contiguous, even though that
855     /// may often occur in practice.
856     ///
857     /// Returns false if a request was already in progress, true if a new request
858     /// was started.  A SteamNetworkingFakeIPResult_t will be posted when the request
859     /// completes.
860     ///
861     /// For gameservers, you *must* call this after initializing the SDK but before
862     /// beginning login.  Steam needs to know in advance that FakeIP will be used.
863     /// Everywhere your public IP would normally appear (such as the server browser) will be
864     /// replaced by the FakeIP, and the fake port at index 0.  The request is actually queued
865     /// until the logon completes, so you must not wait until the allocation completes
866     /// before logging in.  Except for trivial failures that can be detected locally
867     /// (e.g. invalid parameter), a SteamNetworkingFakeIPResult_t callback (whether success or
868     /// failure) will not be posted until after we have logged in.  Furthermore, it is assumed
869     /// that FakeIP allocation is essential for your application to function, and so failure
870     /// will not be reported until *several* retries have been attempted.  This process may
871     /// last several minutes.  It is *highly* recommended to treat failure as fatal.
872     ///
873     /// To communicate using a connection-oriented (TCP-style) API:
874     /// - Server creates a listen socket using CreateListenSocketP2PFakeIP
875     /// - Client connects using ConnectByIPAddress, passing in the FakeIP address.
876     /// - The connection will behave mostly like a P2P connection.  The identities
877     ///   that appear in SteamNetConnectionInfo_t will be the FakeIP identity until
878     ///   we know the real identity.  Then it will be the real identity.  If the
879     ///   SteamNetConnectionInfo_t::m_addrRemote is valid, it will be a real IPv4
880     ///   address of a NAT-punched connection.  Otherwise, it will not be valid.
881     ///
882     /// To communicate using an ad-hoc sendto/recv from (UDP-style) API,
883     /// use CreateFakeUDPPort.
884     bool BeginAsyncRequestFakeIP(int nNumPorts);
885 
886     /// Return info about the FakeIP and port(s) that we have been assigned,
887     /// if any.  idxFirstPort is currently reserved and must be zero.
888     /// Make sure and check SteamNetworkingFakeIPResult_t::m_eResult
889     void GetFakeIP(int idxFirstPort, SteamNetworkingFakeIPResult_t* pInfo);
890 
891     /// Create a listen socket that will listen for P2P connections sent
892     /// to our FakeIP.  A peer can initiate connections to this listen
893     /// socket by calling ConnectByIPAddress.
894     ///
895     /// idxFakePort refers to the *index* of the fake port requested,
896     /// not the actual port number.  For example, pass 0 to refer to the
897     /// first port in the reservation.  You must call this only after calling
898     /// BeginAsyncRequestFakeIP.  However, you do not need to wait for the
899     /// request to complete before creating the listen socket.
900     HSteamListenSocket CreateListenSocketP2PFakeIP(int idxFakePort, int nOptions,
901     const SteamNetworkingConfigValue_t* pOptions);
902 
903     /// If the connection was initiated using the "FakeIP" system, then we
904     /// we can get an IP address for the remote host.  If the remote host had
905     /// a global FakeIP at the time the connection was established, this
906     /// function will return that global IP.  Otherwise, a FakeIP that is
907     /// unique locally will be allocated from the local FakeIP address space,
908     /// and that will be returned.
909     ///
910     /// The allocation of local FakeIPs attempts to assign addresses in
911     /// a consistent manner.  If multiple connections are made to the
912     /// same remote host, they *probably* will return the same FakeIP.
913     /// However, since the namespace is limited, this cannot be guaranteed.
914     ///
915     /// On failure, returns:
916     /// - k_EResultInvalidParam: invalid connection handle
917     /// - k_EResultIPNotFound: This connection wasn't made using FakeIP system
918     EResult GetRemoteFakeIPForConnection(HSteamNetConnection hConn, SteamNetworkingIPAddr* pOutAddr);
919 
920     /// Get an interface that can be used like a UDP port to send/receive
921     /// datagrams to a FakeIP address.  This is intended to make it easy
922     /// to port existing UDP-based code to take advantage of SDR.
923     ///
924     /// idxFakeServerPort refers to the *index* of the port allocated using
925     /// BeginAsyncRequestFakeIP and is used to create "server" ports.  You may
926     /// call this before the allocation has completed.  However, any attempts
927     /// to send packets will fail until the allocation has succeeded.  When
928     /// the peer receives packets sent from this interface, the from address
929     /// of the packet will be the globally-unique FakeIP.  If you call this
930     /// function multiple times and pass the same (nonnegative) fake port index,
931     /// the same object will be returned, and this object is not reference counted.
932     ///
933     /// To create a "client" port (e.g. the equivalent of an ephemeral UDP port)
934     /// pass -1.  In this case, a distinct object will be returned for each call.
935     /// When the peer receives packets sent from this interface, the peer will
936     /// assign a FakeIP from its own locally-controlled namespace.
937     ISteamNetworkingFakeUDPPort* CreateFakeUDPPort(int idxFakeServerPort);
938 
939 };
940 
941 enum STEAMNETWORKINGSOCKETS_INTERFACE_VERSION = "SteamNetworkingSockets012";
942 
943 // Global accessors
944 // Using standalone lib
945 version (STEAMNETWORKINGSOCKETS_STANDALONELIB) {
946 
947     // Standalone lib.
948     static assert(STEAMNETWORKINGSOCKETS_INTERFACE_VERSION[24] == '2', "Version mismatch");
949     extern (C) ISteamNetworkingSockets SteamNetworkingSockets_LibV12();
950     ISteamNetworkingSockets SteamNetworkingSockets_Lib() {
951         return SteamNetworkingSockets_LibV12();
952     }
953 
954     // Those symbols don't even exist in the original libray... They used to be hidden behind an #ifdef but they're not
955     // anymore. Dunno.
956 
957     //extern (C) ISteamNetworkingSockets SteamGameServerNetworkingSockets_LibV12();
958     //ISteamNetworkingSockets SteamGameServerNetworkingSockets_Lib() {
959     //    return SteamGameServerNetworkingSockets_LibV12();
960     //}
961 
962     version (STEAMNETWORKINGSOCKETS_STEAMAPI) { }
963     else {
964         ISteamNetworkingSockets SteamNetworkingSockets() {
965             return SteamNetworkingSockets_LibV12();
966         }
967         //ISteamNetworkingSockets SteamGameServerNetworkingSockets() {
968         //    return SteamGameServerNetworkingSockets_LibV12();
969         //}
970     }
971 }
972 
973 // Using Steamworks SDK
974 version (STEAMNETWORKINGSOCKETS_STEAMAPI) {
975 
976     //STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamNetworkingSockets *, SteamNetworkingSockets_SteamAPI, STEAMNETWORKINGSOCKETS_INTERFACE_VERSION );
977     //STEAM_DEFINE_GAMESERVER_INTERFACE_ACCESSOR( ISteamNetworkingSockets *, SteamGameServerNetworkingSockets_SteamAPI, STEAMNETWORKINGSOCKETS_INTERFACE_VERSION );
978 
979     version (STEAMNETWORKINGSOCKETS_STANDALONELIB) { }
980     else {
981         ISteamNetworkingSockets SteamNetworkingSockets() {
982             return SteamNetworkingSockets_SteamAPI();
983         }
984         ISteamNetworkingSockets SteamGameServerNetworkingSockets() {
985             return SteamGameServerNetworkingSockets_SteamAPI();
986         }
987     }
988 }
989 
990 /// This callback is posted whenever a connection is created, destroyed, or changes state.
991 /// The m_info field will contain a complete description of the connection at the time the
992 /// change occurred and the callback was posted.  In particular, m_eState will have the
993 /// new connection state.
994 ///
995 /// You will usually need to listen for this callback to know when:
996 /// - A new connection arrives on a listen socket.
997 ///   m_info.m_hListenSocket will be set, m_eOldState = k_ESteamNetworkingConnectionState_None,
998 ///   and m_info.m_eState = k_ESteamNetworkingConnectionState_Connecting.
999 ///   See ISteamNetworkigSockets::AcceptConnection.
1000 /// - A connection you initiated has been accepted by the remote host.
1001 ///   m_eOldState = k_ESteamNetworkingConnectionState_Connecting, and
1002 ///   m_info.m_eState = k_ESteamNetworkingConnectionState_Connected.
1003 ///   Some connections might transition to k_ESteamNetworkingConnectionState_FindingRoute first.
1004 /// - A connection has been actively rejected or closed by the remote host.
1005 ///   m_eOldState = k_ESteamNetworkingConnectionState_Connecting or k_ESteamNetworkingConnectionState_Connected,
1006 ///   and m_info.m_eState = k_ESteamNetworkingConnectionState_ClosedByPeer.  m_info.m_eEndReason
1007 ///   and m_info.m_szEndDebug will have for more details.
1008 ///   NOTE: upon receiving this callback, you must still destroy the connection using
1009 ///   ISteamNetworkingSockets::CloseConnection to free up local resources.  (The details
1010 ///   passed to the function are not used in this case, since the connection is already closed.)
1011 /// - A problem was detected with the connection, and it has been closed by the local host.
1012 ///   The most common failure is timeout, but other configuration or authentication failures
1013 ///   can cause this.  m_eOldState = k_ESteamNetworkingConnectionState_Connecting or
1014 ///   k_ESteamNetworkingConnectionState_Connected, and m_info.m_eState = k_ESteamNetworkingConnectionState_ProblemDetectedLocally.
1015 ///   m_info.m_eEndReason and m_info.m_szEndDebug will have for more details.
1016 ///   NOTE: upon receiving this callback, you must still destroy the connection using
1017 ///   ISteamNetworkingSockets::CloseConnection to free up local resources.  (The details
1018 ///   passed to the function are not used in this case, since the connection is already closed.)
1019 ///
1020 /// Remember that callbacks are posted to a queue, and networking connections can
1021 /// change at any time.  It is possible that the connection has already changed
1022 /// state by the time you process this callback.
1023 ///
1024 /// Also note that callbacks will be posted when connections are created and destroyed by your own API calls.
1025 struct SteamNetConnectionStatusChangedCallback_t {
1026 
1027     enum { k_iCallback = k_iSteamNetworkingSocketsCallbacks + 1 };
1028 
1029     /// Connection handle
1030     HSteamNetConnection m_hConn;
1031 
1032     /// Full connection info
1033     SteamNetConnectionInfo_t m_info;
1034 
1035     /// Previous state.  (Current state is in m_info.m_eState)
1036     ESteamNetworkingConnectionState m_eOldState;
1037 
1038 }
1039 
1040 static assert(SteamNetConnectionStatusChangedCallback_t.sizeof == 704);
1041 
1042 /// A struct used to describe our readiness to participate in authenticated,
1043 /// encrypted communication.  In order to do this we need:
1044 ///
1045 /// - The list of trusted CA certificates that might be relevant for this
1046 ///   app.
1047 /// - A valid certificate issued by a CA.
1048 ///
1049 /// This callback is posted whenever the state of our readiness changes.
1050 struct SteamNetAuthenticationStatus_t {
1051 
1052     enum { k_iCallback = k_iSteamNetworkingSocketsCallbacks + 2 };
1053 
1054     /// Status
1055     ESteamNetworkingAvailability m_eAvail;
1056 
1057     /// Non-localized English language status.  For diagnostic/debugging
1058     /// purposes only.
1059     char[256] m_debugMsg;
1060 
1061 };