1 //------------------------------------------------------------------------------
2 // <copyright file="PeerNameResolver.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
6 namespace System.Net.PeerToPeer
9 using System.Collections.Generic;
11 using System.ComponentModel;
12 using System.Threading;
13 using System.Security.Permissions;
14 using System.Runtime.InteropServices;
16 using System.Net.Sockets;
17 using System.Diagnostics;
20 /// This is the event args class we give back each time when
21 /// we have incremental resolution results
23 public class ResolveProgressChangedEventArgs : ProgressChangedEventArgs
25 private PeerNameRecord m_PeerNameRecord;
28 /// We use progress percentage of **0** all times sice
29 /// we will not no upfront how many records we are going to get
31 /// <param name="peerNameRecord"></param>
32 /// <param name="userToken"></param>
33 public ResolveProgressChangedEventArgs(PeerNameRecord peerNameRecord,
34 object userToken) : base(0, userToken)
36 m_PeerNameRecord = peerNameRecord;
38 public PeerNameRecord PeerNameRecord
42 return m_PeerNameRecord;
48 /// When the resolution completes, we invoke the callback with this event args instance
50 public class ResolveCompletedEventArgs : AsyncCompletedEventArgs
52 private PeerNameRecordCollection m_PeerNameRecordCollection;
53 public ResolveCompletedEventArgs(
54 PeerNameRecordCollection peerNameRecordCollection,
58 : base(error, canceled, userToken)
60 m_PeerNameRecordCollection = peerNameRecordCollection;
62 public PeerNameRecordCollection PeerNameRecordCollection
66 return m_PeerNameRecordCollection;
72 internal class PeerNameResolverHelper : IDisposable
74 private const UInt32 FACILITY_P2P = 99;
75 private const UInt32 NO_MORE_RECORDS = 0x4003;
76 private const int PEER_E_NO_MORE = (int)(((int)1 << 31) | ((int)FACILITY_P2P << 16) | NO_MORE_RECORDS);
79 //------------------------------------------
80 //userState the user has supplied
81 //------------------------------------------
82 internal object m_userState;
84 //------------------------------------------
85 //Handle to the resolution process
86 //------------------------------------------
87 internal SafePeerNameEndResolve m_SafePeerNameEndResolve;
89 //------------------------------------------
90 //Event that the native API sets to indicate that
91 //information is available and that we should call
92 //the PeerPnrpGetEndPoint() to get the end point
93 //------------------------------------------
94 internal AutoResetEvent m_EndPointInfoAvailableEvent = new AutoResetEvent(false);
96 //------------------------------------------
97 //The WaitHandle that hooks up a callback to the
99 //------------------------------------------
100 internal RegisteredWaitHandle m_RegisteredWaitHandle;
102 //------------------------------------------
103 //PeerName that is being resolved
104 //------------------------------------------
105 internal PeerName m_PeerName;
107 //------------------------------------------
108 //Cloud in which the resolution must occur
109 //------------------------------------------
110 internal Cloud m_Cloud;
112 //------------------------------------------
113 //Max number of records to resolve
114 //------------------------------------------
115 internal int m_MaxRecords;
117 //------------------------------------------
119 //------------------------------------------
120 internal bool m_Disposed;
123 //-----------------------------------------
124 //Flag to indicate completed or an exception
125 //happened. If you set this flag you own
126 //calling the callback
127 //-----------------------------------------
128 internal bool m_CompletedOrException;
130 //-----------------------------------------
131 //Flag to indicate that the call is canceled
132 //If you set this flag you own calling the callback
133 //-----------------------------------------
134 internal bool m_Cancelled;
136 //------------------------------------------
137 //A place to save the incremental results
138 //so that we can invoke the completed
139 //handler with all the results at once
140 //------------------------------------------
141 PeerNameRecordCollection m_PeerNameRecordCollection = new PeerNameRecordCollection();
143 //------------------------------------------
144 //Async operation to ensure synchornization
146 //------------------------------------------
147 AsyncOperation m_AsyncOp;
149 //------------------------------------------
150 //A link to the resolver to avoid
151 //circular dependencies and enable GC
152 //------------------------------------------
153 WeakReference m_PeerNameResolverWeakReference;
155 //------------------------------------------
156 //Lock to make sure things don't mess up stuff
157 //------------------------------------------
158 object m_Lock = new Object();
160 //------------------------------------------
161 //EventID or Just a trackig id
162 //------------------------------------------
165 internal PeerNameResolverHelper(PeerName peerName, Cloud cloud, int MaxRecords, object userState, PeerNameResolver parent, int NewTraceEventId)
167 m_userState = userState;
168 m_PeerName = peerName;
170 m_MaxRecords = MaxRecords;
171 m_PeerNameResolverWeakReference = new WeakReference(parent);
172 m_TraceEventId = NewTraceEventId;
173 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId, "New PeerNameResolverHelper created with TraceEventID {0}", m_TraceEventId);
174 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId,
175 "\tPeerName: {0}, Cloud: {1}, MaxRecords: {2}, userState {3}, ParentReference {4}",
179 userState.GetHashCode(),
180 m_PeerNameResolverWeakReference.Target.GetHashCode()
184 // <SecurityKernel Critical="True" Ring="0">
185 // <SatisfiesLinkDemand Name="WaitHandle.get_SafeWaitHandle():Microsoft.Win32.SafeHandles.SafeWaitHandle" />
186 // <SatisfiesLinkDemand Name="SafeHandle.get_IsInvalid():System.Boolean" />
187 // <SatisfiesLinkDemand Name="SafeHandle.get_IsClosed():System.Boolean" />
188 // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
189 // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
190 // <CallsSuppressUnmanagedCode Name="UnsafeP2PNativeMethods.PeerPnrpStartResolve(System.String,System.String,System.UInt32,Microsoft.Win32.SafeHandles.SafeWaitHandle,System.Net.PeerToPeer.SafePeerNameEndResolve&):System.Int32" />
191 // <ReferencesCritical Name="Method: EndPointInfoAvailableCallback(Object, Boolean):Void" Ring="1" />
192 // <ReferencesCritical Name="Field: m_SafePeerNameEndResolve" Ring="1" />
193 // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
195 [System.Security.SecurityCritical]
196 internal void StartAsyncResolve()
198 //------------------------------------------
200 //------------------------------------------
201 if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
203 //------------------------------------------
204 //First wire up a callback
205 //------------------------------------------
206 m_RegisteredWaitHandle = ThreadPool.RegisterWaitForSingleObject(m_EndPointInfoAvailableEvent, //Event that triggers the callback
207 new WaitOrTimerCallback(EndPointInfoAvailableCallback), //callback to be called
208 null, //state to be passed
209 -1, //Timeout - aplicable only for timers not for events
210 false //call us everytime the event is set not just one time
213 //------------------------------------------
214 //Now call the native API to start the resolution
215 //process save the handle for later
216 //------------------------------------------
217 Int32 result = UnsafeP2PNativeMethods.PeerPnrpStartResolve(m_PeerName.ToString(),
218 m_Cloud.InternalName,
219 (UInt32)m_MaxRecords,
220 m_EndPointInfoAvailableEvent.SafeWaitHandle,
221 out m_SafePeerNameEndResolve);
224 if (!m_SafePeerNameEndResolve.IsInvalid && !m_SafePeerNameEndResolve.IsClosed)
226 m_SafePeerNameEndResolve.Dispose();
228 m_RegisteredWaitHandle.Unregister(null);
229 m_RegisteredWaitHandle = null;
230 PeerToPeerException ex = PeerToPeerException.CreateFromHr(SR.GetString(SR.Pnrp_CouldNotStartNameResolution), result);
231 Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, m_TraceEventId,
232 "Exception occurred while starting async resolve");
236 //------------------------------------------
237 //Create an async operation with the given
239 //------------------------------------------
240 m_AsyncOp = AsyncOperationManager.CreateOperation(m_userState);
242 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId,
243 "Successfully started the async resolve. The native handle is {0}", m_SafePeerNameEndResolve.DangerousGetHandle());
247 // <SecurityKernel Critical="True" Ring="0">
248 // <UsesUnsafeCode Name="Local pEndPointInfo of type: PEER_PNRP_ENDPOINT_INFO*" />
249 // <UsesUnsafeCode Name="Method: IntPtr.op_Explicit(System.IntPtr):System.Void*" />
250 // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
251 // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
252 // <SatisfiesLinkDemand Name="Marshal.PtrToStringUni(System.IntPtr):System.String" />
253 // <SatisfiesLinkDemand Name="Marshal.Copy(System.IntPtr,System.Byte[],System.Int32,System.Int32):System.Void" />
254 // <SatisfiesLinkDemand Name="Marshal.ReadIntPtr(System.IntPtr):System.IntPtr" />
255 // <SatisfiesLinkDemand Name="Marshal.SizeOf(System.Type):System.Int32" />
256 // <CallsSuppressUnmanagedCode Name="UnsafeP2PNativeMethods.PeerPnrpGetEndpoint(System.IntPtr,System.Net.PeerToPeer.SafePeerData&):System.Int32" />
257 // <ReferencesCritical Name="Local shEndPointInfo of type: SafePeerData" Ring="1" />
258 // <ReferencesCritical Name="Field: m_SafePeerNameEndResolve" Ring="1" />
259 // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
261 [System.Security.SecurityCritical]
262 public void EndPointInfoAvailableCallback(object state, bool timedOut)
264 //------------------------------------------
265 //This callback is called whenever there is an endpoint info
266 //available or the resultion is completed
267 //------------------------------------------
268 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId,
269 "EndPointInfoAvailableCallback called");
270 PeerNameRecord record = null;
271 SafePeerData shEndPointInfo;
273 PeerNameResolver parent = null;
276 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId,
277 "Detected that the async operation is already canceled - before entering the lock");
284 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId,
285 "Detected that the async operation is already canceled - after entering the lock");
288 result = UnsafeP2PNativeMethods.PeerPnrpGetEndpoint(m_SafePeerNameEndResolve.DangerousGetHandle(), out shEndPointInfo);
291 if (result == PEER_E_NO_MORE)
293 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId,
294 "Native API returned that there are no more records - resolve completed successfully");
296 m_CompletedOrException = true;
297 m_SafePeerNameEndResolve.Dispose();
301 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId,
302 "Proceeding to retrieve the endpoint information from incremental resolve");
307 PEER_PNRP_ENDPOINT_INFO* pEndPointInfo = (PEER_PNRP_ENDPOINT_INFO*)shEndPointInfo.DangerousGetHandle();
308 record = new PeerNameRecord();
309 record.PeerName = new PeerName(Marshal.PtrToStringUni(pEndPointInfo->pwszPeerName));
310 string comment = Marshal.PtrToStringUni(pEndPointInfo->pwszComment);
311 if (comment != null && comment.Length > 0)
313 record.Comment = comment;
315 if (pEndPointInfo->payLoad.cbPayload != 0)
317 record.Data = new byte[pEndPointInfo->payLoad.cbPayload];
318 Marshal.Copy(pEndPointInfo->payLoad.pbPayload, record.Data, 0, (int)pEndPointInfo->payLoad.cbPayload);
320 //record.EndPointList = new IPEndPoint[pEndPointInfo->cAddresses];
321 IntPtr ppSOCKADDRs = pEndPointInfo->ArrayOfSOCKADDRIN6Pointers;
322 for (UInt32 j = 0; j < pEndPointInfo->cAddresses; j++)
324 IntPtr pSOCKADDR = Marshal.ReadIntPtr(ppSOCKADDRs);
326 byte[] AddressFamilyBuffer = new byte[2];
327 Marshal.Copy(pSOCKADDR, AddressFamilyBuffer, 0, 2);
328 int addressFamily = 0;
330 addressFamily = AddressFamilyBuffer[1] + ((int)AddressFamilyBuffer[0] << 8);
332 addressFamily = AddressFamilyBuffer[0] + ((int)AddressFamilyBuffer[1] << 8);
334 byte[] buffer = new byte[((AddressFamily)addressFamily == AddressFamily.InterNetwork) ? SystemNetHelpers.IPv4AddressSize : SystemNetHelpers.IPv6AddressSize];
335 Marshal.Copy(pSOCKADDR, buffer, 0, buffer.Length);
336 IPEndPoint ipe = SystemNetHelpers.IPEndPointFromSOCKADDRBuffer(buffer);
337 record.EndPointCollection.Add(ipe);
338 ppSOCKADDRs = (IntPtr)((long)ppSOCKADDRs + Marshal.SizeOf(typeof(IntPtr)));
344 shEndPointInfo.Dispose();
346 record.TracePeerNameRecord();
347 m_PeerNameRecordCollection.Add(record);
349 ResolveProgressChangedEventArgs resolveProgressChangedEventArgs = new ResolveProgressChangedEventArgs(
350 record, m_AsyncOp.UserSuppliedState);
353 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId,
354 "Proceeding to call progress changed event callback");
355 parent = m_PeerNameResolverWeakReference.Target as PeerNameResolver;
358 parent.PrepareToRaiseProgressChangedEvent(m_AsyncOp, resolveProgressChangedEventArgs);
364 ResolveCompletedEventArgs resolveCompletedEventArgs;
365 if (result == PEER_E_NO_MORE)
367 resolveCompletedEventArgs = new ResolveCompletedEventArgs(m_PeerNameRecordCollection,
368 null, false, m_AsyncOp.UserSuppliedState);
372 PeerToPeerException ex = PeerToPeerException.CreateFromHr(SR.GetString(SR.Pnrp_ExceptionWhileResolvingAPeerName), result);
373 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId,
374 "Exception occurred when the native API is called to harvest an incremental resolve notification");
375 resolveCompletedEventArgs = new ResolveCompletedEventArgs(null,
376 ex, false, m_AsyncOp.UserSuppliedState);
379 parent = m_PeerNameResolverWeakReference.Target as PeerNameResolver;
382 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId,
383 "Proceeding to call the ResolveCompleted callback");
384 parent.PrepareToRaiseCompletedEvent(m_AsyncOp, resolveCompletedEventArgs);
389 // <SecurityKernel Critical="True" Ring="0">
390 // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
391 // <ReferencesCritical Name="Field: m_SafePeerNameEndResolve" Ring="1" />
393 [System.Security.SecurityCritical]
394 public void ContineCancelCallback(object state)
396 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId,
397 "ContineCancelCallback called");
400 if (m_CompletedOrException)
402 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId,
403 "ContinueCancelCallback detected (before acquiring lock) that another thread has already called completed event - so returning without calling cancel");
410 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId,
411 "ContinueCancelCallback detected (after acquiring lock) that cancel has already been called");
415 if (m_CompletedOrException)
417 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId,
418 "ContinueCancelCallback detected (after acquiring lock) that another thread has already called completed event - so returning without calling cancel");
423 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, m_TraceEventId,
424 "ContinueCancelCallback is proceeding to close the handle and call the Completed callback with Cancelled = true");
427 m_SafePeerNameEndResolve.Dispose();
429 PeerNameResolver parent = m_PeerNameResolverWeakReference.Target as PeerNameResolver;
432 ResolveCompletedEventArgs e = new ResolveCompletedEventArgs(null, null, true, m_AsyncOp.UserSuppliedState);
433 parent.PrepareToRaiseCompletedEvent(m_AsyncOp, e);
438 Logging.P2PTraceSource.TraceEvent(TraceEventType.Critical, m_TraceEventId, "Exception while cancelling the call ");
442 // <SecurityKernel Critical="True" Ring="1">
443 // <ReferencesCritical Name="Method: ContineCancelCallback(Object):Void" Ring="1" />
445 [System.Security.SecurityCritical]
446 public void CancelAsync()
448 //Defer the work to a callback
449 ThreadPool.QueueUserWorkItem(new WaitCallback(ContineCancelCallback));
451 // <SecurityKernel Critical="True" Ring="1">
452 // <ReferencesCritical Name="Method: Dispose(Boolean):Void" Ring="1" />
454 [System.Security.SecurityCritical]
455 public void Dispose()
458 GC.SuppressFinalize(this);
460 // <SecurityKernel Critical="True" Ring="0">
461 // <SatisfiesLinkDemand Name="SafeHandle.get_IsInvalid():System.Boolean" />
462 // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
463 // <ReferencesCritical Name="Field: m_SafePeerNameEndResolve" Ring="1" />
465 [System.Security.SecurityCritical]
466 public void Dispose(bool disposing)
470 if (!m_SafePeerNameEndResolve.IsInvalid)
472 m_SafePeerNameEndResolve.Dispose();
474 if (m_RegisteredWaitHandle != null)
475 m_RegisteredWaitHandle.Unregister(null);
476 m_RegisteredWaitHandle = null;
477 m_EndPointInfoAvailableEvent.Close();
482 internal int TraceEventId
486 return m_TraceEventId;
493 /// PeerNameResolver does [....] and async resolves.
494 /// PeerNameResolver supports multiple outstanding async calls
496 public class PeerNameResolver
498 static PeerNameResolver()
500 //-------------------------------------------------
501 //Check for the availability of the simpler PNRP APIs
502 //-------------------------------------------------
503 if (!PeerToPeerOSHelper.SupportsP2P)
505 throw new PlatformNotSupportedException(SR.GetString(SR.P2P_NotAvailable));
509 private event EventHandler<ResolveProgressChangedEventArgs> m_ResolveProgressChanged;
511 /// When an event handler is hooked up or removed, we demand the permissions.
512 /// In partial trust cases, this will avoid the security risk of just hooking up an existing instance
513 /// of the PeerNameResolver and then receiving all notification of
514 /// in resolution that is happening
516 public event EventHandler<ResolveProgressChangedEventArgs> ResolveProgressChanged
520 PnrpPermission.UnrestrictedPnrpPermission.Demand();
521 m_ResolveProgressChanged += value;
525 PnrpPermission.UnrestrictedPnrpPermission.Demand();
526 m_ResolveProgressChanged -= value;
530 private event EventHandler<ResolveCompletedEventArgs> m_ResolveCompleted;
533 /// When an event handler is hooked up or removed, we demand the permissions.
534 /// In partial trust cases, this will avoid the security risk of just hooking up an existing instance
535 /// of the PeerNameResolver and then receiving all notification of
536 /// in resolution that is happening
538 public event EventHandler<ResolveCompletedEventArgs> ResolveCompleted
542 PnrpPermission.UnrestrictedPnrpPermission.Demand();
543 m_ResolveCompleted += value;
547 PnrpPermission.UnrestrictedPnrpPermission.Demand();
548 m_ResolveCompleted -= value;
552 SendOrPostCallback OnResolveProgressChangedDelegate;
553 SendOrPostCallback OnResolveCompletedDelegate;
556 /// The following lock and the Sorted Dictionary served
557 /// the purpose of keeping an account of the multiple outstanding async
558 /// resolutions. Each outstanding async operation is
559 /// keyed based on the userState parameter passed in
561 private object m_PeerNameResolverHelperListLock = new object();
562 private Dictionary<object, PeerNameResolverHelper> m_PeerNameResolverHelperList = new Dictionary<object, PeerNameResolverHelper>();
565 public PeerNameResolver()
567 OnResolveProgressChangedDelegate = new SendOrPostCallback(ResolveProgressChangedWaitCallback);
568 OnResolveCompletedDelegate = new SendOrPostCallback(ResolveCompletedWaitCallback);
570 public PeerNameRecordCollection Resolve(PeerName peerName)
572 return Resolve(peerName, Cloud.Available, int.MaxValue);
574 public PeerNameRecordCollection Resolve(PeerName peerName, Cloud cloud)
576 return Resolve(peerName, cloud, int.MaxValue);
578 public PeerNameRecordCollection Resolve(PeerName peerName, int maxRecords)
580 return Resolve(peerName, Cloud.Available, maxRecords);
584 /// Implements [....] resolve of the PeerName in the cloud given
586 /// <param name="peerName"></param>
587 /// <param name="cloud"></param>
588 /// <param name="MaxRecords"></param>
589 /// <returns></returns>
590 // <SecurityKernel Critical="True" Ring="0">
591 // <UsesUnsafeCode Name="Local pEndPoints of type: PEER_PNRP_ENDPOINT_INFO*" />
592 // <UsesUnsafeCode Name="Local pEndPointInfo of type: PEER_PNRP_ENDPOINT_INFO*" />
593 // <UsesUnsafeCode Name="Method: IntPtr.op_Explicit(System.IntPtr):System.Void*" />
594 // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
595 // <SatisfiesLinkDemand Name="Marshal.PtrToStringUni(System.IntPtr):System.String" />
596 // <SatisfiesLinkDemand Name="Marshal.Copy(System.IntPtr,System.Byte[],System.Int32,System.Int32):System.Void" />
597 // <SatisfiesLinkDemand Name="Marshal.ReadIntPtr(System.IntPtr):System.IntPtr" />
598 // <SatisfiesLinkDemand Name="Marshal.SizeOf(System.Type):System.Int32" />
599 // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
600 // <CallsSuppressUnmanagedCode Name="UnsafeP2PNativeMethods.PeerPnrpResolve(System.String,System.String,System.UInt32&,System.Net.PeerToPeer.SafePeerData&):System.Int32" />
601 // <ReferencesCritical Name="Local shEndPointInfoArray of type: SafePeerData" Ring="1" />
602 // <ReferencesCritical Name="Method: UnsafeP2PNativeMethods.PnrpStartup():System.Void" Ring="1" />
603 // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
605 [System.Security.SecurityCritical]
606 public PeerNameRecordCollection Resolve(PeerName peerName, Cloud cloud, int maxRecords)
609 //---------------------------------------------------
611 //---------------------------------------------------
612 if (peerName == null)
614 throw new ArgumentNullException(SR.GetString(SR.Pnrp_PeerNameCantBeNull), "peerName");
619 throw new ArgumentOutOfRangeException("maxRecords", SR.GetString(SR.Pnrp_MaxRecordsParameterMustBeGreaterThanZero));
622 //---------------------------------------------------
623 //Assume all clouds if the clould passed is null?
624 //---------------------------------------------------
627 cloud = Cloud.Available;
630 //---------------------------------------------------
631 //Demand CAS permissions
632 //---------------------------------------------------
633 PnrpPermission.UnrestrictedPnrpPermission.Demand();
635 //---------------------------------------------------------------
636 //No perf hit here, real native call happens only one time if it
637 //did not already happen
638 //---------------------------------------------------------------
639 UnsafeP2PNativeMethods.PnrpStartup();
641 //---------------------------------------------------------------
643 //---------------------------------------------------------------
644 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "[....] Resolve called with PeerName: {0}, Cloud: {1}, MaxRecords {2}", peerName, cloud, maxRecords);
646 SafePeerData shEndPointInfoArray;
647 string NativeCloudName = cloud.InternalName;
648 UInt32 ActualCountOfEndPoints = (UInt32)maxRecords;
649 int result = UnsafeP2PNativeMethods.PeerPnrpResolve(peerName.ToString(),
651 ref ActualCountOfEndPoints,
652 out shEndPointInfoArray);
655 throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Pnrp_CouldNotStartNameResolution), result);
658 //---------------------------------------------------
659 //If there are no endpoints returned, return
660 //an empty PeerNameRecord Collection
661 //---------------------------------------------------
662 PeerNameRecordCollection PeerNameRecords = new PeerNameRecordCollection();
663 if (ActualCountOfEndPoints != 0)
669 IntPtr pEndPointInfoArray = shEndPointInfoArray.DangerousGetHandle();
670 PEER_PNRP_ENDPOINT_INFO* pEndPoints = (PEER_PNRP_ENDPOINT_INFO*)pEndPointInfoArray;
671 for (int i = 0; i < ActualCountOfEndPoints; i++)
673 PeerNameRecord record = new PeerNameRecord();
674 PEER_PNRP_ENDPOINT_INFO* pEndPointInfo = &pEndPoints[i];
675 record.PeerName = new PeerName(Marshal.PtrToStringUni(pEndPointInfo->pwszPeerName));
676 string comment = Marshal.PtrToStringUni(pEndPointInfo->pwszComment);
677 if (comment != null && comment.Length > 0)
679 record.Comment = comment;
682 if (pEndPointInfo->payLoad.cbPayload != 0)
684 record.Data = new byte[pEndPointInfo->payLoad.cbPayload];
685 Marshal.Copy(pEndPointInfo->payLoad.pbPayload, record.Data, 0, (int)pEndPointInfo->payLoad.cbPayload);
688 //record.EndPointList = new IPEndPoint[pEndPointInfo->cAddresses];
689 IntPtr ppSOCKADDRs = pEndPointInfo->ArrayOfSOCKADDRIN6Pointers;
690 for (UInt32 j = 0; j < pEndPointInfo->cAddresses; j++)
692 IntPtr pSOCKADDR = Marshal.ReadIntPtr(ppSOCKADDRs);
694 byte[] AddressFamilyBuffer = new byte[2];
695 Marshal.Copy(pSOCKADDR, AddressFamilyBuffer, 0, 2);
696 int addressFamily = 0;
698 addressFamily = AddressFamilyBuffer[1] + ((int)AddressFamilyBuffer[0] << 8);
700 addressFamily = AddressFamilyBuffer[0] + ((int)AddressFamilyBuffer[1] << 8);
702 byte[] buffer = new byte[((AddressFamily)addressFamily == AddressFamily.InterNetwork) ? SystemNetHelpers.IPv4AddressSize : SystemNetHelpers.IPv6AddressSize];
703 Marshal.Copy(pSOCKADDR, buffer, 0, buffer.Length);
704 IPEndPoint ipe = SystemNetHelpers.IPEndPointFromSOCKADDRBuffer(buffer);
705 record.EndPointCollection.Add(ipe);
706 ppSOCKADDRs = (IntPtr)((long)ppSOCKADDRs + Marshal.SizeOf(typeof(IntPtr)));
708 //----------------------------------
710 //----------------------------------
711 record.TracePeerNameRecord();
712 //----------------------------------
714 //----------------------------------
715 PeerNameRecords.Add(record);
721 shEndPointInfoArray.Dispose();
724 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "[....] Resolve returnig with PeerNameRecord count :{0}", PeerNameRecords.Count);
725 return PeerNameRecords;
728 [HostProtection(ExternalThreading = true)]
729 public void ResolveAsync(PeerName peerName, object userState)
731 ResolveAsync(peerName, Cloud.Available, Int32.MaxValue, userState);
733 [HostProtection(ExternalThreading = true)]
734 public void ResolveAsync(PeerName peerName, Cloud cloud, object userState)
736 ResolveAsync(peerName, cloud, Int32.MaxValue, userState);
738 [HostProtection(ExternalThreading = true)]
739 public void ResolveAsync(PeerName peerName, int maxRecords, object userState)
741 ResolveAsync(peerName, Cloud.Available, maxRecords, userState);
744 // <SecurityKernel Critical="True" Ring="1">
745 // <ReferencesCritical Name="Method: UnsafeP2PNativeMethods.PnrpStartup():System.Void" Ring="1" />
746 // <ReferencesCritical Name="Method: PeerNameResolverHelper.StartAsyncResolve():System.Void" Ring="1" />
748 [System.Security.SecurityCritical]
749 [HostProtection(ExternalThreading = true)]
750 public void ResolveAsync(PeerName peerName, Cloud cloud, int maxRecords, object userState)
752 //-------------------------------------------------
754 //-------------------------------------------------
755 if (peerName == null)
757 throw new ArgumentNullException(SR.GetString(SR.Pnrp_PeerNameCantBeNull), "peerName");
761 cloud = Cloud.Available;
765 throw new ArgumentOutOfRangeException("maxRecords", SR.GetString(SR.Pnrp_MaxRecordsParameterMustBeGreaterThanZero));
768 if (m_ResolveCompleted == null)
770 throw new PeerToPeerException(SR.GetString(SR.Pnrp_AtleastOneEvenHandlerNeeded));
772 //---------------------------------------------------
773 //Demand CAS permissions
774 //---------------------------------------------------
775 PnrpPermission.UnrestrictedPnrpPermission.Demand();
777 //---------------------------------------------------------------
778 //No perf hit here, real native call happens only one time if it
779 //did not already happen
780 //---------------------------------------------------------------
781 UnsafeP2PNativeMethods.PnrpStartup();
783 //----------------------------------------------------
784 //userToken can't be null
785 //----------------------------------------------------
786 if (userState == null)
788 throw new ArgumentNullException(SR.GetString(SR.NullUserToken), "userState");
791 PeerNameResolverHelper peerNameResolverHelper = null;
792 //---------------------------------------------------
793 //The userToken can't be duplicate of what is in the
794 //current list. These are the requriments for the new Async model
795 //that supports multiple outstanding async calls
796 //---------------------------------------------------
797 int newTraceEventId = NewTraceEventId;
798 lock (m_PeerNameResolverHelperListLock)
800 if (m_PeerNameResolverHelperList.ContainsKey(userState))
802 throw new ArgumentException(SR.GetString(SR.DuplicateUserToken));
804 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, newTraceEventId,
805 "PeerNameResolverHelper is being created with TraceEventId {0}", newTraceEventId);
806 peerNameResolverHelper = new PeerNameResolverHelper(peerName, cloud, maxRecords, userState, this, newTraceEventId);
807 m_PeerNameResolverHelperList[userState] = peerNameResolverHelper;
812 //---------------------------------------------------
813 //Start resolution on that resolver
814 //---------------------------------------------------
815 peerNameResolverHelper.StartAsyncResolve();
819 //---------------------------------------------------
820 //If an exception happens clear the userState from the
821 //list so that that token can be reused
822 //---------------------------------------------------
823 lock (m_PeerNameResolverHelperListLock)
825 m_PeerNameResolverHelperList.Remove(userState);
826 Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, newTraceEventId,
827 "Removing userState token from pending list {0}", userState.GetHashCode());
833 protected void OnResolveProgressChanged(ResolveProgressChangedEventArgs e)
835 if (m_ResolveProgressChanged != null)
837 m_ResolveProgressChanged(this, e);
840 void ResolveProgressChangedWaitCallback(object operationState)
842 OnResolveProgressChanged((ResolveProgressChangedEventArgs)operationState);
844 internal void PrepareToRaiseProgressChangedEvent(AsyncOperation asyncOP, ResolveProgressChangedEventArgs args)
846 asyncOP.Post(OnResolveProgressChangedDelegate, args);
849 protected void OnResolveCompleted(ResolveCompletedEventArgs e)
851 if (m_ResolveCompleted != null)
853 m_ResolveCompleted(this, e);
856 void ResolveCompletedWaitCallback(object operationState)
858 OnResolveCompleted((ResolveCompletedEventArgs)operationState);
860 internal void PrepareToRaiseCompletedEvent(AsyncOperation asyncOP, ResolveCompletedEventArgs args)
862 asyncOP.PostOperationCompleted(OnResolveCompletedDelegate, args);
863 lock (m_PeerNameResolverHelperListLock)
865 PeerNameResolverHelper helper = m_PeerNameResolverHelperList[args.UserState];
868 Logging.P2PTraceSource.TraceEvent(TraceEventType.Critical, 0, "userState for which we are about to call Completed event does not exist in the pending async list");
872 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, helper.TraceEventId,
873 "userState {0} is being removed from the pending async list", args.UserState.GetHashCode());
874 m_PeerNameResolverHelperList.Remove(args.UserState);
881 // <SecurityKernel Critical="True" Ring="2">
882 // <ReferencesCritical Name="Method: PeerNameResolverHelper.CancelAsync():System.Void" Ring="2" />
884 [System.Security.SecurityCritical]
885 public void ResolveAsyncCancel(object userState)
887 PnrpPermission.UnrestrictedPnrpPermission.Demand();
888 if (userState == null)
892 PeerNameResolverHelper helper;
893 lock (m_PeerNameResolverHelperListLock)
895 if (!m_PeerNameResolverHelperList.TryGetValue(userState, out helper))
897 Logging.P2PTraceSource.TraceEvent(TraceEventType.Warning, 0, "ResolveAsyncCancel called with a userState token that is not in the pending async list - returning");
901 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, helper.TraceEventId,
902 "Proceeding to cancel the pending async");
903 helper.CancelAsync();
907 private static int s_TraceEventId;
908 private static int NewTraceEventId
912 Interlocked.CompareExchange(ref s_TraceEventId, 0, int.MaxValue);
913 Interlocked.Increment(ref s_TraceEventId);
914 return s_TraceEventId;