diff --git a/nanoFramework.System.Net/DNS.cs b/nanoFramework.System.Net/DNS.cs
index 0941650..ded6b36 100644
--- a/nanoFramework.System.Net/DNS.cs
+++ b/nanoFramework.System.Net/DNS.cs
@@ -41,9 +41,15 @@ public static IPHostEntry GetHostEntry(string hostNameOrAddress)
if (family == AddressFamily.InterNetwork)
{
uint ipAddr = (uint)((address[7] << 24) | (address[6] << 16) | (address[5] << 8) | (address[4]));
-
ipAddresses[i] = new IPAddress(ipAddr);
}
+ else if (family == AddressFamily.InterNetworkV6)
+ {
+ byte[] ipv6addr = new byte[16];
+ Array.Copy(address, 4, ipv6addr, 0, 16);
+
+ ipAddresses[i] = new IPAddress(ipv6addr);
+ }
else
{
throw new NotImplementedException();
diff --git a/nanoFramework.System.Net/IPAddress.cs b/nanoFramework.System.Net/IPAddress.cs
index ff3b20f..ed091f8 100644
--- a/nanoFramework.System.Net/IPAddress.cs
+++ b/nanoFramework.System.Net/IPAddress.cs
@@ -16,6 +16,11 @@ namespace System.Net
[Serializable]
public class IPAddress
{
+ internal const int IPv4AddressBytes = 4;
+ internal const int IPv6AddressBytes = 16;
+
+ internal const int NumberOfLabels = IPv6AddressBytes / 2;
+
///
/// Provides an IP address that indicates that the server must listen for client activity on all network interfaces. This field is read-only.
///
@@ -28,16 +33,25 @@ public class IPAddress
internal readonly long Address;
+ ///
+ /// The Bind(EndPoint) method uses the IPv6Any field to indicate that a Socket must listen for client activity on all network interfaces.
+ ///
+ public static readonly IPAddress IPv6Any = new IPAddress(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0);
+
+ ///
+ /// Provides the IP loopback address. This property is read-only.
+ ///
+ public static readonly IPAddress IPv6Loopback = new IPAddress(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, 0);
+
+
[Diagnostics.DebuggerBrowsable(Diagnostics.DebuggerBrowsableState.Never)]
private readonly AddressFamily _family = AddressFamily.InterNetwork;
[Diagnostics.DebuggerBrowsable(Diagnostics.DebuggerBrowsableState.Never)]
private readonly ushort[] _numbers = new ushort[NumberOfLabels];
- internal const int IPv4AddressBytes = 4;
- internal const int IPv6AddressBytes = 16;
-
- internal const int NumberOfLabels = IPv6AddressBytes / 2;
+ [Diagnostics.DebuggerBrowsable(Diagnostics.DebuggerBrowsableState.Never)]
+ private long _scopeid = 0;
///
/// Gets the address family of the IP address.
@@ -81,7 +95,7 @@ public IPAddress(long newAddress)
///
/// Initializes a new instance of the class with the address specified as a Byte array.
///
- ///
+ /// The byte array value of the IP address.
/// is .
/// contains a bad IP address.
///
@@ -122,6 +136,40 @@ public IPAddress(byte[] address)
}
}
+ ///
+ /// Initializes a new instance of a IPV6 class with the address specified as a Byte array.
+ ///
+ /// The byte array value of the IP address.
+ /// The long value of the scope identifier.
+ /// is .
+ /// contains a bad IP address.
+ ///
+ /// The IPAddress is created with the property set to .
+ /// If the length of is 4, (Byte[]) constructs an IPv4 address; otherwise, an IPv6 address with a scope of 0 is constructed.
+ /// The array is assumed to be in network byte order with the most significant byte first in index position 0.
+ ///
+ public IPAddress(byte[] address, long scopeid) : this(address)
+ {
+ if (address.Length == IPv6AddressBytes)
+ {
+ _scopeid = scopeid;
+ }
+ else
+ {
+ // Not IPV6 address
+#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one
+ throw new ArgumentException();
+#pragma warning restore S3928 // OK to throw this here
+ }
+ }
+
+ private IPAddress(ushort[] address, uint scopeid)
+ {
+ _family = AddressFamily.InterNetworkV6;
+ _numbers = address;
+ _scopeid = scopeid;
+ }
+
///
/// Compares two IP addresses.
///
@@ -133,7 +181,31 @@ public override bool Equals(object obj)
if (obj == null) return false;
- return this.Address == addr.Address;
+ // Compare family before address
+ if (_family != addr.AddressFamily)
+ {
+ return false;
+ }
+
+ if (_family == AddressFamily.InterNetworkV6)
+ {
+ // For IPv6 addresses, compare the full 128bit address
+ for (int i = 0; i < NumberOfLabels; i++)
+ {
+ if (addr._numbers[i] != this._numbers[i])
+ return false;
+ }
+
+ // Also scope must match
+ if (addr._scopeid == this._scopeid)
+ return true;
+
+ return false;
+ }
+ else
+ {
+ return this.Address == addr.Address;
+ }
}
///
@@ -142,13 +214,30 @@ public override bool Equals(object obj)
/// A Byte array.
public byte[] GetAddressBytes()
{
- return new byte[]
+ byte[] bytes;
+
+ if (_family == AddressFamily.InterNetworkV6)
{
- (byte)(Address),
- (byte)(Address >> 8),
- (byte)(Address >> 16),
- (byte)(Address >> 24)
- };
+ bytes = new byte[NumberOfLabels * 2];
+
+ int j = 0;
+ for (int i = 0; i < NumberOfLabels; i++)
+ {
+ bytes[j++] = (byte)((this._numbers[i] >> 8) & 0xFF);
+ bytes[j++] = (byte)((this._numbers[i]) & 0xFF);
+ }
+ return bytes;
+ }
+ else
+ {
+ return new byte[]
+ {
+ (byte)(Address),
+ (byte)(Address >> 8),
+ (byte)(Address >> 16),
+ (byte)(Address >> 24)
+ };
+ }
}
///
@@ -159,7 +248,40 @@ public byte[] GetAddressBytes()
///
public static IPAddress Parse(string ipString)
{
- return new IPAddress(NetworkInterface.IPAddressFromString(ipString));
+ // Check for IPV6 string and use separate parse method
+ if (ipString.IndexOf(':') != -1)
+ {
+ return new IPAddress(NetworkInterface.IPV6AddressFromString(ipString), 0);
+ }
+
+ return new IPAddress(NetworkInterface.IPV4AddressFromString(ipString));
+ }
+
+ ///
+ /// Get or Set IPV6 scope identifier.
+ ///
+ public long ScopeId
+ {
+ get
+ {
+ // Not valid for IPv4 addresses
+ if (_family == AddressFamily.InterNetwork)
+ {
+ throw new SocketException(SocketError.OperationNotSupported);
+ }
+
+ return _scopeid;
+ }
+ set
+ {
+ // Not valid for IPv4 addresses
+ if (_family == AddressFamily.InterNetwork)
+ {
+ throw new SocketException(SocketError.OperationNotSupported);
+ }
+
+ _scopeid = value;
+ }
}
///
@@ -172,6 +294,11 @@ public static IPAddress Parse(string ipString)
///
public override string ToString()
{
+ if (_family == AddressFamily.InterNetworkV6)
+ {
+ return IPv6ToString(_numbers);
+ }
+
return IPv4ToString((uint)Address);
}
@@ -229,18 +356,100 @@ internal IPAddress Snapshot()
case AddressFamily.InterNetwork:
return new IPAddress(Address);
- //case AddressFamily.InterNetworkV6:
- // return new IPAddress(m_Numbers, (uint)m_ScopeId);
+ case AddressFamily.InterNetworkV6:
+ return new IPAddress(_numbers, (uint)_scopeid);
}
throw new NotSupportedException();
}
+ ///
+ /// Gets whether the IP address is an IPv4-mapped IPv6 address.
+ ///
+ ///
+ /// true if the IP address is an IPv4-mapped IPv6 address; otherwise, false.
+ ///
+ public bool IsIPv4MappedToIPv6
+ {
+ get
+ {
+ if (AddressFamily != AddressFamily.InterNetworkV6)
+ {
+ return false;
+ }
+
+ for (int i = 0; i < 5; i++)
+ {
+ if (_numbers[i] != 0)
+ {
+ return false;
+ }
+ }
+
+ return (_numbers[5] == 0xFFFF);
+ }
+ }
+
+ ///
+ /// Maps the object to an IPv6 address.
+ ///
+ ///
+ /// Dual-stack sockets always require IPv6 addresses. The ability to interact with an IPv4 address
+ /// requires the use of the IPv4-mapped IPv6 address format. Any IPv4 addresses must be represented
+ /// in the IPv4-mapped IPv6 address format which enables an IPv6 only application to communicate
+ /// with an IPv4 node.
+ /// For example. IPv4 192.168.1.4 maps as IPV6 ::FFFF:192.168.1.4
+ ///
+ ///
+ /// Returns . An IPV6 address.
+ ///
+ public IPAddress MapToIPv6()
+ {
+ if (AddressFamily == AddressFamily.InterNetworkV6)
+ {
+ return this;
+ }
+
+ ushort[] labels = new ushort[IPAddress.NumberOfLabels];
+ labels[5] = 0xFFFF;
+ labels[6] = (ushort)(((Address & 0x0000FF00) >> 8) | ((Address & 0x000000FF) << 8));
+ labels[7] = (ushort)(((Address & 0xFF000000) >> 24) | ((Address & 0x00FF0000) >> 8));
+
+ return new IPAddress(labels, 0);
+ }
+
+ ///
+ /// Maps the object to an IPv4 address.
+ ///
+ ///
+ /// Dual-stack sockets always require IPv6 addresses. The ability to interact with an IPv4
+ /// address requires the use of the IPv4-mapped IPv6 address format.
+ ///
+ ///
+ /// Returns . An IPV4 address.
+ ///
+ public IPAddress MapToIPv4()
+ {
+ if (AddressFamily == AddressFamily.InterNetwork)
+ {
+ return this;
+ }
+
+ long address = ((((uint)_numbers[6] & 0x0000FF00u) >> 8) |
+ (((uint)_numbers[6] & 0x000000FFu) << 8)) |
+ (((((uint)_numbers[7] & 0x0000FF00u) >> 8) |
+ (((uint)_numbers[7] & 0x000000FFu) << 8)) << 16);
+
+ return new IPAddress(address);
+ }
+
#region native methods
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern string IPv4ToString(uint ipv4Address);
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal static extern string IPv6ToString(ushort[] ipv6Address);
#endregion
}
}
diff --git a/nanoFramework.System.Net/NetworkInformation/NetworkInterface.cs b/nanoFramework.System.Net/NetworkInformation/NetworkInterface.cs
index 04e51ee..3c5e72f 100644
--- a/nanoFramework.System.Net/NetworkInformation/NetworkInterface.cs
+++ b/nanoFramework.System.Net/NetworkInformation/NetworkInterface.cs
@@ -126,9 +126,9 @@ public void EnableStaticIPv4(string ipv4Address, string ipv4SubnetMask, string i
{
try
{
- _ipv4Address = (uint)IPAddressFromString(ipv4Address);
- _ipv4NetMask = (uint)IPAddressFromString(ipv4SubnetMask);
- _ipv4GatewayAddress = (uint)IPAddressFromString(ipv4GatewayAddress);
+ _ipv4Address = (uint)IPV4AddressFromString(ipv4Address);
+ _ipv4NetMask = (uint)IPV4AddressFromString(ipv4SubnetMask);
+ _ipv4GatewayAddress = (uint)IPV4AddressFromString(ipv4GatewayAddress);
_startupAddressMode = AddressMode.Static;
UpdateConfiguration((int)UpdateOperation.Dhcp);
@@ -153,9 +153,9 @@ public void EnableStaticIPv6(string ipv6Address, string ipv6SubnetMask, string i
// FIXME
// need to test this
- //_ipv6Address = IPAddressFromString(ipv6Address);
- //_ipv6NetMask = IPAddressFromString(ipv6subnetMask);
- //_ipv6GatewayAddress = IPAddressFromString(ipv6gatewayAddress);
+ //_ipv6Address = IPV4AddressFromString(ipv6Address);
+ //_ipv6NetMask = IPV4AddressFromString(ipv6subnetMask);
+ //_ipv6GatewayAddress = IPV4AddressFromString(ipv6gatewayAddress);
//_startupAddressMode = AddressMode.Static;
@@ -182,15 +182,15 @@ public void EnableStaticIP(string ipv4Address, string ipv4subnetMask, string ipv
{
throw new NotImplementedException();
- _ipv4Address = (uint)IPAddressFromString(ipv4Address);
- _ipv4NetMask = (uint)IPAddressFromString(ipv4subnetMask);
- _ipv4GatewayAddress = (uint)IPAddressFromString(ipv4gatewayAddress);
+ _ipv4Address = (uint)IPV4AddressFromString(ipv4Address);
+ _ipv4NetMask = (uint)IPV4AddressFromString(ipv4subnetMask);
+ _ipv4GatewayAddress = (uint)IPV4AddressFromString(ipv4gatewayAddress);
// FIXME
// need to test this
- //_ipv6Address = IPAddressFromString(ipv6Address);
- //_ipv6NetMask = IPAddressFromString(ipv6subnetMask);
- //_ipv6GatewayAddress = IPAddressFromString(ipv6gatewayAddress);
+ //_ipv6Address = IPV4AddressFromString(ipv6Address);
+ //_ipv6NetMask = IPV4AddressFromString(ipv6subnetMask);
+ //_ipv6GatewayAddress = IPV4AddressFromString(ipv6gatewayAddress);
_startupAddressMode = AddressMode.Static;
@@ -234,7 +234,7 @@ public void EnableStaticIPv4Dns(string[] dnsAddresses)
int iAddress = 0;
for (int i = 0; i < dnsAddresses.Length; i++)
{
- uint address = (uint)IPAddressFromString(dnsAddresses[i]);
+ uint address = (uint)IPV4AddressFromString(dnsAddresses[i]);
addresses[iAddress] = address;
@@ -281,7 +281,7 @@ public void EnableStaticIPv6Dns(string[] dnsAddresses)
//int iAddress = 0;
//for (int i = 0; i < dnsAddresses.Length; i++)
//{
- // uint address = IPAddressFromString(dnsAddresses[i]);
+ // uint address = IPV4AddressFromString(dnsAddresses[i]);
// addresses[iAddress] = address;
@@ -482,8 +482,10 @@ public NetworkInterfaceType NetworkInterfaceType
private extern void UpdateConfiguration(int updateType);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern long IPAddressFromString(string ipAddress);
+ internal static extern long IPV4AddressFromString(string ipAddress);
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal static extern ushort[] IPV6AddressFromString(string ipAddress);
#endregion
}
}
diff --git a/nanoFramework.System.Net/NetworkInformation/WirelessAPConfiguration.cs b/nanoFramework.System.Net/NetworkInformation/WirelessAPConfiguration.cs
index 2c04d6a..bd6973b 100644
--- a/nanoFramework.System.Net/NetworkInformation/WirelessAPConfiguration.cs
+++ b/nanoFramework.System.Net/NetworkInformation/WirelessAPConfiguration.cs
@@ -125,7 +125,7 @@ public WirelessAPConfiguration(uint id)
///
/// If is less than one.
/// If is less than 8 character or more than 64 characters and not open .
- /// If is longer than <./exception>
+ /// If is longer than
/// If is .
public void SaveConfiguration()
{
@@ -140,7 +140,7 @@ public void SaveConfiguration()
///
/// If is less than one.
/// If is less than 8 character or more than 64 characters and not open .
- /// If is longer than <./exception>
+ /// If is longer than
/// If is .
private void ValidateConfiguration()
{
diff --git a/nanoFramework.System.Net/Properties/AssemblyInfo.cs b/nanoFramework.System.Net/Properties/AssemblyInfo.cs
index 3642cc8..6f37577 100644
--- a/nanoFramework.System.Net/Properties/AssemblyInfo.cs
+++ b/nanoFramework.System.Net/Properties/AssemblyInfo.cs
@@ -11,7 +11,7 @@
////////////////////////////////////////////////////////////////
// update this whenever the native assembly signature changes //
-[assembly: AssemblyNativeVersion("100.1.5.0")]
+[assembly: AssemblyNativeVersion("100.2.0.0")]
////////////////////////////////////////////////////////////////
// Setting ComVisible to false makes the types in this assembly not visible
diff --git a/nanoFramework.System.Net/SocketAddress.cs b/nanoFramework.System.Net/SocketAddress.cs
index aceb6a3..557eb1c 100644
--- a/nanoFramework.System.Net/SocketAddress.cs
+++ b/nanoFramework.System.Net/SocketAddress.cs
@@ -48,29 +48,29 @@ internal SocketAddress(IPAddress ipAddress)
m_Buffer[2] = 0;
m_Buffer[3] = 0;
- //if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
- //{
- // // No handling for Flow Information
- // m_Buffer[4] = 0;
- // m_Buffer[5] = 0;
- // m_Buffer[6] = 0;
- // m_Buffer[7] = 0;
-
- // // Scope serialization
- // long scope = ipAddress.ScopeId;
- // m_Buffer[24] = (byte)scope;
- // m_Buffer[25] = (byte)(scope >> 8);
- // m_Buffer[26] = (byte)(scope >> 16);
- // m_Buffer[27] = (byte)(scope >> 24);
-
- // // Address serialization
- // byte[] addressBytes = ipAddress.GetAddressBytes();
- // for (int i = 0; i < addressBytes.Length; i++)
- // {
- // m_Buffer[8 + i] = addressBytes[i];
- // }
- //}
- //else
+ if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
+ {
+ // No handling for Flow Information
+ m_Buffer[4] = 0;
+ m_Buffer[5] = 0;
+ m_Buffer[6] = 0;
+ m_Buffer[7] = 0;
+
+ // Scope serialization
+ long scope = ipAddress.ScopeId;
+ m_Buffer[24] = (byte)scope;
+ m_Buffer[25] = (byte)(scope >> 8);
+ m_Buffer[26] = (byte)(scope >> 16);
+ m_Buffer[27] = (byte)(scope >> 24);
+
+ // Address serialization
+ byte[] addressBytes = ipAddress.GetAddressBytes();
+ for (int i = 0; i < addressBytes.Length; i++)
+ {
+ m_Buffer[8 + i] = addressBytes[i];
+ }
+ }
+ else
{
// IPv4 Address serialization
m_Buffer[4] = unchecked((byte)(ipAddress.Address));
@@ -187,33 +187,30 @@ public override int GetHashCode()
internal IPAddress GetIPAddress()
{
- //if (Family == AddressFamily.InterNetworkV6)
- //{
- // byte[] address = new byte[IPAddress.IPv6AddressBytes];
- // for (int i = 0; i < address.Length; i++)
- // {
- // address[i] = m_Buffer[i + 8];
- // }
-
- // long scope = (long)((m_Buffer[27] << 24) +
- // (m_Buffer[26] << 16) +
- // (m_Buffer[25] << 8) +
- // (m_Buffer[24]));
-
- // return new IPAddress(address, scope);
-
- //}
- //else if (Family == AddressFamily.InterNetwork)
+ if (Family == AddressFamily.InterNetworkV6)
{
- long address = (
- (m_Buffer[4] & 0x000000FF) |
- (m_Buffer[5] << 8 & 0x0000FF00) |
- (m_Buffer[6] << 16 & 0x00FF0000) |
- (m_Buffer[7] << 24)
- ) & 0x00000000FFFFFFFF;
-
- return new IPAddress(address);
+ byte[] addr = new byte[IPAddress.IPv6AddressBytes];
+ for (int i = 0; i < addr.Length; i++)
+ {
+ addr[i] = m_Buffer[i + 8];
+ }
+
+ long scope = (long)((m_Buffer[27] << 24) +
+ (m_Buffer[26] << 16) +
+ (m_Buffer[25] << 8) +
+ (m_Buffer[24]));
+
+ return new IPAddress(addr, scope);
}
+
+ long address = (
+ (m_Buffer[4] & 0x000000FF) |
+ (m_Buffer[5] << 8 & 0x0000FF00) |
+ (m_Buffer[6] << 16 & 0x00FF0000) |
+ (m_Buffer[7] << 24)
+ ) & 0x00000000FFFFFFFF;
+
+ return new IPAddress(address);
}
}
}
diff --git a/nanoFramework.System.Net/Sockets/NetworkStream.cs b/nanoFramework.System.Net/Sockets/NetworkStream.cs
index 46d11ba..0eb6755 100644
--- a/nanoFramework.System.Net/Sockets/NetworkStream.cs
+++ b/nanoFramework.System.Net/Sockets/NetworkStream.cs
@@ -124,7 +124,7 @@ public NetworkStream(Socket socket, bool ownsSocket)
/// true if data can be read from the stream; otherwise, false. The default value is true.
///
/// If CanRead is true, allows calls to the method. Provide the appropriate FileAccess enumerated value in the constructor to set
- /// the readability and writability of the . The CanRead property is set when the is initialized.
+ /// the readability and write-ability of the . The CanRead property is set when the is initialized.
///
public override bool CanRead { get { return true; } }
diff --git a/nanoFramework.System.Net/Sockets/Socket.cs b/nanoFramework.System.Net/Sockets/Socket.cs
index 7f478a8..3dd7969 100644
--- a/nanoFramework.System.Net/Sockets/Socket.cs
+++ b/nanoFramework.System.Net/Sockets/Socket.cs
@@ -61,7 +61,7 @@ public class Socket : IDisposable
/// The addressFamily parameter specifies the addressing scheme that the class uses, the socketType parameter specifies the type of the class,
/// and the protocolType parameter specifies the protocol used by . The three parameters are not independent. Some address families restrict which
/// protocols can be used with them, and often the type is implicit in the protocol. If the combination of address family, type, and protocol type
- /// esults in an invalid Socket, this constructor throws a SocketException.
+ /// results in an invalid Socket, this constructor throws a SocketException.
///
public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
{
@@ -1100,9 +1100,6 @@ void IDisposable.Dispose()
GC.SuppressFinalize(this);
}
- ///
- /// Deconstructor
- ///
~Socket()
{
Dispose(false);