2016-08-03 10:59:49 +00:00
//------------------------------------------------------------------------------
// <copyright file="PeerNameResolver.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Net.PeerToPeer
{
using System ;
using System.Collections.Generic ;
using System.Text ;
using System.ComponentModel ;
using System.Threading ;
using System.Security.Permissions ;
using System.Runtime.InteropServices ;
using System.Net ;
using System.Net.Sockets ;
using System.Diagnostics ;
/// <summary>
/// This is the event args class we give back each time when
/// we have incremental resolution results
/// </summary>
public class ResolveProgressChangedEventArgs : ProgressChangedEventArgs
{
private PeerNameRecord m_PeerNameRecord ;
/// <summary>
/// We use progress percentage of **0** all times sice
/// we will not no upfront how many records we are going to get
/// </summary>
/// <param name="peerNameRecord"></param>
/// <param name="userToken"></param>
public ResolveProgressChangedEventArgs ( PeerNameRecord peerNameRecord ,
object userToken ) : base ( 0 , userToken )
{
m_PeerNameRecord = peerNameRecord ;
}
public PeerNameRecord PeerNameRecord
{
get
{
return m_PeerNameRecord ;
}
}
}
/// <summary>
/// When the resolution completes, we invoke the callback with this event args instance
/// </summary>
public class ResolveCompletedEventArgs : AsyncCompletedEventArgs
{
private PeerNameRecordCollection m_PeerNameRecordCollection ;
public ResolveCompletedEventArgs (
PeerNameRecordCollection peerNameRecordCollection ,
Exception error ,
bool canceled ,
object userToken )
: base ( error , canceled , userToken )
{
m_PeerNameRecordCollection = peerNameRecordCollection ;
}
public PeerNameRecordCollection PeerNameRecordCollection
{
get
{
return m_PeerNameRecordCollection ;
}
}
}
internal class PeerNameResolverHelper : IDisposable
{
private const UInt32 FACILITY_P2P = 99 ;
private const UInt32 NO_MORE_RECORDS = 0x4003 ;
private const int PEER_E_NO_MORE = ( int ) ( ( ( int ) 1 < < 31 ) | ( ( int ) FACILITY_P2P < < 16 ) | NO_MORE_RECORDS ) ;
//------------------------------------------
//userState the user has supplied
//------------------------------------------
internal object m_userState ;
//------------------------------------------
//Handle to the resolution process
//------------------------------------------
internal SafePeerNameEndResolve m_SafePeerNameEndResolve ;
//------------------------------------------
//Event that the native API sets to indicate that
//information is available and that we should call
//the PeerPnrpGetEndPoint() to get the end point
//------------------------------------------
internal AutoResetEvent m_EndPointInfoAvailableEvent = new AutoResetEvent ( false ) ;
//------------------------------------------
//The WaitHandle that hooks up a callback to the
//event
//------------------------------------------
internal RegisteredWaitHandle m_RegisteredWaitHandle ;
//------------------------------------------
//PeerName that is being resolved
//------------------------------------------
internal PeerName m_PeerName ;
//------------------------------------------
//Cloud in which the resolution must occur
//------------------------------------------
internal Cloud m_Cloud ;
//------------------------------------------
//Max number of records to resolve
//------------------------------------------
internal int m_MaxRecords ;
//------------------------------------------
//Disposed or not
//------------------------------------------
internal bool m_Disposed ;
//-----------------------------------------
//Flag to indicate completed or an exception
//happened. If you set this flag you own
//calling the callback
//-----------------------------------------
internal bool m_CompletedOrException ;
//-----------------------------------------
//Flag to indicate that the call is canceled
//If you set this flag you own calling the callback
//-----------------------------------------
internal bool m_Cancelled ;
//------------------------------------------
//A place to save the incremental results
//so that we can invoke the completed
//handler with all the results at once
//------------------------------------------
PeerNameRecordCollection m_PeerNameRecordCollection = new PeerNameRecordCollection ( ) ;
//------------------------------------------
//Async operation to ensure synchornization
//context
//------------------------------------------
AsyncOperation m_AsyncOp ;
//------------------------------------------
//A link to the resolver to avoid
//circular dependencies and enable GC
//------------------------------------------
WeakReference m_PeerNameResolverWeakReference ;
//------------------------------------------
//Lock to make sure things don't mess up stuff
//------------------------------------------
object m_Lock = new Object ( ) ;
//------------------------------------------
//EventID or Just a trackig id
//------------------------------------------
int m_TraceEventId ;
internal PeerNameResolverHelper ( PeerName peerName , Cloud cloud , int MaxRecords , object userState , PeerNameResolver parent , int NewTraceEventId )
{
m_userState = userState ;
m_PeerName = peerName ;
m_Cloud = cloud ;
m_MaxRecords = MaxRecords ;
m_PeerNameResolverWeakReference = new WeakReference ( parent ) ;
m_TraceEventId = NewTraceEventId ;
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Information , m_TraceEventId , "New PeerNameResolverHelper created with TraceEventID {0}" , m_TraceEventId ) ;
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Information , m_TraceEventId ,
"\tPeerName: {0}, Cloud: {1}, MaxRecords: {2}, userState {3}, ParentReference {4}" ,
m_PeerName ,
m_Cloud ,
m_MaxRecords ,
userState . GetHashCode ( ) ,
m_PeerNameResolverWeakReference . Target . GetHashCode ( )
) ;
}
// <SecurityKernel Critical="True" Ring="0">
// <SatisfiesLinkDemand Name="WaitHandle.get_SafeWaitHandle():Microsoft.Win32.SafeHandles.SafeWaitHandle" />
// <SatisfiesLinkDemand Name="SafeHandle.get_IsInvalid():System.Boolean" />
// <SatisfiesLinkDemand Name="SafeHandle.get_IsClosed():System.Boolean" />
// <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
// <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
// <CallsSuppressUnmanagedCode Name="UnsafeP2PNativeMethods.PeerPnrpStartResolve(System.String,System.String,System.UInt32,Microsoft.Win32.SafeHandles.SafeWaitHandle,System.Net.PeerToPeer.SafePeerNameEndResolve&):System.Int32" />
// <ReferencesCritical Name="Method: EndPointInfoAvailableCallback(Object, Boolean):Void" Ring="1" />
// <ReferencesCritical Name="Field: m_SafePeerNameEndResolve" Ring="1" />
// <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
// </SecurityKernel>
[System.Security.SecurityCritical]
internal void StartAsyncResolve ( )
{
//------------------------------------------
//Check for disposal
//------------------------------------------
if ( m_Disposed ) throw new ObjectDisposedException ( this . GetType ( ) . FullName ) ;
//------------------------------------------
//First wire up a callback
//------------------------------------------
m_RegisteredWaitHandle = ThreadPool . RegisterWaitForSingleObject ( m_EndPointInfoAvailableEvent , //Event that triggers the callback
new WaitOrTimerCallback ( EndPointInfoAvailableCallback ) , //callback to be called
null , //state to be passed
- 1 , //Timeout - aplicable only for timers not for events
false //call us everytime the event is set not just one time
) ;
//------------------------------------------
//Now call the native API to start the resolution
//process save the handle for later
//------------------------------------------
Int32 result = UnsafeP2PNativeMethods . PeerPnrpStartResolve ( m_PeerName . ToString ( ) ,
m_Cloud . InternalName ,
( UInt32 ) m_MaxRecords ,
m_EndPointInfoAvailableEvent . SafeWaitHandle ,
out m_SafePeerNameEndResolve ) ;
if ( result ! = 0 )
{
if ( ! m_SafePeerNameEndResolve . IsInvalid & & ! m_SafePeerNameEndResolve . IsClosed )
{
m_SafePeerNameEndResolve . Dispose ( ) ;
}
m_RegisteredWaitHandle . Unregister ( null ) ;
m_RegisteredWaitHandle = null ;
PeerToPeerException ex = PeerToPeerException . CreateFromHr ( SR . GetString ( SR . Pnrp_CouldNotStartNameResolution ) , result ) ;
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Error , m_TraceEventId ,
"Exception occurred while starting async resolve" ) ;
throw ex ;
}
//------------------------------------------
//Create an async operation with the given
//user state
//------------------------------------------
m_AsyncOp = AsyncOperationManager . CreateOperation ( m_userState ) ;
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Information , m_TraceEventId ,
"Successfully started the async resolve. The native handle is {0}" , m_SafePeerNameEndResolve . DangerousGetHandle ( ) ) ;
}
// <SecurityKernel Critical="True" Ring="0">
// <UsesUnsafeCode Name="Local pEndPointInfo of type: PEER_PNRP_ENDPOINT_INFO*" />
// <UsesUnsafeCode Name="Method: IntPtr.op_Explicit(System.IntPtr):System.Void*" />
// <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
// <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
// <SatisfiesLinkDemand Name="Marshal.PtrToStringUni(System.IntPtr):System.String" />
// <SatisfiesLinkDemand Name="Marshal.Copy(System.IntPtr,System.Byte[],System.Int32,System.Int32):System.Void" />
// <SatisfiesLinkDemand Name="Marshal.ReadIntPtr(System.IntPtr):System.IntPtr" />
// <SatisfiesLinkDemand Name="Marshal.SizeOf(System.Type):System.Int32" />
// <CallsSuppressUnmanagedCode Name="UnsafeP2PNativeMethods.PeerPnrpGetEndpoint(System.IntPtr,System.Net.PeerToPeer.SafePeerData&):System.Int32" />
// <ReferencesCritical Name="Local shEndPointInfo of type: SafePeerData" Ring="1" />
// <ReferencesCritical Name="Field: m_SafePeerNameEndResolve" Ring="1" />
// <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
// </SecurityKernel>
[System.Security.SecurityCritical]
public void EndPointInfoAvailableCallback ( object state , bool timedOut )
{
//------------------------------------------
//This callback is called whenever there is an endpoint info
//available or the resultion is completed
//------------------------------------------
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Information , m_TraceEventId ,
"EndPointInfoAvailableCallback called" ) ;
PeerNameRecord record = null ;
SafePeerData shEndPointInfo ;
Int32 result = 0 ;
PeerNameResolver parent = null ;
if ( m_Cancelled )
{
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Information , m_TraceEventId ,
"Detected that the async operation is already canceled - before entering the lock" ) ;
return ;
}
lock ( m_Lock )
{
if ( m_Cancelled )
{
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Information , m_TraceEventId ,
"Detected that the async operation is already canceled - after entering the lock" ) ;
return ;
}
result = UnsafeP2PNativeMethods . PeerPnrpGetEndpoint ( m_SafePeerNameEndResolve . DangerousGetHandle ( ) , out shEndPointInfo ) ;
if ( result ! = 0 )
{
if ( result = = PEER_E_NO_MORE )
{
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Information , m_TraceEventId ,
"Native API returned that there are no more records - resolve completed successfully" ) ;
}
m_CompletedOrException = true ;
m_SafePeerNameEndResolve . Dispose ( ) ;
}
else
{
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Information , m_TraceEventId ,
"Proceeding to retrieve the endpoint information from incremental resolve" ) ;
try
{
unsafe
{
PEER_PNRP_ENDPOINT_INFO * pEndPointInfo = ( PEER_PNRP_ENDPOINT_INFO * ) shEndPointInfo . DangerousGetHandle ( ) ;
record = new PeerNameRecord ( ) ;
record . PeerName = new PeerName ( Marshal . PtrToStringUni ( pEndPointInfo - > pwszPeerName ) ) ;
string comment = Marshal . PtrToStringUni ( pEndPointInfo - > pwszComment ) ;
if ( comment ! = null & & comment . Length > 0 )
{
record . Comment = comment ;
}
if ( pEndPointInfo - > payLoad . cbPayload ! = 0 )
{
record . Data = new byte [ pEndPointInfo - > payLoad . cbPayload ] ;
Marshal . Copy ( pEndPointInfo - > payLoad . pbPayload , record . Data , 0 , ( int ) pEndPointInfo - > payLoad . cbPayload ) ;
}
//record.EndPointList = new IPEndPoint[pEndPointInfo->cAddresses];
IntPtr ppSOCKADDRs = pEndPointInfo - > ArrayOfSOCKADDRIN6Pointers ;
for ( UInt32 j = 0 ; j < pEndPointInfo - > cAddresses ; j + + )
{
IntPtr pSOCKADDR = Marshal . ReadIntPtr ( ppSOCKADDRs ) ;
byte [ ] AddressFamilyBuffer = new byte [ 2 ] ;
Marshal . Copy ( pSOCKADDR , AddressFamilyBuffer , 0 , 2 ) ;
int addressFamily = 0 ;
#if BIGENDIAN
addressFamily = AddressFamilyBuffer [ 1 ] + ( ( int ) AddressFamilyBuffer [ 0 ] < < 8 ) ;
#else
addressFamily = AddressFamilyBuffer [ 0 ] + ( ( int ) AddressFamilyBuffer [ 1 ] < < 8 ) ;
#endif
byte [ ] buffer = new byte [ ( ( AddressFamily ) addressFamily = = AddressFamily . InterNetwork ) ? SystemNetHelpers . IPv4AddressSize : SystemNetHelpers . IPv6AddressSize ] ;
Marshal . Copy ( pSOCKADDR , buffer , 0 , buffer . Length ) ;
IPEndPoint ipe = SystemNetHelpers . IPEndPointFromSOCKADDRBuffer ( buffer ) ;
record . EndPointCollection . Add ( ipe ) ;
ppSOCKADDRs = ( IntPtr ) ( ( long ) ppSOCKADDRs + Marshal . SizeOf ( typeof ( IntPtr ) ) ) ;
}
}
}
finally
{
shEndPointInfo . Dispose ( ) ;
}
record . TracePeerNameRecord ( ) ;
m_PeerNameRecordCollection . Add ( record ) ;
ResolveProgressChangedEventArgs resolveProgressChangedEventArgs = new ResolveProgressChangedEventArgs (
record , m_AsyncOp . UserSuppliedState ) ;
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Information , m_TraceEventId ,
"Proceeding to call progress changed event callback" ) ;
parent = m_PeerNameResolverWeakReference . Target as PeerNameResolver ;
if ( parent ! = null )
{
parent . PrepareToRaiseProgressChangedEvent ( m_AsyncOp , resolveProgressChangedEventArgs ) ;
}
return ;
}
}
ResolveCompletedEventArgs resolveCompletedEventArgs ;
if ( result = = PEER_E_NO_MORE )
{
resolveCompletedEventArgs = new ResolveCompletedEventArgs ( m_PeerNameRecordCollection ,
null , false , m_AsyncOp . UserSuppliedState ) ;
}
else
{
PeerToPeerException ex = PeerToPeerException . CreateFromHr ( SR . GetString ( SR . Pnrp_ExceptionWhileResolvingAPeerName ) , result ) ;
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Information , m_TraceEventId ,
"Exception occurred when the native API is called to harvest an incremental resolve notification" ) ;
resolveCompletedEventArgs = new ResolveCompletedEventArgs ( null ,
ex , false , m_AsyncOp . UserSuppliedState ) ;
}
parent = m_PeerNameResolverWeakReference . Target as PeerNameResolver ;
if ( parent ! = null )
{
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Information , m_TraceEventId ,
"Proceeding to call the ResolveCompleted callback" ) ;
parent . PrepareToRaiseCompletedEvent ( m_AsyncOp , resolveCompletedEventArgs ) ;
}
return ;
}
// <SecurityKernel Critical="True" Ring="0">
// <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
// <ReferencesCritical Name="Field: m_SafePeerNameEndResolve" Ring="1" />
// </SecurityKernel>
[System.Security.SecurityCritical]
public void ContineCancelCallback ( object state )
{
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Information , m_TraceEventId ,
"ContineCancelCallback called" ) ;
try
{
if ( m_CompletedOrException )
{
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Information , m_TraceEventId ,
"ContinueCancelCallback detected (before acquiring lock) that another thread has already called completed event - so returning without calling cancel" ) ;
return ;
}
lock ( m_Lock )
{
if ( m_Cancelled )
{
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Information , m_TraceEventId ,
"ContinueCancelCallback detected (after acquiring lock) that cancel has already been called" ) ;
return ;
}
if ( m_CompletedOrException )
{
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Information , m_TraceEventId ,
"ContinueCancelCallback detected (after acquiring lock) that another thread has already called completed event - so returning without calling cancel" ) ;
return ;
}
else
{
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Information , m_TraceEventId ,
"ContinueCancelCallback is proceeding to close the handle and call the Completed callback with Cancelled = true" ) ;
}
m_Cancelled = true ;
m_SafePeerNameEndResolve . Dispose ( ) ;
}
PeerNameResolver parent = m_PeerNameResolverWeakReference . Target as PeerNameResolver ;
if ( parent ! = null )
{
ResolveCompletedEventArgs e = new ResolveCompletedEventArgs ( null , null , true , m_AsyncOp . UserSuppliedState ) ;
parent . PrepareToRaiseCompletedEvent ( m_AsyncOp , e ) ;
}
}
catch
{
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Critical , m_TraceEventId , "Exception while cancelling the call " ) ;
throw ;
}
}
// <SecurityKernel Critical="True" Ring="1">
// <ReferencesCritical Name="Method: ContineCancelCallback(Object):Void" Ring="1" />
// </SecurityKernel>
[System.Security.SecurityCritical]
public void CancelAsync ( )
{
//Defer the work to a callback
ThreadPool . QueueUserWorkItem ( new WaitCallback ( ContineCancelCallback ) ) ;
}
// <SecurityKernel Critical="True" Ring="1">
// <ReferencesCritical Name="Method: Dispose(Boolean):Void" Ring="1" />
// </SecurityKernel>
[System.Security.SecurityCritical]
public void Dispose ( )
{
Dispose ( true ) ;
GC . SuppressFinalize ( this ) ;
}
// <SecurityKernel Critical="True" Ring="0">
// <SatisfiesLinkDemand Name="SafeHandle.get_IsInvalid():System.Boolean" />
// <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
// <ReferencesCritical Name="Field: m_SafePeerNameEndResolve" Ring="1" />
// </SecurityKernel>
[System.Security.SecurityCritical]
public void Dispose ( bool disposing )
{
if ( ! m_Disposed )
{
if ( ! m_SafePeerNameEndResolve . IsInvalid )
{
m_SafePeerNameEndResolve . Dispose ( ) ;
}
if ( m_RegisteredWaitHandle ! = null )
m_RegisteredWaitHandle . Unregister ( null ) ;
m_RegisteredWaitHandle = null ;
m_EndPointInfoAvailableEvent . Close ( ) ;
}
m_Disposed = true ;
}
internal int TraceEventId
{
get
{
return m_TraceEventId ;
}
}
}
/// <summary>
2017-08-21 15:34:15 +00:00
/// PeerNameResolver does sync and async resolves.
2016-08-03 10:59:49 +00:00
/// PeerNameResolver supports multiple outstanding async calls
/// </summary>
public class PeerNameResolver
{
static PeerNameResolver ( )
{
//-------------------------------------------------
//Check for the availability of the simpler PNRP APIs
//-------------------------------------------------
if ( ! PeerToPeerOSHelper . SupportsP2P )
{
throw new PlatformNotSupportedException ( SR . GetString ( SR . P2P_NotAvailable ) ) ;
}
}
private event EventHandler < ResolveProgressChangedEventArgs > m_ResolveProgressChanged ;
/// <summary>
/// When an event handler is hooked up or removed, we demand the permissions.
/// In partial trust cases, this will avoid the security risk of just hooking up an existing instance
/// of the PeerNameResolver and then receiving all notification of
/// in resolution that is happening
/// </summary>
public event EventHandler < ResolveProgressChangedEventArgs > ResolveProgressChanged
{
add
{
PnrpPermission . UnrestrictedPnrpPermission . Demand ( ) ;
m_ResolveProgressChanged + = value ;
}
remove
{
PnrpPermission . UnrestrictedPnrpPermission . Demand ( ) ;
m_ResolveProgressChanged - = value ;
}
}
private event EventHandler < ResolveCompletedEventArgs > m_ResolveCompleted ;
/// <summary>
/// When an event handler is hooked up or removed, we demand the permissions.
/// In partial trust cases, this will avoid the security risk of just hooking up an existing instance
/// of the PeerNameResolver and then receiving all notification of
/// in resolution that is happening
/// </summary>
public event EventHandler < ResolveCompletedEventArgs > ResolveCompleted
{
add
{
PnrpPermission . UnrestrictedPnrpPermission . Demand ( ) ;
m_ResolveCompleted + = value ;
}
remove
{
PnrpPermission . UnrestrictedPnrpPermission . Demand ( ) ;
m_ResolveCompleted - = value ;
}
}
SendOrPostCallback OnResolveProgressChangedDelegate ;
SendOrPostCallback OnResolveCompletedDelegate ;
/// <summary>
/// The following lock and the Sorted Dictionary served
/// the purpose of keeping an account of the multiple outstanding async
/// resolutions. Each outstanding async operation is
/// keyed based on the userState parameter passed in
/// </summary>
private object m_PeerNameResolverHelperListLock = new object ( ) ;
private Dictionary < object , PeerNameResolverHelper > m_PeerNameResolverHelperList = new Dictionary < object , PeerNameResolverHelper > ( ) ;
public PeerNameResolver ( )
{
OnResolveProgressChangedDelegate = new SendOrPostCallback ( ResolveProgressChangedWaitCallback ) ;
OnResolveCompletedDelegate = new SendOrPostCallback ( ResolveCompletedWaitCallback ) ;
}
public PeerNameRecordCollection Resolve ( PeerName peerName )
{
return Resolve ( peerName , Cloud . Available , int . MaxValue ) ;
}
public PeerNameRecordCollection Resolve ( PeerName peerName , Cloud cloud )
{
return Resolve ( peerName , cloud , int . MaxValue ) ;
}
public PeerNameRecordCollection Resolve ( PeerName peerName , int maxRecords )
{
return Resolve ( peerName , Cloud . Available , maxRecords ) ;
}
/// <summary>
2017-08-21 15:34:15 +00:00
/// Implements sync resolve of the PeerName in the cloud given
2016-08-03 10:59:49 +00:00
/// </summary>
/// <param name="peerName"></param>
/// <param name="cloud"></param>
/// <param name="MaxRecords"></param>
/// <returns></returns>
// <SecurityKernel Critical="True" Ring="0">
// <UsesUnsafeCode Name="Local pEndPoints of type: PEER_PNRP_ENDPOINT_INFO*" />
// <UsesUnsafeCode Name="Local pEndPointInfo of type: PEER_PNRP_ENDPOINT_INFO*" />
// <UsesUnsafeCode Name="Method: IntPtr.op_Explicit(System.IntPtr):System.Void*" />
// <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
// <SatisfiesLinkDemand Name="Marshal.PtrToStringUni(System.IntPtr):System.String" />
// <SatisfiesLinkDemand Name="Marshal.Copy(System.IntPtr,System.Byte[],System.Int32,System.Int32):System.Void" />
// <SatisfiesLinkDemand Name="Marshal.ReadIntPtr(System.IntPtr):System.IntPtr" />
// <SatisfiesLinkDemand Name="Marshal.SizeOf(System.Type):System.Int32" />
// <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
// <CallsSuppressUnmanagedCode Name="UnsafeP2PNativeMethods.PeerPnrpResolve(System.String,System.String,System.UInt32&,System.Net.PeerToPeer.SafePeerData&):System.Int32" />
// <ReferencesCritical Name="Local shEndPointInfoArray of type: SafePeerData" Ring="1" />
// <ReferencesCritical Name="Method: UnsafeP2PNativeMethods.PnrpStartup():System.Void" Ring="1" />
// <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
// </SecurityKernel>
[System.Security.SecurityCritical]
public PeerNameRecordCollection Resolve ( PeerName peerName , Cloud cloud , int maxRecords )
{
//---------------------------------------------------
//Check arguments
//---------------------------------------------------
if ( peerName = = null )
{
throw new ArgumentNullException ( SR . GetString ( SR . Pnrp_PeerNameCantBeNull ) , "peerName" ) ;
}
if ( maxRecords < = 0 )
{
throw new ArgumentOutOfRangeException ( "maxRecords" , SR . GetString ( SR . Pnrp_MaxRecordsParameterMustBeGreaterThanZero ) ) ;
}
//---------------------------------------------------
//Assume all clouds if the clould passed is null?
//---------------------------------------------------
if ( cloud = = null )
{
cloud = Cloud . Available ;
}
//---------------------------------------------------
//Demand CAS permissions
//---------------------------------------------------
PnrpPermission . UnrestrictedPnrpPermission . Demand ( ) ;
//---------------------------------------------------------------
//No perf hit here, real native call happens only one time if it
//did not already happen
//---------------------------------------------------------------
UnsafeP2PNativeMethods . PnrpStartup ( ) ;
//---------------------------------------------------------------
//Trace log
//---------------------------------------------------------------
2017-08-21 15:34:15 +00:00
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Information , 0 , "Sync Resolve called with PeerName: {0}, Cloud: {1}, MaxRecords {2}" , peerName , cloud , maxRecords ) ;
2016-08-03 10:59:49 +00:00
SafePeerData shEndPointInfoArray ;
string NativeCloudName = cloud . InternalName ;
UInt32 ActualCountOfEndPoints = ( UInt32 ) maxRecords ;
int result = UnsafeP2PNativeMethods . PeerPnrpResolve ( peerName . ToString ( ) ,
NativeCloudName ,
ref ActualCountOfEndPoints ,
out shEndPointInfoArray ) ;
if ( result ! = 0 )
{
throw PeerToPeerException . CreateFromHr ( SR . GetString ( SR . Pnrp_CouldNotStartNameResolution ) , result ) ;
}
//---------------------------------------------------
//If there are no endpoints returned, return
//an empty PeerNameRecord Collection
//---------------------------------------------------
PeerNameRecordCollection PeerNameRecords = new PeerNameRecordCollection ( ) ;
if ( ActualCountOfEndPoints ! = 0 )
{
try
{
unsafe
{
IntPtr pEndPointInfoArray = shEndPointInfoArray . DangerousGetHandle ( ) ;
PEER_PNRP_ENDPOINT_INFO * pEndPoints = ( PEER_PNRP_ENDPOINT_INFO * ) pEndPointInfoArray ;
for ( int i = 0 ; i < ActualCountOfEndPoints ; i + + )
{
PeerNameRecord record = new PeerNameRecord ( ) ;
PEER_PNRP_ENDPOINT_INFO * pEndPointInfo = & pEndPoints [ i ] ;
record . PeerName = new PeerName ( Marshal . PtrToStringUni ( pEndPointInfo - > pwszPeerName ) ) ;
string comment = Marshal . PtrToStringUni ( pEndPointInfo - > pwszComment ) ;
if ( comment ! = null & & comment . Length > 0 )
{
record . Comment = comment ;
}
if ( pEndPointInfo - > payLoad . cbPayload ! = 0 )
{
record . Data = new byte [ pEndPointInfo - > payLoad . cbPayload ] ;
Marshal . Copy ( pEndPointInfo - > payLoad . pbPayload , record . Data , 0 , ( int ) pEndPointInfo - > payLoad . cbPayload ) ;
}
//record.EndPointList = new IPEndPoint[pEndPointInfo->cAddresses];
IntPtr ppSOCKADDRs = pEndPointInfo - > ArrayOfSOCKADDRIN6Pointers ;
for ( UInt32 j = 0 ; j < pEndPointInfo - > cAddresses ; j + + )
{
IntPtr pSOCKADDR = Marshal . ReadIntPtr ( ppSOCKADDRs ) ;
byte [ ] AddressFamilyBuffer = new byte [ 2 ] ;
Marshal . Copy ( pSOCKADDR , AddressFamilyBuffer , 0 , 2 ) ;
int addressFamily = 0 ;
#if BIGENDIAN
addressFamily = AddressFamilyBuffer [ 1 ] + ( ( int ) AddressFamilyBuffer [ 0 ] < < 8 ) ;
#else
addressFamily = AddressFamilyBuffer [ 0 ] + ( ( int ) AddressFamilyBuffer [ 1 ] < < 8 ) ;
#endif
byte [ ] buffer = new byte [ ( ( AddressFamily ) addressFamily = = AddressFamily . InterNetwork ) ? SystemNetHelpers . IPv4AddressSize : SystemNetHelpers . IPv6AddressSize ] ;
Marshal . Copy ( pSOCKADDR , buffer , 0 , buffer . Length ) ;
IPEndPoint ipe = SystemNetHelpers . IPEndPointFromSOCKADDRBuffer ( buffer ) ;
record . EndPointCollection . Add ( ipe ) ;
ppSOCKADDRs = ( IntPtr ) ( ( long ) ppSOCKADDRs + Marshal . SizeOf ( typeof ( IntPtr ) ) ) ;
}
//----------------------------------
//Dump for trace
//----------------------------------
record . TracePeerNameRecord ( ) ;
//----------------------------------
//Add to collection
//----------------------------------
PeerNameRecords . Add ( record ) ;
}
}
}
finally
{
shEndPointInfoArray . Dispose ( ) ;
}
}
2017-08-21 15:34:15 +00:00
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Information , 0 , "Sync Resolve returnig with PeerNameRecord count :{0}" , PeerNameRecords . Count ) ;
2016-08-03 10:59:49 +00:00
return PeerNameRecords ;
}
[HostProtection(ExternalThreading = true)]
public void ResolveAsync ( PeerName peerName , object userState )
{
ResolveAsync ( peerName , Cloud . Available , Int32 . MaxValue , userState ) ;
}
[HostProtection(ExternalThreading = true)]
public void ResolveAsync ( PeerName peerName , Cloud cloud , object userState )
{
ResolveAsync ( peerName , cloud , Int32 . MaxValue , userState ) ;
}
[HostProtection(ExternalThreading = true)]
public void ResolveAsync ( PeerName peerName , int maxRecords , object userState )
{
ResolveAsync ( peerName , Cloud . Available , maxRecords , userState ) ;
}
// <SecurityKernel Critical="True" Ring="1">
// <ReferencesCritical Name="Method: UnsafeP2PNativeMethods.PnrpStartup():System.Void" Ring="1" />
// <ReferencesCritical Name="Method: PeerNameResolverHelper.StartAsyncResolve():System.Void" Ring="1" />
// </SecurityKernel>
[System.Security.SecurityCritical]
[HostProtection(ExternalThreading = true)]
public void ResolveAsync ( PeerName peerName , Cloud cloud , int maxRecords , object userState )
{
//-------------------------------------------------
//Check arguments
//-------------------------------------------------
if ( peerName = = null )
{
throw new ArgumentNullException ( SR . GetString ( SR . Pnrp_PeerNameCantBeNull ) , "peerName" ) ;
}
if ( cloud = = null )
{
cloud = Cloud . Available ;
}
if ( maxRecords < = 0 )
{
throw new ArgumentOutOfRangeException ( "maxRecords" , SR . GetString ( SR . Pnrp_MaxRecordsParameterMustBeGreaterThanZero ) ) ;
}
if ( m_ResolveCompleted = = null )
{
throw new PeerToPeerException ( SR . GetString ( SR . Pnrp_AtleastOneEvenHandlerNeeded ) ) ;
}
//---------------------------------------------------
//Demand CAS permissions
//---------------------------------------------------
PnrpPermission . UnrestrictedPnrpPermission . Demand ( ) ;
//---------------------------------------------------------------
//No perf hit here, real native call happens only one time if it
//did not already happen
//---------------------------------------------------------------
UnsafeP2PNativeMethods . PnrpStartup ( ) ;
//----------------------------------------------------
//userToken can't be null
//----------------------------------------------------
if ( userState = = null )
{
throw new ArgumentNullException ( SR . GetString ( SR . NullUserToken ) , "userState" ) ;
}
PeerNameResolverHelper peerNameResolverHelper = null ;
//---------------------------------------------------
//The userToken can't be duplicate of what is in the
//current list. These are the requriments for the new Async model
//that supports multiple outstanding async calls
//---------------------------------------------------
int newTraceEventId = NewTraceEventId ;
lock ( m_PeerNameResolverHelperListLock )
{
if ( m_PeerNameResolverHelperList . ContainsKey ( userState ) )
{
throw new ArgumentException ( SR . GetString ( SR . DuplicateUserToken ) ) ;
}
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Information , newTraceEventId ,
"PeerNameResolverHelper is being created with TraceEventId {0}" , newTraceEventId ) ;
peerNameResolverHelper = new PeerNameResolverHelper ( peerName , cloud , maxRecords , userState , this , newTraceEventId ) ;
m_PeerNameResolverHelperList [ userState ] = peerNameResolverHelper ;
}
try
{
//---------------------------------------------------
//Start resolution on that resolver
//---------------------------------------------------
peerNameResolverHelper . StartAsyncResolve ( ) ;
}
catch
{
//---------------------------------------------------
//If an exception happens clear the userState from the
//list so that that token can be reused
//---------------------------------------------------
lock ( m_PeerNameResolverHelperListLock )
{
m_PeerNameResolverHelperList . Remove ( userState ) ;
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Error , newTraceEventId ,
"Removing userState token from pending list {0}" , userState . GetHashCode ( ) ) ;
}
throw ;
}
}
protected void OnResolveProgressChanged ( ResolveProgressChangedEventArgs e )
{
if ( m_ResolveProgressChanged ! = null )
{
m_ResolveProgressChanged ( this , e ) ;
}
}
void ResolveProgressChangedWaitCallback ( object operationState )
{
OnResolveProgressChanged ( ( ResolveProgressChangedEventArgs ) operationState ) ;
}
internal void PrepareToRaiseProgressChangedEvent ( AsyncOperation asyncOP , ResolveProgressChangedEventArgs args )
{
asyncOP . Post ( OnResolveProgressChangedDelegate , args ) ;
}
protected void OnResolveCompleted ( ResolveCompletedEventArgs e )
{
if ( m_ResolveCompleted ! = null )
{
m_ResolveCompleted ( this , e ) ;
}
}
void ResolveCompletedWaitCallback ( object operationState )
{
OnResolveCompleted ( ( ResolveCompletedEventArgs ) operationState ) ;
}
internal void PrepareToRaiseCompletedEvent ( AsyncOperation asyncOP , ResolveCompletedEventArgs args )
{
asyncOP . PostOperationCompleted ( OnResolveCompletedDelegate , args ) ;
lock ( m_PeerNameResolverHelperListLock )
{
PeerNameResolverHelper helper = m_PeerNameResolverHelperList [ args . UserState ] ;
if ( helper = = null )
{
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Critical , 0 , "userState for which we are about to call Completed event does not exist in the pending async list" ) ;
}
else
{
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Information , helper . TraceEventId ,
"userState {0} is being removed from the pending async list" , args . UserState . GetHashCode ( ) ) ;
m_PeerNameResolverHelperList . Remove ( args . UserState ) ;
}
}
}
// <SecurityKernel Critical="True" Ring="2">
// <ReferencesCritical Name="Method: PeerNameResolverHelper.CancelAsync():System.Void" Ring="2" />
// </SecurityKernel>
[System.Security.SecurityCritical]
public void ResolveAsyncCancel ( object userState )
{
PnrpPermission . UnrestrictedPnrpPermission . Demand ( ) ;
if ( userState = = null )
{
return ;
}
PeerNameResolverHelper helper ;
lock ( m_PeerNameResolverHelperListLock )
{
if ( ! m_PeerNameResolverHelperList . TryGetValue ( userState , out helper ) )
{
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Warning , 0 , "ResolveAsyncCancel called with a userState token that is not in the pending async list - returning" ) ;
return ;
}
}
Logging . P2PTraceSource . TraceEvent ( TraceEventType . Information , helper . TraceEventId ,
"Proceeding to cancel the pending async" ) ;
helper . CancelAsync ( ) ;
}
private static int s_TraceEventId ;
private static int NewTraceEventId
{
get
{
Interlocked . CompareExchange ( ref s_TraceEventId , 0 , int . MaxValue ) ;
Interlocked . Increment ( ref s_TraceEventId ) ;
return s_TraceEventId ;
}
}
}
}