mirror of https://github.com/dahall/Vanara.git
Working DistributedRoutingTable
parent
76087b0ab5
commit
48b09fd666
|
@ -15,12 +15,194 @@ using static Vanara.PInvoke.Ws2_32;
|
||||||
|
|
||||||
namespace Vanara.Net;
|
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>
|
/// <summary>Represents a distributed routing table from Win32.</summary>
|
||||||
public class DistributedRoutingTable
|
public class DistributedRoutingTable
|
||||||
{
|
{
|
||||||
private readonly SafeRegisteredWaitHandle? drtWaitEvent;
|
private readonly SafeRegisteredWaitHandle? drtWaitEvent;
|
||||||
private readonly SafeEventHandle? evt;
|
private readonly SafeEventHandle? evt;
|
||||||
private readonly SafeHDRT? hDrt;
|
private readonly SafeHDRT? hDrt;
|
||||||
|
private readonly IntPtr selfPin;
|
||||||
private readonly SafeWSA ws = SafeWSA.Initialize();
|
private readonly SafeWSA ws = SafeWSA.Initialize();
|
||||||
private DRT_SETTINGS pSettings;
|
private DRT_SETTINGS pSettings;
|
||||||
|
|
||||||
|
@ -51,44 +233,55 @@ public class DistributedRoutingTable
|
||||||
evt = CreateEvent(null, false, false);
|
evt = CreateEvent(null, false, false);
|
||||||
DrtOpen(pSettings, evt, default, out HDRT h).ThrowIfFailed();
|
DrtOpen(pSettings, evt, default, out HDRT h).ThrowIfFailed();
|
||||||
hDrt = new((IntPtr)h);
|
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("
|
HRESULT hr = DrtGetEventDataSize(Drt.hDrt, out var ulDrtEventDataLen);
|
||||||
// DrtGetEventDataSize failed: {0}\n", hr); goto Cleanup; }
|
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("
|
using (SafeCoTaskMemStruct<DRT_EVENT_DATA> pEventData = new(ulDrtEventDataLen))
|
||||||
// Out of memory\n"); goto Cleanup; }
|
{
|
||||||
|
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("
|
switch (pEventData.Value.type)
|
||||||
// DrtGetEventData failed: {0}\n", hr); goto Cleanup; }
|
{
|
||||||
|
case DRT_EVENT_TYPE.DRT_EVENT_STATUS_CHANGED:
|
||||||
// switch (pEventData.Value.type) { case DRT_EVENT_TYPE.DRT_EVENT_STATUS_CHANGED: switch (pEventData.Value.union.statusChange.status)
|
Drt.StatusChange?.Invoke(Drt, new(pEventData.Value));
|
||||||
// { case DRT_STATUS.DRT_ACTIVE: SetConsoleTitle("DrtSdkSample Current Drt Status: Active"); if (g_DisplayEvents) Console.Write(" DRT
|
break;
|
||||||
// Status Changed to Active\n"); break; case DRT_STATUS.DRT_ALONE: SetConsoleTitle("DrtSdkSample Current Drt Status: Alone"); if
|
case DRT_EVENT_TYPE.DRT_EVENT_LEAFSET_KEY_CHANGED:
|
||||||
// (g_DisplayEvents) Console.Write(" DRT Status Changed to Alone\n"); break; case DRT_STATUS.DRT_NO_NETWORK:
|
Drt.LeafSetKeyChange?.Invoke(Drt, new(pEventData.Value));
|
||||||
// SetConsoleTitle("DrtSdkSample Current Drt Status: No Network"); if (g_DisplayEvents) Console.Write(" DRT Status Changed to No
|
break;
|
||||||
// Network\n"); break; case DRT_STATUS.DRT_FAULTED: SetConsoleTitle("DrtSdkSample Current Drt Status: Faulted"); if (g_DisplayEvents)
|
case DRT_EVENT_TYPE.DRT_EVENT_REGISTRATION_STATE_CHANGED:
|
||||||
// Console.Write(" DRT Status Changed to Faulted\n"); break; }
|
Drt.RegistrationStateChange?.Invoke(Drt, new(pEventData.Value));
|
||||||
|
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("
|
Cleanup:
|
||||||
// Leafset Key Deleted Event: {0}\n", pEventData.Value.hr); break; } }
|
return;
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,8 +304,7 @@ public class DrtBootstrapProvider : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Initializes a new instance of the <see cref="DrtBootstrapProvider"/> class.</summary>
|
/// <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>
|
/// <summary>Initializes a new instance of the <see cref="DrtBootstrapProvider"/> class.</summary>
|
||||||
/// <param name="ptr">The PTR.</param>
|
/// <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;
|
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>
|
/// <summary>Gets a value indicating whether this instance is attached.</summary>
|
||||||
/// <value>
|
/// <value><see langword="true"/> if this instance is attached; otherwise, <see langword="false"/>.</value>
|
||||||
/// <see langword="true" /> if this instance is attached; otherwise, <see langword="false" />.
|
|
||||||
/// </value>
|
|
||||||
protected bool IsAttached => refCount > 0;
|
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>
|
/// <summary>Ends the resolution of an endpoint.</summary>
|
||||||
/// <param name="ResolveContext">
|
/// <param name="ResolveContext">
|
||||||
/// The <c>BOOTSTRAP_RESOLVE_CONTEXT</c> received from the Resolve function of the specified bootstrap provider.
|
/// 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>
|
/// </param>
|
||||||
protected virtual HRESULT Register([In] IPEndPoint[]? pAddressList) => HRESULT.S_OK;
|
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>
|
/// <summary>
|
||||||
/// This function deregisters an endpoint with the bootstrapping mechanism. As a result, other nodes will be unable to find the local
|
/// 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.
|
/// node via the bootstrap resolver.
|
||||||
|
@ -286,32 +495,11 @@ public abstract class DrtCustomBootstrapProvider : DrtBootstrapProvider
|
||||||
AddRef();
|
AddRef();
|
||||||
return HRESULT.S_OK;
|
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)
|
private void InternalDetach(IntPtr pvContext)
|
||||||
{
|
{
|
||||||
InterlockedCompareExchange(ref refCount, 0, 1);
|
InterlockedCompareExchange(ref refCount, 0, 1);
|
||||||
Release();
|
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 void InternalEndResolve(IntPtr pvContext, DRT_BOOTSTRAP_RESOLVE_CONTEXT ResolveContext) => EndResolve(ResolveContext);
|
||||||
|
|
||||||
private HRESULT InternalInitResolve(IntPtr pvContext, bool fSplitDetect, uint timeout, uint cMaxResults,
|
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();
|
private void InternalUnregister(IntPtr pvContext) => Unregister();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>DNS Bootstrapper</summary>
|
/// <summary>Abstract base class for DRT event arguments.</summary>
|
||||||
/// <seealso cref="Vanara.Net.DrtCustomBootstrapProvider"/>
|
/// <seealso cref="System.EventArgs"/>
|
||||||
public class CustomDnsBootstapper : DrtCustomBootstrapProvider
|
public abstract class DrtEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
private readonly string hostname;
|
/// <summary>Initializes a new instance of the <see cref="DrtEventArgs"/> class.</summary>
|
||||||
private readonly string port;
|
/// <param name="data">The data.</param>
|
||||||
private readonly object m_lock = new();
|
protected DrtEventArgs(in DRT_EVENT_DATA data)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
hostname = pNodeName;
|
LastError = data.hr;
|
||||||
port = pServiceName;
|
Context = data.pvContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <summary>
|
||||||
protected override void EndResolve([In] DRT_BOOTSTRAP_RESOLVE_CONTEXT ResolveContext)
|
/// 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;
|
Type = data.union.leafsetKeyChange.change;
|
||||||
|
LocalKey = data.union.leafsetKeyChange.localKey.GetArray();
|
||||||
var CallbackComplete = CreateEvent(default, true, false, default);
|
RemoteKey = data.union.leafsetKeyChange.remoteKey.GetArray();
|
||||||
|
|
||||||
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/>
|
/// <summary>Specifies the local key associated with the leaf set that has changed.</summary>
|
||||||
protected override HRESULT InitResolve(bool fSplitDetect, TimeSpan timeout, uint cMaxResults, out DRT_BOOTSTRAP_RESOLVE_CONTEXT pResolveContext, out bool fFatalError)
|
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;
|
State = data.union.registrationStateChange.state;
|
||||||
pResolveContext = default;
|
LocalKey = data.union.registrationStateChange.localKey.GetArray();
|
||||||
|
|
||||||
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/>
|
/// <summary>Specifies the local key associated with the registration that has changed.</summary>
|
||||||
protected override HRESULT IssueResolve(DRT_BOOTSTRAP_RESOLVE_CALLBACK callback, [In] IntPtr pvCallbackContext, [In] DRT_BOOTSTRAP_RESOLVE_CONTEXT ResolveContext, out bool fFatalError)
|
public byte[]? LocalKey { get; }
|
||||||
{
|
|
||||||
fFatalError = false;
|
|
||||||
|
|
||||||
if (callback is null)
|
/// <summary>Specifies the type of registration state change that has occurred.</summary>
|
||||||
{
|
public DRT_REGISTRATION_STATE State { get; }
|
||||||
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>Base class for a DRT security provider.</summary>
|
/// <summary>Base class for a DRT security provider.</summary>
|
||||||
|
@ -526,8 +595,7 @@ public class DrtSecurityProvider : IDisposable
|
||||||
pProvType = 'h';
|
pProvType = 'h';
|
||||||
}
|
}
|
||||||
|
|
||||||
private DrtSecurityProvider()
|
private DrtSecurityProvider() { }
|
||||||
{ }
|
|
||||||
|
|
||||||
private DrtSecurityProvider(IntPtr ptr, char provType)
|
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
|
internal static class DrtUtil
|
||||||
{
|
{
|
||||||
public static IntPtr Alloc(int size) => Marshal.AllocCoTaskMem(size);
|
public static IntPtr Alloc(int size) => Marshal.AllocCoTaskMem(size);
|
||||||
|
@ -653,7 +746,8 @@ internal static class DrtUtil
|
||||||
public abstract class DrtCustomSecurityProvider : DrtSecurityProvider
|
public abstract class DrtCustomSecurityProvider : DrtSecurityProvider
|
||||||
{
|
{
|
||||||
private int refCount;
|
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>
|
/// <param name="context">The context.</param>
|
||||||
protected DrtCustomSecurityProvider(object? context) : base(default)
|
protected DrtCustomSecurityProvider(object? context) : base(default)
|
||||||
{
|
{
|
||||||
|
@ -678,6 +772,14 @@ public abstract class DrtCustomSecurityProvider : DrtSecurityProvider
|
||||||
AddRef();
|
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>
|
/// <summary>Adds the reference.</summary>
|
||||||
protected void AddRef()
|
protected void AddRef()
|
||||||
{
|
{
|
||||||
|
@ -686,27 +788,6 @@ public abstract class DrtCustomSecurityProvider : DrtSecurityProvider
|
||||||
InterlockedIncrement(ref refCount);
|
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>
|
/// <summary>
|
||||||
/// Called when the DRT receives a message containing encrypted data. This function is only called when the DRT is operating in the
|
/// 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.
|
/// <c>DRT_SECURE_CONFIDENTIALPAYLOAD</c> security mode defined by DRT_SECURITY_MODE.
|
||||||
|
@ -750,6 +831,17 @@ public abstract class DrtCustomSecurityProvider : DrtSecurityProvider
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected virtual HRESULT RegisterKey(in DRT_REGISTRATION pRegistration, [In, Optional] IntPtr pvKeyContext) => HRESULT.S_OK;
|
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>
|
/// <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
|
/// 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.
|
/// 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></summary>
|
||||||
///
|
/// <seealso cref="Vanara.Net.DrtCustomSecurityProvider"/>
|
||||||
/// </summary>
|
|
||||||
/// <seealso cref="Vanara.Net.DrtCustomSecurityProvider" />
|
|
||||||
public class CustomNullSecurityProvider : DrtCustomSecurityProvider
|
public class CustomNullSecurityProvider : DrtCustomSecurityProvider
|
||||||
{
|
{
|
||||||
internal unsafe class CCustomNullSecuredAddressPayload : IDisposable
|
internal unsafe class CCustomNullSecuredAddressPayload : IDisposable
|
||||||
|
@ -998,9 +1088,7 @@ public class CustomNullSecurityProvider : DrtCustomSecurityProvider
|
||||||
//CERT_PUBLIC_KEY_INFO*
|
//CERT_PUBLIC_KEY_INFO*
|
||||||
private SafeCoTaskMemStruct<CERT_PUBLIC_KEY_INFO>? m_pPublicKey;
|
private SafeCoTaskMemStruct<CERT_PUBLIC_KEY_INFO>? m_pPublicKey;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>Initializes a new instance of the <see cref="CCustomNullSecuredAddressPayload"/> class.</summary>
|
||||||
/// Initializes a new instance of the <see cref="CCustomNullSecuredAddressPayload"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="bMajor">The b major.</param>
|
/// <param name="bMajor">The b major.</param>
|
||||||
/// <param name="bMinor">The b minor.</param>
|
/// <param name="bMinor">The b minor.</param>
|
||||||
/// <param name="key">The key.</param>
|
/// <param name="key">The key.</param>
|
||||||
|
|
|
@ -1826,64 +1826,93 @@ namespace Vanara.PInvoke
|
||||||
[StructLayout(LayoutKind.Explicit)]
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
public struct UNION
|
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)]
|
[FieldOffset(0)]
|
||||||
public LEAFSETKEYCHANGE leafsetKeyChange;
|
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)]
|
[FieldOffset(0)]
|
||||||
public REGISTRATIONSTATECHANGE registrationStateChange;
|
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)]
|
[FieldOffset(0)]
|
||||||
public STATUSCHANGE statusChange;
|
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)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct LEAFSETKEYCHANGE
|
public struct LEAFSETKEYCHANGE
|
||||||
|
|
||||||
{
|
{
|
||||||
/// <summary/>
|
/// <summary>Specifies the type of key change that has occurred.</summary>
|
||||||
public DRT_LEAFSET_KEY_CHANGE_TYPE change;
|
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;
|
public DRT_DATA localKey;
|
||||||
|
|
||||||
/// <summary/>
|
/// <summary>Specifies the remote key that changed.</summary>
|
||||||
public DRT_DATA remoteKey;
|
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)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct REGISTRATIONSTATECHANGE
|
public struct REGISTRATIONSTATECHANGE
|
||||||
{
|
{
|
||||||
/// <summary/>
|
/// <summary>Specifies the type of registration state change that has occurred.</summary>
|
||||||
public DRT_REGISTRATION_STATE state;
|
public DRT_REGISTRATION_STATE state;
|
||||||
|
|
||||||
/// <summary/>
|
/// <summary>Specifies the local key associated with the registration that has changed.</summary>
|
||||||
public DRT_DATA localKey;
|
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)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct STATUSCHANGE
|
public struct STATUSCHANGE
|
||||||
|
|
||||||
{
|
{
|
||||||
/// <summary/>
|
/// <summary>Contains the current DRT_STATUS of the local DRT instance.</summary>
|
||||||
public DRT_STATUS status;
|
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;
|
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)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct BOOTSTRAPADDRESSES
|
public struct BOOTSTRAPADDRESSES
|
||||||
{
|
{
|
||||||
/// <summary/>
|
/// <summary>Contains the number of addresses in pAddresses.</summary>
|
||||||
public uint cntAddress;
|
public uint cntAddress;
|
||||||
|
|
||||||
/// <summary>PSOCKADDR_STORAGE</summary>
|
/// <summary>Contains an array of SOCKADDR_STORAGE addresses returned by the bootstrap provider.</summary>
|
||||||
public IntPtr pAddresses;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue