diff --git a/Lidgren.Network/NetConnection.cs b/Lidgren.Network/NetConnection.cs
index 3e1b8929..18fbaf0c 100644
--- a/Lidgren.Network/NetConnection.cs
+++ b/Lidgren.Network/NetConnection.cs
@@ -555,6 +555,15 @@ public void GetSendQueueInfo(NetDeliveryMethod method, int sequenceChannel, out
return;
}
+ ///
+ /// Test whether the client window allows a message to be sent immediately.
+ ///
+ /// The delivery method that a message would be sent on.
+ /// The sequence channel that a message would be sent on.
+ ///
+ /// If this returns false, messages may still be queued but will not be sent out
+ /// until the client window allows it.
+ ///
public bool CanSendImmediately(NetDeliveryMethod method, int sequenceChannel)
{
int channelSlot = (int)method - 1 + sequenceChannel;
diff --git a/Lidgren.Network/NetRandomSeed.cs b/Lidgren.Network/NetRandomSeed.cs
index 375cbc13..f8b47f8f 100644
--- a/Lidgren.Network/NetRandomSeed.cs
+++ b/Lidgren.Network/NetRandomSeed.cs
@@ -39,7 +39,7 @@ public static ulong GetUInt64()
((ulong)guidBytes[6] << (8 * 6)) |
((ulong)guidBytes[7] << (8 * 7));
- return seed ^ NetUtility.GetPlatformSeed(m_seedIncrement);
+ return seed ^ NetUtility.GetPlatformSeedCore(m_seedIncrement);
}
}
}
diff --git a/Lidgren.Network/NetUtility.Dns.cs b/Lidgren.Network/NetUtility.Dns.cs
index 49380ab5..a0fa0766 100644
--- a/Lidgren.Network/NetUtility.Dns.cs
+++ b/Lidgren.Network/NetUtility.Dns.cs
@@ -14,23 +14,81 @@ namespace Lidgren.Network
public static partial class NetUtility
{
///
- /// Resolve endpoint callback
+ /// Asynchronous callback raised when a remote has been resolved.
///
+ ///
+ /// This callback is not raised on any particular thread.
+ ///
+ ///
+ /// Null if the resolved host name does not exist or does not contain suitable DNS records.
+ ///
public delegate void ResolveEndPointCallback(NetEndPoint? endPoint);
///
/// Resolve address callback
///
+ ///
+ /// This callback is not raised on any particular thread.
+ ///
+ ///
+ /// Null if the resolved host name does not exist or does not contain suitable DNS records.
+ ///
public delegate void ResolveAddressCallback(NetAddress? adr);
///
- /// Get IPv4 or IPv6 address from notation (xxx.xxx.xxx.xxx or xxxx:xxxx:...:xxxx) or hostname (asynchronous version)
+ /// Resolve an IP address or hostname into a . (asynchronous callback version)
///
+ ///
+ ///
+ /// This function can accept host names or direct IP addresses
+ /// (in standard notation, i.e. xxx.xxx.xxx.xxx for IPv4 or xxxx:xxxx:...:xxxx for IPv6).
+ /// If an IP address is given, it is parsed and immediately returned.
+ ///
+ ///
+ /// This is an asynchronous callback version.
+ /// Instead of returning a value directly, is called with the result.
+ ///
+ ///
+ /// IP address or host name string to resolve.
+ /// Port to use on the returned instance.
+ /// Callback that is ran when resolution completes.
+ /// Thrown if is empty.
+ /// Thrown if a network error occurs.
+ [Obsolete("This function does not handle network errors properly, prefer task-based ResolveAsync instead.")]
public static void ResolveAsync(string ipOrHost, int port, ResolveEndPointCallback callback)
{
ResolveAsync(ipOrHost, port, null, callback);
}
+ ///
+ /// Resolve an IP address or hostname into a . (asynchronous callback version)
+ ///
+ ///
+ ///
+ /// This function can accept host names or direct IP addresses
+ /// (in standard notation, i.e. xxx.xxx.xxx.xxx for IPv4 or xxxx:xxxx:...:xxxx for IPv6).
+ /// If an IP address is given, it is parsed and immediately returned.
+ ///
+ ///
+ /// This is an asynchronous callback version.
+ /// Instead of returning a value directly, is called with the result.
+ ///
+ ///
+ /// IP address or host name string to resolve.
+ /// Port to use on the returned instance.
+ ///
+ /// If not , only allow the given address family to be returned.
+ /// Otherwise, both IPv4 and IPv6 addresses can be returned.
+ ///
+ /// Callback that is ran when resolution completes.
+ ///
+ /// Thrown if is empty
+ /// OR
+ /// is not null and not one of
+ /// or .
+ ///
+ /// Thrown if a network error occurs.
+ [Obsolete("This function does not handle network errors properly, prefer task-based ResolveAsync instead.")]
public static void ResolveAsync(string ipOrHost, int port, AddressFamily? allowedFamily,
ResolveEndPointCallback callback)
{
@@ -48,13 +106,59 @@ public static void ResolveAsync(string ipOrHost, int port, AddressFamily? allowe
}
///
- /// Get IPv4 or IPv6 address from notation (xxx.xxx.xxx.xxx or xxxx:xxxx:...:xxxx) or hostname
+ /// Resolve an IP address or hostname into a .
///
+ ///
+ ///
+ /// This function can accept host names or direct IP addresses
+ /// (in standard notation, i.e. xxx.xxx.xxx.xxx for IPv4 or xxxx:xxxx:...:xxxx for IPv6).
+ /// If an IP address is given, it is parsed and immediately returned.
+ ///
+ ///
+ /// This function is synchronous,
+ /// prefer using
+ /// to avoid hanging the current thread if the network has to be accessed.
+ ///
+ ///
+ /// IP address or host name string to resolve.
+ /// Port to use on the returned instance.
+ /// Thrown if is empty.
+ /// Thrown if a network error occurs.
+ /// if the given host does not exist.
public static NetEndPoint? Resolve(string ipOrHost, int port)
{
return Resolve(ipOrHost, port, null);
}
+ ///
+ /// Resolve an IP address or hostname into a .
+ ///
+ ///
+ ///
+ /// This function can accept host names or direct IP addresses
+ /// (in standard notation, i.e. xxx.xxx.xxx.xxx for IPv4 or xxxx:xxxx:...:xxxx for IPv6).
+ /// If an IP address is given, it is parsed and immediately returned.
+ ///
+ ///
+ /// This function is synchronous,
+ /// prefer using
+ /// to avoid hanging the current thread if the network has to be accessed.
+ ///
+ ///
+ /// IP address or host name string to resolve.
+ /// Port to use on the returned instance.
+ ///
+ /// If not , only allow the given address family to be returned.
+ /// Otherwise, both IPv4 and IPv6 addresses can be returned.
+ ///
+ ///
+ /// Thrown if is empty
+ /// OR
+ /// is not null and not one of
+ /// or .
+ ///
+ /// Thrown if a network error occurs.
+ /// if the given host does not exist.
public static NetEndPoint? Resolve(string ipOrHost, int port, AddressFamily? allowedFamily)
{
var adr = Resolve(ipOrHost, allowedFamily);
@@ -62,16 +166,57 @@ public static void ResolveAsync(string ipOrHost, int port, AddressFamily? allowe
}
///
- /// Get IPv4 or IPv6 address from notation (xxx.xxx.xxx.xxx or xxxx:xxxx:...:xxxx) or hostname (asynchronous version)
+ /// Resolve an IP address or hostname into a . (asynchronous callback version)
///
+ ///
+ ///
+ /// This function can accept host names or direct IP addresses
+ /// (in standard notation, i.e. xxx.xxx.xxx.xxx for IPv4 or xxxx:xxxx:...:xxxx for IPv6).
+ /// If an IP address is given, it is parsed and immediately returned.
+ ///
+ ///
+ /// This is an asynchronous callback version.
+ /// Instead of returning a value directly, is called with the result.
+ ///
+ ///
+ /// IP address or host name string to resolve.
+ /// Callback that is ran when resolution completes.
+ /// Thrown if is empty.
+ /// Thrown if a network error occurs.
+ [Obsolete("This function does not handle network errors properly, prefer task-based ResolveAsync instead.")]
public static void ResolveAsync(string ipOrHost, ResolveAddressCallback callback)
{
ResolveAsync(ipOrHost, null, callback);
}
///
- /// Get IPv4 or IPv6 address from notation (xxx.xxx.xxx.xxx or xxxx:xxxx:...:xxxx) or hostname (asynchronous version)
+ /// Resolve an IP address or hostname into a . (asynchronous callback version)
///
+ ///
+ ///
+ /// This function can accept host names or direct IP addresses
+ /// (in standard notation, i.e. xxx.xxx.xxx.xxx for IPv4 or xxxx:xxxx:...:xxxx for IPv6).
+ /// If an IP address is given, it is parsed and immediately returned.
+ ///
+ ///
+ /// This is an asynchronous callback version.
+ /// Instead of returning a value directly, is called with the result.
+ ///
+ ///
+ /// IP address or host name string to resolve.
+ ///
+ /// If not , only allow the given address family to be returned.
+ /// Otherwise, both IPv4 and IPv6 addresses can be returned.
+ ///
+ /// Callback that is ran when resolution completes.
+ ///
+ /// Thrown if is empty
+ /// OR
+ /// is not null and not one of
+ /// or .
+ ///
+ /// Thrown if a network error occurs.
+ [Obsolete("This function does not handle network errors properly, prefer task-based ResolveAsync instead.")]
public static void ResolveAsync(string ipOrHost, AddressFamily? allowedFamily, ResolveAddressCallback callback)
{
if (ResolveHead(ref ipOrHost, allowedFamily, out var resolve))
@@ -128,17 +273,79 @@ public static void ResolveAsync(string ipOrHost, AddressFamily? allowedFamily, R
}
}
+ ///
+ /// Resolve an IP address or hostname into a . (asynchronous task version)
+ ///
+ ///
+ ///
+ /// This function can accept host names or direct IP addresses
+ /// (in standard notation, i.e. xxx.xxx.xxx.xxx for IPv4 or xxxx:xxxx:...:xxxx for IPv6).
+ /// If an IP address is given, it is parsed and immediately returned.
+ ///
+ ///
+ /// IP address or host name string to resolve.
+ /// Port to use on the returned instance.
+ /// Thrown if is empty.
+ /// Thrown if a network error occurs.
+ /// if the given host does not exist.
public static async Task ResolveAsync(string ipOrHost, int port)
{
return await ResolveAsync(ipOrHost, port, (AddressFamily?)null);
}
+ ///
+ /// Resolve an IP address or hostname into a . (asynchronous task version)
+ ///
+ ///
+ ///
+ /// This function can accept host names or direct IP addresses
+ /// (in standard notation, i.e. xxx.xxx.xxx.xxx for IPv4 or xxxx:xxxx:...:xxxx for IPv6).
+ /// If an IP address is given, it is parsed and immediately returned.
+ ///
+ ///
+ /// IP address or host name string to resolve.
+ /// Port to use on the returned instance.
+ ///
+ /// If not , only allow the given address family to be returned.
+ /// Otherwise, both IPv4 and IPv6 addresses can be returned.
+ ///
+ ///
+ /// Thrown if is empty
+ /// OR
+ /// is not null and not one of
+ /// or .
+ ///
+ /// Thrown if a network error occurs.
+ /// if the given host does not exist.
public static async Task ResolveAsync(string ipOrHost, int port, AddressFamily? allowedFamily)
{
var adr = await ResolveAsync(ipOrHost, allowedFamily);
return adr == null ? null : new NetEndPoint(adr, port);
}
+ ///
+ /// Resolve an IP address or hostname into a . (asynchronous task version)
+ ///
+ ///
+ ///
+ /// This function can accept host names or direct IP addresses
+ /// (in standard notation, i.e. xxx.xxx.xxx.xxx for IPv4 or xxxx:xxxx:...:xxxx for IPv6).
+ /// If an IP address is given, it is parsed and immediately returned.
+ ///
+ ///
+ /// IP address or host name string to resolve.
+ ///
+ /// If not , only allow the given address family to be returned.
+ /// Otherwise, both IPv4 and IPv6 addresses can be returned.
+ ///
+ ///
+ /// Thrown if is empty
+ /// OR
+ /// is not null and not one of
+ /// or .
+ ///
+ /// Thrown if a network error occurs.
+ /// if the given host does not exist.
public static async Task ResolveAsync(string ipOrHost, AddressFamily? allowedFamily = null)
{
if (ResolveHead(ref ipOrHost, allowedFamily, out var resolve))
@@ -169,14 +376,29 @@ public static void ResolveAsync(string ipOrHost, AddressFamily? allowedFamily, R
}
///
- /// Get IPv4 or IPv6 address from notation (xxx.xxx.xxx.xxx or xxxx:xxxx:...:xxxx) or hostname
+ /// Resolve an IP address or hostname into a .
///
+ ///
+ ///
+ /// This function can accept host names or direct IP addresses
+ /// (in standard notation, i.e. xxx.xxx.xxx.xxx for IPv4 or xxxx:xxxx:...:xxxx for IPv6).
+ /// If an IP address is given, it is parsed and immediately returned.
+ ///
+ ///
+ /// This function is synchronous,
+ /// prefer using
+ /// to avoid hanging the current thread if the network has to be accessed.
+ ///
+ ///
+ /// IP address or host name string to resolve.
+ /// Thrown if is empty.
+ /// Thrown if a network error occurs.
+ /// if the given host does not exist.
public static NetAddress? Resolve(string ipOrHost)
{
return Resolve(ipOrHost, null);
}
-
///
/// Get IPv4 or IPv6 address from notation (xxx.xxx.xxx.xxx or xxxx:xxxx:...:xxxx) or hostname,
/// taking in an allowed address family to filter resolved addresses by.
diff --git a/Lidgren.Network/NetUtility.Platform.cs b/Lidgren.Network/NetUtility.Platform.cs
new file mode 100644
index 00000000..45646ce2
--- /dev/null
+++ b/Lidgren.Network/NetUtility.Platform.cs
@@ -0,0 +1,92 @@
+using System;
+using System.Threading;
+
+#if !__NOIPENDPOINT__
+using NetAddress = System.Net.IPAddress;
+#endif
+
+namespace Lidgren.Network;
+
+//
+// This file contains stubs for utilities with special implementations per-platform (Platform/)
+// Note: I couldn't be bothered to update the definitions for platforms other than PlatformWin32.cs,
+// so you'll have to do some maintenance to make them compile, I apologize.
+//
+
+public static partial class NetUtility
+{
+ ///
+ /// If available, returns the bytes of the physical (MAC) address for the first usable network interface
+ ///
+ ///
+ public static byte[]? GetMacAddressBytes() => GetMacAddressBytesCore();
+
+ ///
+ /// Get the IPv4 address for broadcast on the local network.
+ ///
+ ///
+ /// This may return either the IPv4 "limited broadcast" address
+ /// (, i.e. 255.255.255.255) or a directed broadcast address for the local
+ /// network, e.g. 192.168.1.255.
+ ///
+ /// Null if we are unable to detect a suitable network interface.
+ ///
+ ///
+ public static NetAddress? GetBroadcastAddress() => GetBroadcastAddressCore();
+
+ ///
+ /// Gets our local IPv4 address (not necessarily external) and subnet mask.
+ ///
+ ///
+ /// The IP address we have on the local network.
+ /// Null if we are unable to detect a suitable network interface.
+ ///
+ ///
+ ///
+ public static NetAddress? GetMyAddress(out NetAddress? mask) => GetMyAddressCore(out mask);
+
+ ///
+ /// Pause execution of the current thread for a given amount of milliseconds.
+ /// Equivalent to .
+ ///
+ ///
+ /// The duration, in milliseconds, to sleep for.
+ ///
+ public static void Sleep(int milliseconds) => SleepCore(milliseconds);
+
+ ///
+ /// Create a instance from an array of bytes.
+ ///
+ ///
+ /// An array of bytes describing the IP address.
+ ///
+ public static NetAddress CreateAddressFromBytes(byte[] bytes) => CreateAddressFromBytesCore(bytes);
+
+ ///
+ /// Compute the SHA-256 hash of an array of data.
+ ///
+ /// Array containing the data to hash.
+ /// Position in that the data to hash starts at.
+ /// Amount of bytes of data to hash from .
+ /// The computed hash.
+ public static byte[] ComputeSHAHash(byte[] bytes, int offset, int count) =>
+ ComputeSHAHashCore(bytes, offset, count);
+
+ ///
+ /// Get a seed for initializing a random number generator.
+ ///
+ ///
+ /// This is not cryptographically secure.
+ ///
+ [CLSCompliant(false)]
+ [Obsolete("Use NetRandomSeed instead.")]
+ public static ulong GetPlatformSeed(int seedInc) => GetPlatformSeedCore(seedInc);
+
+ ///
+ /// Return a stopwatch for the current time.
+ ///
+ ///
+ /// Values represent seconds since the stopwatch started timing.
+ ///
+ public static double Now => NowCore;
+}
diff --git a/Lidgren.Network/NetUtility.cs b/Lidgren.Network/NetUtility.cs
index e1ebb40c..bf618202 100644
--- a/Lidgren.Network/NetUtility.cs
+++ b/Lidgren.Network/NetUtility.cs
@@ -44,6 +44,15 @@ public static partial class NetUtility
private static readonly bool IsMono = Type.GetType("Mono.Runtime") != null;
private static IPAddress? s_broadcastAddress;
+
+ ///
+ /// Get a cached copy of .
+ ///
+ ///
+ /// This value is cached when this function is first called.
+ ///
+ ///
+ ///
public static IPAddress? GetCachedBroadcastAddress()
{
if (s_broadcastAddress == null)
@@ -67,6 +76,14 @@ public static string ToHexString(byte[] data)
return ToHexString(data.AsSpan());
}
+ ///
+ /// Create a hex string from an array of bytes
+ ///
+ /// Array containing the bytes to turn into hex.
+ /// Position in that the data to convert starts at.
+ /// Amount of bytes of data to convert from .
+ ///
+ ///
public static string ToHexString(byte[] data, int offset, int length)
{
return ToHexString(data.AsSpan(offset, length));
@@ -294,6 +311,11 @@ public static string MakeCommaDelimitedList(IReadOnlyList list) where T :
return bdr.ToString();
}
+ ///
+ /// Compute the SHA-256 hash of an array of data.
+ ///
+ /// An array containing the data to hash.
+ /// The hash result.
public static byte[] ComputeSHAHash(byte[] bytes)
{
// this is defined in the platform specific files
diff --git a/Lidgren.Network/Platform/PlatformWin32.cs b/Lidgren.Network/Platform/PlatformWin32.cs
index 80e36858..1fe86eff 100644
--- a/Lidgren.Network/Platform/PlatformWin32.cs
+++ b/Lidgren.Network/Platform/PlatformWin32.cs
@@ -16,14 +16,13 @@ public static partial class NetUtility
private static readonly long s_timeInitialized = Stopwatch.GetTimestamp();
private static readonly double s_dInvFreq = 1.0 / (double)Stopwatch.Frequency;
- [CLSCompliant(false)]
- public static ulong GetPlatformSeed(int seedInc)
+ internal static ulong GetPlatformSeedCore(int seedInc)
{
ulong seed = (ulong)System.Diagnostics.Stopwatch.GetTimestamp();
return seed ^ ((ulong)Environment.WorkingSet + (ulong)seedInc);
}
- public static double Now { get { return (double)(Stopwatch.GetTimestamp() - s_timeInitialized) * s_dInvFreq; } }
+ private static double NowCore { get { return (double)(Stopwatch.GetTimestamp() - s_timeInitialized) * s_dInvFreq; } }
private static NetworkInterface? GetNetworkInterface()
{
@@ -80,11 +79,8 @@ public static ulong GetPlatformSeed(int seedInc)
return null;
}
}
-
- ///
- /// If available, returns the bytes of the physical (MAC) address for the first usable network interface
- ///
- public static byte[]? GetMacAddressBytes()
+
+ private static byte[]? GetMacAddressBytesCore()
{
var ni = GetNetworkInterface();
if (ni == null)
@@ -92,7 +88,7 @@ public static ulong GetPlatformSeed(int seedInc)
return ni.GetPhysicalAddress().GetAddressBytes();
}
- public static IPAddress? GetBroadcastAddress()
+ private static IPAddress? GetBroadcastAddressCore()
{
var ni = GetNetworkInterface();
if (ni == null)
@@ -121,10 +117,7 @@ public static ulong GetPlatformSeed(int seedInc)
return IPAddress.Broadcast;
}
- ///
- /// Gets my local IPv4 address (not necessarily external) and subnet mask
- ///
- public static IPAddress? GetMyAddress(out IPAddress? mask)
+ private static IPAddress? GetMyAddressCore(out IPAddress? mask)
{
var ni = GetNetworkInterface();
if (ni == null)
@@ -147,17 +140,17 @@ public static ulong GetPlatformSeed(int seedInc)
return null;
}
- public static void Sleep(int milliseconds)
+ private static void SleepCore(int milliseconds)
{
System.Threading.Thread.Sleep(milliseconds);
}
- public static IPAddress CreateAddressFromBytes(byte[] bytes)
+ private static IPAddress CreateAddressFromBytesCore(byte[] bytes)
{
return new IPAddress(bytes);
}
- public static byte[] ComputeSHAHash(byte[] bytes, int offset, int count)
+ private static byte[] ComputeSHAHashCore(byte[] bytes, int offset, int count)
{
using var sha = SHA256.Create();
return sha.ComputeHash(bytes, offset, count);
diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index 690e9fd5..14b9ed90 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -5,6 +5,7 @@
- Add explicit .NET 8 target framework
- Removed .NET Core 3.1 and .NET 5 target frameworks
- Updated dependencies
+- More and improved doc comments.
## 0.2.7