|
//------------------------------------------------------------------------------
// <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>
/// PeerNameResolver does sync and async resolves.
/// 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>
/// Implements sync resolve of the PeerName in the cloud given
/// </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
//---------------------------------------------------------------
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Sync Resolve called with PeerName: {0}, Cloud: {1}, MaxRecords {2}", peerName, cloud, maxRecords);
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();
}
}
Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Sync Resolve returnig with PeerNameRecord count :{0}", PeerNameRecords.Count);
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;
}
}
}
}
|