mirror of https://github.com/dahall/Vanara.git
commit
26f61b9189
|
@ -54,6 +54,24 @@ namespace Vanara.Extensions
|
|||
}
|
||||
#endif
|
||||
|
||||
/// <summary>Returns the pointer.</summary>
|
||||
/// <typeparam name="T">The type of items.</typeparam>
|
||||
/// <param name="ptr">A pointer to the starting address of a specified number of <typeparamref name="T"/> elements in memory.</param>
|
||||
/// <param name="length">The number of <typeparamref name="T"/> elements to be included in the pointer.</param>
|
||||
/// <param name="prefixBytes">Bytes to skip before starting the span.</param>
|
||||
/// <param name="allocatedBytes">If known, the total number of bytes allocated to the native memory in <paramref name="ptr"/>.</param>
|
||||
/// <returns>A pointer that represents the memory.</returns>
|
||||
/// <exception cref="System.InsufficientMemoryException"></exception>
|
||||
public static unsafe T* AsUnmanagedArrayPointer<T>(this IntPtr ptr, int length, int prefixBytes = 0, SizeT allocatedBytes = default) where T : unmanaged
|
||||
{
|
||||
if (ptr == IntPtr.Zero) return null;
|
||||
if (length < 0) throw new ArgumentOutOfRangeException(nameof(length));
|
||||
if (allocatedBytes > 0 && SizeOf<T>() * length + prefixBytes > allocatedBytes)
|
||||
throw new InsufficientMemoryException();
|
||||
|
||||
return (T*)ptr.Offset(prefixBytes).ToPointer();
|
||||
}
|
||||
|
||||
/// <summary>Copies the number of specified bytes from one unmanaged memory block to another.</summary>
|
||||
/// <param name="ptr">The allocated memory pointer.</param>
|
||||
/// <param name="dest">The allocated memory pointer to copy to.</param>
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Vanara.PInvoke
|
||||
{
|
||||
/// <summary>
|
||||
/// Enumerator with zero copy access using ref.
|
||||
/// </summary>
|
||||
public unsafe ref struct RefEnumerator<T> where T : unmanaged
|
||||
{
|
||||
private T* _arrayPtr;
|
||||
private readonly int _count;
|
||||
private int _index;
|
||||
|
||||
/// <summary>
|
||||
/// Create RefEnumerator.
|
||||
/// </summary>
|
||||
/// <param name="arrayPtr">Pointer to unmanaged array</param>
|
||||
/// <param name="count">Number of elements in the <paramref name="arrayPtr"/></param>
|
||||
public RefEnumerator(T* arrayPtr, int count)
|
||||
{
|
||||
_arrayPtr = arrayPtr;
|
||||
_count = count;
|
||||
_index = -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Move to next element.
|
||||
/// </summary>
|
||||
public bool MoveNext()
|
||||
{
|
||||
int index = _index + 1;
|
||||
if (index < _count)
|
||||
{
|
||||
_index = index;
|
||||
_arrayPtr++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return current element.
|
||||
/// </summary>
|
||||
public ref T Current => ref *_arrayPtr;
|
||||
}
|
||||
}
|
|
@ -7801,6 +7801,9 @@ namespace Vanara.PInvoke
|
|||
/// <returns>Dashed hex value string representation of a Physical Address (MAC).</returns>
|
||||
public static string PhysicalAddressToString(byte[] physAddr) => $"{physAddr[0]:X}-{physAddr[1]:X}-{physAddr[2]:X}-{physAddr[3]:X}-{physAddr[4]:X}-{physAddr[5]:X}";
|
||||
|
||||
/// <inheritdoc cref="PhysicalAddressToString(byte[])"/>
|
||||
public static unsafe string PhysicalAddressToString(byte* physAddr) => $"{physAddr[0]:X}-{physAddr[1]:X}-{physAddr[2]:X}-{physAddr[3]:X}-{physAddr[4]:X}-{physAddr[5]:X}";
|
||||
|
||||
/// <summary>
|
||||
/// The <c>RestoreMediaSense</c> function restores the media sensing capability of the TCP/IP stack on a local computer on which the
|
||||
/// DisableMediaSense function was previously called.
|
||||
|
|
|
@ -3365,6 +3365,14 @@ namespace Vanara.PInvoke
|
|||
[PInvokeData("netioapi.h", MSDNShortId = "6c45d735-9a07-41ca-8d8a-919f32c98a3c")]
|
||||
public static extern Win32Error GetIpNetTable2(ADDRESS_FAMILY Family, out MIB_IPNET_TABLE2 Table);
|
||||
|
||||
/// <inheritdoc cref="GetIpNetTable2"/>
|
||||
/// <remarks>Unlike <see cref="GetIpNetTable2"/> this returns structure with zero copy.</remarks>
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-getipnettable2 _NETIOAPI_SUCCESS_ NETIOAPI_API
|
||||
// GetIpNetTable2( ADDRESS_FAMILY Family, PMIB_IPNET_TABLE2 *Table );
|
||||
[DllImport(Lib.IpHlpApi, SetLastError = false, ExactSpelling = true, EntryPoint = "GetIpNetTable2")]
|
||||
[PInvokeData("netioapi.h", MSDNShortId = "6c45d735-9a07-41ca-8d8a-919f32c98a3c")]
|
||||
public static extern Win32Error GetIpNetTable2_Unmanaged(ADDRESS_FAMILY Family, out MIB_IPNET_TABLE2_Unmanaged Table);
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// The <c>GetIpNetworkConnectionBandwidthEstimates</c> function retrieves historical bandwidth estimates for a network connection on
|
||||
|
@ -6975,6 +6983,203 @@ namespace Vanara.PInvoke
|
|||
public override string ToString() => $"{Address}; MAC:{PhysicalAddressToString(PhysicalAddress)}; If:{(InterfaceIndex != 0 ? InterfaceIndex.ToString() : InterfaceLuid.ToString())}";
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="MIB_IPNET_ROW2"/>
|
||||
/// <remarks>Unlike <see cref="MIB_IPNET_ROW2"/> this structure is zero copy</remarks>
|
||||
[PInvokeData("netioapi.h", MSDNShortId = "164dbd93-4464-40f9-989a-17597102b1d8")]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 2)]
|
||||
public unsafe struct MIB_IPNET_ROW2_Unmanaged
|
||||
{
|
||||
/// <summary>
|
||||
/// <para>Type: <c>SOCKADDR_INET</c></para>
|
||||
/// <para>The neighbor IP address. This member can be an IPv6 address or an IPv4 address.</para>
|
||||
/// </summary>
|
||||
public SOCKADDR_INET Address;
|
||||
|
||||
/// <summary>
|
||||
/// <para>Type: <c>NET_IFINDEX</c></para>
|
||||
/// <para>
|
||||
/// The local index value for the network interface associated with this IP address. This index value may change when a network
|
||||
/// adapter is disabled and then enabled, or under other circumstances, and should not be considered persistent.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public uint InterfaceIndex;
|
||||
|
||||
/// <summary>
|
||||
/// <para>Type: <c>NET_LUID</c></para>
|
||||
/// <para>The locally unique identifier (LUID) for the network interface associated with this IP address.</para>
|
||||
/// </summary>
|
||||
public NET_LUID InterfaceLuid;
|
||||
|
||||
/// <summary>
|
||||
/// <para>Type: <c>UCHAR[IF_MAX_PHYS_ADDRESS_LENGTH]</c></para>
|
||||
/// <para>The physical hardware address of the adapter for the network interface associated with this IP address.</para>
|
||||
/// </summary>
|
||||
public fixed byte PhysicalAddress[IF_MAX_PHYS_ADDRESS_LENGTH];
|
||||
|
||||
/// <summary>
|
||||
/// <para>Type: <c>ULONG</c></para>
|
||||
/// <para>
|
||||
/// The length, in bytes, of the physical hardware address specified by the <c>PhysicalAddress</c> member. The maximum value
|
||||
/// supported is 32 bytes.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public uint PhysicalAddressLength;
|
||||
|
||||
/// <summary>
|
||||
/// <para>Type: <c>NL_NEIGHBOR_STATE</c></para>
|
||||
/// <para>
|
||||
/// The state of a network neighbor IP address as defined in RFC 2461, section 7.3.2. For more information, see
|
||||
/// http://www.ietf.org/rfc/rfc2461.txt. This member can be one of the values from the <c>NL_NEIGHBOR_STATE</c> enumeration type
|
||||
/// defined in the Nldef.h header file.
|
||||
/// </para>
|
||||
/// <list type="table">
|
||||
/// <listheader>
|
||||
/// <term>Value</term>
|
||||
/// <term>Meaning</term>
|
||||
/// </listheader>
|
||||
/// <item>
|
||||
/// <term>NlnsUnreachable</term>
|
||||
/// <term>The IP address is unreachable.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>NlnsIncomplete</term>
|
||||
/// <term>
|
||||
/// Address resolution is in progress and the link-layer address of the neighbor has not yet been determined. Specifically for
|
||||
/// IPv6, a Neighbor Solicitation has been sent to the solicited-node multicast IP address of the target, but the corresponding
|
||||
/// neighbor advertisement has not yet been received.
|
||||
/// </term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>NlnsProbe</term>
|
||||
/// <term>
|
||||
/// The neighbor is no longer known to be reachable, and probes are being sent to verify reachability. For IPv6, a reachability
|
||||
/// confirmation is actively being sought by retransmitting unicast Neighbor Solicitation probes at regular intervals until a
|
||||
/// reachability confirmation is received.
|
||||
/// </term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>NlnsDelay</term>
|
||||
/// <term>
|
||||
/// The neighbor is no longer known to be reachable, and traffic has recently been sent to the neighbor. Rather than probe the
|
||||
/// neighbor immediately, however, delay sending probes for a short while in order to give upper layer protocols a chance to
|
||||
/// provide reachability confirmation. For IPv6, more time has elapsed than is specified in the ReachabilityTime.ReachableTime
|
||||
/// member since the last positive confirmation was received that the forward path was functioning properly and a packet was
|
||||
/// sent. If no reachability confirmation is received within a period of time (used to delay the first probe) of entering the
|
||||
/// NlnsDelay state, then a neighbor solicitation is sent and the State member is changed to NlnsProbe.
|
||||
/// </term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>NlnsStale</term>
|
||||
/// <term>
|
||||
/// The neighbor is no longer known to be reachable but until traffic is sent to the neighbor, no attempt should be made to
|
||||
/// verify its reachability. For IPv6, more time has elapsed than is specified in the ReachabilityTime.ReachableTime member since
|
||||
/// the last positive confirmation was received that the forward path was functioning properly. While the State is NlnsStale, no
|
||||
/// action takes place until a packet is sent. The NlnsStale state is entered upon receiving an unsolicited neighbor discovery
|
||||
/// message that updates the cached IP address. Receipt of such a message does not confirm reachability, and entering the
|
||||
/// NlnsStale state insures reachability is verified quickly if the entry is actually being used. However, reachability is not
|
||||
/// actually verified until the entry is actually used.
|
||||
/// </term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>NlnsReachable</term>
|
||||
/// <term>
|
||||
/// The neighbor is known to have been reachable recently (within tens of seconds ago). For IPv6, a positive confirmation was
|
||||
/// received within the time specified in the ReachabilityTime.ReachableTime member that the forward path to the neighbor was
|
||||
/// functioning properly. While the State is NlnsReachable, no special action takes place as packets are sent.
|
||||
/// </term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>NlnsPermanent</term>
|
||||
/// <term>The IP address is a permanent address.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>NlnsMaximum</term>
|
||||
/// <term>The maximum possible value for the NL_NEIGHBOR_STATE enumeration type. This is not a legal value for the State member.</term>
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public NL_NEIGHBOR_STATE State;
|
||||
|
||||
/// <summary>Undocumented.</summary>
|
||||
public MIB_IPNET_ROW2_FLAGS Flags;
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// <c>Type: <c>ULONG</c></c> The time, in milliseconds, that a node assumes a neighbor is reachable after having received a
|
||||
/// reachability confirmation or is unreachable after not having received a reachability confirmation.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public uint ReachabilityTime;
|
||||
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="MIB_IPNET_ROW2"/> struct.</summary>
|
||||
/// <param name="ipV4">The neighbor IP address.</param>
|
||||
/// <param name="ifLuid">The locally unique identifier (LUID) for the network interface associated with this IP address.</param>
|
||||
/// <param name="macAddr">The physical hardware address of the adapter for the network interface associated with this IP address.</param>
|
||||
public MIB_IPNET_ROW2_Unmanaged(SOCKADDR_IN ipV4, NET_LUID ifLuid, byte[] macAddr = null) : this(ipV4, macAddr) => InterfaceLuid = ifLuid;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="MIB_IPNET_ROW2_Unmanaged"/> struct.</summary>
|
||||
/// <param name="ipV4">The neighbor IP address.</param>
|
||||
/// <param name="ifIdx">
|
||||
/// The local index value for the network interface associated with this IP address. This index value may change when a network
|
||||
/// adapter is disabled and then enabled, or under other circumstances, and should not be considered persistent.
|
||||
/// </param>
|
||||
/// <param name="macAddr">The physical hardware address of the adapter for the network interface associated with this IP address.</param>
|
||||
public MIB_IPNET_ROW2_Unmanaged(SOCKADDR_IN ipV4, uint ifIdx, byte[] macAddr = null) : this(ipV4, macAddr) => InterfaceIndex = ifIdx;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="MIB_IPNET_ROW2_Unmanaged"/> struct.</summary>
|
||||
/// <param name="ipV6">The neighbor IP address.</param>
|
||||
/// <param name="ifLuid">The locally unique identifier (LUID) for the network interface associated with this IP address.</param>
|
||||
/// <param name="macAddr">The physical hardware address of the adapter for the network interface associated with this IP address.</param>
|
||||
public MIB_IPNET_ROW2_Unmanaged(SOCKADDR_IN6 ipV6, NET_LUID ifLuid, byte[] macAddr = null) : this(ipV6, macAddr) => InterfaceLuid = ifLuid;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="MIB_IPNET_ROW2_Unmanaged"/> struct.</summary>
|
||||
/// <param name="ipV6">The neighbor IP address.</param>
|
||||
/// <param name="ifIdx">
|
||||
/// The local index value for the network interface associated with this IP address. This index value may change when a network
|
||||
/// adapter is disabled and then enabled, or under other circumstances, and should not be considered persistent.
|
||||
/// </param>
|
||||
/// <param name="macAddr">The physical hardware address of the adapter for the network interface associated with this IP address.</param>
|
||||
public MIB_IPNET_ROW2_Unmanaged(SOCKADDR_IN6 ipV6, uint ifIdx, byte[] macAddr = null) : this(ipV6, macAddr) => InterfaceIndex = ifIdx;
|
||||
|
||||
private MIB_IPNET_ROW2_Unmanaged(SOCKADDR_IN ipV4, byte[] macAddr) : this()
|
||||
{
|
||||
Address.Ipv4 = ipV4;
|
||||
SetMac(macAddr);
|
||||
}
|
||||
|
||||
private MIB_IPNET_ROW2_Unmanaged(SOCKADDR_IN6 ipV6, byte[] macAddr) : this()
|
||||
{
|
||||
Address.Ipv6 = ipV6;
|
||||
SetMac(macAddr);
|
||||
}
|
||||
|
||||
private void SetMac(byte[] macAddr)
|
||||
{
|
||||
if (macAddr == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PhysicalAddressLength = IF_MAX_PHYS_ADDRESS_LENGTH;
|
||||
|
||||
fixed (byte* physicalAddress = PhysicalAddress)
|
||||
{
|
||||
Marshal.Copy(macAddr, 0, (IntPtr)physicalAddress, 6);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
fixed (byte* physicalAddress = PhysicalAddress)
|
||||
{
|
||||
return
|
||||
$"{Address}; MAC:{PhysicalAddressToString(physicalAddress)}; If:{(InterfaceIndex != 0 ? InterfaceIndex.ToString() : InterfaceLuid.ToString())}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>The <c>MIB_IPPATH_ROW</c> structure stores information about an IP path entry.</para>
|
||||
/// </summary>
|
||||
|
@ -7536,6 +7741,18 @@ namespace Vanara.PInvoke
|
|||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="MIB_IPNET_TABLE2"/>
|
||||
/// <remarks>Unlike <see cref="MIB_IPNET_TABLE2"/> this provides is zero copy</remarks>///
|
||||
[PInvokeData("Netioapi.h", MSDNShortId = "ff559267")]
|
||||
#if ALLOWSPAN
|
||||
[CorrespondingType(typeof(MIB_IPNET_ROW2_Unmanaged)), DefaultProperty(nameof(TableAsSpan))]
|
||||
#else
|
||||
[CorrespondingType(typeof(MIB_IPNET_ROW2_Unmanaged))]
|
||||
#endif
|
||||
public class MIB_IPNET_TABLE2_Unmanaged : SafeUnmanagedMibEntryBase<MIB_IPNET_ROW2_Unmanaged>
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>The MIB_IPPATH_TABLE structure contains a table of IP path entries.</summary>
|
||||
// typedef struct _MIB_IPPATH_TABLE { ULONG NumEntries; MIB_IPPATH_ROW Table[ANY_SIZE];} MIB_IPPATH_TABLE, *PMIB_IPPATH_TABLE; https://msdn.microsoft.com/en-us/library/windows/hardware/ff559273(v=vs.85).aspx
|
||||
[PInvokeData("Netioapi.h", MSDNShortId = "ff559273")]
|
||||
|
@ -7623,6 +7840,28 @@ namespace Vanara.PInvoke
|
|||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>Base class for all structures that support a variable length array of structures with a count in the first field.</summary>
|
||||
/// <typeparam name="T">Type of the structure array.</typeparam>
|
||||
public abstract class SafeUnmanagedMibEntryBase<T> : SafeMibTableHandle where T : unmanaged
|
||||
{
|
||||
/// <summary>Gets the number of interface entries in the array.</summary>
|
||||
public virtual uint NumEntries => IsInvalid ? 0 : handle.ToStructure<uint>();
|
||||
|
||||
/// <summary>Exposes the pointer to the array of structures.</summary>
|
||||
public unsafe T* AsUnmanagedArrayPointer() => IsInvalid ? null : handle.AsUnmanagedArrayPointer<T>((int)NumEntries, Marshal.SizeOf(typeof(ulong)));
|
||||
|
||||
#if !ALLOWSPAN
|
||||
/// <summary>Gets the enumerator.</summary>
|
||||
public unsafe RefEnumerator<T> GetEnumerator() => new RefEnumerator<T>(AsUnmanagedArrayPointer(), (int)NumEntries);
|
||||
#else
|
||||
/// <summary>Gets the enumerator.</summary>
|
||||
public Span<T>.Enumerator GetEnumerator() => TableAsSpan.GetEnumerator();
|
||||
|
||||
/// <summary>Gets the <see cref="Span{T}"/> containing interface entries.</summary>
|
||||
public virtual Span<T> TableAsSpan => AsSpan<T>((int)NumEntries, Marshal.SizeOf(typeof(ulong)));
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>SafeHandle for all objects that must be freed with FreeMibTable.</summary>
|
||||
/// <seealso cref="Vanara.InteropServices.GenericSafeHandle"/>
|
||||
public class SafeMibTableHandle : GenericSafeHandle
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
|
@ -30,6 +31,7 @@
|
|||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
|
|
|
@ -376,5 +376,19 @@ namespace Vanara.Extensions.Tests
|
|||
Assert.That(ss, Is.Null);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public unsafe void AsUnmanagedArrayPointerTest()
|
||||
{
|
||||
var h = new SafeHGlobalHandle(Marshal.SizeOf(typeof(RECT)) * 2 + i);
|
||||
var rs = new[] { new RECT(), new RECT(10, 11, 12, 13) };
|
||||
((IntPtr)h).Write(rs, i, h.Size);
|
||||
|
||||
RECT* r = h.DangerousGetHandle().AsUnmanagedArrayPointer<RECT>(Marshal.SizeOf<RECT>(), i);
|
||||
Assert.That(r->left, Is.EqualTo(10));
|
||||
Assert.That(r->top, Is.EqualTo(11));
|
||||
Assert.That(r->right, Is.EqualTo(12));
|
||||
Assert.That(r->bottom, Is.EqualTo(13));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -117,6 +117,90 @@ namespace Vanara.PInvoke.Tests
|
|||
t.Any(tr => tr.Address.Ipv4.sin_addr == r.Address.Ipv4.sin_addr && tr.InterfaceIndex == r.InterfaceIndex && tr.PhysicalAddress.SequenceEqual(r.PhysicalAddress));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public unsafe void CreateSetDeleteIpNetEntry2UnmanagedPointerTest()
|
||||
{
|
||||
var target = new IN_ADDR(192, 168, 0, 202);
|
||||
Assert.That(GetBestRoute(target, 0, out var fwdRow), ResultIs.Successful);
|
||||
var mibrow = new MIB_IPNET_ROW2(new SOCKADDR_IN(target), fwdRow.dwForwardIfIndex, SendARP(target));
|
||||
Assert.That(GetIpNetTable2_Unmanaged(ADDRESS_FAMILY.AF_INET, out var t1), ResultIs.Successful);
|
||||
if (HasVal(t1.AsUnmanagedArrayPointer(), mibrow, t1.NumEntries))
|
||||
Assert.That(DeleteIpNetEntry2(ref mibrow), ResultIs.Successful);
|
||||
|
||||
Assert.That(CreateIpNetEntry2(ref mibrow), ResultIs.Successful);
|
||||
GetIpNetTable2_Unmanaged(ADDRESS_FAMILY.AF_INET, out var t2);
|
||||
Assert.That(HasVal(t2.AsUnmanagedArrayPointer(), mibrow, t1.NumEntries), Is.True);
|
||||
|
||||
Assert.That(DeleteIpNetEntry2(ref mibrow), ResultIs.Successful);
|
||||
GetIpNetTable2_Unmanaged(ADDRESS_FAMILY.AF_INET, out var t3);
|
||||
Assert.That(HasVal(t3.AsUnmanagedArrayPointer(), mibrow, t1.NumEntries), Is.False);
|
||||
|
||||
static bool HasVal(MIB_IPNET_ROW2_Unmanaged* tr, MIB_IPNET_ROW2 r, uint numEntries)
|
||||
{
|
||||
for (uint i = 0; i < numEntries; i++, tr++)
|
||||
{
|
||||
if (tr->Address.Ipv4.sin_addr == r.Address.Ipv4.sin_addr &&
|
||||
tr->InterfaceIndex == r.InterfaceIndex &&
|
||||
CompareArrays(tr->PhysicalAddress, r.PhysicalAddress))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool CompareArrays(byte* left, byte[] right)
|
||||
{
|
||||
return !right.Where((t, i) => left[i] != t).Any();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreateSetDeleteIpNetEntry2UnmanagedSpanTest()
|
||||
{
|
||||
var target = new IN_ADDR(192, 168, 0, 202);
|
||||
Assert.That(GetBestRoute(target, 0, out var fwdRow), ResultIs.Successful);
|
||||
var mibrow = new MIB_IPNET_ROW2(new SOCKADDR_IN(target), fwdRow.dwForwardIfIndex, SendARP(target));
|
||||
Assert.That(GetIpNetTable2_Unmanaged(ADDRESS_FAMILY.AF_INET, out var t1), ResultIs.Successful);
|
||||
if (HasVal(ref t1, mibrow))
|
||||
Assert.That(DeleteIpNetEntry2(ref mibrow), ResultIs.Successful);
|
||||
|
||||
Assert.That(CreateIpNetEntry2(ref mibrow), ResultIs.Successful);
|
||||
GetIpNetTable2_Unmanaged(ADDRESS_FAMILY.AF_INET, out var t2);
|
||||
Assert.That(HasVal(ref t2, mibrow), Is.True);
|
||||
|
||||
Assert.That(DeleteIpNetEntry2(ref mibrow), ResultIs.Successful);
|
||||
GetIpNetTable2_Unmanaged(ADDRESS_FAMILY.AF_INET, out var t3);
|
||||
Assert.That(HasVal(ref t3, mibrow), Is.False);
|
||||
|
||||
static bool HasVal(ref MIB_IPNET_TABLE2_Unmanaged t, MIB_IPNET_ROW2 r)
|
||||
{
|
||||
foreach (ref MIB_IPNET_ROW2_Unmanaged tr in t)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* physicalAddress = tr.PhysicalAddress)
|
||||
{
|
||||
if (tr.Address.Ipv4.sin_addr == r.Address.Ipv4.sin_addr &&
|
||||
tr.InterfaceIndex == r.InterfaceIndex &&
|
||||
CompareArrays(physicalAddress, r.PhysicalAddress))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static unsafe bool CompareArrays(byte* left, byte[] right)
|
||||
{
|
||||
return !right.Where((t, i) => left[i] != t).Any();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreateSetGetDeleteUnicastIpAddressEntryTest()
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue