Working DistributedRoutingTable

pull/328/head
David Hall 2022-10-04 09:30:13 -06:00
parent 76087b0ab5
commit 48b09fd666
2 changed files with 390 additions and 273 deletions

View File

@ -15,12 +15,194 @@ using static Vanara.PInvoke.Ws2_32;
namespace Vanara.Net;
/// <summary>DNS Bootstrapper</summary>
/// <seealso cref="Vanara.Net.DrtCustomBootstrapProvider"/>
public class CustomDnsBootstapper : DrtCustomBootstrapProvider
{
private readonly string hostname;
private readonly object m_lock = new();
private readonly string port;
private uint m_CallbackThreadId;
private uint m_dwMaxResults;
private bool m_fEndResolve;
private bool m_fResolveInProgress;
private SafeEventHandle? m_hCallbackComplete;
/// <summary>Initializes a new instance of the <see cref="CustomDnsBootstapper"/> class.</summary>
/// <param name="pNodeName">
/// A string that contains a host (node) name or a numeric host address string. For the Internet protocol, the numeric host address
/// string is a dotted-decimal IPv4 address or an IPv6 hex address.
/// </param>
/// <param name="pServiceName">
/// <para>A string that contains either a service name or port number represented as a string.</para>
/// <para>
/// A service name is a string alias for a port number. For example, “http” is an alias for port 80 defined by the Internet Engineering
/// Task Force (IETF) as the default port used by web servers for the HTTP protocol. Possible values for the pServiceName parameter when
/// a port number is not specified are listed in the following file:
/// </para>
/// </param>
public CustomDnsBootstapper(string pNodeName, string pServiceName)
{
hostname = pNodeName;
port = pServiceName;
}
/// <inheritdoc/>
protected override void EndResolve([In] DRT_BOOTSTRAP_RESOLVE_CONTEXT ResolveContext)
{
var fWaitForCallback = false;
var CallbackComplete = CreateEvent(default, true, false, default);
lock (m_lock)
{
if (m_fResolveInProgress && (GetCurrentThreadId() != m_CallbackThreadId))
{
if (!m_fEndResolve)
{
// This is the first thread to call EndResolve and we need to wait for a callback to complete so initialize the class
// member event
m_fEndResolve = true;
m_hCallbackComplete = CallbackComplete;
}
fWaitForCallback = true;
}
}
if (!CallbackComplete.IsInvalid && (m_hCallbackComplete != CallbackComplete))
{
// This thread was not the first to call EndResolve, so its event is not in use, release it (m_hCallbackComplete is released in
// the destructor)
CallbackComplete.Dispose();
}
if (fWaitForCallback && m_hCallbackComplete != null)
{
WaitForSingleObject(m_hCallbackComplete, INFINITE);
}
Release();
}
/// <inheritdoc/>
protected override HRESULT InitResolve(bool fSplitDetect, TimeSpan timeout, uint cMaxResults, out DRT_BOOTSTRAP_RESOLVE_CONTEXT pResolveContext, out bool fFatalError)
{
fFatalError = false;
pResolveContext = default;
var hr = HRESULT.DRT_E_BOOTSTRAPPROVIDER_NOT_ATTACHED;
if (IsAttached)
{
// The cache is not scope aware so we ask for a larger number of addresses than the cache wants. In the expectation that one of
// them may be good for us
m_dwMaxResults = cMaxResults;
AddRef();
hr = HRESULT.S_OK;
}
if (hr.Failed)
{
// CustomDNSResolver has no retry cases, so any failed HRESULT is fatal
fFatalError = true;
}
return hr;
}
/// <inheritdoc/>
protected override HRESULT IssueResolve(DRT_BOOTSTRAP_RESOLVE_CALLBACK callback, [In] IntPtr pvCallbackContext, [In] DRT_BOOTSTRAP_RESOLVE_CONTEXT ResolveContext, out bool fFatalError)
{
fFatalError = false;
if (callback is null)
{
return HRESULT.E_INVALIDARG;
}
var hr = HRESULT.DRT_E_BOOTSTRAPPROVIDER_NOT_ATTACHED;
if (IsAttached)
{
lock (m_lock)
{
m_fResolveInProgress = true;
m_CallbackThreadId = GetCurrentThreadId();
}
if (m_dwMaxResults > 0)
{
var addresses = hostname.Split(new[] { ';', ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).ToArray();
foreach (var CurrentAddress in addresses)
{
if (m_fEndResolve)
break;
// Retrieve bootstrap possibilities
var addrInf = new ADDRINFOW
{
ai_flags = ADDRINFO_FLAGS.AI_CANONNAME,
ai_family = ADDRESS_FAMILY.AF_UNSPEC,
ai_socktype = SOCK.SOCK_STREAM
};
var nStat = GetAddrInfoW(CurrentAddress, port, addrInf, out var results);
if (nStat.Succeeded)
{
using (results)
{
var cbSA6 = Marshal.SizeOf(typeof(SOCKADDR_IN6));
using var psockAddrs = new SafeNativeArray<SOCKADDR_IN6>(results.Select(a => { using var ar = a.addr; return (SOCKADDR_IN6)ar; }).ToArray());
var Addresses = new SOCKET_ADDRESS_LIST
{
iAddressCount = psockAddrs.Count,
Address = psockAddrs.Select((a, i) => new SOCKET_ADDRESS { iSockaddrLength = cbSA6, lpSockaddr = ((IntPtr)psockAddrs).Offset(cbSA6) }).ToArray()
};
// Call the callback to signal completion
using var pAddresses = Addresses.Pack();
callback?.Invoke(hr, pvCallbackContext, pAddresses, false);
}
}
else
{
// GetAddrInfoW Failed but there may be more addresses in the string so keep going otherwise we return
// HRESULT.E_NO_MORE and retry next cycle
}
}
}
// Tell the drt there will be no more results
if (!m_fEndResolve)
callback?.Invoke(HRESULT.DRT_E_NO_MORE, pvCallbackContext, default, false);
lock (m_lock)
{
if (m_hCallbackComplete != null && !m_hCallbackComplete.IsInvalid)
{
// Notify EndResolve that callbacks have completed
m_hCallbackComplete.Set();
}
m_fResolveInProgress = false;
}
hr = HRESULT.S_OK;
}
if (hr.Failed)
{
// DNSResolver has no retry cases, so any failed HRESULT is fatal
fFatalError = true;
}
return hr;
}
}
/// <summary>Represents a distributed routing table from Win32.</summary>
public class DistributedRoutingTable
{
private readonly SafeRegisteredWaitHandle? drtWaitEvent;
private readonly SafeEventHandle? evt;
private readonly SafeHDRT? hDrt;
private readonly IntPtr selfPin;
private readonly SafeWSA ws = SafeWSA.Initialize();
private DRT_SETTINGS pSettings;
@ -51,44 +233,55 @@ public class DistributedRoutingTable
evt = CreateEvent(null, false, false);
DrtOpen(pSettings, evt, default, out HDRT h).ThrowIfFailed();
hDrt = new((IntPtr)h);
Win32Error.ThrowLastErrorIfFalse(RegisterWaitForSingleObject(out drtWaitEvent, evt, DrtEventCallback, default /*AddCtx(Drt)*/, INFINITE, WT.WT_EXECUTEDEFAULT));
selfPin = GCHandle.Alloc(this).AddrOfPinnedObject();
Win32Error.ThrowLastErrorIfFalse(RegisterWaitForSingleObject(out drtWaitEvent, evt, DrtEventCallback, selfPin, INFINITE, WT.WT_EXECUTEDEFAULT));
}
private void DrtEventCallback(IntPtr Param, bool TimedOut)
/// <summary>Occurs when the leaf set key changes.</summary>
public event EventHandler<DrtLeafSetKeyChangeEventArgs>? LeafSetKeyChange;
/// <summary>Occurs when the registration state changes.</summary>
public event EventHandler<DrtRegistrationStateChangeEventArgs>? RegistrationStateChange;
/// <summary>Occurs when the status changes.</summary>
public event EventHandler<DrtStatusChangeEventArgs>? StatusChange;
private static void DrtEventCallback(IntPtr Param, bool TimedOut)
{
// HRESULT hr; var Drt = GetCtx(Param);
var Drt = (DistributedRoutingTable)GCHandle.FromIntPtr(Param).Target;
// hr = DrtGetEventDataSize(Drt.hDrt, out var ulDrtEventDataLen); if (hr.Failed) { if (hr != HRESULT.DRT_E_NO_MORE) Console.Write("
// DrtGetEventDataSize failed: {0}\n", hr); goto Cleanup; }
HRESULT hr = DrtGetEventDataSize(Drt.hDrt, out var ulDrtEventDataLen);
if (hr.Failed)
{
if (hr != HRESULT.DRT_E_NO_MORE)
throw hr.GetException();
goto Cleanup;
}
// using (var pEventData = new SafeCoTaskMemStruct<DRT_EVENT_DATA>(ulDrtEventDataLen)) { if (pEventData.IsInvalid) { Console.Write("
// Out of memory\n"); goto Cleanup; }
using (SafeCoTaskMemStruct<DRT_EVENT_DATA> pEventData = new(ulDrtEventDataLen))
{
hr = DrtGetEventData(Drt.hDrt, ulDrtEventDataLen, pEventData);
if (hr.Failed)
{
if (hr != HRESULT.DRT_E_NO_MORE)
throw hr.GetException();
goto Cleanup;
}
// hr = DrtGetEventData(Drt.hDrt, ulDrtEventDataLen, pEventData); if (hr.Failed) { if (hr != HRESULT.DRT_E_NO_MORE) Console.Write("
// DrtGetEventData failed: {0}\n", hr); goto Cleanup; }
// switch (pEventData.Value.type) { case DRT_EVENT_TYPE.DRT_EVENT_STATUS_CHANGED: switch (pEventData.Value.union.statusChange.status)
// { case DRT_STATUS.DRT_ACTIVE: SetConsoleTitle("DrtSdkSample Current Drt Status: Active"); if (g_DisplayEvents) Console.Write(" DRT
// Status Changed to Active\n"); break; case DRT_STATUS.DRT_ALONE: SetConsoleTitle("DrtSdkSample Current Drt Status: Alone"); if
// (g_DisplayEvents) Console.Write(" DRT Status Changed to Alone\n"); break; case DRT_STATUS.DRT_NO_NETWORK:
// SetConsoleTitle("DrtSdkSample Current Drt Status: No Network"); if (g_DisplayEvents) Console.Write(" DRT Status Changed to No
// Network\n"); break; case DRT_STATUS.DRT_FAULTED: SetConsoleTitle("DrtSdkSample Current Drt Status: Faulted"); if (g_DisplayEvents)
// Console.Write(" DRT Status Changed to Faulted\n"); break; }
// break; case DRT_EVENT_TYPE.DRT_EVENT_LEAFSET_KEY_CHANGED: if (g_DisplayEvents) { switch
// (pEventData.Value.union.leafsetKeyChange.change) { case DRT_LEAFSET_KEY_CHANGE_TYPE.DRT_LEAFSET_KEY_ADDED: Console.Write(" Leafset
// Key Added Event: {0}\n", pEventData.Value.hr); break; case DRT_LEAFSET_KEY_CHANGE_TYPE.DRT_LEAFSET_KEY_DELETED: Console.Write("
// Leafset Key Deleted Event: {0}\n", pEventData.Value.hr); break; } }
// break;
// case DRT_EVENT_TYPE.DRT_EVENT_REGISTRATION_STATE_CHANGED:
// if (g_DisplayEvents)
// Console.Write(" Registration State Changed Event: [hr: 0x%x, registration state: %i]\n", pEventData.Value.hr, pEventData.Value.union.registrationStateChange.state);
// break;
// }
// }
//Cleanup:
// return;
switch (pEventData.Value.type)
{
case DRT_EVENT_TYPE.DRT_EVENT_STATUS_CHANGED:
Drt.StatusChange?.Invoke(Drt, new(pEventData.Value));
break;
case DRT_EVENT_TYPE.DRT_EVENT_LEAFSET_KEY_CHANGED:
Drt.LeafSetKeyChange?.Invoke(Drt, new(pEventData.Value));
break;
case DRT_EVENT_TYPE.DRT_EVENT_REGISTRATION_STATE_CHANGED:
Drt.RegistrationStateChange?.Invoke(Drt, new(pEventData.Value));
break;
}
}
Cleanup:
return;
}
}
@ -111,8 +304,7 @@ public class DrtBootstrapProvider : IDisposable
}
/// <summary>Initializes a new instance of the <see cref="DrtBootstrapProvider"/> class.</summary>
private DrtBootstrapProvider()
{ }
private DrtBootstrapProvider() { }
/// <summary>Initializes a new instance of the <see cref="DrtBootstrapProvider"/> class.</summary>
/// <param name="ptr">The PTR.</param>
@ -224,11 +416,17 @@ public abstract class DrtCustomBootstrapProvider : DrtBootstrapProvider
protected virtual object? Context => prov.pvContext == IntPtr.Zero ? null : GCHandle.FromIntPtr(prov.pvContext).Target;
/// <summary>Gets a value indicating whether this instance is attached.</summary>
/// <value>
/// <see langword="true" /> if this instance is attached; otherwise, <see langword="false" />.
/// </value>
/// <value><see langword="true"/> if this instance is attached; otherwise, <see langword="false"/>.</value>
protected bool IsAttached => refCount > 0;
/// <summary>Adds the reference.</summary>
protected void AddRef()
{
if (refCount == 0)
GC.SuppressFinalize(this);
InterlockedIncrement(ref refCount);
}
/// <summary>Ends the resolution of an endpoint.</summary>
/// <param name="ResolveContext">
/// The <c>BOOTSTRAP_RESOLVE_CONTEXT</c> received from the Resolve function of the specified bootstrap provider.
@ -273,6 +471,17 @@ public abstract class DrtCustomBootstrapProvider : DrtBootstrapProvider
/// </param>
protected virtual HRESULT Register([In] IPEndPoint[]? pAddressList) => HRESULT.S_OK;
/// <summary>Releases this instance.</summary>
protected void Release()
{
if (InterlockedDecrement(ref refCount) == 0)
{
if (prov.pvContext != default)
GCHandle.FromIntPtr(prov.pvContext).Free();
GC.ReRegisterForFinalize(this);
}
}
/// <summary>
/// This function deregisters an endpoint with the bootstrapping mechanism. As a result, other nodes will be unable to find the local
/// node via the bootstrap resolver.
@ -286,32 +495,11 @@ public abstract class DrtCustomBootstrapProvider : DrtBootstrapProvider
AddRef();
return HRESULT.S_OK;
}
/// <summary>Adds the reference.</summary>
protected void AddRef()
{
if (refCount == 0)
GC.SuppressFinalize(this);
InterlockedIncrement(ref refCount);
}
private void InternalDetach(IntPtr pvContext)
{
InterlockedCompareExchange(ref refCount, 0, 1);
Release();
}
/// <summary>Releases this instance.</summary>
protected void Release()
{
if (InterlockedDecrement(ref refCount) == 0)
{
if (prov.pvContext != default)
GCHandle.FromIntPtr(prov.pvContext).Free();
GC.ReRegisterForFinalize(this);
}
}
private void InternalEndResolve(IntPtr pvContext, DRT_BOOTSTRAP_RESOLVE_CONTEXT ResolveContext) => EndResolve(ResolveContext);
private HRESULT InternalInitResolve(IntPtr pvContext, bool fSplitDetect, uint timeout, uint cMaxResults,
@ -327,185 +515,66 @@ public abstract class DrtCustomBootstrapProvider : DrtBootstrapProvider
private void InternalUnregister(IntPtr pvContext) => Unregister();
}
/// <summary>DNS Bootstrapper</summary>
/// <seealso cref="Vanara.Net.DrtCustomBootstrapProvider"/>
public class CustomDnsBootstapper : DrtCustomBootstrapProvider
/// <summary>Abstract base class for DRT event arguments.</summary>
/// <seealso cref="System.EventArgs"/>
public abstract class DrtEventArgs : EventArgs
{
private readonly string hostname;
private readonly string port;
private readonly object m_lock = new();
private bool m_fResolveInProgress;
private uint m_CallbackThreadId;
private bool m_fEndResolve;
private SafeEventHandle? m_hCallbackComplete;
private uint m_dwMaxResults;
/// <summary>Initializes a new instance of the <see cref="CustomDnsBootstapper"/> class.</summary>
/// <param name="pNodeName">
/// A string that contains a host (node) name or a numeric host address string. For the Internet protocol, the numeric host address
/// string is a dotted-decimal IPv4 address or an IPv6 hex address.
/// </param>
/// <param name="pServiceName">
/// <para>A string that contains either a service name or port number represented as a string.</para>
/// <para>
/// A service name is a string alias for a port number. For example, “http” is an alias for port 80 defined by the Internet Engineering
/// Task Force (IETF) as the default port used by web servers for the HTTP protocol. Possible values for the pServiceName parameter when
/// a port number is not specified are listed in the following file:
/// </para>
/// </param>
public CustomDnsBootstapper(string pNodeName, string pServiceName)
/// <summary>Initializes a new instance of the <see cref="DrtEventArgs"/> class.</summary>
/// <param name="data">The data.</param>
protected DrtEventArgs(in DRT_EVENT_DATA data)
{
hostname = pNodeName;
port = pServiceName;
LastError = data.hr;
Context = data.pvContext;
}
/// <inheritdoc/>
protected override void EndResolve([In] DRT_BOOTSTRAP_RESOLVE_CONTEXT ResolveContext)
/// <summary>
/// Pointer to the context data passed to the API that generated the event. For example, if data is passed into the pvContext parameter
/// of DrtOpen, that data is returned through this field.
/// </summary>
public IntPtr Context { get; }
/// <summary>
/// The HRESULT of the operation for which the event was signaled that indicates if a result is the last result within a search.
/// </summary>
public HRESULT LastError { get; }
}
/// <summary>Arguments associated with a DRT leaf set key change event.</summary>
/// <seealso cref="Vanara.Net.DrtEventArgs"/>
public class DrtLeafSetKeyChangeEventArgs : DrtEventArgs
{
internal DrtLeafSetKeyChangeEventArgs(in DRT_EVENT_DATA data) : base(data)
{
var fWaitForCallback = false;
var CallbackComplete = CreateEvent(default, true, false, default);
lock (m_lock)
{
if (m_fResolveInProgress && (GetCurrentThreadId() != m_CallbackThreadId))
{
if (!m_fEndResolve)
{
// This is the first thread to call EndResolve and we need to wait for a callback to complete so initialize the class
// member event
m_fEndResolve = true;
m_hCallbackComplete = CallbackComplete;
}
fWaitForCallback = true;
}
}
if (!CallbackComplete.IsInvalid && (m_hCallbackComplete != CallbackComplete))
{
// This thread was not the first to call EndResolve, so its event is not in use, release it (m_hCallbackComplete is released
// in the destructor)
CallbackComplete.Dispose();
}
if (fWaitForCallback && m_hCallbackComplete != null)
{
WaitForSingleObject(m_hCallbackComplete, INFINITE);
}
Release();
Type = data.union.leafsetKeyChange.change;
LocalKey = data.union.leafsetKeyChange.localKey.GetArray();
RemoteKey = data.union.leafsetKeyChange.remoteKey.GetArray();
}
/// <inheritdoc/>
protected override HRESULT InitResolve(bool fSplitDetect, TimeSpan timeout, uint cMaxResults, out DRT_BOOTSTRAP_RESOLVE_CONTEXT pResolveContext, out bool fFatalError)
/// <summary>Specifies the local key associated with the leaf set that has changed.</summary>
public byte[]? LocalKey { get; private set; }
/// <summary>Specifies the remote key that changed.</summary>
public byte[]? RemoteKey { get; private set; }
/// <summary>Specifies the type of key change that has occurred.</summary>
public DRT_LEAFSET_KEY_CHANGE_TYPE Type { get; private set; }
}
/// <summary>Arguments associated with a DRT registration state change event.</summary>
/// <seealso cref="Vanara.Net.DrtEventArgs"/>
public class DrtRegistrationStateChangeEventArgs : DrtEventArgs
{
internal DrtRegistrationStateChangeEventArgs(in DRT_EVENT_DATA data) : base(data)
{
fFatalError = false;
pResolveContext = default;
var hr = HRESULT.DRT_E_BOOTSTRAPPROVIDER_NOT_ATTACHED;
if (IsAttached)
{
// The cache is not scope aware so we ask for a larger number of addresses than the cache wants. In the expectation that one
// of them may be good for us
m_dwMaxResults = cMaxResults;
AddRef();
hr = HRESULT.S_OK;
}
if (hr.Failed)
{
// CustomDNSResolver has no retry cases, so any failed HRESULT is fatal
fFatalError = true;
}
return hr;
State = data.union.registrationStateChange.state;
LocalKey = data.union.registrationStateChange.localKey.GetArray();
}
/// <inheritdoc/>
protected override HRESULT IssueResolve(DRT_BOOTSTRAP_RESOLVE_CALLBACK callback, [In] IntPtr pvCallbackContext, [In] DRT_BOOTSTRAP_RESOLVE_CONTEXT ResolveContext, out bool fFatalError)
{
fFatalError = false;
/// <summary>Specifies the local key associated with the registration that has changed.</summary>
public byte[]? LocalKey { get; }
if (callback is null)
{
return HRESULT.E_INVALIDARG;
}
var hr = HRESULT.DRT_E_BOOTSTRAPPROVIDER_NOT_ATTACHED;
if (IsAttached)
{
lock (m_lock)
{
m_fResolveInProgress = true;
m_CallbackThreadId = GetCurrentThreadId();
}
if (m_dwMaxResults > 0)
{
var addresses = hostname.Split(new[] { ';', ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).ToArray();
foreach (var CurrentAddress in addresses)
{
if (m_fEndResolve)
break;
// Retrieve bootstrap possibilities
var addrInf = new ADDRINFOW
{
ai_flags = ADDRINFO_FLAGS.AI_CANONNAME,
ai_family = ADDRESS_FAMILY.AF_UNSPEC,
ai_socktype = SOCK.SOCK_STREAM
};
var nStat = GetAddrInfoW(CurrentAddress, port, addrInf, out var results);
if (nStat.Succeeded)
{
using (results)
{
var cbSA6 = Marshal.SizeOf(typeof(SOCKADDR_IN6));
using var psockAddrs = new SafeNativeArray<SOCKADDR_IN6>(results.Select(a => { using var ar = a.addr; return (SOCKADDR_IN6)ar; }).ToArray());
var Addresses = new SOCKET_ADDRESS_LIST
{
iAddressCount = psockAddrs.Count,
Address = psockAddrs.Select((a, i) => new SOCKET_ADDRESS { iSockaddrLength = cbSA6, lpSockaddr = ((IntPtr)psockAddrs).Offset(cbSA6) }).ToArray()
};
// Call the callback to signal completion
using var pAddresses = Addresses.Pack();
callback?.Invoke(hr, pvCallbackContext, pAddresses, false);
}
}
else
{
// GetAddrInfoW Failed but there may be more addresses in the string so keep going otherwise we return
// HRESULT.E_NO_MORE and retry next cycle
}
}
}
// Tell the drt there will be no more results
if (!m_fEndResolve)
callback?.Invoke(HRESULT.DRT_E_NO_MORE, pvCallbackContext, default, false);
lock (m_lock)
{
if (m_hCallbackComplete != null && !m_hCallbackComplete.IsInvalid)
{
// Notify EndResolve that callbacks have completed
m_hCallbackComplete.Set();
}
m_fResolveInProgress = false;
}
hr = HRESULT.S_OK;
}
if (hr.Failed)
{
// DNSResolver has no retry cases, so any failed HRESULT is fatal
fFatalError = true;
}
return hr;
}
/// <summary>Specifies the type of registration state change that has occurred.</summary>
public DRT_REGISTRATION_STATE State { get; }
}
/// <summary>Base class for a DRT security provider.</summary>
@ -526,8 +595,7 @@ public class DrtSecurityProvider : IDisposable
pProvType = 'h';
}
private DrtSecurityProvider()
{ }
private DrtSecurityProvider() { }
private DrtSecurityProvider(IntPtr ptr, char provType)
{
@ -585,6 +653,31 @@ public class DrtSecurityProvider : IDisposable
}
}
/// <summary>Arguments associated with a DRT status change event.</summary>
/// <seealso cref="Vanara.Net.DrtEventArgs"/>
public class DrtStatusChangeEventArgs : DrtEventArgs
{
internal DrtStatusChangeEventArgs(in DRT_EVENT_DATA data) : base(data)
{
Status = data.union.statusChange.status;
BootstrapAddresses = Array.ConvertAll(data.union.statusChange.bootstrapAddresses.Addresses, Cvt);
static IPEndPoint Cvt(SOCKADDR_STORAGE input)
{
var inet = (SOCKADDR_INET)input;
return inet.si_family is ADDRESS_FAMILY.AF_INET or ADDRESS_FAMILY.AF_UNSPEC
? new IPEndPoint(inet.Ipv4.sin_addr, inet.Ipv4.sin_port)
: new IPEndPoint(new IPAddress(inet.Ipv6.sin6_addr.bytes, inet.Ipv6.sin6_scope_id), inet.Ipv6.sin6_port);
}
}
/// <summary>Contains an array of <see cref="IPEndPoint"/> returned by the bootstrap provider.</summary>
public IPEndPoint[] BootstrapAddresses { get; }
/// <summary>Contains the current DRT_STATUS of the local DRT instance.</summary>
public DRT_STATUS Status { get; }
}
internal static class DrtUtil
{
public static IntPtr Alloc(int size) => Marshal.AllocCoTaskMem(size);
@ -653,7 +746,8 @@ internal static class DrtUtil
public abstract class DrtCustomSecurityProvider : DrtSecurityProvider
{
private int refCount;
/// <summary>Initializes a new instance of the <see cref="DrtSecurityProvider" /> class.</summary>
/// <summary>Initializes a new instance of the <see cref="DrtSecurityProvider"/> class.</summary>
/// <param name="context">The context.</param>
protected DrtCustomSecurityProvider(object? context) : base(default)
{
@ -678,6 +772,14 @@ public abstract class DrtCustomSecurityProvider : DrtSecurityProvider
AddRef();
}
/// <summary>Gets the context provided for all methods.</summary>
/// <value>The context object.</value>
protected virtual object? Context => prov.pvContext == IntPtr.Zero ? null : GCHandle.FromIntPtr(prov.pvContext).Target;
/// <summary>Gets a value indicating whether this instance is attached.</summary>
/// <value><see langword="true"/> if this instance is attached; otherwise, <see langword="false"/>.</value>
protected bool IsAttached => refCount > 0;
/// <summary>Adds the reference.</summary>
protected void AddRef()
{
@ -686,27 +788,6 @@ public abstract class DrtCustomSecurityProvider : DrtSecurityProvider
InterlockedIncrement(ref refCount);
}
/// <summary>Releases this instance.</summary>
protected void Release()
{
if (InterlockedDecrement(ref refCount) == 0)
{
if (prov.pvContext != default)
GCHandle.FromIntPtr(prov.pvContext).Free();
GC.ReRegisterForFinalize(this);
}
}
/// <summary>Gets the context provided for all methods.</summary>
/// <value>The context object.</value>
protected virtual object? Context => prov.pvContext == IntPtr.Zero ? null : GCHandle.FromIntPtr(prov.pvContext).Target;
/// <summary>Gets a value indicating whether this instance is attached.</summary>
/// <value>
/// <see langword="true" /> if this instance is attached; otherwise, <see langword="false" />.
/// </value>
protected bool IsAttached => refCount > 0;
/// <summary>
/// Called when the DRT receives a message containing encrypted data. This function is only called when the DRT is operating in the
/// <c>DRT_SECURE_CONFIDENTIALPAYLOAD</c> security mode defined by DRT_SECURITY_MODE.
@ -750,6 +831,17 @@ public abstract class DrtCustomSecurityProvider : DrtSecurityProvider
/// <returns></returns>
protected virtual HRESULT RegisterKey(in DRT_REGISTRATION pRegistration, [In, Optional] IntPtr pvKeyContext) => HRESULT.S_OK;
/// <summary>Releases this instance.</summary>
protected void Release()
{
if (InterlockedDecrement(ref refCount) == 0)
{
if (prov.pvContext != default)
GCHandle.FromIntPtr(prov.pvContext).Free();
GC.ReRegisterForFinalize(this);
}
}
/// <summary>
/// Called when an Authority message is about to be sent on the wire. It is responsible for securing the data before it is sent, and for
/// packing the service addresses, revoked flag, nonce, and other application data into the Secured Address Payload.
@ -962,10 +1054,8 @@ public abstract class DrtCustomSecurityProvider : DrtSecurityProvider
}
/*
/// <summary>
///
/// </summary>
/// <seealso cref="Vanara.Net.DrtCustomSecurityProvider" />
/// <summary></summary>
/// <seealso cref="Vanara.Net.DrtCustomSecurityProvider"/>
public class CustomNullSecurityProvider : DrtCustomSecurityProvider
{
internal unsafe class CCustomNullSecuredAddressPayload : IDisposable
@ -998,9 +1088,7 @@ public class CustomNullSecurityProvider : DrtCustomSecurityProvider
//CERT_PUBLIC_KEY_INFO*
private SafeCoTaskMemStruct<CERT_PUBLIC_KEY_INFO>? m_pPublicKey;
/// <summary>
/// Initializes a new instance of the <see cref="CCustomNullSecuredAddressPayload"/> class.
/// </summary>
/// <summary>Initializes a new instance of the <see cref="CCustomNullSecuredAddressPayload"/> class.</summary>
/// <param name="bMajor">The b major.</param>
/// <param name="bMinor">The b minor.</param>
/// <param name="key">The key.</param>

View File

@ -1826,64 +1826,93 @@ namespace Vanara.PInvoke
[StructLayout(LayoutKind.Explicit)]
public struct UNION
{
/// <summary/>
/// <summary>
/// This structure appears when the event has been raised to signal a change in a leaf set of a locally registered key; the
/// type field of the DRT_EVENT_DATA structure is set to DRT_EVENT_LEAFSET_KEY_CHANGED.
/// </summary>
[FieldOffset(0)]
public LEAFSETKEYCHANGE leafsetKeyChange;
/// <summary/>
/// <summary>
/// This structure appears when the event has been raised to signal a change in a local key registration; the type field of
/// the DRT_EVENT_DATA structure is set to DRT_EVENT_REGISTRATION_STATE_CHANGED.
/// </summary>
[FieldOffset(0)]
public REGISTRATIONSTATECHANGE registrationStateChange;
/// <summary/>
/// <summary>
/// This structure appears when the event has been raised to signal a state change in the local DRT instance; the type field
/// of the DRT_EVENT_DATA structure is set to DRT_EVENT_STATUS_CHANGED.
/// </summary>
[FieldOffset(0)]
public STATUSCHANGE statusChange;
/// <summary/>
/// <summary>
/// This structure appears when the event has been raised to signal a change in a leaf set of a locally registered key; the
/// type field of the DRT_EVENT_DATA structure is set to DRT_EVENT_LEAFSET_KEY_CHANGED.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct LEAFSETKEYCHANGE
{
/// <summary/>
/// <summary>Specifies the type of key change that has occurred.</summary>
public DRT_LEAFSET_KEY_CHANGE_TYPE change;
/// <summary/>
/// <summary>Specifies the local key associated with the leaf set that has changed.</summary>
public DRT_DATA localKey;
/// <summary/>
/// <summary>Specifies the remote key that changed.</summary>
public DRT_DATA remoteKey;
}
/// <summary/>
/// <summary>
/// This structure appears when the event has been raised to signal a change in a local key registration; the type field of
/// the DRT_EVENT_DATA structure is set to DRT_EVENT_REGISTRATION_STATE_CHANGED.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct REGISTRATIONSTATECHANGE
{
/// <summary/>
/// <summary>Specifies the type of registration state change that has occurred.</summary>
public DRT_REGISTRATION_STATE state;
/// <summary/>
/// <summary>Specifies the local key associated with the registration that has changed.</summary>
public DRT_DATA localKey;
}
/// <summary/>
/// <summary>
/// This structure appears when the event has been raised to signal a state change in the local DRT instance; the type field
/// of the DRT_EVENT_DATA structure is set to DRT_EVENT_STATUS_CHANGED.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct STATUSCHANGE
{
/// <summary/>
/// <summary>Contains the current DRT_STATUS of the local DRT instance.</summary>
public DRT_STATUS status;
/// <summary/>
/// <summary>
/// This structure contains the addresses returned by the bootstrap provider when the DRT attempts to join the mesh. This
/// structure is completed only when the DRT transitions to the DRT_ALONE state. The contents of this structure can be
/// used to diagnose connectivity issues between the local DRT instance and other nodes already present in the mesh.
/// </summary>
public BOOTSTRAPADDRESSES bootstrapAddresses;
/// <summary/>
/// <summary>
/// This structure contains the addresses returned by the bootstrap provider when the DRT attempts to join the mesh. This
/// structure is completed only when the DRT transitions to the DRT_ALONE state. The contents of this structure can be
/// used to diagnose connectivity issues between the local DRT instance and other nodes already present in the mesh.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct BOOTSTRAPADDRESSES
{
/// <summary/>
/// <summary>Contains the number of addresses in pAddresses.</summary>
public uint cntAddress;
/// <summary>PSOCKADDR_STORAGE</summary>
/// <summary>Contains an array of SOCKADDR_STORAGE addresses returned by the bootstrap provider.</summary>
public IntPtr pAddresses;
/// <summary>Gets the array of SOCKADDR_STORAGE addresses returned by the bootstrap provider.</summary>
public SOCKADDR_STORAGE[] Addresses => pAddresses.ToArray<SOCKADDR_STORAGE>((int)cntAddress);
}
}
}