From c68aca71ac1f9de82e70845c9df5bc048b158edc Mon Sep 17 00:00:00 2001 From: David Hall Date: Wed, 24 Apr 2019 08:37:46 -0600 Subject: [PATCH] Updated tests for iphlpapi --- UnitTests/PInvoke/IpHlpApi/IpHlpApi.csproj | 3 + UnitTests/PInvoke/IpHlpApi/IpHlpApiTests.cs | 896 ++++++++++++++-------------- UnitTests/PInvoke/IpHlpApi/NetIOApiTests.cs | 545 +++++++++++++++++ 3 files changed, 1006 insertions(+), 438 deletions(-) create mode 100644 UnitTests/PInvoke/IpHlpApi/NetIOApiTests.cs diff --git a/UnitTests/PInvoke/IpHlpApi/IpHlpApi.csproj b/UnitTests/PInvoke/IpHlpApi/IpHlpApi.csproj index 024bdac7..c1530526 100644 --- a/UnitTests/PInvoke/IpHlpApi/IpHlpApi.csproj +++ b/UnitTests/PInvoke/IpHlpApi/IpHlpApi.csproj @@ -21,6 +21,7 @@ DEBUG;TRACE prompt 4 + true pdbonly @@ -29,12 +30,14 @@ TRACE prompt 4 + true + diff --git a/UnitTests/PInvoke/IpHlpApi/IpHlpApiTests.cs b/UnitTests/PInvoke/IpHlpApi/IpHlpApiTests.cs index a41a5bc6..07c7a8fa 100644 --- a/UnitTests/PInvoke/IpHlpApi/IpHlpApiTests.cs +++ b/UnitTests/PInvoke/IpHlpApi/IpHlpApiTests.cs @@ -1,12 +1,9 @@ using NUnit.Framework; using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; -using System.Net; using System.Runtime.InteropServices; using System.Text; -using System.Threading; using Vanara.Extensions; using Vanara.InteropServices; using static Vanara.PInvoke.IpHlpApi; @@ -22,8 +19,10 @@ namespace Vanara.PInvoke.Tests { case ADDRESS_FAMILY.AF_INET: return new System.Net.IPAddress((long)sockAddr.lpSockAddr.ToStructure().sin_addr); + case ADDRESS_FAMILY.AF_INET6: return new System.Net.IPAddress(sockAddr.lpSockAddr.ToStructure().sin6_addr); + default: throw new Exception("Non-IP address family"); } @@ -31,10 +30,14 @@ namespace Vanara.PInvoke.Tests } [TestFixture()] - public class IpHlpApiTests + public partial class IpHlpApiTests { private static readonly IntPtr NotifyData = new IntPtr(8943934); + private static SOCKADDR_IN localv4; + private static SOCKADDR_IN6 localv6; private static IP_ADAPTER_ADDRESSES primaryAdapter; + private static SOCKADDR_IN LocalAddrV4 => localv4.sin_family == 0 ? (localv4 = primaryAdapter.UnicastAddresses.Select(r => r.Address.GetSOCKADDR()).First(a => a.si_family == ADDRESS_FAMILY.AF_INET).Ipv4) : localv4; + private static SOCKADDR_IN6 LocalAddrV6 => localv6.sin6_family == 0 ? (localv6 = primaryAdapter.UnicastAddresses.Select(r => r.Address.GetSOCKADDR()).First(a => a.si_family == ADDRESS_FAMILY.AF_INET6).Ipv6) : localv6; [Test] public void AddDeleteIPAddressTest() @@ -48,122 +51,105 @@ namespace Vanara.PInvoke.Tests } [Test] - public void SetGetIpInterfaceEntryTest() + public void CreateDelPersistentTcpPortReservationTest() { - var mibrow = new MIB_IPINTERFACE_ROW(ADDRESS_FAMILY.AF_INET, primaryAdapter.Luid); - Assert.That(GetIpInterfaceEntry(ref mibrow), Is.Zero); - var prev = mibrow.SitePrefixLength; - mibrow.SitePrefixLength = 0; - Assert.That(SetIpInterfaceEntry(mibrow), Is.Zero); - - mibrow = new MIB_IPINTERFACE_ROW(ADDRESS_FAMILY.AF_INET, primaryAdapter.Luid); - Assert.That(GetIpInterfaceEntry(ref mibrow), Is.Zero); - Assert.That(mibrow.PathMtuDiscoveryTimeout, Is.EqualTo(600000)); - - mibrow.SitePrefixLength = prev; - Assert.That(SetIpInterfaceEntry(mibrow), Is.Zero); + const ushort start = 5000; + const ushort num = 20; + Assert.That(CreatePersistentTcpPortReservation(start, num, out var tok), Is.Zero); + Assert.That(LookupPersistentTcpPortReservation(start, num, out var tok2), Is.Zero); + Assert.That(tok, Is.EqualTo(tok2)); + Assert.That(DeletePersistentTcpPortReservation(start, num), Is.Zero); } [Test] - public void CreateSetDeleteIpNetEntry2Test() + public void CreateDelPersistentUdpPortReservationTest() + { + const ushort start = 5000; + const ushort num = 20; + Assert.That(CreatePersistentUdpPortReservation(start, num, out var tok), Is.Zero); + Assert.That(LookupPersistentUdpPortReservation(start, num, out var tok2), Is.Zero); + Assert.That(tok, Is.EqualTo(tok2)); + Assert.That(DeletePersistentUdpPortReservation(start, num), Is.Zero); + } + + // [Test] TODO - Figure out which parameters work + public void CreateDelProxyArpEntryTest() + { + var target = primaryAdapter.MulticastAddresses.First().Address.GetSOCKADDR().Ipv4.sin_addr; // new IN_ADDR(192, 168, 0, 202); + uint a = target.S_addr, m = 0x00FFFFFF, i = primaryAdapter.IfIndex; + Assert.That(CreateProxyArpEntry(a, m, i), Is.Zero); + Assert.That(DeleteProxyArpEntry(a, m, i), Is.Zero); + } + + [Test] + public void CreateSetDeleteIpForwardEntryTest() + { + Assert.That(() => + { + MIB_IPFORWARDROW row = default; + foreach (var rrow in GetIpForwardTable(true).Where(r => r.dwForwardDest == 0)) + { + if (row.dwForwardType == 0) row = rrow; + DeleteIpForwardEntry(rrow).ThrowIfFailed(); + } + + row.dwForwardNextHop = 0xDDBBCCAA; + CreateIpForwardEntry(row).ThrowIfFailed(); + + //row.dwForwardProto = MIB_IPFORWARD_PROTO.MIB_IPPROTO_DHCP; + SetIpForwardEntry(row).ThrowIfFailed(); + + DeleteIpForwardEntry(row).ThrowIfFailed(); + }, Throws.Nothing); + } + + [Test] + public void CreateSetDeleteIpNetEntryTest() { var target = new IN_ADDR(192, 168, 0, 202); Assert.That(GetBestRoute(target, 0, out var fwdRow), Is.Zero); - var mibrow = new MIB_IPNET_ROW2(new SOCKADDR_IN(target), fwdRow.dwForwardIfIndex, SendARP(target)); - Assert.That(GetIpNetTable2(ADDRESS_FAMILY.AF_INET, out var t1), Is.Zero); - if (HasVal(t1, mibrow)) - Assert.That(DeleteIpNetEntry2(ref mibrow), Is.Zero); + var mibrow = new MIB_IPNETROW(target, fwdRow.dwForwardIfIndex, SendARP(target), MIB_IPNET_TYPE.MIB_IPNET_TYPE_DYNAMIC); - Assert.That(CreateIpNetEntry2(ref mibrow), Is.Zero); - GetIpNetTable2(ADDRESS_FAMILY.AF_INET, out var t2); - Assert.That(HasVal(t2, mibrow), Is.True); + MIB_IPNETTABLE t1 = null; + Assert.That(() => t1 = GetIpNetTable(true), Throws.Nothing); + if (t1 != null && HasVal(t1, mibrow)) + Assert.That(DeleteIpNetEntry(mibrow), Is.Zero); - Assert.That(DeleteIpNetEntry2(ref mibrow), Is.Zero); - GetIpNetTable2(ADDRESS_FAMILY.AF_INET, out var t3); + Assert.That(CreateIpNetEntry(mibrow), Is.Zero); + var t = GetIpNetTable(true); + Assert.That(HasVal(t, mibrow), Is.True); + + Assert.That(SetIpNetEntry(mibrow), Is.Zero); + + Assert.That(DeleteIpNetEntry(mibrow), Is.Zero); + var t3 = GetIpNetTable(true); Assert.That(HasVal(t3, mibrow), Is.False); - bool HasVal(IEnumerable t, MIB_IPNET_ROW2 r) => - t.Any(tr => tr.Address.Ipv4.sin_addr == r.Address.Ipv4.sin_addr && tr.InterfaceIndex == r.InterfaceIndex && tr.PhysicalAddress.SequenceEqual(r.PhysicalAddress)); + bool HasVal(IEnumerable tb, MIB_IPNETROW r) => + tb.Any(tr => tr.dwAddr.S_addr == r.dwAddr.S_addr && tr.dwIndex == r.dwIndex && tr.bPhysAddr.SequenceEqual(r.bPhysAddr)); } - [Test] - public void CreateGetDeleteAnycastIpAddressEntryTest() + public void DisableRestoreMediaSenseTest() { - var target = new IN6_ADDR(new byte[] { 0xfe, 0x3f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x20, 0x00 }); - var mibrow = new MIB_ANYCASTIPADDRESS_ROW(new SOCKADDR_IN6(target, 0), primaryAdapter.Luid); - Assert.That(GetAnycastIpAddressTable(ADDRESS_FAMILY.AF_INET6, out var t1), Is.Zero); - if (t1.Contains(mibrow)) - Assert.That(DeleteAnycastIpAddressEntry(ref mibrow), Is.Zero); - - Assert.That(CreateAnycastIpAddressEntry(ref mibrow), Is.Zero); - GetAnycastIpAddressTable(ADDRESS_FAMILY.AF_INET6, out var t2); - Assert.That(t2, Has.Member(mibrow)); - - Assert.That(GetAnycastIpAddressEntry(ref mibrow), Is.Zero); - - Assert.That(DeleteAnycastIpAddressEntry(ref mibrow), Is.Zero); - GetAnycastIpAddressTable(ADDRESS_FAMILY.AF_INET6, out var t3); - Assert.That(t3, Has.No.Member(mibrow)); - } - - [Test] - public void CreateSetGetDeleteUnicastIpAddressEntryTest() - { - var target = new IN6_ADDR(new byte[] { 0xfe, 0x3f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x20, 0x00 }); - var mibrow = new MIB_UNICASTIPADDRESS_ROW(new SOCKADDR_IN6(target, 0), primaryAdapter.Luid); - Assert.That(GetUnicastIpAddressTable(ADDRESS_FAMILY.AF_INET6, out var t1), Is.Zero); - if (t1.Contains(mibrow)) - Assert.That(DeleteUnicastIpAddressEntry(ref mibrow), Is.Zero); - - Assert.That(CreateUnicastIpAddressEntry(ref mibrow), Is.Zero); - GetUnicastIpAddressTable(ADDRESS_FAMILY.AF_INET6, out var t2); - Assert.That(t2, Has.Member(mibrow)); - - mibrow.PreferredLifetime = 500000; - Assert.That(SetUnicastIpAddressEntry(mibrow), Is.Zero); - Assert.That(GetUnicastIpAddressEntry(ref mibrow), Is.Zero); - - Assert.That(DeleteUnicastIpAddressEntry(ref mibrow), Is.Zero); - GetUnicastIpAddressTable(ADDRESS_FAMILY.AF_INET6, out var t4); - Assert.That(t4, Has.No.Member(mibrow)); - } - - [Test] - public void CreateSetDeleteIpForwardEntry2Test() - { - var target = new IN6_ADDR(new byte[] { 0xfe, 0x3f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x20, 0x00 }); - var mibrow = new MIB_IPFORWARD_ROW2(new IP_ADDRESS_PREFIX((SOCKADDR_IN6)IN6_ADDR.Unspecified, 128), (SOCKADDR_IN6)target, primaryAdapter.Luid) + var hEvent = new System.Threading.EventWaitHandle(false, System.Threading.EventResetMode.ManualReset); + var pOverLapped = new System.Threading.NativeOverlapped { EventHandle = hEvent.SafeWaitHandle.DangerousGetHandle() }; + unsafe { - Protocol = MIB_IPFORWARD_PROTO.MIB_IPPROTO_NETMGMT, - Metric = 1 - }; - DeleteIpForwardEntry2(ref mibrow); - - Assert.That(CreateIpForwardEntry2(ref mibrow), Is.Zero); - - mibrow.PreferredLifetime = 500000; - Assert.That(SetIpForwardEntry2(mibrow), Is.Zero); - Assert.That(GetIpForwardEntry2(ref mibrow), Is.Zero); - - Assert.That(DeleteIpForwardEntry2(ref mibrow), Is.Zero); + Assert.That(DisableMediaSense(out _, &pOverLapped), Is.Zero.Or.EqualTo(Win32Error.ERROR_IO_PENDING)); + Assert.That(RestoreMediaSense(&pOverLapped, out _), Is.Zero.Or.EqualTo(Win32Error.ERROR_IO_PENDING)); + } } - // TODO: [Test] + [Test] public void EnableUnenableRouterTest() { - throw new NotImplementedException(); - } - - [Test] - public void FlushIpNetTable2Test() - { - Assert.That(FlushIpNetTable2(ADDRESS_FAMILY.AF_INET6, primaryAdapter.IfIndex), Is.Zero); - } - - [Test] - public void FlushIpPathTableTest() - { - Assert.That(FlushIpPathTable(ADDRESS_FAMILY.AF_INET6), Is.Zero); + var hEvent = new System.Threading.EventWaitHandle(false, System.Threading.EventResetMode.ManualReset); + var pOverLapped = new System.Threading.NativeOverlapped { EventHandle = hEvent.SafeWaitHandle.DangerousGetHandle() }; + unsafe + { + Assert.That(EnableRouter(out _, &pOverLapped), Is.Zero.Or.EqualTo(Win32Error.ERROR_IO_PENDING)); + Assert.That(UnenableRouter(&pOverLapped, out _), Is.Zero.Or.EqualTo(Win32Error.ERROR_IO_PENDING)); + } } [Test] @@ -176,6 +162,14 @@ namespace Vanara.PInvoke.Tests Assert.That(GetAdapterIndex("__Bogus**__", out idx), Is.EqualTo(Win32Error.ERROR_INVALID_PARAMETER)); } + [Test] + public void GetAdapterOrderMapTest() + { + var map = GetAdapterOrderMap(); + Assert.That(map, Is.Not.Null); + Assert.That(map.NumAdapters, Is.GreaterThan(0)); + } + [Test] public void GetAdaptersAddressesTest() { @@ -183,15 +177,15 @@ namespace Vanara.PInvoke.Tests { foreach (var addrs in GetAdaptersAddresses(GetAdaptersAddressesFlags.GAA_FLAG_INCLUDE_PREFIX, ADDRESS_FAMILY.AF_UNSPEC)) { - Debug.WriteLine($"{addrs.IfIndex}) {addrs.AdapterName} ({addrs.FriendlyName});{addrs.Description};MAC:{PhysicalAddressToString(addrs.PhysicalAddress)}"); - Debug.WriteLine(" Uni:" + string.Join(";", addrs.UnicastAddresses.Select(a => a.Address))); - Debug.WriteLine(" Any:" + string.Join(";", addrs.AnycastAddresses.Select(a => a.Address))); - Debug.WriteLine(" MCS:" + string.Join(";", addrs.MulticastAddresses.Select(a => a.Address))); - Debug.WriteLine(" DNS:" + string.Join(";", addrs.DnsServerAddresses.Select(a => a.Address))); - Debug.WriteLine(" Prfx:" + string.Join(";", addrs.Prefixes.Select(a => a.Address))); - Debug.WriteLine(" WINS:" + string.Join(";", addrs.WinsServerAddresses.Select(a => a.Address))); - Debug.WriteLine(" GTWY:" + string.Join(";", addrs.GatewayAddresses.Select(a => a.Address))); - Debug.WriteLine(" Sufx:" + string.Join(";", addrs.DnsSuffixes.Select(a => a.String))); + TestContext.WriteLine($"{addrs.IfIndex}) {addrs.AdapterName} ({addrs.FriendlyName});{addrs.Description};MAC:{PhysicalAddressToString(addrs.PhysicalAddress)}"); + TestContext.WriteLine(" Uni:" + string.Join(";", addrs.UnicastAddresses.Select(a => a.Address))); + TestContext.WriteLine(" Any:" + string.Join(";", addrs.AnycastAddresses.Select(a => a.Address))); + TestContext.WriteLine(" MCS:" + string.Join(";", addrs.MulticastAddresses.Select(a => a.Address))); + TestContext.WriteLine(" DNS:" + string.Join(";", addrs.DnsServerAddresses.Select(a => a.Address))); + TestContext.WriteLine(" Prfx:" + string.Join(";", addrs.Prefixes.Select(a => a.Address))); + TestContext.WriteLine(" WINS:" + string.Join(";", addrs.WinsServerAddresses.Select(a => a.Address))); + TestContext.WriteLine(" GTWY:" + string.Join(";", addrs.GatewayAddresses.Select(a => a.Address))); + TestContext.WriteLine(" Sufx:" + string.Join(";", addrs.DnsSuffixes.Select(a => a.String))); } }, Throws.Nothing); } @@ -207,16 +201,6 @@ namespace Vanara.PInvoke.Tests #pragma warning restore CS0618 // Type or member is obsolete } - [Test] - public void GetAnycastIpAddressEntryTableTest() - { - Assert.That(GetAnycastIpAddressTable(ADDRESS_FAMILY.AF_UNSPEC, out var table), Is.Zero); - Assert.That(table.NumEntries, Is.Zero); - - var row = new MIB_ANYCASTIPADDRESS_ROW(); - Assert.That(GetAnycastIpAddressEntry(ref row), Is.Not.Zero); - } - [Test] public void GetBestInterfaceExTest() { @@ -239,15 +223,6 @@ namespace Vanara.PInvoke.Tests Assert.That(idx, Is.EqualTo(primaryAdapter.IfIndex)); } - [Test] - public void GetBestRoute2Test() - { - var addr = new SOCKADDR_INET { Ipv4 = new SOCKADDR_IN(new IN_ADDR(192, 168, 0, 202)) }; - Assert.That(GetBestRoute2(IntPtr.Zero, primaryAdapter.IfIndex, IntPtr.Zero, ref addr, 0, out var rt, out var src), Is.Zero); - Assert.That(rt.InterfaceIndex, Is.EqualTo(primaryAdapter.IfIndex)); - Assert.That(src.Ipv4.sin_addr, Is.EqualTo(new IN_ADDR(192, 168, 0, 203))); - } - [Test] public void GetExtendedTcpTableTest() { @@ -311,47 +286,18 @@ namespace Vanara.PInvoke.Tests } [Test] - public void GetIfEntry2ExTest() + public void GetFriendlyIfIndexTest() { - var row = new MIB_IF_ROW2(primaryAdapter.IfIndex); - Assert.That(GetIfEntry2Ex(MIB_IF_ENTRY_LEVEL.MibIfEntryNormalWithoutStatistics, ref row), Is.Zero); - Assert.That(row.InterfaceLuid, Is.EqualTo(primaryAdapter.Luid)); + Assert.That(GetFriendlyIfIndex(primaryAdapter.IfIndex), Is.Not.Zero); } [Test] - public void GetIfEntry2Test() + public void GetIcmpStatisticsTest() { - var row = new MIB_IF_ROW2(primaryAdapter.IfIndex); - Assert.That(GetIfEntry2(ref row), Is.Zero); - Assert.That(row.InterfaceLuid, Is.EqualTo(primaryAdapter.Luid)); - } - - [Test] - public void GetIfStackTableTest() - { - Assert.That(GetIfStackTable(out var table), Is.Zero); - Assert.That(table.NumEntries, Is.GreaterThan(0)); - Assert.That(() => table.Table, Throws.Nothing); - } - - [Test] - public void GetIfTable2ExTest() - { - var e = GetIfTable2Ex(MIB_IF_TABLE_LEVEL.MibIfTableNormal, out var itbl); - Assert.That(e.Succeeded); - Assert.That(itbl.Table, Is.Not.Empty); - itbl.Dispose(); - Assert.That(itbl.IsInvalid); - } - - [Test] - public void GetIfTable2Test() - { - var e = GetIfTable2(out var itbl); - Assert.That(e.Succeeded); - Assert.That(itbl.Table, Is.Not.Empty); - itbl.Dispose(); - Assert.That(itbl.IsInvalid); + Assert.That(GetIcmpStatistics(out var stat), Is.Zero); + Assert.That(stat.stats.icmpInStats.dwMsgs, Is.Not.Zero); + Assert.That(GetIcmpStatisticsEx(out var statx, ADDRESS_FAMILY.AF_INET), Is.Zero); + Assert.That(statx.icmpInStats.dwMsgs, Is.Not.Zero); } [Test] @@ -361,7 +307,13 @@ namespace Vanara.PInvoke.Tests { var t = GetIfTable(); Assert.That(t.dwNumEntries, Is.GreaterThan(0)); - foreach (var r in t) ; + foreach (var r in t) + { + var r2 = new MIB_IFROW(r.dwIndex); + Assert.That(GetIfEntry(ref r2), Is.Zero); + Assert.That(r.wszName, Is.EqualTo(r2.wszName)); + Assert.That(SetIfEntry(r2), Is.Zero); + } }, Throws.Nothing); } @@ -376,14 +328,6 @@ namespace Vanara.PInvoke.Tests }, Throws.Nothing); } - [Test] - public void GetInvertedIfStackTableTest() - { - Assert.That(GetInvertedIfStackTable(out var table), Is.Zero); - Assert.That(table.NumEntries, Is.GreaterThan(0)); - Assert.That(() => table.Table, Throws.Nothing); - } - [Test] public void GetIpAddrTableTest() { @@ -396,76 +340,28 @@ namespace Vanara.PInvoke.Tests } [Test] - public void GetIpForwardEntryTable2Test() + public void GetIpErrorStringTest() { - Assert.That(GetIpForwardTable2(ADDRESS_FAMILY.AF_UNSPEC, out var table), Is.Zero); - Assert.That(table.NumEntries, Is.GreaterThan(0)); - Assert.That(() => table.Table, Throws.Nothing); - - var goodRow = table.Table[0]; - var row = new MIB_IPFORWARD_ROW2 { DestinationPrefix = goodRow.DestinationPrefix, NextHop = goodRow.NextHop, InterfaceLuid = goodRow.InterfaceLuid }; - Assert.That(GetIpForwardEntry2(ref row), Is.Zero); - Assert.That(row.InterfaceIndex, Is.Not.Zero.And.EqualTo(goodRow.InterfaceIndex)); + var sz = 1024U; + var sb = new StringBuilder((int)sz); + Assert.That(GetIpErrorString(Win32Error.ERROR_CAN_NOT_COMPLETE, sb, ref sz), Is.Zero); + Assert.That(sb.Length, Is.GreaterThan(0)); } [Test] - public void GetIpInterfaceEntryTableTest() + public void GetSetIpStatisticsTest() { - Assert.That(GetIpInterfaceTable(ADDRESS_FAMILY.AF_UNSPEC, out var table), Is.Zero); - Assert.That(table.NumEntries, Is.GreaterThan(0)); - Assert.That(() => table.Table, Throws.Nothing); + Assert.That(GetIpStatistics(out var stat), Is.Zero); + Assert.That(stat.dwNumIf, Is.Not.Zero); - var goodRow = table.Table[0]; - var row = new MIB_IPINTERFACE_ROW { Family = goodRow.Family, InterfaceLuid = goodRow.InterfaceLuid }; - Assert.That(GetIpInterfaceEntry(ref row), Is.Zero); - Assert.That(row.InterfaceIndex, Is.Not.Zero.And.EqualTo(goodRow.InterfaceIndex)); - } + var sstat = new MIB_IPSTATS { Forwarding = MIB_IPSTATS_FORWARDING.MIB_USE_CURRENT_FORWARDING, dwDefaultTTL = stat.dwDefaultTTL + 1 }; + Assert.That(SetIpStatisticsEx(sstat, ADDRESS_FAMILY.AF_INET), Is.Zero); - [Test] - public void GetIpNetEntryTable2Test() - { - Assert.That(GetIpNetTable2(ADDRESS_FAMILY.AF_UNSPEC, out var table), Is.Zero); - Assert.That(table.NumEntries, Is.GreaterThan(0)); - Assert.That(() => table.Table, Throws.Nothing); + Assert.That(GetIpStatisticsEx(out var statx, ADDRESS_FAMILY.AF_INET), Is.Zero); + Assert.That(statx.dwDefaultTTL, Is.EqualTo(stat.dwDefaultTTL + 1)); - var goodRow = table.Table[0]; - var row = new MIB_IPNET_ROW2 { Address = goodRow.Address, InterfaceLuid = goodRow.InterfaceLuid }; - Assert.That(GetIpNetEntry2(ref row), Is.Zero); - Assert.That(row.InterfaceIndex, Is.Not.Zero.And.EqualTo(goodRow.InterfaceIndex)); - } - - [Test] - public void GetIpNetworkConnectionBandwidthEstimatesTest() - { - Assert.That(GetIpNetworkConnectionBandwidthEstimates(primaryAdapter.IfIndex, ADDRESS_FAMILY.AF_INET, out var est), Is.Zero); - Assert.That(est.InboundBandwidthInformation.Bandwidth, Is.GreaterThan(0)); - Assert.That(est.OutboundBandwidthInformation.Bandwidth, Is.GreaterThan(0)); - } - - [Test] - public void GetIpPathEntryTableTest() - { - Assert.That(GetIpPathTable(ADDRESS_FAMILY.AF_UNSPEC, out var table), Is.Zero); - Assert.That(table.NumEntries, Is.GreaterThan(0)); - Assert.That(() => table.Table, Throws.Nothing); - - var goodRow = table.Table[0]; - var row = new MIB_IPPATH_ROW { Destination = goodRow.Destination, InterfaceLuid = goodRow.InterfaceLuid }; - Assert.That(GetIpPathEntry(ref row), Is.Zero); - Assert.That((int)row.Source.si_family, Is.Not.Zero); - } - - [Test] - public void GetMulticastIpAddressEntryTableTest() - { - Assert.That(GetMulticastIpAddressTable(ADDRESS_FAMILY.AF_UNSPEC, out var table), Is.Zero); - Assert.That(table.NumEntries, Is.GreaterThan(0)); - Assert.That(() => table.Table, Throws.Nothing); - - var goodRow = table.Table[0]; - var row = new MIB_MULTICASTIPADDRESS_ROW { Address = goodRow.Address, InterfaceLuid = goodRow.InterfaceLuid }; - Assert.That(GetMulticastIpAddressEntry(ref row), Is.Zero); - Assert.That(row.InterfaceIndex, Is.Not.Zero.And.EqualTo(goodRow.InterfaceIndex)); + sstat.dwDefaultTTL = stat.dwDefaultTTL; + Assert.That(SetIpStatistics(sstat), Is.Zero); } [Test] @@ -478,6 +374,112 @@ namespace Vanara.PInvoke.Tests }, Throws.Nothing); } + [Test] + public void GetNumberOfInterfacesTest() + { + Assert.That(GetNumberOfInterfaces(out var num), Is.Zero); + Assert.That(num, Is.GreaterThan(0)); + } + + [Test] + public void GetOwnerModuleFromPidAndInfoTest() + { + foreach (var om in GetExtendedTcpTable(TCP_TABLE_CLASS.TCP_TABLE_OWNER_MODULE_ALL, ADDRESS_FAMILY.AF_INET6)) + { + uint sz = 0; + var err = GetOwnerModuleFromPidAndInfo(om.dwOwningPid, om.OwningModuleInfo, TCPIP_OWNER_MODULE_INFO_CLASS.TCPIP_OWNER_MODULE_INFO_BASIC, IntPtr.Zero, ref sz); + TestContext.WriteLine($"{om.dwOwningPid} {string.Join(":", om.OwningModuleInfo)} {sz} {err}"); + } + } + + [Test] + public void GetOwnerModuleFromTcp6EntryTest() + { + Assert.That(() => + { + foreach (var om in GetExtendedTcpTable(TCP_TABLE_CLASS.TCP_TABLE_OWNER_MODULE_ALL, ADDRESS_FAMILY.AF_INET6, true)) + { + try + { + var info = GetOwnerModuleFromTcp6Entry(om); + Assert.That(info.pModuleName, Is.Not.Null); + TestContext.WriteLine($"{om.dwOwningPid} {om.ucLocalAddr}=>{om.ucRemoteAddr} {info.pModuleName}"); + } + catch (Exception ex) + { + TestContext.WriteLine($"{om.dwOwningPid} {om.ucLocalAddr}=>{om.ucRemoteAddr} {ex.HResult}"); + //Assert.That(ex.HResult, Is.EqualTo(((Win32Error)Win32Error.ERROR_NOT_FOUND).ToHRESULT())); + } + } + }, Throws.Nothing); + } + + [Test] + public void GetOwnerModuleFromTcpEntryTest() + { + Assert.That(() => + { + foreach (var om in GetExtendedTcpTable(TCP_TABLE_CLASS.TCP_TABLE_OWNER_MODULE_ALL, ADDRESS_FAMILY.AF_INET, true)) + { + try + { + var info = GetOwnerModuleFromTcpEntry(om); + Assert.That(info.pModuleName, Is.Not.Null); + TestContext.WriteLine($"{om.dwOwningPid} {om.dwLocalAddr}=>{om.dwRemoteAddr} {info.pModuleName}"); + } + catch (Exception ex) + { + TestContext.WriteLine($"{om.dwOwningPid} {om.dwLocalAddr}=>{om.dwRemoteAddr} {ex.HResult}"); + //Assert.That(ex.HResult, Is.EqualTo(((Win32Error)Win32Error.ERROR_NOT_FOUND).ToHRESULT())); + } + } + }, Throws.Nothing); + } + + [Test] + public void GetOwnerModuleFromUdp6EntryTest() + { + Assert.That(() => + { + foreach (var om in GetExtendedUdpTable(UDP_TABLE_CLASS.UDP_TABLE_OWNER_MODULE, ADDRESS_FAMILY.AF_INET6)) + { + try + { + var info = GetOwnerModuleFromUdp6Entry(om); + Assert.That(info.pModuleName, Is.Not.Null); + TestContext.WriteLine($"{om.dwOwningPid} {om.ucLocalAddr} {info.pModuleName}"); + } + catch (Exception ex) + { + TestContext.WriteLine($"{om.dwOwningPid} {om.ucLocalAddr} {ex.HResult}"); + //Assert.That(ex.HResult, Is.EqualTo(((Win32Error)Win32Error.ERROR_NOT_FOUND).ToHRESULT())); + } + } + }, Throws.Nothing); + } + + [Test] + public void GetOwnerModuleFromUdpEntryTest() + { + Assert.That(() => + { + foreach (var om in GetExtendedUdpTable(UDP_TABLE_CLASS.UDP_TABLE_OWNER_MODULE, ADDRESS_FAMILY.AF_INET)) + { + try + { + var info = GetOwnerModuleFromUdpEntry(om); + Assert.That(info.pModuleName, Is.Not.Null); + TestContext.WriteLine($"{om.dwOwningPid} {om.dwLocalAddr} {info.pModuleName}"); + } + catch (Exception ex) + { + TestContext.WriteLine($"{om.dwOwningPid} {om.dwLocalAddr} {ex.HResult}"); + //Assert.That(ex.HResult, Is.EqualTo(((Win32Error)Win32Error.ERROR_NOT_FOUND).ToHRESULT())); + } + } + }, Throws.Nothing); + } + [Test] public void GetPerAdapterInfoTest() { @@ -489,22 +491,85 @@ namespace Vanara.PInvoke.Tests } [Test] - public void GetTeredoPortTest() + public void GetPerTcp6ConnectionEStatsTest() { - Assert.That(GetTeredoPort(out var port), Is.Zero.Or.EqualTo(Win32Error.ERROR_NOT_READY)); + var addr = LocalAddrV6.sin6_addr; + var row = GetTcp6Table(true).First(r => r.LocalAddr == addr && r.dwLocalPort != 0 && r.dwRemotePort != 0); + ToggleAllEstats(row, true); + foreach (TCP_ESTATS_TYPE type in Enum.GetValues(typeof(TCP_ESTATS_TYPE))) + { + if (type == TCP_ESTATS_TYPE.TcpConnectionEstatsSynOpts) continue; + Assert.That(GetPerTcp6ConnectionEStats(row, type, out var srw, out _, out _), Is.Zero); + Console.Write(GetStats(srw)); + } + ToggleAllEstats(row, false); } [Test] - public void GetUnicastIpAddressEntryTableTest() + public void GetPerTcpConnectionEStatsTest() { - Assert.That(GetUnicastIpAddressTable(ADDRESS_FAMILY.AF_UNSPEC, out var table), Is.Zero); - Assert.That(table.NumEntries, Is.GreaterThan(0)); - Assert.That(() => table.Table, Throws.Nothing); + var addr = LocalAddrV4.sin_addr; + var row = GetTcpTable(true).First(r => r.dwLocalAddr == addr && r.dwLocalPort != 0 && r.dwRemotePort != 0); + ToggleAllEstats(row, true); + foreach (TCP_ESTATS_TYPE type in Enum.GetValues(typeof(TCP_ESTATS_TYPE))) + { + if (type == TCP_ESTATS_TYPE.TcpConnectionEstatsSynOpts) continue; + Assert.That(GetPerTcpConnectionEStats(row, type, out var srw, out _, out _), Is.Zero); + Console.Write(GetStats(srw)); + } + ToggleAllEstats(row, false); + } - var goodRow = table.Table[0]; - var row = new MIB_UNICASTIPADDRESS_ROW { Address = goodRow.Address, InterfaceLuid = goodRow.InterfaceLuid }; - Assert.That(GetUnicastIpAddressEntry(ref row), Is.Zero); - Assert.That(row.CreationTimeStamp, Is.Not.Zero.And.EqualTo(goodRow.CreationTimeStamp)); + [Test] + public void GetRTTAndHopCountTest() + { + var target = new IN_ADDR(192, 168, 0, 202); + Assert.That(GetRTTAndHopCount(target, out var hops, uint.MaxValue, out var rtt), Is.True); + TestContext.WriteLine($"{target}: hops={hops} rtt={rtt}"); + Assert.That(hops, Is.GreaterThan(0)); + Assert.That(rtt, Is.GreaterThanOrEqualTo(0)); + } + + [Test] + public void GetTcpStatisticsTest() + { + Assert.That(GetTcpStatistics(out var stats), Is.Zero); + Assert.That(stats.dwNumConns, Is.GreaterThan(0)); + } + + [Test] + public void GetTcpStatisticsExTest() + { + Assert.That(GetTcpStatisticsEx(out var stats, ADDRESS_FAMILY.AF_INET), Is.Zero); + Assert.That(stats.dwNumConns, Is.GreaterThan(0)); + } + + [Test] + public void GetTcpStatisticsEx2Test() + { + Assert.That(GetTcpStatisticsEx2(out var stats, ADDRESS_FAMILY.AF_INET), Is.Zero); + Assert.That(stats.dwNumConns, Is.GreaterThan(0)); + } + + [Test] + public void GetUdpStatisticsTest() + { + Assert.That(GetUdpStatistics(out var stats), Is.Zero); + Assert.That(stats.dwNumAddrs, Is.GreaterThan(0)); + } + + [Test] + public void GetUdpStatisticsExTest() + { + Assert.That(GetUdpStatisticsEx(out var stats, ADDRESS_FAMILY.AF_INET), Is.Zero); + Assert.That(stats.dwNumAddrs, Is.GreaterThan(0)); + } + + [Test] + public void GetUdpStatisticsEx2Test() + { + Assert.That(GetUdpStatisticsEx2(out var stats, ADDRESS_FAMILY.AF_INET), Is.Zero); + Assert.That(stats.dwNumAddrs, Is.GreaterThan(0)); } [Test] @@ -517,40 +582,6 @@ namespace Vanara.PInvoke.Tests }, Throws.Nothing); } - [Test] - public void if_indextonameANDif_nametoindexTest() - { - var sb = new StringBuilder(IF_MAX_STRING_SIZE, IF_MAX_STRING_SIZE); - Assert.That(if_indextoname(primaryAdapter.IfIndex, sb), Is.Not.EqualTo(IntPtr.Zero)); - TestContext.WriteLine(sb); - Assert.That(if_nametoindex(sb.ToString()), Is.EqualTo(primaryAdapter.IfIndex)); - } - - [Test] - public void InitializeIpForwardEntryTest() - { - InitializeIpForwardEntry(out var entry); - Assert.That(entry.ValidLifetime, Is.Not.Zero); - Assert.That(entry.Loopback, Is.True); - } - - [Test] - public void InitializeIpInterfaceEntryTest() - { - InitializeIpInterfaceEntry(out var entry); - Assert.That((int)entry.Family, Is.Zero); - Assert.That(entry.InterfaceIdentifier, Is.Not.Zero); - Assert.That(entry.SupportsNeighborDiscovery, Is.True); - } - - [Test] - public void InitializeUnicastIpAddressEntryTest() - { - InitializeUnicastIpAddressEntry(out var entry); - Assert.That(entry.ValidLifetime, Is.Not.Zero); - Assert.That(entry.PrefixOrigin, Is.EqualTo(NL_PREFIX_ORIGIN.IpPrefixOriginUnchanged)); - } - [Test] public void IpReleaseRenewAddressTest() { @@ -568,167 +599,12 @@ namespace Vanara.PInvoke.Tests throw new NotImplementedException(); } - [Test] - public void NotifyIpInterfaceChangeTest() - { - var fired = new ManualResetEvent(false); - var done = new ManualResetEvent(false); - new Thread(() => - { - try - { - Assert.That(NotifyIpInterfaceChange(ADDRESS_FAMILY.AF_UNSPEC, NotifyFunc, NotifyData, true, out var hNot), Is.Zero); - fired.WaitOne(3000); - Assert.That(CancelMibChangeNotify2(hNot), Is.Zero); - } - finally - { - done.Set(); - } - }).Start(); - Assert.That(done.WaitOne(5000), Is.True); - - void NotifyFunc(IntPtr CallerContext, IntPtr Row, MIB_NOTIFICATION_TYPE NotificationType) - { - Assert.That(CallerContext, Is.EqualTo(NotifyData)); - TestContext.WriteLine(Row.ToString()); - Assert.That(NotificationType, Is.EqualTo(MIB_NOTIFICATION_TYPE.MibInitialNotification)); - fired.Set(); - } - } - - [Test] - public void NotifyRouteChange2Test() - { - var fired = new ManualResetEvent(false); - var done = new ManualResetEvent(false); - new Thread(() => - { - try - { - Assert.That(NotifyRouteChange2(ADDRESS_FAMILY.AF_UNSPEC, NotifyFunc, NotifyData, true, out var hNot), Is.Zero); - fired.WaitOne(3000); - Assert.That(CancelMibChangeNotify2(hNot), Is.Zero); - } - finally - { - done.Set(); - } - }).Start(); - Assert.That(done.WaitOne(5000), Is.True); - - void NotifyFunc(IntPtr CallerContext, ref MIB_IPFORWARD_ROW2 Row, MIB_NOTIFICATION_TYPE NotificationType) - { - Assert.That(CallerContext, Is.EqualTo(NotifyData)); - TestContext.WriteLine(Row.ToString()); - Assert.That(NotificationType, Is.EqualTo(MIB_NOTIFICATION_TYPE.MibInitialNotification)); - fired.Set(); - } - } - // TODO: [Test] public void NotifyRouteChangeTest() { throw new NotImplementedException(); } - [Test] - public void NotifyStableUnicastIpAddressTableTest() - { - var fired = new ManualResetEvent(false); - var done = new ManualResetEvent(false); - new Thread(() => - { - try - { - Assert.That(NotifyStableUnicastIpAddressTable(ADDRESS_FAMILY.AF_UNSPEC, out var table, NotifyFunc, NotifyData, out var hNot), Is.Zero.Or.EqualTo(Win32Error.ERROR_IO_PENDING)); - if (table == IntPtr.Zero) - { - fired.WaitOne(3000); - Assert.That(CancelMibChangeNotify2(hNot), Is.Zero); - } - } - finally - { - done.Set(); - } - }).Start(); - Assert.That(done.WaitOne(5000), Is.True); - - void NotifyFunc(IntPtr CallerContext, IntPtr Table) - { - Assert.That(CallerContext, Is.EqualTo(NotifyData)); - TestContext.WriteLine(Table.ToString()); - fired.Set(); - } - } - - [Test] - public void NotifyTeredoPortChangeTest() - { - var fired = new ManualResetEvent(false); - var done = new ManualResetEvent(false); - new Thread(() => - { - try - { - Assert.That(NotifyTeredoPortChange(NotifyFunc, NotifyData, true, out var hNot), Is.Zero); - fired.WaitOne(3000); - Assert.That(CancelMibChangeNotify2(hNot), Is.Zero); - } - finally - { - done.Set(); - } - }).Start(); - Assert.That(done.WaitOne(5000), Is.True); - - void NotifyFunc(IntPtr CallerContext, ushort Port, MIB_NOTIFICATION_TYPE NotificationType) - { - Assert.That(CallerContext, Is.EqualTo(NotifyData)); - TestContext.WriteLine(Port.ToString()); - Assert.That(NotificationType, Is.EqualTo(MIB_NOTIFICATION_TYPE.MibInitialNotification)); - fired.Set(); - } - } - - [Test] - public void NotifyUnicastIpAddressChangeTest() - { - var fired = new ManualResetEvent(false); - var done = new ManualResetEvent(false); - new Thread(() => - { - try - { - Assert.That(NotifyUnicastIpAddressChange(ADDRESS_FAMILY.AF_UNSPEC, NotifyFunc, NotifyData, true, out var hNot), Is.Zero); - fired.WaitOne(3000); - Assert.That(CancelMibChangeNotify2(hNot), Is.Zero); - } - finally - { - done.Set(); - } - }).Start(); - Assert.That(done.WaitOne(5000), Is.True); - - void NotifyFunc(IntPtr CallerContext, IntPtr Row, MIB_NOTIFICATION_TYPE NotificationType) - { - Assert.That(CallerContext, Is.EqualTo(NotifyData)); - TestContext.WriteLine(Row.ToString()); - Assert.That(NotificationType, Is.EqualTo(MIB_NOTIFICATION_TYPE.MibInitialNotification)); - fired.Set(); - } - } - - [Test] - public void ResolveIpNetEntry2Test() - { - var e = new MIB_IPNET_ROW2(new SOCKADDR_IN(new IN_ADDR(192, 168, 0, 202)), primaryAdapter.IfIndex); - Assert.That(ResolveIpNetEntry2(ref e), Is.Zero); - Assert.That(e.State, Is.EqualTo(NL_NEIGHBOR_STATE.NlnsReachable)); - } - [Test] public void SendARPTest() { @@ -744,8 +620,152 @@ namespace Vanara.PInvoke.Tests [SetUp] public void Setup() { - primaryAdapter = GetAdaptersAddresses(GetAdaptersAddressesFlags.GAA_FLAG_INCLUDE_GATEWAYS).FirstOrDefault(r => r.OperStatus == IF_OPER_STATUS.IfOperStatusUp && r.TunnelType == TUNNEL_TYPE.TUNNEL_TYPE_NONE); + primaryAdapter = GetAdaptersAddresses(GetAdaptersAddressesFlags.GAA_FLAG_INCLUDE_GATEWAYS).FirstOrDefault(r => r.OperStatus == IF_OPER_STATUS.IfOperStatusUp && r.TunnelType == TUNNEL_TYPE.TUNNEL_TYPE_NONE && r.FirstGatewayAddress != IntPtr.Zero); } + + private static Win32Error CreateTcpConnection(bool v6, out SafeSOCKET serviceSocket, out SafeSOCKET clientSocket, out SOCKET acceptSocket, out ushort serverPort, out ushort clientPort) + { + Win32Error status; + var aiFamily = v6 ? ADDRESS_FAMILY.AF_INET6 : ADDRESS_FAMILY.AF_INET; + var hints = new ADDRINFOW + { + ai_family = aiFamily, + ai_socktype = SOCK.SOCK_STREAM, + ai_protocol = IPPROTO.IPPROTO_TCP + }; + var loopback = v6 ? "::1" : "127.0.0.1"; + + serviceSocket = SafeSOCKET.INVALID_SOCKET; + clientSocket = SafeSOCKET.INVALID_SOCKET; + acceptSocket = SOCKET.INVALID_SOCKET; + serverPort = clientPort = 0; + + status = GetAddrInfoW(loopback, "", hints, out var result); + if (status.Failed) + goto bail; + + using (result) + { + var localhost = result.FirstOrDefault(); + + serviceSocket = socket(aiFamily, SOCK.SOCK_STREAM, IPPROTO.IPPROTO_TCP); + clientSocket = socket(aiFamily, SOCK.SOCK_STREAM, IPPROTO.IPPROTO_TCP); + if (serviceSocket == SOCKET.INVALID_SOCKET || clientSocket == SOCKET.INVALID_SOCKET) + goto bail; + + status = bind(serviceSocket, localhost.addr, localhost.ai_addrlen); + if (status.Failed) + goto bail; + } + + var serverSockName = SOCKADDR.Empty; + var nameLen = serverSockName.Size; + status = getsockname(serviceSocket, serverSockName, ref nameLen); + if (status.Failed) + goto bail; + serverPort = v6 ? ((SOCKADDR_IN6)serverSockName).sin6_port : ((SOCKADDR_IN)serverSockName).sin_port; + + status = listen(serviceSocket, SOMAXCONN); + if (status.Failed) + goto bail; + + status = connect(clientSocket, serverSockName, nameLen); + if (status.Failed) + goto bail; + + var clientSockName = SOCKADDR.Empty; + nameLen = clientSockName.Size; + status = getsockname(clientSocket, clientSockName, ref nameLen); + if (status.Failed) + goto bail; + + clientPort = v6 ? ((SOCKADDR_IN6)clientSockName).sin6_port : ((SOCKADDR_IN)clientSockName).sin_port; + + acceptSocket = accept(serviceSocket); + if (acceptSocket == SOCKET.INVALID_SOCKET) + goto bail; + + return Win32Error.ERROR_SUCCESS; + + bail: + return status == -1 ? WSAGetLastError() : status; + } + + private static SafeAllocatedMemoryHandle GetRwForType(TCP_ESTATS_TYPE type, bool enable) + { + switch (type) + { + case TCP_ESTATS_TYPE.TcpConnectionEstatsData: + return SafeHGlobalHandle.CreateFromStructure(new TCP_ESTATS_DATA_RW_v0 { EnableCollection = enable }); + case TCP_ESTATS_TYPE.TcpConnectionEstatsSndCong: + return SafeHGlobalHandle.CreateFromStructure(new TCP_ESTATS_SND_CONG_RW_v0 { EnableCollection = enable }); + case TCP_ESTATS_TYPE.TcpConnectionEstatsPath: + return SafeHGlobalHandle.CreateFromStructure(new TCP_ESTATS_PATH_RW_v0 { EnableCollection = enable }); + case TCP_ESTATS_TYPE.TcpConnectionEstatsSendBuff: + return SafeHGlobalHandle.CreateFromStructure(new TCP_ESTATS_SEND_BUFF_RW_v0 { EnableCollection = enable }); + case TCP_ESTATS_TYPE.TcpConnectionEstatsRec: + return SafeHGlobalHandle.CreateFromStructure(new TCP_ESTATS_REC_RW_v0 { EnableCollection = enable }); + case TCP_ESTATS_TYPE.TcpConnectionEstatsObsRec: + return SafeHGlobalHandle.CreateFromStructure(new TCP_ESTATS_OBS_REC_RW_v0 { EnableCollection = enable }); + case TCP_ESTATS_TYPE.TcpConnectionEstatsBandwidth: + var operation = enable ? TCP_BOOLEAN_OPTIONAL.TcpBoolOptEnabled : TCP_BOOLEAN_OPTIONAL.TcpBoolOptDisabled; + return SafeHGlobalHandle.CreateFromStructure(new TCP_ESTATS_BANDWIDTH_RW_v0 { EnableCollectionInbound = operation, EnableCollectionOutbound = operation }); + case TCP_ESTATS_TYPE.TcpConnectionEstatsFineRtt: + return SafeHGlobalHandle.CreateFromStructure(new TCP_ESTATS_FINE_RTT_RW_v0 { EnableCollection = enable }); + default: + return null; + } + } + + private static string GetStats(object rw) + { + var sb = new StringBuilder(); + foreach (var fi in rw.GetType().GetFields()) + sb.AppendLine($"{rw.GetType().Name}.{fi.Name} = {fi.GetValue(rw)}"); + return sb.ToString(); + } + + private static void ToggleAllEstats(in MIB_TCP6ROW row, bool enable) + { + foreach (TCP_ESTATS_TYPE type in Enum.GetValues(typeof(TCP_ESTATS_TYPE))) + { + using (var mem = GetRwForType(type, enable)) + if (mem != null) + SetPerTcp6ConnectionEStats(row, type, (IntPtr)mem, 0, (uint)mem.Size, 0); + } + } + + private static void ToggleAllEstats(in MIB_TCPROW row, bool enable) + { + foreach (TCP_ESTATS_TYPE type in Enum.GetValues(typeof(TCP_ESTATS_TYPE))) + { + using (var mem = GetRwForType(type, enable)) + if (mem != null) + SetPerTcpConnectionEStats(row, type, (IntPtr)mem, 0, (uint)mem.Size, 0); + } + } + + //[Test] -- BROKEN + private void BrokenGetPerTcp6ConnectionEStatsTest() + { + CreateTcpConnection(true, out var serviceSocket, out var clientSocket, out var acceptSocket, out var serverPort, out var clientPort).ThrowIfFailed(); + var serverConnectRow = GetTcp6Row(serverPort, clientPort, MIB_TCP_STATE.MIB_TCP_STATE_ESTAB); + var clientConnectRow = GetTcp6Row(clientPort, serverPort, MIB_TCP_STATE.MIB_TCP_STATE_ESTAB); + ToggleAllEstats(serverConnectRow, true); + ToggleAllEstats(clientConnectRow, true); + foreach (TCP_ESTATS_TYPE type in Enum.GetValues(typeof(TCP_ESTATS_TYPE))) + { + if (type == TCP_ESTATS_TYPE.TcpConnectionEstatsSynOpts) continue; + Assert.That(GetPerTcp6ConnectionEStats(serverConnectRow, type, out var srw, out _, out _), Is.Zero); + Console.Write(GetStats(srw)); + Assert.That(GetPerTcp6ConnectionEStats(clientConnectRow, type, out var crw, out _, out _), Is.Zero); + Console.Write(GetStats(crw)); + } + } + private MIB_TCP6ROW GetTcp6Row(ushort localPort, ushort remotePort, MIB_TCP_STATE state) => + GetTcp6Table(true).First(r => r.dwLocalPort == localPort && r.dwRemotePort == remotePort && r.dwState == state); + + private MIB_TCPROW GetTcpRow(ushort localPort, ushort remotePort, MIB_TCP_STATE state) => + GetTcpTable(true).First(r => r.dwLocalPort == localPort && r.dwRemotePort == remotePort && r.dwState == state); } -} - \ No newline at end of file +} \ No newline at end of file diff --git a/UnitTests/PInvoke/IpHlpApi/NetIOApiTests.cs b/UnitTests/PInvoke/IpHlpApi/NetIOApiTests.cs new file mode 100644 index 00000000..70e7a93e --- /dev/null +++ b/UnitTests/PInvoke/IpHlpApi/NetIOApiTests.cs @@ -0,0 +1,545 @@ +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using static Vanara.PInvoke.IpHlpApi; +using static Vanara.PInvoke.Ws2_32; + +#pragma warning disable CS0618 // Type or member is obsolete + +namespace Vanara.PInvoke.Tests +{ + public partial class IpHlpApiTests + { + [Test] + public void ConversionTests() + { + var luid = primaryAdapter.Luid; + const int sblen = 1024; + var sb = new StringBuilder(sblen, sblen); + + Assert.That(ConvertInterfaceLuidToAlias(luid, sb, sblen), Is.Zero); + Assert.That(sb.ToString(), Is.EqualTo(primaryAdapter.FriendlyName)); + var alias = sb.ToString(); + TestContext.WriteLine($"LUID=>Alias = {alias}"); + + Assert.That(ConvertInterfaceLuidToGuid(luid, out var ifGuid), Is.Zero); + Assert.That(ifGuid, Is.EqualTo(Guid.Parse(primaryAdapter.AdapterName))); + TestContext.WriteLine($"LUID=>GUID = {ifGuid}"); + + Assert.That(ConvertInterfaceLuidToIndex(luid, out var ifIdx), Is.Zero); + Assert.That(ifIdx, Is.EqualTo(primaryAdapter.IfIndex)); + TestContext.WriteLine($"LUID=>Idx = {ifIdx}"); + + sb.Clear(); + Assert.That(ConvertInterfaceLuidToName(luid, sb, sblen), Is.Zero); + var name = sb.ToString(); + TestContext.WriteLine($"LUID=>Name = {name}"); + + Assert.That(ConvertInterfaceAliasToLuid(alias, out var luid2), Is.Zero); + Assert.That(luid2, Is.EqualTo(luid)); + + Assert.That(ConvertInterfaceGuidToLuid(ifGuid, out luid2), Is.Zero); + Assert.That(luid2, Is.EqualTo(luid)); + + Assert.That(ConvertInterfaceIndexToLuid(ifIdx, out luid2), Is.Zero); + Assert.That(luid2, Is.EqualTo(luid)); + + Assert.That(ConvertInterfaceNameToLuid(name, out luid2), Is.Zero); + Assert.That(luid2, Is.EqualTo(luid)); + + uint mask = 0x00FFFFFF; // 255.255.255.0 + Assert.That(ConvertIpv4MaskToLength(mask, out var maskLen), Is.Zero); + Assert.That(maskLen, Is.EqualTo(24)); + Assert.That(ConvertLengthToIpv4Mask(maskLen, out var mask2), Is.Zero); + Assert.That(mask2, Is.EqualTo(mask)); + } + + [Test] + public void CreateGetDeleteAnycastIpAddressEntryTest() + { + var mibrow = new MIB_ANYCASTIPADDRESS_ROW(GetV6Addr(), primaryAdapter.Luid); + Assert.That(GetAnycastIpAddressTable(ADDRESS_FAMILY.AF_INET6, out var t1), Is.Zero); + if (t1.Contains(mibrow)) + Assert.That(DeleteAnycastIpAddressEntry(ref mibrow), Is.Zero); + + Assert.That(CreateAnycastIpAddressEntry(ref mibrow), Is.Zero); + GetAnycastIpAddressTable(ADDRESS_FAMILY.AF_INET6, out var t2); + Assert.That(t2, Has.Member(mibrow)); + + Assert.That(GetAnycastIpAddressEntry(ref mibrow), Is.Zero); + + Assert.That(DeleteAnycastIpAddressEntry(ref mibrow), Is.Zero); + GetAnycastIpAddressTable(ADDRESS_FAMILY.AF_INET6, out var t3); + Assert.That(t3, Has.No.Member(mibrow)); + } + + [Test] + public void CreateSetDeleteIpForwardEntry2Test() + { + var mibrow = new MIB_IPFORWARD_ROW2(new IP_ADDRESS_PREFIX((SOCKADDR_IN6)IN6_ADDR.Unspecified, 128), GetV6Addr(), primaryAdapter.Luid) + { + Protocol = MIB_IPFORWARD_PROTO.MIB_IPPROTO_NETMGMT, + Metric = 1 + }; + DeleteIpForwardEntry2(ref mibrow); + + Assert.That(CreateIpForwardEntry2(ref mibrow), Is.Zero); + + mibrow.PreferredLifetime = 500000; + Assert.That(SetIpForwardEntry2(mibrow), Is.Zero); + Assert.That(GetIpForwardEntry2(ref mibrow), Is.Zero); + + Assert.That(DeleteIpForwardEntry2(ref mibrow), Is.Zero); + } + + [Test] + public void CreateSetDeleteIpNetEntry2Test() + { + var target = new IN_ADDR(192, 168, 0, 202); + Assert.That(GetBestRoute(target, 0, out var fwdRow), Is.Zero); + var mibrow = new MIB_IPNET_ROW2(new SOCKADDR_IN(target), fwdRow.dwForwardIfIndex, SendARP(target)); + Assert.That(GetIpNetTable2(ADDRESS_FAMILY.AF_INET, out var t1), Is.Zero); + if (HasVal(t1, mibrow)) + Assert.That(DeleteIpNetEntry2(ref mibrow), Is.Zero); + + Assert.That(CreateIpNetEntry2(ref mibrow), Is.Zero); + GetIpNetTable2(ADDRESS_FAMILY.AF_INET, out var t2); + Assert.That(HasVal(t2, mibrow), Is.True); + + Assert.That(DeleteIpNetEntry2(ref mibrow), Is.Zero); + GetIpNetTable2(ADDRESS_FAMILY.AF_INET, out var t3); + Assert.That(HasVal(t3, mibrow), Is.False); + + bool HasVal(IEnumerable t, MIB_IPNET_ROW2 r) => + t.Any(tr => tr.Address.Ipv4.sin_addr == r.Address.Ipv4.sin_addr && tr.InterfaceIndex == r.InterfaceIndex && tr.PhysicalAddress.SequenceEqual(r.PhysicalAddress)); + } + + [Test] + public void CreateSetGetDeleteUnicastIpAddressEntryTest() + { + Assert.That(GetUnicastIpAddressTable(ADDRESS_FAMILY.AF_INET6, out var t1), Is.Zero); + var mibrow = t1.First(); + Assert.That(DeleteUnicastIpAddressEntry(ref mibrow), Is.Zero); + + Assert.That(CreateUnicastIpAddressEntry(ref mibrow), Is.Zero); + GetUnicastIpAddressTable(ADDRESS_FAMILY.AF_INET6, out var t2); + Assert.That(t2, Has.Member(mibrow)); + + mibrow.PreferredLifetime = 500000; + Assert.That(SetUnicastIpAddressEntry(mibrow), Is.Zero); + Assert.That(GetUnicastIpAddressEntry(ref mibrow), Is.Zero); + + Assert.That(DeleteUnicastIpAddressEntry(ref mibrow), Is.Zero); + GetUnicastIpAddressTable(ADDRESS_FAMILY.AF_INET6, out var t4); + Assert.That(t4, Has.No.Member(mibrow)); + } + + [Test] + public void CreateSortedAddressPairsTest() + { + var dest = primaryAdapter.MulticastAddresses.Select(ma => ma.Address.GetSOCKADDR().Ipv6).ToArray(); + TestContext.WriteLine(string.Join("\r\n", dest)); + SOCKADDR_IN6_PAIR_NATIVE[] result = null; + Assert.That(() => result = CreateSortedAddressPairs(dest), Throws.Nothing); + TestContext.WriteLine("\r\n" + string.Join("\r\n", result)); + Assert.That(result, Has.Length.GreaterThan(0)); + } + + [Test] + public void FlushIpNetTable2Test() + { + Assert.That(FlushIpNetTable2(ADDRESS_FAMILY.AF_INET6, primaryAdapter.IfIndex), Is.Zero); + } + + [Test] + public void FlushIpPathTableTest() + { + Assert.That(FlushIpPathTable(ADDRESS_FAMILY.AF_INET6), Is.Zero); + } + + [Test] + public void GetAnycastIpAddressEntryTableTest() + { + Assert.That(GetAnycastIpAddressTable(ADDRESS_FAMILY.AF_UNSPEC, out var table), Is.Zero); + Assert.That(table.NumEntries, Is.Zero); + + var row = new MIB_ANYCASTIPADDRESS_ROW(); + Assert.That(GetAnycastIpAddressEntry(ref row), Is.Not.Zero); + } + + [Test] + public void GetBestRoute2Test() + { + var addr = new SOCKADDR_INET { Ipv4 = new SOCKADDR_IN(new IN_ADDR(192, 168, 0, 202)) }; + Assert.That(GetBestRoute2(IntPtr.Zero, primaryAdapter.IfIndex, IntPtr.Zero, addr, 0, out var rt, out var src), Is.Zero); + Assert.That(rt.InterfaceIndex, Is.EqualTo(primaryAdapter.IfIndex)); + Assert.That(src.Ipv4.sin_addr, Is.EqualTo(new IN_ADDR(192, 168, 0, 203))); + } + + [Test] + public void GetIfEntry2ExTest() + { + var row = new MIB_IF_ROW2(primaryAdapter.IfIndex); + Assert.That(GetIfEntry2Ex(MIB_IF_ENTRY_LEVEL.MibIfEntryNormalWithoutStatistics, ref row), Is.Zero); + Assert.That(row.InterfaceLuid, Is.EqualTo(primaryAdapter.Luid)); + } + + [Test] + public void GetIfEntry2Test() + { + var row = new MIB_IF_ROW2(primaryAdapter.IfIndex); + Assert.That(GetIfEntry2(ref row), Is.Zero); + Assert.That(row.InterfaceLuid, Is.EqualTo(primaryAdapter.Luid)); + } + + [Test] + public void GetIfStackTableTest() + { + Assert.That(GetIfStackTable(out var table), Is.Zero); + Assert.That(table.NumEntries, Is.GreaterThan(0)); + Assert.That(() => table.Table, Throws.Nothing); + } + + [Test] + public void GetIfTable2ExTest() + { + var e = GetIfTable2Ex(MIB_IF_TABLE_LEVEL.MibIfTableNormal, out var itbl); + Assert.That(e.Succeeded); + Assert.That(itbl.Table, Is.Not.Empty); + itbl.Dispose(); + Assert.That(itbl.IsInvalid); + } + + [Test] + public void GetIfTable2Test() + { + var e = GetIfTable2(out var itbl); + Assert.That(e.Succeeded); + Assert.That(itbl.Table, Is.Not.Empty); + itbl.Dispose(); + Assert.That(itbl.IsInvalid); + } + + [Test] + public void GetInvertedIfStackTableTest() + { + Assert.That(GetInvertedIfStackTable(out var table), Is.Zero); + Assert.That(table.NumEntries, Is.GreaterThan(0)); + Assert.That(() => table.Table, Throws.Nothing); + } + + [Test] + public void GetIpForwardEntryTable2Test() + { + Assert.That(GetIpForwardTable2(ADDRESS_FAMILY.AF_UNSPEC, out var table), Is.Zero); + Assert.That(table.NumEntries, Is.GreaterThan(0)); + Assert.That(() => table.Table, Throws.Nothing); + + var goodRow = table.Table[0]; + var row = new MIB_IPFORWARD_ROW2 { DestinationPrefix = goodRow.DestinationPrefix, NextHop = goodRow.NextHop, InterfaceLuid = goodRow.InterfaceLuid }; + Assert.That(GetIpForwardEntry2(ref row), Is.Zero); + Assert.That(row.InterfaceIndex, Is.Not.Zero.And.EqualTo(goodRow.InterfaceIndex)); + } + + [Test] + public void GetIpInterfaceEntryTableTest() + { + Assert.That(GetIpInterfaceTable(ADDRESS_FAMILY.AF_UNSPEC, out var table), Is.Zero); + Assert.That(table.NumEntries, Is.GreaterThan(0)); + Assert.That(() => table.Table, Throws.Nothing); + + var goodRow = table.Table[0]; + var row = new MIB_IPINTERFACE_ROW { Family = goodRow.Family, InterfaceLuid = goodRow.InterfaceLuid }; + Assert.That(GetIpInterfaceEntry(ref row), Is.Zero); + Assert.That(row.InterfaceIndex, Is.Not.Zero.And.EqualTo(goodRow.InterfaceIndex)); + } + + [Test] + public void GetIpNetworkConnectionBandwidthEstimatesTest() + { + Assert.That(GetIpNetworkConnectionBandwidthEstimates(primaryAdapter.IfIndex, ADDRESS_FAMILY.AF_INET, out var est), Is.Zero); + Assert.That(est.InboundBandwidthInformation.Bandwidth, Is.GreaterThan(0)); + Assert.That(est.OutboundBandwidthInformation.Bandwidth, Is.GreaterThan(0)); + } + + [Test] + public void GetIpPathEntryTableTest() + { + Assert.That(GetIpPathTable(ADDRESS_FAMILY.AF_UNSPEC, out var table), Is.Zero); + Assert.That(table.NumEntries, Is.GreaterThan(0)); + Assert.That(() => table.Table, Throws.Nothing); + + var goodRow = table.Table[0]; + var row = new MIB_IPPATH_ROW { Destination = goodRow.Destination, InterfaceLuid = goodRow.InterfaceLuid }; + Assert.That(GetIpPathEntry(ref row), Is.Zero); + Assert.That((int)row.Source.si_family, Is.Not.Zero); + } + + [Test] + public void GetMulticastIpAddressEntryTableTest() + { + Assert.That(GetMulticastIpAddressTable(ADDRESS_FAMILY.AF_UNSPEC, out var table), Is.Zero); + Assert.That(table.NumEntries, Is.GreaterThan(0)); + Assert.That(() => table.Table, Throws.Nothing); + + var goodRow = table.Table[0]; + var row = new MIB_MULTICASTIPADDRESS_ROW { Address = goodRow.Address, InterfaceLuid = goodRow.InterfaceLuid }; + Assert.That(GetMulticastIpAddressEntry(ref row), Is.Zero); + Assert.That(row.InterfaceIndex, Is.Not.Zero.And.EqualTo(goodRow.InterfaceIndex)); + } + + [Test] + public void GetSetIpInterfaceEntryTest() + { + var mibrow = new MIB_IPINTERFACE_ROW(ADDRESS_FAMILY.AF_INET, primaryAdapter.Luid); + Assert.That(GetIpInterfaceEntry(ref mibrow), Is.Zero); + var prev = mibrow.SitePrefixLength; + mibrow.SitePrefixLength = 0; + Assert.That(SetIpInterfaceEntry(mibrow), Is.Zero); + + mibrow = new MIB_IPINTERFACE_ROW(ADDRESS_FAMILY.AF_INET, primaryAdapter.Luid); + Assert.That(GetIpInterfaceEntry(ref mibrow), Is.Zero); + Assert.That(mibrow.PathMtuDiscoveryTimeout, Is.EqualTo(600000)); + + mibrow.SitePrefixLength = prev; + Assert.That(SetIpInterfaceEntry(mibrow), Is.Zero); + } + + [Test] + public void GetSetIpNetEntryTable2Test() + { + Assert.That(GetIpNetTable2(ADDRESS_FAMILY.AF_UNSPEC, out var table), Is.Zero); + Assert.That(table.NumEntries, Is.GreaterThan(0)); + Assert.That(() => table.Table, Throws.Nothing); + + var goodRow = table.Table[0]; + var row = new MIB_IPNET_ROW2 { Address = goodRow.Address, InterfaceLuid = goodRow.InterfaceLuid }; + Assert.That(GetIpNetEntry2(ref row), Is.Zero); + Assert.That(row.InterfaceIndex, Is.Not.Zero.And.EqualTo(goodRow.InterfaceIndex)); + + row = new MIB_IPNET_ROW2 { Address = primaryAdapter.MulticastAddresses.First().Address.GetSOCKADDR(), InterfaceIndex = primaryAdapter.IfIndex }; + Assert.That(() => SetIpNetEntry2(row), Throws.Nothing); // This call always fails w/ ERROR_NOT_FOUND, but it works + } + + [Test] + public void GetTeredoPortTest() + { + Assert.That(GetTeredoPort(out var port), Is.Zero.Or.EqualTo(Win32Error.ERROR_NOT_READY)); + } + + [Test] + public void GetUnicastIpAddressEntryTableTest() + { + Assert.That(GetUnicastIpAddressTable(ADDRESS_FAMILY.AF_UNSPEC, out var table), Is.Zero); + Assert.That(table.NumEntries, Is.GreaterThan(0)); + Assert.That(() => table.Table, Throws.Nothing); + + var goodRow = table.Table[0]; + var row = new MIB_UNICASTIPADDRESS_ROW { Address = goodRow.Address, InterfaceLuid = goodRow.InterfaceLuid }; + Assert.That(GetUnicastIpAddressEntry(ref row), Is.Zero); + Assert.That(row.CreationTimeStamp, Is.Not.Zero.And.EqualTo(goodRow.CreationTimeStamp)); + } + + [Test] + public void if_indextonameANDif_nametoindexTest() + { + var sb = new StringBuilder(IF_MAX_STRING_SIZE, IF_MAX_STRING_SIZE); + Assert.That(if_indextoname(primaryAdapter.IfIndex, sb), Is.Not.EqualTo(IntPtr.Zero)); + TestContext.WriteLine(sb); + Assert.That(if_nametoindex(sb.ToString()), Is.EqualTo(primaryAdapter.IfIndex)); + } + + [Test] + public void InitializeIpForwardEntryTest() + { + InitializeIpForwardEntry(out var entry); + Assert.That(entry.ValidLifetime, Is.Not.Zero); + Assert.That(entry.Loopback, Is.True); + } + + [Test] + public void InitializeIpInterfaceEntryTest() + { + InitializeIpInterfaceEntry(out var entry); + Assert.That((int)entry.Family, Is.Zero); + Assert.That(entry.InterfaceIdentifier, Is.Not.Zero); + Assert.That(entry.SupportsNeighborDiscovery, Is.True); + } + + [Test] + public void InitializeUnicastIpAddressEntryTest() + { + InitializeUnicastIpAddressEntry(out var entry); + Assert.That(entry.ValidLifetime, Is.Not.Zero); + Assert.That(entry.PrefixOrigin, Is.EqualTo(NL_PREFIX_ORIGIN.IpPrefixOriginUnchanged)); + } + + [Test] + public void NotifyIpInterfaceChangeTest() + { + var fired = new ManualResetEvent(false); + var done = new ManualResetEvent(false); + new Thread(() => + { + try + { + Assert.That(NotifyIpInterfaceChange(ADDRESS_FAMILY.AF_UNSPEC, NotifyFunc, NotifyData, true, out var hNot), Is.Zero); + fired.WaitOne(3000); + Assert.That(CancelMibChangeNotify2(hNot), Is.Zero); + } + finally + { + done.Set(); + } + }).Start(); + Assert.That(done.WaitOne(5000), Is.True); + + void NotifyFunc(IntPtr CallerContext, IntPtr Row, MIB_NOTIFICATION_TYPE NotificationType) + { + Assert.That(CallerContext, Is.EqualTo(NotifyData)); + TestContext.WriteLine(Row.ToString()); + Assert.That(NotificationType, Is.EqualTo(MIB_NOTIFICATION_TYPE.MibInitialNotification)); + fired.Set(); + } + } + + [Test] + public void NotifyRouteChange2Test() + { + var fired = new ManualResetEvent(false); + var done = new ManualResetEvent(false); + new Thread(() => + { + try + { + Assert.That(NotifyRouteChange2(ADDRESS_FAMILY.AF_UNSPEC, NotifyFunc, NotifyData, true, out var hNot), Is.Zero); + fired.WaitOne(3000); + Assert.That(CancelMibChangeNotify2(hNot), Is.Zero); + } + finally + { + done.Set(); + } + }).Start(); + Assert.That(done.WaitOne(5000), Is.True); + + void NotifyFunc(IntPtr CallerContext, ref MIB_IPFORWARD_ROW2 Row, MIB_NOTIFICATION_TYPE NotificationType) + { + Assert.That(CallerContext, Is.EqualTo(NotifyData)); + TestContext.WriteLine(Row.ToString()); + Assert.That(NotificationType, Is.EqualTo(MIB_NOTIFICATION_TYPE.MibInitialNotification)); + fired.Set(); + } + } + + [Test] + public void NotifyStableUnicastIpAddressTableTest() + { + var fired = new ManualResetEvent(false); + var done = new ManualResetEvent(false); + new Thread(() => + { + try + { + Assert.That(NotifyStableUnicastIpAddressTable(ADDRESS_FAMILY.AF_UNSPEC, out var table, NotifyFunc, NotifyData, out var hNot), Is.Zero.Or.EqualTo(Win32Error.ERROR_IO_PENDING)); + if (table == IntPtr.Zero) + { + fired.WaitOne(3000); + Assert.That(CancelMibChangeNotify2(hNot), Is.Zero); + } + } + finally + { + done.Set(); + } + }).Start(); + Assert.That(done.WaitOne(5000), Is.True); + + void NotifyFunc(IntPtr CallerContext, IntPtr Table) + { + Assert.That(CallerContext, Is.EqualTo(NotifyData)); + TestContext.WriteLine(Table.ToString()); + fired.Set(); + } + } + + [Test] + public void NotifyTeredoPortChangeTest() + { + var fired = new ManualResetEvent(false); + var done = new ManualResetEvent(false); + new Thread(() => + { + try + { + Assert.That(NotifyTeredoPortChange(NotifyFunc, NotifyData, true, out var hNot), Is.Zero); + fired.WaitOne(3000); + Assert.That(CancelMibChangeNotify2(hNot), Is.Zero); + } + finally + { + done.Set(); + } + }).Start(); + Assert.That(done.WaitOne(5000), Is.True); + + void NotifyFunc(IntPtr CallerContext, ushort Port, MIB_NOTIFICATION_TYPE NotificationType) + { + Assert.That(CallerContext, Is.EqualTo(NotifyData)); + TestContext.WriteLine(Port.ToString()); + Assert.That(NotificationType, Is.EqualTo(MIB_NOTIFICATION_TYPE.MibInitialNotification)); + fired.Set(); + } + } + + [Test] + public void NotifyUnicastIpAddressChangeTest() + { + var fired = new ManualResetEvent(false); + var done = new ManualResetEvent(false); + new Thread(() => + { + try + { + Assert.That(NotifyUnicastIpAddressChange(ADDRESS_FAMILY.AF_UNSPEC, NotifyFunc, NotifyData, true, out var hNot), Is.Zero); + fired.WaitOne(3000); + Assert.That(CancelMibChangeNotify2(hNot), Is.Zero); + } + finally + { + done.Set(); + } + }).Start(); + Assert.That(done.WaitOne(5000), Is.True); + + void NotifyFunc(IntPtr CallerContext, IntPtr Row, MIB_NOTIFICATION_TYPE NotificationType) + { + Assert.That(CallerContext, Is.EqualTo(NotifyData)); + TestContext.WriteLine(Row.ToString()); + Assert.That(NotificationType, Is.EqualTo(MIB_NOTIFICATION_TYPE.MibInitialNotification)); + fired.Set(); + } + } + + [Test] + public void ResolveIpNetEntry2Test() + { + var e = new MIB_IPNET_ROW2(new SOCKADDR_IN(new IN_ADDR(192, 168, 0, 202)), primaryAdapter.IfIndex); + Assert.That(ResolveIpNetEntry2(ref e), Is.Zero); + Assert.That(e.State, Is.EqualTo(NL_NEIGHBOR_STATE.NlnsReachable)); + } + + [Test] + public void FutureUseTest() + { + Assert.That(SetCurrentThreadCompartmentId(1), Is.GreaterThanOrEqualTo(0)); + Assert.That(SetNetworkInformation(Guid.NewGuid(), 1, "Fred"), Is.GreaterThanOrEqualTo(0)); + Assert.That(SetSessionCompartmentId(1, 1), Is.GreaterThanOrEqualTo(0)); + } + + private SOCKADDR_IN6 GetV6Addr() => new SOCKADDR_IN6(new IN6_ADDR(new byte[] { 0xfe, 0x3f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x20, 0x00 }), 0); + } +} \ No newline at end of file