Vanara/UnitTests/PInvoke/Dhcp/DhcpTests.cs

101 lines
4.5 KiB
C#

using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using static Vanara.PInvoke.Dhcp;
namespace Vanara.PInvoke.Tests;
[TestFixture]
public class DhcpTests
{
internal readonly static NetworkInterface? adp = NetworkInterface.GetAllNetworkInterfaces().Where(i => i.OperationalStatus == OperationalStatus.Up).FirstOrDefault();
internal readonly static string? dhcpSvr = GetDhcpServers().FirstOrDefault()?.ToString();
internal const string dhcpSub = "192.168.0.0";
[OneTimeSetUp]
public void _Setup() => DhcpCApiInitialize(out _).ThrowIfFailed();
[OneTimeTearDown]
public void _TearDown() => DhcpCApiCleanup();
[Test]
public void DhcpRequestParamsTest()
{
Assert.NotNull(adp);
Assert.That(() =>
{
TestContext.WriteLine(new IPAddress(RequestParam<uint>(adp!.Id, DHCP_OPTION_ID.OPTION_SUBNET_MASK)));
TestContext.WriteLine(new IPAddress(RequestParam<uint>(adp!.Id, DHCP_OPTION_ID.OPTION_ROUTER_ADDRESS)));
TestContext.WriteLine(new IPAddress(RequestParam<uint>(adp!.Id, DHCP_OPTION_ID.OPTION_BROADCAST_ADDRESS)));
Array.ConvertAll(RequestParam<uint[]>(adp.Id, DHCP_OPTION_ID.OPTION_TIME_SERVERS) ?? new uint[0], a => new IPAddress(a)).WriteValues();
TestContext.WriteLine(RequestParam<string>(adp.Id, DHCP_OPTION_ID.OPTION_HOST_NAME));
TestContext.WriteLine(RequestParam<string>(adp.Id, DHCP_OPTION_ID.OPTION_DOMAIN_NAME));
TestContext.WriteLine(RequestParam<string>(adp.Id, DHCP_OPTION_ID.OPTION_MSFT_IE_PROXY));
}, Throws.Nothing);
}
[Test]
public void DhcpRegisterParamChangeTest()
{
Assert.NotNull(adp);
using var pparam = new SafeCoTaskMemStruct<DHCPAPI_PARAMS>(new DHCPAPI_PARAMS { OptionId = DHCP_OPTION_ID.OPTION_ROUTER_ADDRESS });
//using var pparam = new SafeCoTaskMemStruct<DHCPAPI_PARAMS>(new DHCPAPI_PARAMS { OptionId = DHCP_OPTION_ID.OPTION_HOST_NAME });
var watchParams = new DHCPCAPI_PARAMS_ARRAY { nParams = 1, Params = pparam };
Assert.That(DhcpRegisterParamChange(DHCPCAPI_REGISTER_HANDLE_EVENT, default, adp!.Id, IntPtr.Zero, watchParams, out var hEvent), ResultIs.Successful);
Kernel32.WaitForSingleObject(hEvent, 2000);
Assert.That(DhcpDeRegisterParamChange(Event: hEvent), ResultIs.Successful);
}
private static T? RequestParam<T>(string adapterName, DHCP_OPTION_ID optionId, byte[]? classId = null)
{
using SafeCoTaskMemHandle pClassIdData = classId is null ? SafeCoTaskMemHandle.Null : new(classId);
using SafeCoTaskMemStruct<DHCPCAPI_CLASSID> pClass = (DHCPCAPI_CLASSID?)(classId is null ? null : new DHCPCAPI_CLASSID() { nBytesData = (uint)classId.Length, Data = pClassIdData });
DHCPCAPI_PARAMS_ARRAY sendParams = new();
using var pparam = new SafeCoTaskMemStruct<DHCPAPI_PARAMS>(new DHCPAPI_PARAMS { OptionId = optionId });
DHCPCAPI_PARAMS_ARRAY reqParams = new() { nParams = 1, Params = pparam };
uint sz = 0;
DhcpRequestParams(DHCPCAPI_REQUEST.DHCPCAPI_REQUEST_SYNCHRONOUS, default, adapterName, pClass, sendParams, reqParams, IntPtr.Zero, ref sz, null).ThrowUnless(Win32Error.ERROR_MORE_DATA);
if (sz == 0) return default;
using var buffer = new SafeCoTaskMemHandle(sz);
Guid appId = Guid.NewGuid();
DhcpRequestParams(DHCPCAPI_REQUEST.DHCPCAPI_REQUEST_SYNCHRONOUS, default, adapterName, pClass, sendParams, reqParams, buffer, ref sz, appId.ToString("N")).ThrowIfFailed();
try
{
//if (!typeof(T).IsPrimitive && typeof(T) != typeof(string))
// reqParamCache.Add(appId, buffer);
var p = pparam.Value;
if (typeof(T).IsArray)
{
try
{
var elemType = typeof(T).GetElementType() ?? throw new Exception();
var elemSz = InteropExtensions.SizeOf(elemType);
return (T?)(object?)p.Data.ToArray(elemType, p.nBytesData / elemSz, 0, p.nBytesData);
}
catch
{
throw new ArgumentException("Unable to process array of specfied type.");
}
}
return p.Data.Convert<T>(p.nBytesData, CharSet.Ansi);
}
finally
{
DhcpUndoRequestParams(0, default, adapterName, appId.ToString("N"));
}
}
internal static DHCP_IP_ADDRESS IPAddrFromStr(string addr)
{
if (!IPAddress.TryParse(addr, out var ip) || ip.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork)
return 0;
#pragma warning disable CS0618 // Type or member is obsolete
return (uint)ip.Address;
#pragma warning restore CS0618 // Type or member is obsolete
}
static IEnumerable<IPAddress> GetDhcpServers() => NetworkInterface.GetAllNetworkInterfaces().Where(i => i.OperationalStatus == OperationalStatus.Up).SelectMany(i => i.GetIPProperties().DhcpServerAddresses).Distinct();
}