1 /// Transcription of steamnetworkingtypes.h to D.
2 ///
3 /// Copyright: Valve Corporation, all rights reserved
4 module steam_gns.types;
5 
6 import steam_gns.utils;
7 import steam_gns.sockets;
8 import steam_gns.client_public;
9 
10 //import steam_gns.stypes;
11 //#include "steamclientpublic.h"
12 
13 @nogc nothrow extern (C++) align(4):
14 
15 version = STEAMNETWORKINGSOCKETS_STANDALONELIB;
16 
17 // Where are those defined‽
18 struct SteamNetworkingMessagesSessionRequest_t;
19 struct SteamNetworkingMessagesSessionFailed_t;
20 struct SteamNetworkingFakeIPResult_t;
21 
22 alias FnSteamNetConnectionStatusChanged = void function(SteamNetConnectionStatusChangedCallback_t*);
23 alias FnSteamNetAuthenticationStatusChanged = void function(SteamNetAuthenticationStatus_t*);
24 alias FnSteamRelayNetworkStatusChanged = void function(SteamRelayNetworkStatus_t*);
25 alias FnSteamNetworkingMessagesSessionRequest = void function(SteamNetworkingMessagesSessionRequest_t*);
26 alias FnSteamNetworkingMessagesSessionFailed = void function(SteamNetworkingMessagesSessionFailed_t*);
27 alias FnSteamNetworkingFakeIPResult = void function(SteamNetworkingFakeIPResult_t*);
28 
29 /// Handle used to identify a connection to a remote host.
30 alias HSteamNetConnection = uint;
31 enum HSteamNetConnection k_HSteamNetConnection_Invalid = 0;
32 
33 /// Handle used to identify a "listen socket".  Unlike traditional
34 /// Berkeley sockets, a listen socket and a connection are two
35 /// different abstractions.
36 alias HSteamListenSocket = uint;
37 enum HSteamListenSocket k_HSteamListenSocket_Invalid = 0;
38 
39 /// Handle used to identify a poll group, used to query many
40 /// connections at once efficiently.
41 alias HSteamNetPollGroup = uint;
42 enum HSteamNetPollGroup k_HSteamNetPollGroup_Invalid = 0;
43 
44 /// Max length of diagnostic error message
45 enum int k_cchMaxSteamNetworkingErrMsg = 1024;
46 
47 /// Used to return English-language diagnostic error messages to caller.
48 /// (For debugging or spewing to a console, etc.  Not intended for UI.)
49 alias SteamNetworkingErrMsg = char[k_cchMaxSteamNetworkingErrMsg];
50 
51 /// Identifier used for a network location point of presence.  (E.g. a Valve data center.)
52 /// Typically you won't need to directly manipulate these.
53 alias SteamNetworkingPOPID = uint;
54 
55 /// A local timestamp.  You can subtract two timestamps to get the number of elapsed
56 /// microseconds.  This is guaranteed to increase over time during the lifetime
57 /// of a process, but not globally across runs.  You don't need to worry about
58 /// the value wrapping around.  Note that the underlying clock might not actually have
59 /// microsecond resolution.
60 alias SteamNetworkingMicroseconds = long;
61 
62 /// Describe the status of a particular network resource
63 enum ESteamNetworkingAvailability {
64 
65     // Negative values indicate a problem.
66     //
67     // In general, we will not automatically retry unless you take some action that
68     // depends on of requests this resource, such as querying the status, attempting
69     // to initiate a connection, receive a connection, etc.  If you do not take any
70     // action at all, we do not automatically retry in the background.
71     CannotTry = -102,        // A dependent resource is missing, so this service is unavailable.  (E.g. we cannot talk to routers because Internet is down or we don't have the network config.)
72     Failed = -101,           // We have tried for enough time that we would expect to have been successful by now.  We have never been successful
73     Previously = -100,       // We tried and were successful at one time, but now it looks like we have a problem
74 
75     Retrying = -10,      // We previously failed and are currently retrying
76 
77     // Not a problem, but not ready either
78     NeverTried = 1,      // We don't know because we haven't ever checked/tried
79     Waiting = 2,         // We're waiting on a dependent resource to be acquired.  (E.g. we cannot obtain a cert until we are logged into Steam.  We cannot measure latency to relays until we have the network config.)
80     Attempting = 3,      // We're actively trying now, but are not yet successful.
81 
82     Current = 100,           // Resource is online/available
83 
84 
85     Unknown = 0,         // Internal dummy/sentinel, or value is not applicable in this context
86     _Force32bit = 0x7fffffff,
87 
88 }
89 
90 //
91 // Describing network hosts
92 //
93 
94 /// Different methods of describing the identity of a network host
95 enum ESteamNetworkingIdentityType {
96 
97     // Dummy/empty/invalid.
98     // Please note that if we parse a string that we don't recognize
99     // but that appears reasonable, we will NOT use this type.  Instead
100     // we'll use k_ESteamNetworkingIdentityType_UnknownType.
101     Invalid = 0,
102 
103     //
104     // Basic platform-specific identifiers.
105     //
106     SteamID = 16, // 64-bit CSteamID
107 
108     //
109     // Special identifiers.
110     //
111 
112     // Use their IP address (and port) as their "identity".
113     // These types of identities are always unauthenticated.
114     // They are useful for porting plain sockets code, and other
115     // situations where you don't care about authentication.  In this
116     // case, the local identity will be "localhost",
117     // and the remote address will be their network address.
118     //
119     // We use the same type for either IPv4 or IPv6, and
120     // the address is always store as IPv6.  We use IPv4
121     // mapped addresses to handle IPv4.
122     IPAddress = 1,
123 
124     // Generic string/binary blobs.  It's up to your app to interpret this.
125     // This library can tell you if the remote host presented a certificate
126     // signed by somebody you have chosen to trust, with this identity on it.
127     // It's up to you to ultimately decide what this identity means.
128     GenericString = 2,
129     GenericBytes = 3,
130 
131     // This identity type is used when we parse a string that looks like is a
132     // valid identity, just of a kind that we don't recognize.  In this case, we
133     // can often still communicate with the peer!  Allowing such identities
134     // for types we do not recognize useful is very useful for forward
135     // compatibility.
136     UnknownType = 4,
137 
138     // Make sure this enum is stored in an int.
139     _Force32bit = 0x7fffffff,
140 
141 }
142 
143 /// "Fake IPs" are assigned to hosts, to make it easier to interface with
144 /// older code that assumed all hosts will have an IPv4 address
145 enum ESteamNetworkingFakeIPType {
146 
147     Invalid, // Error, argument was not even an IP address, etc.
148     NotFake, // Argument was a valid IP, but was not from the reserved "fake" range
149     GlobalIPv4, // Globally unique (for a given app) IPv4 address.  Address space managed by Steam
150     LocalIPv4, // Locally unique IPv4 address.  Address space managed by the local process.  For internal use only; should not be shared!
151 
152     _Force32Bit = 0x7fffffff
153 
154 }
155 
156 
157 private extern (C) {
158     void SteamNetworkingIPAddr_ToString(const SteamNetworkingIPAddr* pAddr, char* buf, size_t cbBuf, bool bWithPort);
159     bool SteamNetworkingIPAddr_ParseString(SteamNetworkingIPAddr* pAddr, const(char*) pszStr);
160     ESteamNetworkingFakeIPType SteamNetworkingIPAddr_GetFakeIPType(const(SteamNetworkingIPAddr)* pAddr);
161     void SteamNetworkingIdentity_ToString(const(SteamNetworkingIdentity)* pIdentity, char* buf, size_t cbBuf);
162     bool SteamNetworkingIdentity_ParseString(const(SteamNetworkingIdentity)* pIdentity, size_t sizeofIdentity,
163         const(char)* pszStr);
164 
165 }
166 
167 
168 /// Store an IP and port.  IPv6 is always used; IPv4 is represented using
169 /// "IPv4-mapped" addresses: IPv4 aa.bb.cc.dd => IPv6 ::ffff:aabb:ccdd
170 /// (RFC 4291 section 2.5.5.2.)
171 align (1) struct SteamNetworkingIPAddr {
172 
173     /// RFC4038, section 4.2
174     struct IPv4MappedAddress {
175         ulong m_8zeros;
176         ushort m_0000;
177         ushort m_ffff;
178         ubyte[4] m_ip; // NOTE: As bytes, i.e. network byte order
179     }
180 
181     union {
182         ubyte[16] m_ipv6;
183         IPv4MappedAddress m_ipv4;
184     };
185     ushort m_port; // Host byte order
186 
187     /// Set everything to zero.  E.g. [::]:0
188     void Clear() {
189 
190         m_ipv6 = 0;
191         m_port = 0;
192 
193     }
194 
195     /// Return true if the IP is ::0.  (Doesn't check port.)
196     bool IsIPv6AllZeros() const {
197 
198         import std.algorithm;
199 
200         return m_ipv6[].all!q{ a == 0 };
201 
202     }
203 
204     //void SetIPv6(const(ubyte)* ipv6, ushort nPort); // Set IPv6 address.  IP is interpreted as bytes, so there are no endian issues.  (Same as inaddr_in6.)  The IP can be a mapped IPv4 address
205     //void SetIPv4(uint nIP, ushort nPort); // Sets to IPv4 mapped address.  IP and port are in host byte order.
206 
207     /// Return true if IP is mapped IPv4
208     bool IsIPv4() const {
209 
210         return m_ipv4.m_8zeros == 0 && m_ipv4.m_0000 == 0 && m_ipv4.m_ffff == 0xffff;
211 
212     }
213     //uint GetIPv4() const; // Returns IP in host byte order (e.g. aa.bb.cc.dd as 0xaabbccdd).  Returns 0 if IP is not mapped IPv4.
214     //void SetIPv6LocalHost(ushort nPort = 0); // Set to the IPv6 localhost address ::1, and the specified port.
215 
216     /// Return true if this identity is localhost. (Either IPv6 ::1, or IPv4 127.0.0.1)
217     //bool IsLocalHost() const;
218 
219     // Max length of the buffer needed to hold IP formatted using ToString, including '\0'
220     // ([0123:4567:89ab:cdef:0123:4567:89ab:cdef]:12345)
221     enum k_cchMaxString = 48;
222 
223     /// Print to a string, with or without the port.  Mapped IPv4 addresses are printed
224     /// as dotted decimal (12.34.56.78), otherwise this will print the canonical
225     /// form according to RFC5952.  If you include the port, IPv6 will be surrounded by
226     /// brackets, e.g. [::1:2]:80.  Your buffer should be at least k_cchMaxString bytes
227     /// to avoid truncation
228     ///
229     /// See also SteamNetworkingIdentityRender
230     void ToString(char* buf, size_t cbBuf, bool bWithPort) const {
231 
232         SteamNetworkingIPAddr_ToString(&this, buf, cbBuf, bWithPort);
233 
234     }
235 
236     /// Parse an IP address and optional port.  If a port is not present, it is set to 0.
237     /// (This means that you cannot tell if a zero port was explicitly specified.)
238     bool ParseString(const(char)* pszStr) {
239 
240         return SteamNetworkingIPAddr_ParseString(&this, pszStr);
241 
242     }
243 
244     /// See if two addresses are identical
245     //bool opEquals(const ref SteamNetworkingIPAddr x) const;
246 
247     /// Classify address as FakeIP.  This function never returns
248     /// k_ESteamNetworkingFakeIPType_Invalid.
249     ESteamNetworkingFakeIPType GetFakeIPType() const {
250 
251         return SteamNetworkingIPAddr_GetFakeIPType(&this);
252 
253     }
254 
255     /// Return true if we are a FakeIP
256     bool IsFakeIP() const {
257         return GetFakeIPType() > ESteamNetworkingFakeIPType.NotFake;
258     }
259 
260 }
261 
262 /// An abstract way to represent the identity of a network host.  All identities can
263 /// be represented as simple string.  Furthermore, this string representation is actually
264 /// used on the wire in several places, even though it is less efficient, in order to
265 /// facilitate forward compatibility.  (Old client code can handle an identity type that
266 /// it doesn't understand.)
267 align(1) struct SteamNetworkingIdentity {
268 
269     /// Type of identity.
270     ESteamNetworkingIdentityType m_eType;
271 
272     //
273     // Get/Set in various formats.
274     //
275 
276     void Clear();
277     bool IsInvalid() const; // Return true if we are the invalid type.  Does not make any other validity checks (e.g. is SteamID actually valid)
278 
279     void SetSteamID(CSteamID steamID);
280     CSteamID GetSteamID() const; // Return black CSteamID (!IsValid()) if identity is not a SteamID
281     void SetSteamID64(ulong steamID); // Takes SteamID as raw 64-bit number
282     ulong GetSteamID64() const; // Returns 0 if identity is not SteamID
283 
284     void SetIPAddr(const ref SteamNetworkingIPAddr addr); // Set to specified IP:port
285     const(SteamNetworkingIPAddr*) GetIPAddr() const; // returns null if we are not an IP address.
286     void SetIPv4Addr(uint nIPv4, ushort nPort ); // Set to specified IPv4:port
287     uint GetIPv4() const; // returns 0 if we are not an IPv4 address.
288 
289     ESteamNetworkingFakeIPType GetFakeIPType() const {
290         return m_eType == ESteamNetworkingIdentityType.IPAddress
291             ? m_ip.GetFakeIPType()
292             : ESteamNetworkingFakeIPType.Invalid;
293     }
294     bool IsFakeIP() const {
295         return GetFakeIPType() > ESteamNetworkingFakeIPType.NotFake;
296     }
297 
298     // "localhost" is equivalent for many purposes to "anonymous."  Our remote
299     // will identify us by the network address we use.
300     void SetLocalHost(); // Set to localhost.  (We always use IPv6 ::1 for this, not 127.0.0.1)
301     bool IsLocalHost() const; // Return true if this identity is localhost.
302 
303     bool SetGenericString(const char* pszString); // Returns false if invalid length
304     const(char*) GetGenericString() const; // Returns nullptr if not generic string type
305 
306     bool SetGenericBytes(const void* data, size_t cbLen); // Returns false if invalid size.
307     const(ubyte*) GetGenericBytes(ref int cbLen) const; // Returns null if not generic bytes type
308 
309     /// See if two identities are identical
310     //bool opEquals(const ref SteamNetworkingIdentity x) const;
311 
312     /// Print to a human-readable string.  This is suitable for debug messages
313     /// or any other time you need to encode the identity as a string.  It has a
314     /// URL-like format (type:<type-data>).  Your buffer should be at least
315     /// k_cchMaxString bytes big to avoid truncation.
316     ///
317     /// See also SteamNetworkingIPAddrRender
318     void ToString(char* buf, size_t cbBuf) const;
319 
320     /// Parse back a string that was generated using ToString.  If we don't understand the
321     /// string, but it looks "reasonable" (it matches the pattern type:<type-data> and doesn't
322     /// have any funky characters, etc), then we will return true, and the type is set to
323     /// k_ESteamNetworkingIdentityType_UnknownType.  false will only be returned if the string
324     /// looks invalid.
325     bool ParseString(const char* pszStr);
326 
327     // Max sizes
328     enum {
329         k_cchMaxString = 128, // Max length of the buffer needed to hold any identity, formatted in string format by ToString
330         k_cchMaxGenericString = 32, // Max length of the string for generic string identities.  Including terminating '\0'
331         k_cbMaxGenericBytes = 32,
332     }
333 
334     //
335     // Internal representation.  Don't access this directly, use the accessors!
336     //
337     // Number of bytes that are relevant below.  This MUST ALWAYS be
338     // set.  (Use the accessors!)  This is important to enable old code to work
339     // with new identity types.
340     int m_cbSize;
341 
342     union {
343         ulong m_steamID64;
344         char[k_cchMaxGenericString] m_szGenericString;
345         ubyte[k_cbMaxGenericBytes] m_genericBytes;
346         char[k_cchMaxString] m_szUnknownRawString;
347         SteamNetworkingIPAddr m_ip;
348         uint[32] m_reserved; // Pad structure to leave easy room for future expansion
349     };
350 };
351 
352 //
353 // Connection status
354 //
355 
356 /// High level connection status
357 enum ESteamNetworkingConnectionState {
358 
359     /// Dummy value used to indicate an error condition in the API.
360     /// Specified connection doesn't exist or has already been closed.
361     None = 0,
362 
363     /// We are trying to establish whether peers can talk to each other,
364     /// whether they WANT to talk to each other, perform basic auth,
365     /// and exchange crypt keys.
366     ///
367     /// - For connections on the "client" side (initiated locally):
368     ///   We're in the process of trying to establish a connection.
369     ///   Depending on the connection type, we might not know who they are.
370     ///   Note that it is not possible to tell if we are waiting on the
371     ///   network to complete handshake packets, or for the application layer
372     ///   to accept the connection.
373     ///
374     /// - For connections on the "server" side (accepted through listen socket):
375     ///   We have completed some basic handshake and the client has presented
376     ///   some proof of identity.  The connection is ready to be accepted
377     ///   using AcceptConnection().
378     ///
379     /// In either case, any unreliable packets sent now are almost certain
380     /// to be dropped.  Attempts to receive packets are guaranteed to fail.
381     /// You may send messages if the send mode allows for them to be queued.
382     /// but if you close the connection before the connection is actually
383     /// established, any queued messages will be discarded immediately.
384     /// (We will not attempt to flush the queue and confirm delivery to the
385     /// remote host, which ordinarily happens when a connection is closed.)
386     Connecting = 1,
387 
388     /// Some connection types use a back channel or trusted 3rd party
389     /// for earliest communication.  If the server accepts the connection,
390     /// then these connections switch into the rendezvous state.  During this
391     /// state, we still have not yet established an end-to-end route (through
392     /// the relay network), and so if you send any messages unreliable, they
393     /// are going to be discarded.
394     FindingRoute = 2,
395 
396     /// We've received communications from our peer (and we know
397     /// who they are) and are all good.  If you close the connection now,
398     /// we will make our best effort to flush out any reliable sent data that
399     /// has not been acknowledged by the peer.  (But note that this happens
400     /// from within the application process, so unlike a TCP connection, you are
401     /// not totally handing it off to the operating system to deal with it.)
402     Connected = 3,
403 
404     /// Connection has been closed by our peer, but not closed locally.
405     /// The connection still exists from an API perspective.  You must close the
406     /// handle to free up resources.  If there are any messages in the inbound queue,
407     /// you may retrieve them.  Otherwise, nothing may be done with the connection
408     /// except to close it.
409     ///
410     /// This stats is similar to CLOSE_WAIT in the TCP state machine.
411     ClosedByPeer = 4,
412 
413     /// A disruption in the connection has been detected locally.  (E.g. timeout,
414     /// local internet connection disrupted, etc.)
415     ///
416     /// The connection still exists from an API perspective.  You must close the
417     /// handle to free up resources.
418     ///
419     /// Attempts to send further messages will fail.  Any remaining received messages
420     /// in the queue are available.
421     ProblemDetectedLocally = 5,
422 
423 //
424 // The following values are used internally and will not be returned by any API.
425 // We document them here to provide a little insight into the state machine that is used
426 // under the hood.
427 //
428 
429     /// We've disconnected on our side, and from an API perspective the connection is closed.
430     /// No more data may be sent or received.  All reliable data has been flushed, or else
431     /// we've given up and discarded it.  We do not yet know for sure that the peer knows
432     /// the connection has been closed, however, so we're just hanging around so that if we do
433     /// get a packet from them, we can send them the appropriate packets so that they can
434     /// know why the connection was closed (and not have to rely on a timeout, which makes
435     /// it appear as if something is wrong).
436     FinWait = -1,
437 
438     /// We've disconnected on our side, and from an API perspective the connection is closed.
439     /// No more data may be sent or received.  From a network perspective, however, on the wire,
440     /// we have not yet given any indication to the peer that the connection is closed.
441     /// We are in the process of flushing out the last bit of reliable data.  Once that is done,
442     /// we will inform the peer that the connection has been closed, and transition to the
443     /// FinWait state.
444     ///
445     /// Note that no indication is given to the remote host that we have closed the connection,
446     /// until the data has been flushed.  If the remote host attempts to send us data, we will
447     /// do whatever is necessary to keep the connection alive until it can be closed properly.
448     /// But in fact the data will be discarded, since there is no way for the application to
449     /// read it back.  Typically this is not a problem, as application protocols that utilize
450     /// the lingering functionality are designed for the remote host to wait for the response
451     /// before sending any more data.
452     Linger = -2,
453 
454     /// Connection is completely inactive and ready to be destroyed
455     Dead = -3,
456 
457     _Force32Bit = 0x7fffffff
458 
459 }
460 
461 /// Enumerate various causes of connection termination.  These are designed to work similar
462 /// to HTTP error codes: the numeric range gives you a rough classification as to the source
463 /// of the problem.
464 enum ESteamNetConnectionEnd {
465     // Invalid/sentinel value
466     Invalid = 0,
467 
468     //
469     // Application codes.  These are the values you will pass to
470     // ISteamNetworkingSockets::CloseConnection.  You can use these codes if
471     // you want to plumb through application-specific reason codes.  If you don't
472     // need this facility, feel free to always pass
473     // k_ESteamNetConnectionEnd_App_Generic.
474     //
475     // The distinction between "normal" and "exceptional" termination is
476     // one you may use if you find useful, but it's not necessary for you
477     // to do so.  The only place where we distinguish between normal and
478     // exceptional is in connection analytics.  If a significant
479     // proportion of connections terminates in an exceptional manner,
480     // this can trigger an alert.
481     //
482 
483     // 1xxx: Application ended the connection in a "usual" manner.
484     //       E.g.: user intentionally disconnected from the server,
485     //             gameplay ended normally, etc
486     App_Min = 1000,
487         App_Generic = App_Min,
488         // Use codes in this range for "normal" disconnection
489     App_Max = 1999,
490 
491     // 2xxx: Application ended the connection in some sort of exceptional
492     //       or unusual manner that might indicate a bug or configuration
493     //       issue.
494     //
495     AppException_Min = 2000,
496         AppException_Generic = AppException_Min,
497         // Use codes in this range for "unusual" disconnection
498     AppException_Max = 2999,
499 
500     //
501     // System codes.  These will be returned by the system when
502     // the connection state is k_ESteamNetworkingConnectionState_ClosedByPeer
503     // or k_ESteamNetworkingConnectionState_ProblemDetectedLocally.  It is
504     // illegal to pass a code in this range to ISteamNetworkingSockets::CloseConnection
505     //
506 
507     // 3xxx: Connection failed or ended because of problem with the
508     //       local host or their connection to the Internet.
509     Local_Min = 3000,
510 
511         // You cannot do what you want to do because you're running in offline mode.
512         Local_OfflineMode = 3001,
513 
514         // We're having trouble contacting many (perhaps all) relays.
515         // Since it's unlikely that they all went offline at once, the best
516         // explanation is that we have a problem on our end.  Note that we don't
517         // bother distinguishing between "many" and "all", because in practice,
518         // it takes time to detect a connection problem, and by the time
519         // the connection has timed out, we might not have been able to
520         // actively probe all of the relay clusters, even if we were able to
521         // contact them at one time.  So this code just means that:
522         //
523         // * We don't have any recent successful communication with any relay.
524         // * We have evidence of recent failures to communicate with multiple relays.
525         Local_ManyRelayConnectivity = 3002,
526 
527         // A hosted server is having trouble talking to the relay
528         // that the client was using, so the problem is most likely
529         // on our end
530         Local_HostedServerPrimaryRelay = 3003,
531 
532         // We're not able to get the SDR network config.  This is
533         // *almost* always a local issue, since the network config
534         // comes from the CDN, which is pretty darn reliable.
535         Local_NetworkConfig = 3004,
536 
537         // Steam rejected our request because we don't have rights
538         // to do this.
539         Local_Rights = 3005,
540 
541         // ICE P2P rendezvous failed because we were not able to
542         // determine our "public" address (e.g. reflexive address via STUN)
543         //
544         // If relay fallback is available (it always is on Steam), then
545         // this is only used internally and will not be returned as a high
546         // level failure.
547         Local_P2P_ICE_NoPublicAddresses = 3006,
548 
549     Local_Max = 3999,
550 
551     // 4xxx: Connection failed or ended, and it appears that the
552     //       cause does NOT have to do with the local host or their
553     //       connection to the Internet.  It could be caused by the
554     //       remote host, or it could be somewhere in between.
555     Remote_Min = 4000,
556 
557         // The connection was lost, and as far as we can tell our connection
558         // to relevant services (relays) has not been disrupted.  This doesn't
559         // mean that the problem is "their fault", it just means that it doesn't
560         // appear that we are having network issues on our end.
561         Remote_Timeout = 4001,
562 
563         // Something was invalid with the cert or crypt handshake
564         // info you gave me, I don't understand or like your key types,
565         // etc.
566         Remote_BadCrypt = 4002,
567 
568         // You presented me with a cert that was I was able to parse
569         // and *technically* we could use encrypted communication.
570         // But there was a problem that prevents me from checking your identity
571         // or ensuring that somebody int he middle can't observe our communication.
572         // E.g.: - the CA key was missing (and I don't accept unsigned certs)
573         // - The CA key isn't one that I trust,
574         // - The cert doesn't was appropriately restricted by app, user, time, data center, etc.
575         // - The cert wasn't issued to you.
576         // - etc
577         Remote_BadCert = 4003,
578 
579         // These will never be returned
580         //k_ESteamNetConnectionEnd_Remote_NotLoggedIn_DEPRECATED = 4004,
581         //k_ESteamNetConnectionEnd_Remote_NotRunningApp_DEPRECATED = 4005,
582 
583         // Something wrong with the protocol version you are using.
584         // (Probably the code you are running is too old.)
585         Remote_BadProtocolVersion = 4006,
586 
587         // NAT punch failed failed because we never received any public
588         // addresses from the remote host.  (But we did receive some
589         // signals form them.)
590         //
591         // If relay fallback is available (it always is on Steam), then
592         // this is only used internally and will not be returned as a high
593         // level failure.
594         Remote_P2P_ICE_NoPublicAddresses = 4007,
595 
596     Remote_Max = 4999,
597 
598     // 5xxx: Connection failed for some other reason.
599     Misc_Min = 5000,
600 
601         // A failure that isn't necessarily the result of a software bug,
602         // but that should happen rarely enough that it isn't worth specifically
603         // writing UI or making a localized message for.
604         // The debug string should contain further details.
605         Misc_Generic = 5001,
606 
607         // Generic failure that is most likely a software bug.
608         Misc_InternalError = 5002,
609 
610         // The connection to the remote host timed out, but we
611         // don't know if the problem is on our end, in the middle,
612         // or on their end.
613         Misc_Timeout = 5003,
614 
615         //k_ESteamNetConnectionEnd_Misc_RelayConnectivity_DEPRECATED = 5004,
616 
617         // There's some trouble talking to Steam.
618         Misc_SteamConnectivity = 5005,
619 
620         // A server in a dedicated hosting situation has no relay sessions
621         // active with which to talk back to a client.  (It's the client's
622         // job to open and maintain those sessions.)
623         Misc_NoRelaySessionsToClient = 5006,
624 
625         // While trying to initiate a connection, we never received
626         // *any* communication from the peer.
627         //k_ESteamNetConnectionEnd_Misc_ServerNeverReplied = 5007,
628 
629         // P2P rendezvous failed in a way that we don't have more specific
630         // information
631         Misc_P2P_Rendezvous = 5008,
632 
633         // NAT punch failed, probably due to NAT/firewall configuration.
634         //
635         // If relay fallback is available (it always is on Steam), then
636         // this is only used internally and will not be returned as a high
637         // level failure.
638         Misc_P2P_NAT_Firewall = 5009,
639 
640         // Our peer replied that it has no record of the connection.
641         // This should not happen ordinarily, but can happen in a few
642         // exception cases:
643         //
644         // - This is an old connection, and the peer has already cleaned
645         //   up and forgotten about it.  (Perhaps it timed out and they
646         //   closed it and were not able to communicate this to us.)
647         // - A bug or internal protocol error has caused us to try to
648         //   talk to the peer about the connection before we received
649         //   confirmation that the peer has accepted the connection.
650         // - The peer thinks that we have closed the connection for some
651         //   reason (perhaps a bug), and believes that is it is
652         //   acknowledging our closure.
653         Misc_PeerSentNoConnection = 5010,
654 
655     Misc_Max = 5999,
656 
657     _Force32Bit = 0x7fffffff
658 
659 }
660 
661 /// Max length, in bytes (including null terminator) of the reason string
662 /// when a connection is closed.
663 enum int k_cchSteamNetworkingMaxConnectionCloseReason = 128;
664 
665 /// Max length, in bytes (include null terminator) of debug description
666 /// of a connection.
667 enum int k_cchSteamNetworkingMaxConnectionDescription = 128;
668 
669 /// Max length o the app's part of the description
670 enum int k_cchSteamNetworkingMaxConnectionAppName = 32;
671 
672 enum int k_nSteamNetworkConnectionInfoFlags_Unauthenticated = 1; // We don't have a certificate for the remote host.
673 enum int k_nSteamNetworkConnectionInfoFlags_Unencrypted = 2; // Information is being sent out over a wire unencrypted (by this library)
674 enum int k_nSteamNetworkConnectionInfoFlags_LoopbackBuffers = 4; // Internal loopback buffers.  Won't be true for localhost.  (You can check the address to determine that.)  This implies k_nSteamNetworkConnectionInfoFlags_FastLAN
675 enum int k_nSteamNetworkConnectionInfoFlags_Fast = 8; // The connection is "fast" and "reliable".  Either internal/localhost (check the address to find out), or the peer is on the same LAN.  (Probably.  It's based on the address and the ping time, this is actually hard to determine unambiguously).
676 enum int k_nSteamNetworkConnectionInfoFlags_Relayed = 16; // The connection is relayed somehow (SDR or TURN).
677 enum int k_nSteamNetworkConnectionInfoFlags_DualWifi = 32; // We're taking advantage of dual-wifi multi-path
678 
679 /// Describe the state of a connection.
680 struct SteamNetConnectionInfo_t {
681 
682     /// Who is on the other end?  Depending on the connection type and phase of the connection, we might not know
683     SteamNetworkingIdentity m_identityRemote;
684 
685     /// Arbitrary user data set by the local application code
686     long m_nUserData;
687 
688     /// Handle to listen socket this was connected on, or k_HSteamListenSocket_Invalid if we initiated the connection
689     HSteamListenSocket m_hListenSocket;
690 
691     /// Remote address.  Might be all 0's if we don't know it, or if this is N/A.
692     /// (E.g. Basically everything except direct UDP connection.)
693     SteamNetworkingIPAddr m_addrRemote;
694     ushort m__pad1;
695 
696     /// What data center is the remote host in?  (0 if we don't know.)
697     SteamNetworkingPOPID m_idPOPRemote;
698 
699     /// What relay are we using to communicate with the remote host?
700     /// (0 if not applicable.)
701     SteamNetworkingPOPID m_idPOPRelay;
702 
703     /// High level state of the connection
704     ESteamNetworkingConnectionState m_eState;
705 
706     /// Basic cause of the connection termination or problem.
707     /// See ESteamNetConnectionEnd for the values used
708     int m_eEndReason;
709 
710     /// Human-readable, but non-localized explanation for connection
711     /// termination or problem.  This is intended for debugging /
712     /// diagnostic purposes only, not to display to users.  It might
713     /// have some details specific to the issue.
714     char[k_cchSteamNetworkingMaxConnectionCloseReason] m_szEndDebug;
715 
716     /// Debug description.  This includes the internal connection ID,
717     /// connection type (and peer information), and any name
718     /// given to the connection by the app.  This string is used in various
719     /// internal logging messages.
720     char[k_cchSteamNetworkingMaxConnectionDescription] m_szConnectionDescription;
721 
722     /// Misc flags.  Bitmask of k_nSteamNetworkConnectionInfoFlags_Xxxx
723     int m_nFlags;
724 
725     /// Internal stuff, room to change API easily
726     uint[63] reserved;
727 
728 }
729 
730 static assert(SteamNetConnectionInfo_t.sizeof == 696);
731 static assert(SteamNetConnectionInfo_t.alignof == 4);
732 
733 /// Quick connection state, pared down to something you could call
734 /// more frequently without it being too big of a perf hit.
735 struct SteamNetConnectionRealTimeStatus_t {
736 
737     /// High level state of the connection
738     ESteamNetworkingConnectionState m_eState;
739 
740     /// Current ping (ms)
741     int m_nPing;
742 
743     /// Connection quality measured locally, 0...1.  (Percentage of packets delivered
744     /// end-to-end in order).
745     float m_flConnectionQualityLocal;
746 
747     /// Packet delivery success rate as observed from remote host
748     float m_flConnectionQualityRemote;
749 
750     /// Current data rates from recent history.
751     float m_flOutPacketsPerSec;
752     float m_flOutBytesPerSec;
753     float m_flInPacketsPerSec;
754     float m_flInBytesPerSec;
755 
756     /// Estimate rate that we believe that we can send data to our peer.
757     /// Note that this could be significantly higher than m_flOutBytesPerSec,
758     /// meaning the capacity of the channel is higher than you are sending data.
759     /// (That's OK!)
760     int m_nSendRateBytesPerSecond;
761 
762     /// Number of bytes pending to be sent.  This is data that you have recently
763     /// requested to be sent but has not yet actually been put on the wire.  The
764     /// reliable number ALSO includes data that was previously placed on the wire,
765     /// but has now been scheduled for re-transmission.  Thus, it's possible to
766     /// observe m_cbPendingReliable increasing between two checks, even if no
767     /// calls were made to send reliable data between the checks.  Data that is
768     /// awaiting the Nagle delay will appear in these numbers.
769     int m_cbPendingUnreliable;
770     int m_cbPendingReliable;
771 
772     /// Number of bytes of reliable data that has been placed the wire, but
773     /// for which we have not yet received an acknowledgment, and thus we may
774     /// have to re-transmit.
775     int m_cbSentUnackedReliable;
776 
777     /// If you queued a message right now, approximately how long would that message
778     /// wait in the queue before we actually started putting its data on the wire in
779     /// a packet?
780     ///
781     /// In general, data that is sent by the application is limited by the bandwidth
782     /// of the channel.  If you send data faster than this, it must be queued and
783     /// put on the wire at a metered rate.  Even sending a small amount of data (e.g.
784     /// a few MTU, say ~3k) will require some of the data to be delayed a bit.
785     ///
786     /// Ignoring multiple lanes, the estimated delay will be approximately equal to
787     ///
788     ///     ( m_cbPendingUnreliable+m_cbPendingReliable ) / m_nSendRateBytesPerSecond
789     ///
790     /// plus or minus one MTU.  It depends on how much time has elapsed since the last
791     /// packet was put on the wire.  For example, the queue might have *just* been emptied,
792     /// and the last packet placed on the wire, and we are exactly up against the send
793     /// rate limit.  In that case we might need to wait for one packet's worth of time to
794     /// elapse before we can send again.  On the other extreme, the queue might have data
795     /// in it waiting for Nagle.  (This will always be less than one packet, because as
796     /// soon as we have a complete packet we would send it.)  In that case, we might be
797     /// ready to send data now, and this value will be -1.
798     ///
799     /// This value is only valid if multiple lanes are not used.  If multiple lanes are
800     /// in use, then the queue time will be different for each lane, and you must use
801     /// the value in SteamNetConnectionRealTimeLaneStatus_t.
802     ///
803     /// Nagle delay is ignored for the purposes of this calculation.
804     SteamNetworkingMicroseconds m_usecQueueTime;
805 
806     /// Internal stuff, room to change API easily
807     uint[16] reserved;
808 
809 }
810 
811 /// Quick status of a particular lane
812 struct SteamNetConnectionRealTimeLaneStatus_t {
813 
814        // Counters for this particular lane.  See the corresponding variables
815        // in SteamNetConnectionRealTimeStatus_t
816        int m_cbPendingUnreliable;
817        int m_cbPendingReliable;
818        int m_cbSentUnackedReliable;
819        int _reservePad1; // Reserved for future use
820 
821        /// Lane-specific queue time.  This value takes into consideration lane priorities
822        /// and weights, and how much data is queued in each lane, and attempts to predict
823        /// how any data currently queued will be sent out.
824        SteamNetworkingMicroseconds m_usecQueueTime;
825 
826        // Internal stuff, room to change API easily
827        uint[10] reserved;
828 };
829 
830 //
831 // Network messages
832 //
833 
834 /// Max size of a single message that we can SEND.
835 /// Note: We might be wiling to receive larger messages,
836 /// and our peer might, too.
837 enum int k_cbMaxSteamNetworkingSocketsMessageSizeSend = 512 * 1024;
838 
839 /// A message that has been received.
840 struct SteamNetworkingMessage_t {
841 
842     /// Message payload
843     void* m_pData;
844 
845     /// Size of the payload.
846     int m_cbSize;
847 
848     /// For messages received on connections: what connection did this come from?
849     /// For outgoing messages: what connection to send it to?
850     /// Not used when using the ISteamNetworkingMessages interface
851     HSteamNetConnection m_conn;
852 
853     /// For inbound messages: Who sent this to us?
854     /// For outbound messages on connections: not used.
855     /// For outbound messages on the ad-hoc ISteamNetworkingMessages interface: who should we send this to?
856     SteamNetworkingIdentity m_identityPeer;
857 
858     /// For messages received on connections, this is the user data
859     /// associated with the connection.
860     ///
861     /// This is *usually* the same as calling GetConnection() and then
862     /// fetching the user data associated with that connection, but for
863     /// the following subtle differences:
864     ///
865     /// - This user data will match the connection's user data at the time
866     ///   is captured at the time the message is returned by the API.
867     ///   If you subsequently change the userdata on the connection,
868     ///   this won't be updated.
869     /// - This is an inline call, so it's *much* faster.
870     /// - You might have closed the connection, so fetching the user data
871     ///   would not be possible.
872     ///
873     /// Not used when sending messages.
874     long m_nConnUserData;
875 
876     /// Local timestamp when the message was received
877     /// Not used for outbound messages.
878     SteamNetworkingMicroseconds m_usecTimeReceived;
879 
880     /// Message number assigned by the sender.  This is not used for outbound
881     /// messages.  Note that if multiple lanes are used, each lane has its own
882     /// message numbers, which are assigned sequentially, so messages from
883     /// different lanes will share the same numbers.
884     long m_nMessageNumber;
885 
886     /// Function used to free up m_pData.  This mechanism exists so that
887     /// apps can create messages with buffers allocated from their own
888     /// heap, and pass them into the library.  This function will
889     /// usually be something like:
890     ///
891     /// free( pMsg->m_pData );
892     void function(SteamNetworkingMessage_t*) m_pfnFreeData;
893 
894     /// Function to used to decrement the internal reference count and, if
895     /// it's zero, release the message.  You should not set this function pointer,
896     /// or need to access this directly!  Use the Release() function instead!
897     void function(SteamNetworkingMessage_t*) m_pfnRelease;
898 
899     /// When using ISteamNetworkingMessages, the channel number the message was received on
900     /// (Not used for messages sent or received on "connections")
901     int m_nChannel;
902 
903     /// Bitmask of k_nSteamNetworkingSend_xxx flags.
904     /// For received messages, only the k_nSteamNetworkingSend_Reliable bit is valid.
905     /// For outbound messages, all bits are relevant
906     int m_nFlags;
907 
908     /// Arbitrary user data that you can use when sending messages using
909     /// ISteamNetworkingUtils::AllocateMessage and ISteamNetworkingSockets::SendMessage.
910     /// (The callback you set in m_pfnFreeData might use this field.)
911     ///
912     /// Not used for received messages.
913     long m_nUserData;
914 
915     /// For outbound messages, which lane to use?  See ISteamNetworkingSockets::ConfigureConnectionLanes.
916     /// For inbound messages, what lane was the message received on?
917     ushort m_idxLane;
918     ushort _pad1__;
919 
920     /// You MUST call this when you're done with the object,
921     /// to free up memory, etc.
922     void Release() {
923 
924         m_pfnRelease(&this);
925 
926     }
927 
928     // For code compatibility, some accessors
929     uint GetSize() const { return m_cbSize; }
930     const(void*) GetData() const { return m_pData; }
931     int GetChannel() const { return m_nChannel; }
932     HSteamNetConnection GetConnection() const { return m_conn; }
933     long GetConnectionUserData() const { return m_nConnUserData; }
934     SteamNetworkingMicroseconds GetTimeReceived() const { return m_usecTimeReceived; }
935     long GetMessageNumber() const { return m_nMessageNumber; }
936 
937 }
938 
939 //
940 // Flags used to set options for message sending
941 //
942 
943 // Send the message unreliably. Can be lost.  Messages *can* be larger than a
944 // single MTU (UDP packet), but there is no retransmission, so if any piece
945 // of the message is lost, the entire message will be dropped.
946 //
947 // The sending API does have some knowledge of the underlying connection, so
948 // if there is no NAT-traversal accomplished or there is a recognized adjustment
949 // happening on the connection, the packet will be batched until the connection
950 // is open again.
951 //
952 // Migration note: This is not exactly the same as k_EP2PSendUnreliable!  You
953 // probably want k_ESteamNetworkingSendType_UnreliableNoNagle
954 enum int k_nSteamNetworkingSend_Unreliable = 0;
955 
956 // Disable Nagle's algorithm.
957 // By default, Nagle's algorithm is applied to all outbound messages.  This means
958 // that the message will NOT be sent immediately, in case further messages are
959 // sent soon after you send this, which can be grouped together.  Any time there
960 // is enough buffered data to fill a packet, the packets will be pushed out immediately,
961 // but partially-full packets not be sent until the Nagle timer expires.  See
962 // ISteamNetworkingSockets::FlushMessagesOnConnection, ISteamNetworkingMessages::FlushMessagesToUser
963 //
964 // NOTE: Don't just send every message without Nagle because you want packets to get there
965 // quicker.  Make sure you understand the problem that Nagle is solving before disabling it.
966 // If you are sending small messages, often many at the same time, then it is very likely that
967 // it will be more efficient to leave Nagle enabled.  A typical proper use of this flag is
968 // when you are sending what you know will be the last message sent for a while (e.g. the last
969 // in the server simulation tick to a particular client), and you use this flag to flush all
970 // messages.
971 enum int k_nSteamNetworkingSend_NoNagle = 1;
972 
973 // Send a message unreliably, bypassing Nagle's algorithm for this message and any messages
974 // currently pending on the Nagle timer.  This is equivalent to using k_ESteamNetworkingSend_Unreliable
975 // and then immediately flushing the messages using ISteamNetworkingSockets::FlushMessagesOnConnection
976 // or ISteamNetworkingMessages::FlushMessagesToUser.  (But using this flag is more efficient since you
977 // only make one API call.)
978 enum int k_nSteamNetworkingSend_UnreliableNoNagle = k_nSteamNetworkingSend_Unreliable|k_nSteamNetworkingSend_NoNagle;
979 
980 // If the message cannot be sent very soon (because the connection is still doing some initial
981 // handshaking, route negotiations, etc), then just drop it.  This is only applicable for unreliable
982 // messages.  Using this flag on reliable messages is invalid.
983 enum int k_nSteamNetworkingSend_NoDelay = 4;
984 
985 // Send an unreliable message, but if it cannot be sent relatively quickly, just drop it instead of queuing it.
986 // This is useful for messages that are not useful if they are excessively delayed, such as voice data.
987 // NOTE: The Nagle algorithm is not used, and if the message is not dropped, any messages waiting on the
988 // Nagle timer are immediately flushed.
989 //
990 // A message will be dropped under the following circumstances:
991 // - the connection is not fully connected.  (E.g. the "Connecting" or "FindingRoute" states)
992 // - there is a sufficiently large number of messages queued up already such that the current message
993 //   will not be placed on the wire in the next ~200ms or so.
994 //
995 // If a message is dropped for these reasons, k_EResultIgnored will be returned.
996 enum int k_nSteamNetworkingSend_UnreliableNoDelay = k_nSteamNetworkingSend_Unreliable|k_nSteamNetworkingSend_NoDelay|k_nSteamNetworkingSend_NoNagle;
997 
998 // Reliable message send. Can send up to k_cbMaxSteamNetworkingSocketsMessageSizeSend bytes in a single message.
999 // Does fragmentation/re-assembly of messages under the hood, as well as a sliding window for
1000 // efficient sends of large chunks of data.
1001 //
1002 // The Nagle algorithm is used.  See notes on k_ESteamNetworkingSendType_Unreliable for more details.
1003 // See k_ESteamNetworkingSendType_ReliableNoNagle, ISteamNetworkingSockets::FlushMessagesOnConnection,
1004 // ISteamNetworkingMessages::FlushMessagesToUser
1005 //
1006 // Migration note: This is NOT the same as k_EP2PSendReliable, it's more like k_EP2PSendReliableWithBuffering
1007 enum int k_nSteamNetworkingSend_Reliable = 8;
1008 
1009 // Send a message reliably, but bypass Nagle's algorithm.
1010 //
1011 // Migration note: This is equivalent to k_EP2PSendReliable
1012 enum int k_nSteamNetworkingSend_ReliableNoNagle = k_nSteamNetworkingSend_Reliable|k_nSteamNetworkingSend_NoNagle;
1013 
1014 // By default, message sending is queued, and the work of encryption and talking to
1015 // the operating system sockets, etc is done on a service thread.  This is usually a
1016 // a performance win when messages are sent from the "main thread".  However, if this
1017 // flag is set, and data is ready to be sent immediately (either from this message
1018 // or earlier queued data), then that work will be done in the current thread, before
1019 // the current call returns.  If data is not ready to be sent (due to rate limiting
1020 // or Nagle), then this flag has no effect.
1021 //
1022 // This is an advanced flag used to control performance at a very low level.  For
1023 // most applications running on modern hardware with more than one CPU core, doing
1024 // the work of sending on a service thread will yield the best performance.  Only
1025 // use this flag if you have a really good reason and understand what you are doing.
1026 // Otherwise you will probably just make performance worse.
1027 enum int k_nSteamNetworkingSend_UseCurrentThread = 16;
1028 
1029 // When sending a message using ISteamNetworkingMessages, automatically re-establish
1030 // a broken session, without returning k_EResultNoConnection.  Without this flag,
1031 // if you attempt to send a message, and the session was proactively closed by the
1032 // peer, or an error occurred that disrupted communications, then you must close the
1033 // session using ISteamNetworkingMessages::CloseSessionWithUser before attempting to
1034 // send another message.  (Or you can simply add this flag and retry.)  In this way,
1035 // the disruption cannot go unnoticed, and a more clear order of events can be
1036 // ascertained. This is especially important when reliable messages are used, since
1037 // if the connection is disrupted, some of those messages will not have been delivered,
1038 // and it is in general not possible to know which.  Although a
1039 // SteamNetworkingMessagesSessionFailed_t callback will be posted when an error occurs
1040 // to notify you that a failure has happened, callbacks are asynchronous, so it is not
1041 // possible to tell exactly when it happened.  And because the primary purpose of
1042 // ISteamNetworkingMessages is to be like UDP, there is no notification when a peer closes
1043 // the session.
1044 //
1045 // If you are not using any reliable messages (e.g. you are using ISteamNetworkingMessages
1046 // exactly as a transport replacement for UDP-style datagrams only), you may not need to
1047 // know when an underlying connection fails, and so you may not need this notification.
1048 enum int k_nSteamNetworkingSend_AutoRestartBrokenSession = 32;
1049 
1050 //
1051 // Ping location / measurement
1052 //
1053 
1054 /// Object that describes a "location" on the Internet with sufficient
1055 /// detail that we can reasonably estimate an upper bound on the ping between
1056 /// the two hosts, even if a direct route between the hosts is not possible,
1057 /// and the connection must be routed through the Steam Datagram Relay network.
1058 /// This does not contain any information that identifies the host.  Indeed,
1059 /// if two hosts are in the same building or otherwise have nearly identical
1060 /// networking characteristics, then it's valid to use the same location
1061 /// object for both of them.
1062 ///
1063 /// NOTE: This object should only be used in the same process!  Do not serialize it,
1064 /// send it over the wire, or persist it in a file or database!  If you need
1065 /// to do that, convert it to a string representation using the methods in
1066 /// ISteamNetworkingUtils().
1067 struct SteamNetworkPingLocation_t {
1068     ubyte[512] m_data;
1069 };
1070 
1071 /// Max possible length of a ping location, in string format.  This is
1072 /// an extremely conservative worst case value which leaves room for future
1073 /// syntax enhancements.  Most strings in practice are a lot shorter.
1074 /// If you are storing many of these, you will very likely benefit from
1075 /// using dynamic memory.
1076 enum int k_cchMaxSteamNetworkingPingLocationString = 1024;
1077 
1078 /// Special values that are returned by some functions that return a ping.
1079 enum int k_nSteamNetworkingPing_Failed = -1;
1080 enum int k_nSteamNetworkingPing_Unknown = -2;
1081 
1082 //
1083 // Configuration values
1084 //
1085 
1086 /// Configuration values can be applied to different types of objects.
1087 enum ESteamNetworkingConfigScope {
1088 
1089     /// Get/set global option, or defaults.  Even options that apply to more specific scopes
1090     /// have global scope, and you may be able to just change the global defaults.  If you
1091     /// need different settings per connection (for example), then you will need to set those
1092     /// options at the more specific scope.
1093     Global = 1,
1094 
1095     /// Some options are specific to a particular interface.  Note that all connection
1096     /// and listen socket settings can also be set at the interface level, and they will
1097     /// apply to objects created through those interfaces.
1098     SocketsInterface = 2,
1099 
1100     /// Options for a listen socket.  Listen socket options can be set at the interface layer,
1101     /// if  you have multiple listen sockets and they all use the same options.
1102     /// You can also set connection options on a listen socket, and they set the defaults
1103     /// for all connections accepted through this listen socket.  (They will be used if you don't
1104     /// set a connection option.)
1105     ListenSocket = 3,
1106 
1107     /// Options for a specific connection.
1108     Connection = 4,
1109 
1110     _Force32Bit = 0x7fffffff
1111 
1112 }
1113 
1114 // Different configuration values have different data types
1115 enum ESteamNetworkingConfigDataType {
1116 
1117     Int32 = 1,
1118     Int64 = 2,
1119     Float = 3,
1120     String = 4,
1121     Ptr = 5,
1122 
1123     _Force32Bit = 0x7fffffff
1124 
1125 }
1126 
1127 /// Configuration options
1128 enum ESteamNetworkingConfigValue {
1129 
1130     Invalid = 0,
1131 
1132 //
1133 // Connection options
1134 //
1135 
1136     /// [connection int32] Timeout value (in ms) to use when first connecting
1137     TimeoutInitial = 24,
1138 
1139     /// [connection int32] Timeout value (in ms) to use after connection is established
1140     TimeoutConnected = 25,
1141 
1142     /// [connection int32] Upper limit of buffered pending bytes to be sent,
1143     /// if this is reached SendMessage will return k_EResultLimitExceeded
1144     /// Default is 512k (524288 bytes)
1145     SendBufferSize = 9,
1146 
1147     /// [connection int64] Get/set userdata as a configuration option.
1148     /// The default value is -1.   You may want to set the user data as
1149     /// a config value, instead of using ISteamNetworkingSockets::SetConnectionUserData
1150     /// in two specific instances:
1151     ///
1152     /// - You wish to set the userdata atomically when creating
1153     ///   an outbound connection, so that the userdata is filled in properly
1154     ///   for any callbacks that happen.  However, note that this trick
1155     ///   only works for connections initiated locally!  For incoming
1156     ///   connections, multiple state transitions may happen and
1157     ///   callbacks be queued, before you are able to service the first
1158     ///   callback!  Be careful!
1159     ///
1160     /// - You can set the default userdata for all newly created connections
1161     ///   by setting this value at a higher level (e.g. on the listen
1162     ///   socket or at the global level.)  Then this default
1163     ///   value will be inherited when the connection is created.
1164     ///   This is useful in case -1 is a valid userdata value, and you
1165     ///   wish to use something else as the default value so you can
1166     ///   tell if it has been set or not.
1167     ///
1168     ///   HOWEVER: once a connection is created, the effective value is
1169     ///   then bound to the connection.  Unlike other connection options,
1170     ///   if you change it again at a higher level, the new value will not
1171     ///   be inherited by connections.
1172     ///
1173     /// Using the userdata field in callback structs is not advised because
1174     /// of tricky race conditions.  Instead, you might try one of these methods:
1175     ///
1176     /// - Use a separate map with the HSteamNetConnection as the key.
1177     /// - Fetch the userdata from the connection in your callback
1178     ///   using ISteamNetworkingSockets::GetConnectionUserData, to
1179     //    ensure you have the current value.
1180     ConnectionUserData = 40,
1181 
1182     /// [connection int32] Minimum/maximum send rate clamp, 0 is no limit.
1183     /// This value will control the min/max allowed sending rate that
1184     /// bandwidth estimation is allowed to reach.  Default is 0 (no-limit)
1185     SendRateMin = 10,
1186     SendRateMax = 11,
1187 
1188     /// [connection int32] Nagle time, in microseconds.  When SendMessage is called, if
1189     /// the outgoing message is less than the size of the MTU, it will be
1190     /// queued for a delay equal to the Nagle timer value.  This is to ensure
1191     /// that if the application sends several small messages rapidly, they are
1192     /// coalesced into a single packet.
1193     /// See historical RFC 896.  Value is in microseconds.
1194     /// Default is 5000us (5ms).
1195     NagleTime = 12,
1196 
1197     /// [connection int32] Don't automatically fail IP connections that don't have
1198     /// strong auth.  On clients, this means we will attempt the connection even if
1199     /// we don't know our identity or can't get a cert.  On the server, it means that
1200     /// we won't automatically reject a connection due to a failure to authenticate.
1201     /// (You can examine the incoming connection and decide whether to accept it.)
1202     ///
1203     /// This is a dev configuration value, and you should not let users modify it in
1204     /// production.
1205     IP_AllowWithoutAuth = 23,
1206 
1207     /// [connection int32] Do not send UDP packets with a payload of
1208     /// larger than N bytes.  If you set this, k_ESteamNetworkingConfig_MTU_DataSize
1209     /// is automatically adjusted
1210     MTU_PacketSize = 32,
1211 
1212     /// [connection int32] (read only) Maximum message size you can send that
1213     /// will not fragment, based on k_ESteamNetworkingConfig_MTU_PacketSize
1214     MTU_DataSize = 33,
1215 
1216     /// [connection int32] Allow unencrypted (and unauthenticated) communication.
1217     /// 0: Not allowed (the default)
1218     /// 1: Allowed, but prefer encrypted
1219     /// 2: Allowed, and preferred
1220     /// 3: Required.  (Fail the connection if the peer requires encryption.)
1221     ///
1222     /// This is a dev configuration value, since its purpose is to disable encryption.
1223     /// You should not let users modify it in production.  (But note that it requires
1224     /// the peer to also modify their value in order for encryption to be disabled.)
1225     Unencrypted = 34,
1226 
1227     /// [connection int32] Set this to 1 on outbound connections and listen sockets,
1228     /// to enable "symmetric connect mode", which is useful in the following
1229     /// common peer-to-peer use case:
1230     ///
1231     /// - The two peers are "equal" to each other.  (Neither is clearly the "client"
1232     ///   or "server".)
1233     /// - Either peer may initiate the connection, and indeed they may do this
1234     ///   at the same time
1235     /// - The peers only desire a single connection to each other, and if both
1236     ///   peers initiate connections simultaneously, a protocol is needed for them
1237     ///   to resolve the conflict, so that we end up with a single connection.
1238     ///
1239     /// This use case is both common, and involves subtle race conditions and tricky
1240     /// pitfalls, which is why the API has support for dealing with it.
1241     ///
1242     /// If an incoming connection arrives on a listen socket or via custom signaling,
1243     /// and the application has not attempted to make a matching outbound connection
1244     /// in symmetric mode, then the incoming connection can be accepted as usual.
1245     /// A "matching" connection means that the relevant endpoint information matches.
1246     /// (At the time this comment is being written, this is only supported for P2P
1247     /// connections, which means that the peer identities must match, and the virtual
1248     /// port must match.  At a later time, symmetric mode may be supported for other
1249     /// connection types.)
1250     ///
1251     /// If connections are initiated by both peers simultaneously, race conditions
1252     /// can arise, but fortunately, most of them are handled internally and do not
1253     /// require any special awareness from the application.  However, there
1254     /// is one important case that application code must be aware of:
1255     /// If application code attempts an outbound connection using a ConnectXxx
1256     /// function in symmetric mode, and a matching incoming connection is already
1257     /// waiting on a listen socket, then instead of forming a new connection,
1258     /// the ConnectXxx call will accept the existing incoming connection, and return
1259     /// a connection handle to this accepted connection.
1260     /// IMPORTANT: in this case, a SteamNetConnectionStatusChangedCallback_t
1261     /// has probably *already* been posted to the queue for the incoming connection!
1262     /// (Once callbacks are posted to the queue, they are not modified.)  It doesn't
1263     /// matter if the callback has not been consumed by the app.  Thus, application
1264     /// code that makes use of symmetric connections must be aware that, when processing a
1265     /// SteamNetConnectionStatusChangedCallback_t for an incoming connection, the
1266     /// m_hConn may refer to a new connection that the app has has not
1267     /// seen before (the usual case), but it may also refer to a connection that
1268     /// has already been accepted implicitly through a call to Connect()!  In this
1269     /// case, AcceptConnection() will return k_EResultDuplicateRequest.
1270     ///
1271     /// Only one symmetric connection to a given peer (on a given virtual port)
1272     /// may exist at any given time.  If client code attempts to create a connection,
1273     /// and a (live) connection already exists on the local host, then either the
1274     /// existing connection will be accepted as described above, or the attempt
1275     /// to create a new connection will fail.  Furthermore, linger mode functionality
1276     /// is not supported on symmetric connections.
1277     ///
1278     /// A more complicated race condition can arise if both peers initiate a connection
1279     /// at roughly the same time.  In this situation, each peer will receive an incoming
1280     /// connection from the other peer, when the application code has already initiated
1281     /// an outgoing connection to that peer.  The peers must resolve this conflict and
1282     /// decide who is going to act as the "server" and who will act as the "client".
1283     /// Typically the application does not need to be aware of this case as it is handled
1284     /// internally.  On both sides, the will observe their outbound connection being
1285     /// "accepted", although one of them one have been converted internally to act
1286     /// as the "server".
1287     ///
1288     /// In general, symmetric mode should be all-or-nothing: do not mix symmetric
1289     /// connections with a non-symmetric connection that it might possible "match"
1290     /// with.  If you use symmetric mode on any connections, then both peers should
1291     /// use it on all connections, and the corresponding listen socket, if any.  The
1292     /// behaviour when symmetric and ordinary connections are mixed is not defined by
1293     /// this API, and you should not rely on it.  (This advice only applies when connections
1294     /// might possibly "match".  For example, it's OK to use all symmetric mode
1295     /// connections on one virtual port, and all ordinary, non-symmetric connections
1296     /// on a different virtual port, as there is no potential for ambiguity.)
1297     ///
1298     /// When using the feature, you should set it in the following situations on
1299     /// applicable objects:
1300     ///
1301     /// - When creating an outbound connection using ConnectXxx function
1302     /// - When creating a listen socket.  (Note that this will automatically cause
1303     ///   any accepted connections to inherit the flag.)
1304     /// - When using custom signaling, before accepting an incoming connection.
1305     ///
1306     /// Setting the flag on listen socket and accepted connections will enable the
1307     /// API to automatically deal with duplicate incoming connections, even if the
1308     /// local host has not made any outbound requests.  (In general, such duplicate
1309     /// requests from a peer are ignored internally and will not be visible to the
1310     /// application code.  The previous connection must be closed or resolved first.)
1311     SymmetricConnect = 37,
1312 
1313     /// [connection int32] For connection types that use "virtual ports", this can be used
1314     /// to assign a local virtual port.  For incoming connections, this will always be the
1315     /// virtual port of the listen socket (or the port requested by the remote host if custom
1316     /// signaling is used and the connection is accepted), and cannot be changed.  For
1317     /// connections initiated locally, the local virtual port will default to the same as the
1318     /// requested remote virtual port, if you do not specify a different option when creating
1319     /// the connection.  The local port is only relevant for symmetric connections, when
1320     /// determining if two connections "match."  In this case, if you need the local and remote
1321     /// port to differ, you can set this value.
1322     ///
1323     /// You can also read back this value on listen sockets.
1324     ///
1325     /// This value should not be read or written in any other context.
1326     LocalVirtualPort = 38,
1327 
1328     /// [connection int32] True to enable diagnostics reporting through
1329     /// generic platform UI.  (Only available on Steam.)
1330     EnableDiagnosticsUI = 46,
1331 
1332 //
1333 // Simulating network conditions
1334 //
1335 // These are global (not per-connection) because they apply at
1336 // a relatively low UDP layer.
1337 //
1338 
1339     /// [global float, 0--100] Randomly discard N pct of packets instead of sending/recv
1340     /// This is a global option only, since it is applied at a low level
1341     /// where we don't have much context
1342     FakePacketLoss_Send = 2,
1343     FakePacketLoss_Recv = 3,
1344 
1345     /// [global int32].  Delay all outbound/inbound packets by N ms
1346     FakePacketLag_Send = 4,
1347     FakePacketLag_Recv = 5,
1348 
1349     /// [global float] 0-100 Percentage of packets we will add additional delay
1350     /// to (causing them to be reordered)
1351     FakePacketReorder_Send = 6,
1352     FakePacketReorder_Recv = 7,
1353 
1354     /// [global int32] Extra delay, in ms, to apply to reordered packets.
1355     FakePacketReorder_Time = 8,
1356 
1357     /// [global float 0--100] Globally duplicate some percentage of packets we send
1358     FakePacketDup_Send = 26,
1359     FakePacketDup_Recv = 27,
1360 
1361     /// [global int32] Amount of delay, in ms, to delay duplicated packets.
1362     /// (We chose a random delay between 0 and this value)
1363     FakePacketDup_TimeMax = 28,
1364 
1365     /// [global int32] Trace every UDP packet, similar to Wireshark or tcpdump.
1366     /// Value is max number of bytes to dump.  -1 disables tracing.
1367     // 0 only traces the info but no actual data bytes
1368     PacketTraceMaxBytes = 41,
1369 
1370 
1371     // [global int32] Global UDP token bucket rate limits.
1372     // "Rate" refers to the steady state rate. (Bytes/sec, the
1373     // rate that tokens are put into the bucket.)  "Burst"
1374     // refers to the max amount that could be sent in a single
1375     // burst.  (In bytes, the max capacity of the bucket.)
1376     // Rate=0 disables the limiter entirely, which is the default.
1377     // Burst=0 disables burst.  (This is not realistic.  A
1378     // burst of at least 4K is recommended; the default is higher.)
1379     FakeRateLimit_Send_Rate = 42,
1380     FakeRateLimit_Send_Burst = 43,
1381     FakeRateLimit_Recv_Rate = 44,
1382     FakeRateLimit_Recv_Burst = 45,
1383 
1384 //
1385 // Callbacks
1386 //
1387 
1388     // On Steam, you may use the default Steam callback dispatch mechanism.  If you prefer
1389     // to not use this dispatch mechanism (or you are not running with Steam), or you want
1390     // to associate specific functions with specific listen sockets or connections, you can
1391     // register them as configuration values.
1392     //
1393     // Note also that ISteamNetworkingUtils has some helpers to set these globally.
1394 
1395     /// [connection FnSteamNetConnectionStatusChanged] Callback that will be invoked
1396     /// when the state of a connection changes.
1397     ///
1398     /// IMPORTANT: callbacks are dispatched to the handler that is in effect at the time
1399     /// the event occurs, which might be in another thread.  For example, immediately after
1400     /// creating a listen socket, you may receive an incoming connection.  And then immediately
1401     /// after this, the remote host may close the connection.  All of this could happen
1402     /// before the function to create the listen socket has returned.  For this reason,
1403     /// callbacks usually must be in effect at the time of object creation.  This means
1404     /// you should set them when you are creating the listen socket or connection, or have
1405     /// them in effect so they will be inherited at the time of object creation.
1406     ///
1407     /// For example:
1408     ///
1409     /// exterm void MyStatusChangedFunc( SteamNetConnectionStatusChangedCallback_t *info );
1410     /// SteamNetworkingConfigValue_t opt; opt.SetPtr( k_ESteamNetworkingConfig_Callback_ConnectionStatusChanged, MyStatusChangedFunc );
1411     /// SteamNetworkingIPAddr localAddress; localAddress.Clear();
1412     /// HSteamListenSocket hListenSock = SteamNetworkingSockets()->CreateListenSocketIP( localAddress, 1, &opt );
1413     ///
1414     /// When accepting an incoming connection, there is no atomic way to switch the
1415     /// callback.  However, if the connection is DOA, AcceptConnection() will fail, and
1416     /// you can fetch the state of the connection at that time.
1417     ///
1418     /// If all connections and listen sockets can use the same callback, the simplest
1419     /// method is to set it globally before you create any listen sockets or connections.
1420     Callback_ConnectionStatusChanged = 201,
1421 
1422     /// [global FnSteamNetAuthenticationStatusChanged] Callback that will be invoked
1423     /// when our auth state changes.  If you use this, install the callback before creating
1424     /// any connections or listen sockets, and don't change it.
1425     /// See: ISteamNetworkingUtils::SetGlobalCallback_SteamNetAuthenticationStatusChanged
1426     Callback_AuthStatusChanged = 202,
1427 
1428     /// [global FnSteamRelayNetworkStatusChanged] Callback that will be invoked
1429     /// when our auth state changes.  If you use this, install the callback before creating
1430     /// any connections or listen sockets, and don't change it.
1431     /// See: ISteamNetworkingUtils::SetGlobalCallback_SteamRelayNetworkStatusChanged
1432     Callback_RelayNetworkStatusChanged = 203,
1433 
1434     /// [global FnSteamNetworkingMessagesSessionRequest] Callback that will be invoked
1435     /// when a peer wants to initiate a SteamNetworkingMessagesSessionRequest.
1436     /// See: ISteamNetworkingUtils::SetGlobalCallback_MessagesSessionRequest
1437     Callback_MessagesSessionRequest = 204,
1438 
1439     /// [global FnSteamNetworkingMessagesSessionFailed] Callback that will be invoked
1440     /// when a session you have initiated, or accepted either fails to connect, or loses
1441     /// connection in some unexpected way.
1442     /// See: ISteamNetworkingUtils::SetGlobalCallback_MessagesSessionFailed
1443     Callback_MessagesSessionFailed = 205,
1444 
1445     /// [global FnSteamNetworkingSocketsCreateConnectionSignaling] Callback that will
1446     /// be invoked when we need to create a signaling object for a connection
1447     /// initiated locally.  See: ISteamNetworkingSockets::ConnectP2P,
1448     /// ISteamNetworkingMessages.
1449     Callback_CreateConnectionSignaling = 206,
1450 
1451     /// [global FnSteamNetworkingFakeIPResult] Callback that's invoked when
1452     /// a FakeIP allocation finishes.  See: ISteamNetworkingSockets::BeginAsyncRequestFakeIP,
1453     /// ISteamNetworkingUtils::SetGlobalCallback_FakeIPResult
1454     Callback_FakeIPResult = 207,
1455 
1456 //
1457 // P2P connection settings
1458 //
1459 
1460 //  /// [listen socket int32] When you create a P2P listen socket, we will automatically
1461 //  /// open up a UDP port to listen for LAN connections.  LAN connections can be made
1462 //  /// without any signaling: both sides can be disconnected from the Internet.
1463 //  ///
1464 //  /// This value can be set to zero to disable the feature.
1465 //  k_ESteamNetworkingConfig_P2P_Discovery_Server_LocalPort = 101,
1466 //
1467 //  /// [connection int32] P2P connections can perform broadcasts looking for the peer
1468 //  /// on the LAN.
1469 //  k_ESteamNetworkingConfig_P2P_Discovery_Client_RemotePort = 102,
1470 
1471     /// [connection string] Comma-separated list of STUN servers that can be used
1472     /// for NAT piercing.  If you set this to an empty string, NAT piercing will
1473     /// not be attempted.  Also if "public" candidates are not allowed for
1474     /// P2P_Transport_ICE_Enable, then this is ignored.
1475     P2P_STUN_ServerList = 103,
1476 
1477     /// [connection int32] What types of ICE candidates to share with the peer.
1478     /// See k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_xxx values
1479     P2P_Transport_ICE_Enable = 104,
1480 
1481     /// [connection int32] When selecting P2P transport, add various
1482     /// penalties to the scores for selected transports.  (Route selection
1483     /// scores are on a scale of milliseconds.  The score begins with the
1484     /// route ping time and is then adjusted.)
1485     P2P_Transport_ICE_Penalty = 105,
1486     P2P_Transport_SDR_Penalty = 106,
1487     P2P_TURN_ServerList = 107,
1488     P2P_TURN_UserList = 108,
1489     P2P_TURN_PassList = 109,
1490     //k_ESteamNetworkingConfig_P2P_Transport_LANBeacon_Penalty = 107,
1491     P2P_Transport_ICE_Implementation = 110,
1492 
1493 //
1494 // Settings for SDR relayed connections
1495 //
1496 
1497     /// [int32 global] If the first N pings to a port all fail, mark that port as unavailable for
1498     /// a while, and try a different one.  Some ISPs and routers may drop the first
1499     /// packet, so setting this to 1 may greatly disrupt communications.
1500     SDRClient_ConsecutitivePingTimeoutsFailInitial = 19,
1501 
1502     /// [int32 global] If N consecutive pings to a port fail, after having received successful
1503     /// communication, mark that port as unavailable for a while, and try a
1504     /// different one.
1505     SDRClient_ConsecutitivePingTimeoutsFail = 20,
1506 
1507     /// [int32 global] Minimum number of lifetime pings we need to send, before we think our estimate
1508     /// is solid.  The first ping to each cluster is very often delayed because of NAT,
1509     /// routers not having the best route, etc.  Until we've sent a sufficient number
1510     /// of pings, our estimate is often inaccurate.  Keep pinging until we get this
1511     /// many pings.
1512     SDRClient_MinPingsBeforePingAccurate = 21,
1513 
1514     /// [int32 global] Set all steam datagram traffic to originate from the same
1515     /// local port. By default, we open up a new UDP socket (on a different local
1516     /// port) for each relay.  This is slightly less optimal, but it works around
1517     /// some routers that don't implement NAT properly.  If you have intermittent
1518     /// problems talking to relays that might be NAT related, try toggling
1519     /// this flag
1520     SDRClient_SingleSocket = 22,
1521 
1522     /// [global string] Code of relay cluster to force use.  If not empty, we will
1523     /// only use relays in that cluster.  E.g. 'iad'
1524     SDRClient_ForceRelayCluster = 29,
1525 
1526     /// [connection string] For debugging, generate our own (unsigned) ticket, using
1527     /// the specified  gameserver address.  Router must be configured to accept unsigned
1528     /// tickets.
1529     SDRClient_DebugTicketAddress = 30,
1530 
1531     /// [global string] For debugging.  Override list of relays from the config with
1532     /// this set (maybe just one).  Comma-separated list.
1533     SDRClient_ForceProxyAddr = 31,
1534 
1535     /// [global string] For debugging.  Force ping times to clusters to be the specified
1536     /// values.  A comma separated list of <cluster>=<ms> values.  E.g. "sto=32,iad=100"
1537     ///
1538     /// This is a dev configuration value, you probably should not let users modify it
1539     /// in production.
1540     SDRClient_FakeClusterPing = 36,
1541 
1542 //
1543 // Log levels for debugging information of various subsystems.
1544 // Higher numeric values will cause more stuff to be printed.
1545 // See ISteamNetworkingUtils::SetDebugOutputFunction for more
1546 // information
1547 //
1548 // The default for all values is k_ESteamNetworkingSocketsDebugOutputType_Warning.
1549 //
1550     LogLevel_AckRTT = 13, // [connection int32] RTT calculations for inline pings and replies
1551     LogLevel_PacketDecode = 14, // [connection int32] log SNP packets send/recv
1552     LogLevel_Message = 15, // [connection int32] log each message send/recv
1553     LogLevel_PacketGaps = 16, // [connection int32] dropped packets
1554     LogLevel_P2PRendezvous = 17, // [connection int32] P2P rendezvous messages
1555     LogLevel_SDRRelayPings = 18, // [global int32] Ping relays
1556 
1557 
1558     // Deleted, do not use
1559     DELETED_EnumerateDevVars = 35,
1560 
1561     _Force32Bit = 0x7fffffff
1562 
1563 }
1564 
1565 // Bitmask of types to share
1566 enum int k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_Default = -1; // Special value - use user defaults
1567 enum int k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_Disable = 0; // Do not do any ICE work at all or share any IP addresses with peer
1568 enum int k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_Relay = 1; // Relayed connection via TURN server.
1569 enum int k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_Private = 2; // host addresses that appear to be link-local or RFC1918 addresses
1570 enum int k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_Public = 4; // STUN reflexive addresses, or host address that isn't a "private" address
1571 enum int k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_All = 0x7fffffff;
1572 
1573 /// In a few places we need to set configuration options on listen sockets and connections, and
1574 /// have them take effect *before* the listen socket or connection really starts doing anything.
1575 /// Creating the object and then setting the options "immediately" after creation doesn't work
1576 /// completely, because network packets could be received between the time the object is created and
1577 /// when the options are applied.  To set options at creation time in a reliable way, they must be
1578 /// passed to the creation function.  This structure is used to pass those options.
1579 ///
1580 /// For the meaning of these fields, see ISteamNetworkingUtils::SetConfigValue.  Basically
1581 /// when the object is created, we just iterate over the list of options and call
1582 /// ISteamNetworkingUtils::SetConfigValueStruct, where the scope arguments are supplied by the
1583 /// object being created.
1584 struct SteamNetworkingConfigValue_t {
1585 
1586     /// Which option is being set
1587     ESteamNetworkingConfigValue m_eValue;
1588 
1589     /// Which field below did you fill in?
1590     ESteamNetworkingConfigDataType m_eDataType;
1591 
1592     /// Option value
1593     union Value_t {
1594 
1595         int m_int32;
1596         long m_int64;
1597         float m_float;
1598         const(char)* m_string; // Points to your '\0'-terminated buffer
1599         void* m_ptr;
1600     }
1601 
1602     Value_t m_val;
1603 
1604     //
1605     // Shortcut helpers to set the type and value in a single call
1606     //
1607     void SetInt32(ESteamNetworkingConfigValue eVal, int data) {
1608         m_eValue = eVal;
1609         m_eDataType = ESteamNetworkingConfigDataType.Int32;
1610         m_val.m_int32 = data;
1611     }
1612 
1613     void SetInt64(ESteamNetworkingConfigValue eVal, long data) {
1614         m_eValue = eVal;
1615         m_eDataType = ESteamNetworkingConfigDataType.Int64;
1616         m_val.m_int64 = data;
1617     }
1618 
1619     void SetFloat(ESteamNetworkingConfigValue eVal, float data) {
1620         m_eValue = eVal;
1621         m_eDataType = ESteamNetworkingConfigDataType.Float;
1622         m_val.m_float = data;
1623     }
1624 
1625     void SetPtr(ESteamNetworkingConfigValue eVal, void* data) {
1626         m_eValue = eVal;
1627         m_eDataType = ESteamNetworkingConfigDataType.Ptr;
1628         m_val.m_ptr = data;
1629     }
1630 
1631     void SetString(ESteamNetworkingConfigValue eVal, const(char)* data) { // WARNING - Just saves your pointer.  Does NOT make a copy of the string
1632         m_eValue = eVal;
1633         m_eDataType = ESteamNetworkingConfigDataType.Ptr;
1634         m_val.m_string = data;
1635     }
1636 
1637 }
1638 
1639 /// Return value of ISteamNetworkintgUtils::GetConfigValue
1640 enum ESteamNetworkingGetConfigValueResult {
1641 
1642     BadValue = -1, // No such configuration value
1643     BadScopeObj = -2,  // Bad connection handle, etc
1644     BufferTooSmall = -3, // Couldn't fit the result in your buffer
1645     OK = 1,
1646     OKInherited = 2, // A value was not set at this level, but the effective (inherited) value was returned.
1647 
1648     _Force32Bit = 0x7fffffff
1649 
1650 }
1651 
1652 //
1653 // Debug output
1654 //
1655 
1656 /// Detail level for diagnostic output callback.
1657 /// See ISteamNetworkingUtils::SetDebugOutputFunction
1658 enum ESteamNetworkingSocketsDebugOutputType {
1659 
1660     None = 0,
1661     Bug = 1, // You used the API incorrectly, or an internal error happened
1662     Error = 2, // Run-time error condition that isn't the result of a bug.  (E.g. we are offline, cannot bind a port, etc)
1663     Important = 3, // Nothing is wrong, but this is an important notification
1664     Warning = 4,
1665     Msg = 5, // Recommended amount
1666     Verbose = 6, // Quite a bit
1667     Debug = 7, // Practically everything
1668     Everything = 8, // Wall of text, detailed packet contents breakdown, etc
1669 
1670     _Force32Bit = 0x7fffffff
1671 
1672 }
1673 
1674 /// Setup callback for debug output, and the desired verbosity you want.
1675 alias FSteamNetworkingSocketsDebugOutput = void function(ESteamNetworkingSocketsDebugOutputType nType,
1676 const char* pszMsg);
1677 
1678 //
1679 // Valve data centers
1680 //
1681 
1682 /// Convert 3- or 4-character ID to 32-bit int.
1683 SteamNetworkingPOPID CalculateSteamNetworkingPOPIDFromString(const char* pszCode) {
1684 
1685     // OK we made a bad decision when we decided how to pack 3-character codes into a uint32.  We'd like to support
1686     // 4-character codes, but we don't want to break compatibility.  The migration path has some subtleties that make
1687     // this nontrivial, and there are already some IDs stored in SQL.  Ug, so the 4 character code "abcd" will
1688     // be encoded with the digits like "0xddaabbcc".
1689     //
1690     // Also: we don't currently use 1- or 2-character codes, but if ever do in the future, let's make sure don't read
1691     // past the end of the string and access uninitialized memory.  (And if the string is empty, we always want
1692     // to return 0 and not read bytes past the '\0'.)
1693     //
1694     // There is also extra paranoia to make sure the bytes are not treated as signed.
1695     SteamNetworkingPOPID result = cast(ushort) cast(ubyte) pszCode[0] << 16U;
1696     if (pszCode[1]) {
1697         result |= (cast(ushort) cast(ubyte) pszCode[1] << 8U );
1698         if (pszCode[2]) {
1699             result |= cast(ushort) cast(ubyte) pszCode[2] | (cast(ushort) cast(ubyte) pszCode[3] << 24U);
1700         }
1701     }
1702     return result;
1703 }
1704 
1705 /+
1706 
1707 /// Unpack integer to string representation, including terminating '\0'
1708 ///
1709 /// See also SteamNetworkingPOPIDRender
1710 void GetSteamNetworkingLocationPOPStringFromID(int N)(SteamNetworkingPOPID id, ref char[N] szCode) {
1711     static assert( N >= 5, "Fixed-size buffer not big enough to hold SDR POP ID" );
1712     szCode[0] = cast(char) (id >> 16U);
1713     szCode[1] = cast(char) (id >> 8U);
1714     szCode[2] = cast(char) (id);
1715     szCode[3] = cast(char) (id >> 24U); // See comment above about deep regret and sadness
1716     szCode[4] = 0;
1717 }
1718 
1719 +/
1720 
1721 /// The POPID "dev" is used in non-production environments for testing.
1722 enum SteamNetworkingPOPID k_SteamDatagramPOPID_dev = (cast(uint)'d' << 16U) | (cast(uint)'e' << 8U ) | cast(uint)'v';
1723 
1724 /// Utility class for printing a SteamNetworkingPOPID.
1725 struct SteamNetworkingPOPIDRender {
1726 
1727     //this(SteamNetworkingPOPID x) { GetSteamNetworkingLocationPOPStringFromID( x, buf ); }
1728 
1729     const(char)* c_str() const return { return buf.ptr; }
1730 
1731 private:
1732 
1733     char[8] buf;
1734 
1735 }
1736 
1737 
1738 /+ Implemented locally, not here
1739 
1740 ///////////////////////////////////////////////////////////////////////////////
1741 //
1742 // Internal stuff
1743 #ifndef API_GEN
1744 
1745 // For code compatibility
1746 typedef SteamNetworkingMessage_t ISteamNetworkingMessage;
1747 typedef SteamNetworkingErrMsg SteamDatagramErrMsg;
1748 
1749 inline void SteamNetworkingIPAddr::Clear() { memset( this, 0, sizeof(*this) ); }
1750 inline bool SteamNetworkingIPAddr::IsIPv6AllZeros() const { const uint64 *q = (const uint64 *)m_ipv6; return q[0] == 0 && q[1] == 0; }
1751 inline void SteamNetworkingIPAddr::SetIPv6( const uint8 *ipv6, uint16 nPort ) { memcpy( m_ipv6, ipv6, 16 ); m_port = nPort; }
1752 inline void SteamNetworkingIPAddr::SetIPv4( uint32 nIP, uint16 nPort ) { m_ipv4.m_8zeros = 0; m_ipv4.m_0000 = 0; m_ipv4.m_ffff = 0xffff; m_ipv4.m_ip[0] = uint8(nIP>>24); m_ipv4.m_ip[1] = uint8(nIP>>16); m_ipv4.m_ip[2] = uint8(nIP>>8); m_ipv4.m_ip[3] = uint8(nIP); m_port = nPort; }
1753 inline bool SteamNetworkingIPAddr::IsIPv4() const { return m_ipv4.m_8zeros == 0 && m_ipv4.m_0000 == 0 && m_ipv4.m_ffff == 0xffff; }
1754 inline uint32 SteamNetworkingIPAddr::GetIPv4() const { return IsIPv4() ? ( (uint32(m_ipv4.m_ip[0])<<24) | (uint32(m_ipv4.m_ip[1])<<16) | (uint32(m_ipv4.m_ip[2])<<8) | uint32(m_ipv4.m_ip[3]) ) : 0; }
1755 inline void SteamNetworkingIPAddr::SetIPv6LocalHost( uint16 nPort ) { m_ipv4.m_8zeros = 0; m_ipv4.m_0000 = 0; m_ipv4.m_ffff = 0; m_ipv6[12] = 0; m_ipv6[13] = 0; m_ipv6[14] = 0; m_ipv6[15] = 1; m_port = nPort; }
1756 inline bool SteamNetworkingIPAddr::IsLocalHost() const { return ( m_ipv4.m_8zeros == 0 && m_ipv4.m_0000 == 0 && m_ipv4.m_ffff == 0 && m_ipv6[12] == 0 && m_ipv6[13] == 0 && m_ipv6[14] == 0 && m_ipv6[15] == 1 ) || ( GetIPv4() == 0x7f000001 ); }
1757 inline bool SteamNetworkingIPAddr::operator==(const SteamNetworkingIPAddr &x ) const { return memcmp( this, &x, sizeof(SteamNetworkingIPAddr) ) == 0; }
1758 
1759 inline void SteamNetworkingIdentity::Clear() { memset( this, 0, sizeof(*this) ); }
1760 inline bool SteamNetworkingIdentity::IsInvalid() const { return m_eType == k_ESteamNetworkingIdentityType_Invalid; }
1761 inline void SteamNetworkingIdentity::SetSteamID( CSteamID steamID ) { SetSteamID64( steamID.ConvertToUint64() ); }
1762 inline CSteamID SteamNetworkingIdentity::GetSteamID() const { return CSteamID( GetSteamID64() ); }
1763 inline void SteamNetworkingIdentity::SetSteamID64( uint64 steamID ) { m_eType = k_ESteamNetworkingIdentityType_SteamID; m_cbSize = sizeof( m_steamID64 ); m_steamID64 = steamID; }
1764 inline uint64 SteamNetworkingIdentity::GetSteamID64() const { return m_eType == k_ESteamNetworkingIdentityType_SteamID ? m_steamID64 : 0; }
1765 inline void SteamNetworkingIdentity::SetIPAddr( const SteamNetworkingIPAddr &addr ) { m_eType = k_ESteamNetworkingIdentityType_IPAddress; m_cbSize = (int)sizeof(m_ip); m_ip = addr; }
1766 inline const SteamNetworkingIPAddr *SteamNetworkingIdentity::GetIPAddr() const { return m_eType == k_ESteamNetworkingIdentityType_IPAddress ? &m_ip : NULL; }
1767 inline void SteamNetworkingIdentity::SetIPv4Addr( uint32 nIPv4, uint16 nPort ) { m_eType = k_ESteamNetworkingIdentityType_IPAddress; m_cbSize = (int)sizeof(m_ip); m_ip.SetIPv4( nIPv4, nPort ); }
1768 inline uint32 SteamNetworkingIdentity::GetIPv4() const { return m_eType == k_ESteamNetworkingIdentityType_IPAddress ? m_ip.GetIPv4() : 0; }
1769 inline ESteamNetworkingFakeIPType SteamNetworkingIdentity::GetFakeIPType() const { return m_eType == k_ESteamNetworkingIdentityType_IPAddress ? m_ip.GetFakeIPType() : k_ESteamNetworkingFakeIPType_Invalid; }
1770 inline void SteamNetworkingIdentity::SetLocalHost() { m_eType = k_ESteamNetworkingIdentityType_IPAddress; m_cbSize = (int)sizeof(m_ip); m_ip.SetIPv6LocalHost(); }
1771 inline bool SteamNetworkingIdentity::IsLocalHost() const { return m_eType == k_ESteamNetworkingIdentityType_IPAddress && m_ip.IsLocalHost(); }
1772 inline bool SteamNetworkingIdentity::SetGenericString( const char *pszString ) { size_t l = strlen( pszString ); if ( l >= sizeof(m_szGenericString) ) return false;
1773     m_eType = k_ESteamNetworkingIdentityType_GenericString; m_cbSize = int(l+1); memcpy( m_szGenericString, pszString, m_cbSize ); return true; }
1774 inline const char *SteamNetworkingIdentity::GetGenericString() const { return m_eType == k_ESteamNetworkingIdentityType_GenericString ? m_szGenericString : NULL; }
1775 inline bool SteamNetworkingIdentity::SetGenericBytes( const void *data, size_t cbLen ) { if ( cbLen > sizeof(m_genericBytes) ) return false;
1776     m_eType = k_ESteamNetworkingIdentityType_GenericBytes; m_cbSize = int(cbLen); memcpy( m_genericBytes, data, m_cbSize ); return true; }
1777 inline const uint8 *SteamNetworkingIdentity::GetGenericBytes( int &cbLen ) const { if ( m_eType != k_ESteamNetworkingIdentityType_GenericBytes ) return NULL;
1778     cbLen = m_cbSize; return m_genericBytes; }
1779 inline bool SteamNetworkingIdentity::operator==(const SteamNetworkingIdentity &x ) const { return m_eType == x.m_eType && m_cbSize == x.m_cbSize && memcmp( m_genericBytes, x.m_genericBytes, m_cbSize ) == 0; }
1780 inline void SteamNetworkingMessage_t::Release() { (*m_pfnRelease)( this ); }
1781 
1782 #endif // #ifndef API_GEN
1783 
1784 #endif // #ifndef STEAMNETWORKINGTYPES
1785 
1786 +/