//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ 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; /// /// This is the event args class we give back each time when /// we have incremental resolution results /// public class ResolveProgressChangedEventArgs : ProgressChangedEventArgs { private PeerNameRecord m_PeerNameRecord; /// /// We use progress percentage of **0** all times sice /// we will not no upfront how many records we are going to get /// /// /// public ResolveProgressChangedEventArgs(PeerNameRecord peerNameRecord, object userToken) : base(0, userToken) { m_PeerNameRecord = peerNameRecord; } public PeerNameRecord PeerNameRecord { get { return m_PeerNameRecord; } } } /// /// When the resolution completes, we invoke the callback with this event args instance /// 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() ); } // // // // // // // // // // // [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()); } // // // // // // // // // // // // // // [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; } // // // // [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; } } // // // [System.Security.SecurityCritical] public void CancelAsync() { //Defer the work to a callback ThreadPool.QueueUserWorkItem(new WaitCallback(ContineCancelCallback)); } // // // [System.Security.SecurityCritical] public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } // // // // // [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; } } } /// /// PeerNameResolver does sync and async resolves. /// PeerNameResolver supports multiple outstanding async calls /// 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 m_ResolveProgressChanged; /// /// 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 /// public event EventHandler ResolveProgressChanged { add { PnrpPermission.UnrestrictedPnrpPermission.Demand(); m_ResolveProgressChanged += value; } remove { PnrpPermission.UnrestrictedPnrpPermission.Demand(); m_ResolveProgressChanged -= value; } } private event EventHandler m_ResolveCompleted; /// /// 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 /// public event EventHandler ResolveCompleted { add { PnrpPermission.UnrestrictedPnrpPermission.Demand(); m_ResolveCompleted += value; } remove { PnrpPermission.UnrestrictedPnrpPermission.Demand(); m_ResolveCompleted -= value; } } SendOrPostCallback OnResolveProgressChangedDelegate; SendOrPostCallback OnResolveCompletedDelegate; /// /// 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 /// private object m_PeerNameResolverHelperListLock = new object(); private Dictionary m_PeerNameResolverHelperList = new Dictionary(); 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); } /// /// Implements sync resolve of the PeerName in the cloud given /// /// /// /// /// // // // // // // // // // // // // // // // [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); } // // // // [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); } } } // // // [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; } } } }