Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Net / net / PeerToPeer / Collaboration / PeerNearMe.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="PeerNearMe.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>                                                                
5 //------------------------------------------------------------------------------
6 namespace System.Net.PeerToPeer.Collaboration
7 {
8     using System;
9     using System.Collections;
10     using System.Collections.Generic;
11     using System.Collections.ObjectModel;
12     using System.Runtime.InteropServices;
13     using System.Threading;
14     using System.ComponentModel;
15     using System.Text;
16     using System.Net.Mail;
17     using System.Diagnostics;
18     using System.Diagnostics.CodeAnalysis;
19     using System.Runtime.Serialization;
20     using System.Security.Permissions;
21
22     /// <summary>
23     /// This is the event args class we give back when 
24     /// we have a peer near me change event triggered by native
25     /// </summary>
26     public class PeerNearMeChangedEventArgs : EventArgs
27     {
28         private PeerNearMe m_peerNearMe;
29         private PeerChangeType m_peerChangeType;
30
31         internal PeerNearMeChangedEventArgs(PeerNearMe peerNearMe, PeerChangeType peerChangeType)
32         {
33             m_peerNearMe = peerNearMe;
34             m_peerChangeType = peerChangeType;
35         }
36
37         public PeerNearMe PeerNearMe
38         {
39             get{
40                 return m_peerNearMe;
41             }
42         }
43
44         public PeerChangeType PeerChangeType
45         {
46             get{
47                 return m_peerChangeType;
48             }
49         }
50     }
51
52     /// <summary>
53     /// This class contains the functionality of the people near me concept
54     /// in windows collaboration i.e. people on the same subnet
55     /// </summary>
56     [Serializable]
57     public class PeerNearMe : Peer, IEquatable<PeerNearMe>, ISerializable
58     {
59         private string m_nickname;
60         private Guid m_id;
61
62         // <SecurityKernel Critical="True" Ring="1">
63         // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
64         // </SecurityKernel>
65         [System.Security.SecurityCritical]
66         static PeerNearMe(){
67             CollaborationHelperFunctions.Initialize();
68         }
69
70         public PeerNearMe(){
71             OnRefreshDataCompletedDelegate = new SendOrPostCallback(RefreshDataCompletedWaitCallback);
72         }
73
74         /// <summary>
75         /// Constructor to enable serialization 
76         /// </summary>
77         [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
78         protected PeerNearMe(SerializationInfo serializationInfo, StreamingContext streamingContext)
79             :base(serializationInfo, streamingContext)
80         {
81             m_id = (Guid) serializationInfo.GetValue("_Id", typeof(Guid));
82             m_nickname = serializationInfo.GetString("_NickName");
83
84             OnRefreshDataCompletedDelegate = new SendOrPostCallback(RefreshDataCompletedWaitCallback);
85         }
86
87         public string Nickname
88         {
89             get {
90                 if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
91                 
92                 return m_nickname;
93             }
94             internal set {
95                 if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
96                 
97                 m_nickname = value;
98             }
99         }
100
101         internal Guid Id
102         {
103             get{
104                 if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
105                 
106                 return m_id;
107             }
108             set
109             {
110                 if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
111                 
112                 m_id = value;
113             }
114         }
115
116         //
117         // Adds this peer to the contact manager
118         //
119         public PeerContact AddToContactManager()
120         {
121             Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering AddToContactManager.");
122             PeerContact peerContact = null;
123             try{
124                 peerContact = PeerCollaboration.ContactManager.CreateContact(this);
125                 PeerCollaboration.ContactManager.AddContact(peerContact);
126             }
127             catch (Exception e){
128                 throw new PeerToPeerException(SR.GetString(SR.Collab_AddToContactMgrFailed), (e.InnerException != null ? e.InnerException : e));
129             }
130             Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving AddToContactManager.");
131             return peerContact;
132         }
133
134         //
135         // Adds this peer to the contact manager
136         //
137         public PeerContact AddToContactManager(string displayName, string nickname, MailAddress emailAddress)
138         {
139             Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering AddToContactManager with Display name: {0}" + 
140                 " Nickname: {1} and Email Address: {2}", displayName, nickname, emailAddress);
141
142             PeerContact peerContact = null;
143
144             try{
145                 peerContact = PeerCollaboration.ContactManager.CreateContact(this);
146                 PeerCollaboration.ContactManager.AddContact(peerContact);
147             }
148             catch (Exception e){
149                 throw new PeerToPeerException(SR.GetString(SR.Collab_AddToContactMgrFailed), (e.InnerException != null ? e.InnerException : e));
150             }
151
152             peerContact.DisplayName = displayName;
153             peerContact.Nickname = nickname;
154             peerContact.EmailAddress = emailAddress;
155
156             try{
157                 PeerCollaboration.ContactManager.UpdateContact(peerContact);
158             }
159             catch (Exception e){
160                 throw new PeerToPeerException(SR.GetString(SR.Collab_AddToContactMgrFailed) + " " + SR.GetString(SR.Collab_AddToContactMgrFailedUpdate), (e.InnerException != null ? e.InnerException : e));
161             }
162
163             Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving AddToContactManager.");
164             return peerContact;
165         }
166
167         // <SecurityKernel Critical="True" Ring="1">
168         // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
169         // </SecurityKernel>
170         [System.Security.SecurityCritical]
171         public static PeerNearMe CreateFromPeerEndPoint(PeerEndPoint peerEndPoint)
172         {
173             Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering CreateFromPeerEndPoint.");
174             CollaborationHelperFunctions.Initialize();
175
176             if (peerEndPoint == null)
177                 throw new ArgumentNullException("peerEndPoint");
178             if (peerEndPoint.EndPoint == null)
179                 throw new PeerToPeerException(SR.GetString(SR.Collab_NoEndPointInPeerEndPoint));
180
181             PeerNearMeCollection peers = PeerCollaboration.GetPeersNearMe();
182             PeerNearMe peer = null;
183
184             foreach (PeerNearMe peerNearMe in peers){
185                 PeerEndPointCollection peerEndPoints = peerNearMe.PeerEndPoints;
186                 if ((peerEndPoints != null) && (peerEndPoints.Count != 0) && (peerEndPoints[0].Equals(peerEndPoint)))
187                     peer = peerNearMe;
188             }
189             if (peer == null){
190                 //
191                 // No peer found, throw
192                 //
193                 throw new PeerToPeerException(SR.GetString(SR.Collab_EndPointNotAPeerNearMe)); 
194             }
195
196             Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving CreateFromPeerEndPoint.");
197             return peer;
198         }
199
200         //
201         // Checks if we need refreshing of an unsubscribed peer near me
202         //
203         internal override void RefreshIfNeeded()
204         {
205             RefreshData();
206         }
207
208         //
209         // Refresh the endpoint with new data from collab
210         //
211         // <SecurityKernel Critical="True" Ring="1">
212         // <ReferencesCritical Name="Method: InternalRefreshData(Object):Void" Ring="1" />
213         // </SecurityKernel>
214         [System.Security.SecurityCritical]
215         public void RefreshData()
216         {
217             if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
218             PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
219
220             InternalRefreshData(false);
221         }
222
223         // <SecurityKernel Critical="True" Ring="0">
224         // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabRegisterEvent(Microsoft.Win32.SafeHandles.SafeWaitHandle,System.UInt32,System.Net.PeerToPeer.Collaboration.PEER_COLLAB_EVENT_REGISTRATION&,System.Net.PeerToPeer.Collaboration.SafeCollabEvent&):System.Int32" />
225         // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabGetEventData(System.Net.PeerToPeer.Collaboration.SafeCollabEvent,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
226         // <SatisfiesLinkDemand Name="WaitHandle.get_SafeWaitHandle():Microsoft.Win32.SafeHandles.SafeWaitHandle" />
227         // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
228         // <SatisfiesLinkDemand Name="Marshal.PtrToStructure(System.IntPtr,System.Type):System.Object" />
229         // <ReferencesCritical Name="Local safeRefreshedEPDataEvent of type: SafeCollabEvent" Ring="1" />
230         // <ReferencesCritical Name="Local eventData of type: SafeCollabData" Ring="1" />
231         // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
232         // <ReferencesCritical Name="Method: InternalRefreshData(PeerEndPoint):Void" Ring="1" />
233         // <ReferencesCritical Name="Method: CollaborationHelperFunctions.ConvertPEER_ENDPOINTToPeerEndPoint(System.Net.PeerToPeer.Collaboration.PEER_ENDPOINT):System.Net.PeerToPeer.Collaboration.PeerEndPoint" Ring="1" />
234         // </SecurityKernel>
235         [System.Security.SecurityCritical]
236         internal protected void InternalRefreshData(object state)
237         {
238             Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "InternalRefreshEndpointData called.");
239             
240             int errorCode = 0;
241             bool isAsync = (bool)state;
242             Exception exception = null;
243
244             AutoResetEvent refreshedEPDataEvent = new AutoResetEvent(false);
245             SafeCollabEvent safeRefreshedEPDataEvent;
246
247             PEER_COLLAB_EVENT_REGISTRATION pcer = new PEER_COLLAB_EVENT_REGISTRATION();
248             pcer.eventType = PeerCollabEventType.RequestStatusChanged;
249             pcer.pInstance = IntPtr.Zero;
250
251             //
252             // Register to receive status changed event from collab
253             //
254             errorCode = UnsafeCollabNativeMethods.PeerCollabRegisterEvent(
255                                                                 refreshedEPDataEvent.SafeWaitHandle,
256                                                                 1,
257                                                                 ref pcer,
258                                                                 out safeRefreshedEPDataEvent);
259             if (errorCode != 0){
260                 Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabRegisterEvent returned with errorcode {0}", errorCode);
261                 exception = PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_ReqStatusChangedRegFailed), errorCode);
262                 if (!isAsync)
263                     throw exception;
264             }
265
266             PeerEndPointCollection peerEndPoints = PeerEndPoints;
267             
268             if (peerEndPoints.Count == 0) return;
269
270             try{
271             InternalRefreshData(peerEndPoints[0]);
272             }
273             catch (Exception e){
274                 if (!isAsync)
275                     throw;
276                 else
277                     exception = e;
278             }
279
280             //
281             // Wait till all the endpoints are refreshed
282             //
283             while (exception == null){
284                 refreshedEPDataEvent.WaitOne();
285
286                 SafeCollabData eventData;
287
288                 errorCode = UnsafeCollabNativeMethods.PeerCollabGetEventData(safeRefreshedEPDataEvent,
289                                                                                     out eventData);
290                 if (errorCode != 0){
291                     Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabGetEventData returned with errorcode {0}", errorCode);
292                     exception = PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_RefreshDataFailed), errorCode);
293                     if (!isAsync)
294                         throw exception;
295                     else 
296                         break;
297                 }
298
299                 PEER_COLLAB_EVENT_DATA ped = (PEER_COLLAB_EVENT_DATA)Marshal.PtrToStructure(eventData.DangerousGetHandle(),
300                                                                                             typeof(PEER_COLLAB_EVENT_DATA));
301                 
302                 if (ped.eventType == PeerCollabEventType.RequestStatusChanged){
303                     PEER_EVENT_REQUEST_STATUS_CHANGED_DATA statusData = ped.requestStatusChangedData;
304
305                     PeerEndPoint peerEndPoint = null;
306
307                     if (statusData.pEndPoint != IntPtr.Zero){
308                         PEER_ENDPOINT pe = (PEER_ENDPOINT)Marshal.PtrToStructure(statusData.pEndPoint, typeof(PEER_ENDPOINT));
309                         peerEndPoint = CollaborationHelperFunctions.ConvertPEER_ENDPOINTToPeerEndPoint(pe);
310                     }
311
312                     if (statusData.hrChange < 0){
313                         exception = PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_RefreshDataFailed), statusData.hrChange);
314                     }
315
316                     if (exception != null){
317                         //
318                         // Throw exception for sync but call callback for async with exception
319                         //
320                         if (!isAsync)
321                             throw exception;
322                     }
323
324                     //
325                     // Check if this is our endpoint
326                     //
327                     if (PeerEndPoints[0].Equals(peerEndPoint)){
328                         Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Found endpoint match in Request status changed.");
329
330                         //
331                         // For async call the callback and for sync just return
332                         //
333                         if (isAsync){
334                             RefreshDataCompletedEventArgs args = new
335                                         RefreshDataCompletedEventArgs(  peerEndPoint,
336                                                                         null,
337                                                                         false,
338                                                                         m_refreshDataAsyncOp.UserSuppliedState);
339                             
340                             if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Information)){
341                                 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Firing RefreshDataCompleted event with folloding peer endpoint.");
342                                 peerEndPoint.TracePeerEndPoint();
343                             } 
344                             
345                             this.PrepareToRaiseRefreshDataCompletedEvent(m_refreshDataAsyncOp, args);
346                         }
347
348                         break;
349                     }
350                 }
351             }
352
353             //
354             // Async case with exception fire callback here
355             // Sync would have already thrown this by now
356             //
357             if (exception != null){
358                 RefreshDataCompletedEventArgs args = new
359                             RefreshDataCompletedEventArgs(null,
360                                                             exception,
361                                                             false,
362                                                             m_refreshDataAsyncOp.UserSuppliedState);
363                 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Firing RefreshDataCompleted event with exception {0}.", exception);
364                 this.PrepareToRaiseRefreshDataCompletedEvent(m_refreshDataAsyncOp, args);
365             }
366
367             Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving InternalRefreshEndpointData.");
368         }
369
370         //
371         // Refreshes on endpoint 
372         //
373
374         // <SecurityKernel Critical="True" Ring="0">
375         // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabRefreshEndpointData(System.IntPtr):System.Int32" />
376         // <SatisfiesLinkDemand Name="GCHandle.Alloc(System.Object,System.Runtime.InteropServices.GCHandleType):System.Runtime.InteropServices.GCHandle" />
377         // <SatisfiesLinkDemand Name="GCHandle.AddrOfPinnedObject():System.IntPtr" />
378         // <SatisfiesLinkDemand Name="GCHandle.Free():System.Void" />
379         // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
380         // </SecurityKernel>
381         [System.Security.SecurityCritical]
382         internal static void InternalRefreshData(PeerEndPoint peerEndPoint)
383         {
384             int errorCode;
385             PEER_ENDPOINT pep = new PEER_ENDPOINT();
386             pep.peerAddress = CollaborationHelperFunctions.ConvertIPEndpointToPEER_ADDRESS(peerEndPoint.EndPoint);
387
388             GCHandle pepName = GCHandle.Alloc(peerEndPoint.Name, GCHandleType.Pinned);
389             pep.pwzEndpointName = pepName.AddrOfPinnedObject();
390
391             GCHandle peerEP = GCHandle.Alloc(pep, GCHandleType.Pinned);
392             IntPtr ptrPeerEP = peerEP.AddrOfPinnedObject();
393
394             try{
395                 errorCode = UnsafeCollabNativeMethods.PeerCollabRefreshEndpointData(ptrPeerEP);
396             }
397             finally{
398                 if (pepName.IsAllocated) pepName.Free();
399                 if (peerEP.IsAllocated) peerEP.Free();
400             }
401
402             if (errorCode != 0){
403                 Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabRefreshEndpointData returned with errorcode {0}", errorCode);
404                 throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_RefreshDataFailed), errorCode);
405             }
406         }
407         
408         #region RefreshEndpoint Async variables
409         AsyncOperation m_refreshDataAsyncOp;
410         private object m_refreshDataAsyncOpLock;
411         private object RefreshDataAsyncOpLock
412         {
413             get{
414                 if (m_refreshDataAsyncOpLock == null){
415                     object o = new object();
416                     Interlocked.CompareExchange(ref m_refreshDataAsyncOpLock, o, null);
417                 }
418                 return m_refreshDataAsyncOpLock;
419             }
420         }
421         SendOrPostCallback OnRefreshDataCompletedDelegate;
422         #endregion
423
424         private event EventHandler<RefreshDataCompletedEventArgs> m_refreshDataCompleted;
425         public event EventHandler<RefreshDataCompletedEventArgs> RefreshDataCompleted
426         {
427             add
428             {
429                 if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
430                 PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
431                 
432                 m_refreshDataCompleted += value;
433             }
434             remove
435             {
436                 if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
437                 PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
438
439                 m_refreshDataCompleted -= value;
440             }
441         }
442
443         //
444         // Async refresh endpoint data
445         //
446         // <SecurityKernel Critical="True" Ring="1">
447         // <ReferencesCritical Name="Method: InternalRefreshData(Object):Void" Ring="1" />
448         // </SecurityKernel>
449         [System.Security.SecurityCritical]
450         public void RefreshDataAsync(object userToken)
451         {
452             if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
453             PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
454
455             if (userToken == null)
456                 throw new ArgumentNullException("userToken");
457
458             lock (RefreshDataAsyncOpLock){
459                 if (m_refreshDataAsyncOp != null)
460                     throw new PeerToPeerException(SR.GetString(SR.Collab_DuplicateRefreshAsync));
461                 m_refreshDataAsyncOp = AsyncOperationManager.CreateOperation(userToken);
462             }
463             ThreadPool.QueueUserWorkItem(new WaitCallback(InternalRefreshData), true);
464
465             Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving RefreshDataAsync().");
466         }
467
468         protected void OnRefreshDataCompleted(RefreshDataCompletedEventArgs e)
469         {
470             EventHandler<RefreshDataCompletedEventArgs> handlerCopy = m_refreshDataCompleted;
471
472             if (handlerCopy != null){
473                 handlerCopy(this, e);
474                 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Fired the refresh endpoint completed event callback.");
475             }
476         }
477
478         void RefreshDataCompletedWaitCallback(object operationState)
479         {
480             m_refreshDataAsyncOp = null;
481             OnRefreshDataCompleted((RefreshDataCompletedEventArgs)operationState);
482         }
483
484         internal void PrepareToRaiseRefreshDataCompletedEvent(AsyncOperation asyncOP, RefreshDataCompletedEventArgs args)
485         {
486             asyncOP.PostOperationCompleted(OnRefreshDataCompletedDelegate, args);
487         }
488
489         private static event EventHandler<PeerNearMeChangedEventArgs> s_peerNearMeChanged;
490         public static event EventHandler<PeerNearMeChangedEventArgs> PeerNearMeChanged
491         {
492             // <SecurityKernel Critical="True" Ring="1">
493             // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
494             // <ReferencesCritical Name="Method: AddPeerNearMeChanged(EventHandler`1<System.Net.PeerToPeer.Collaboration.PeerNearMeChangedEventArgs>):Void" Ring="1" />
495             // </SecurityKernel>
496             [System.Security.SecurityCritical]
497             add
498             {
499                 PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
500                 CollaborationHelperFunctions.Initialize();
501
502                 AddPeerNearMeChanged(value);
503             }
504             // <SecurityKernel Critical="True" Ring="1">
505             // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
506             // <ReferencesCritical Name="Method: RemovePeerNearMeChanged(EventHandler`1<System.Net.PeerToPeer.Collaboration.PeerNearMeChangedEventArgs>):Void" Ring="2" />
507             // </SecurityKernel>
508             [System.Security.SecurityCritical]
509             remove
510             {
511                 PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
512                 CollaborationHelperFunctions.Initialize();
513
514                 RemovePeerNearMeChanged(value);
515             }
516         }
517
518         #region PeerNearMe changed event variables
519         private static object s_lockPNMChangedEvent;
520         private static object LockPNMChangedEvent
521         {
522             get{
523                 if (s_lockPNMChangedEvent == null){
524                     object o = new object();
525                     Interlocked.CompareExchange(ref s_lockPNMChangedEvent, o, null);
526                 }
527                 return s_lockPNMChangedEvent;
528             }
529         }
530         private static RegisteredWaitHandle s_registeredPNMWaitHandle;
531         private static AutoResetEvent s_peerNearMeChangedEvent;
532         private static SafeCollabEvent s_safePeerNearMeChangedEvent;
533         #endregion
534
535         // <SecurityKernel Critical="True" Ring="0">
536         // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabRegisterEvent(Microsoft.Win32.SafeHandles.SafeWaitHandle,System.UInt32,System.Net.PeerToPeer.Collaboration.PEER_COLLAB_EVENT_REGISTRATION&,System.Net.PeerToPeer.Collaboration.SafeCollabEvent&):System.Int32" />
537         // <SatisfiesLinkDemand Name="WaitHandle.get_SafeWaitHandle():Microsoft.Win32.SafeHandles.SafeWaitHandle" />
538         // <ReferencesCritical Name="Method: PeerNearMeChangedCallback(Object, Boolean):Void" Ring="1" />
539         // <ReferencesCritical Name="Field: s_safePeerNearMeChangedEvent" Ring="1" />
540         // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
541         // </SecurityKernel>
542         [System.Security.SecurityCritical]
543         private static void AddPeerNearMeChanged(EventHandler<PeerNearMeChangedEventArgs> cb)
544         {
545             //
546             // Register a wait handle if one has not been registered already
547             //
548
549             Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering AddPeerNearMeChanged().");
550
551             lock (LockPNMChangedEvent){
552                 if (s_peerNearMeChanged == null){
553
554                     s_peerNearMeChangedEvent = new AutoResetEvent(false);
555                     
556                     //
557                     // Register callback with a wait handle
558                     //
559
560                     s_registeredPNMWaitHandle = ThreadPool.RegisterWaitForSingleObject(s_peerNearMeChangedEvent, //Event that triggers the callback
561                                             new WaitOrTimerCallback(PeerNearMeChangedCallback), //callback to be called 
562                                             null, //state to be passed
563                                             -1,   //Timeout - aplicable only for timers
564                                             false //call us everytime the event is set
565                                             );
566                     PEER_COLLAB_EVENT_REGISTRATION pcer = new PEER_COLLAB_EVENT_REGISTRATION();
567                     pcer.eventType = PeerCollabEventType.PeopleNearMeChanged;
568                     pcer.pInstance = IntPtr.Zero;
569
570                     //
571                     // Register event with collab
572                     //
573
574                     int errorCode = UnsafeCollabNativeMethods.PeerCollabRegisterEvent(
575                                                                         s_peerNearMeChangedEvent.SafeWaitHandle,
576                                                                         1,
577                                                                         ref pcer,
578                                                                         out s_safePeerNearMeChangedEvent);
579                     if (errorCode != 0){
580                         Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabRegisterEvent returned with errorcode {0}", errorCode);
581                         throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_PeerNearMeChangedRegFailed), errorCode);
582                     }
583                 }
584                 s_peerNearMeChanged += cb;
585             }
586
587             Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "AddPeerNearMeChanged() successful.");
588         }
589
590         // <SecurityKernel Critical="True" Ring="1">
591         // <ReferencesCritical Name="Field: s_safePeerNearMeChangedEvent" Ring="1" />
592         // <ReferencesCritical Name="Method: CollaborationHelperFunctions.CleanEventVars(System.Threading.RegisteredWaitHandle&,System.Net.PeerToPeer.Collaboration.SafeCollabEvent&,System.Threading.AutoResetEvent&):System.Void" Ring="1" />
593         // </SecurityKernel>
594         [System.Security.SecurityCritical]
595         private static void RemovePeerNearMeChanged(EventHandler<PeerNearMeChangedEventArgs> cb)
596         {
597             Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemovePeerNearMeChanged() called.");
598             lock (LockPNMChangedEvent){
599                 s_peerNearMeChanged -= cb;
600                 if (s_peerNearMeChanged == null){
601                     CollaborationHelperFunctions.CleanEventVars(ref s_registeredPNMWaitHandle,
602                                                                 ref s_safePeerNearMeChangedEvent,
603                                                                 ref s_peerNearMeChangedEvent);
604
605                     Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Clean PeerNearMeChanged variables successful.");
606                 }
607             }
608             Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemovePeerNearMeChanged() successful.");
609         }
610
611         // <SecurityKernel Critical="True" Ring="0">
612         // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabGetEventData(System.Net.PeerToPeer.Collaboration.SafeCollabEvent,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
613         // <SatisfiesLinkDemand Name="SafeHandle.get_IsInvalid():System.Boolean" />
614         // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
615         // <SatisfiesLinkDemand Name="Marshal.PtrToStructure(System.IntPtr,System.Type):System.Object" />
616         // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
617         // <ReferencesCritical Name="Local eventData of type: SafeCollabData" Ring="1" />
618         // <ReferencesCritical Name="Field: s_safePeerNearMeChangedEvent" Ring="1" />
619         // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
620         // <ReferencesCritical Name="Method: CollaborationHelperFunctions.PEER_PEOPLE_NEAR_METoPeerNearMe(System.Net.PeerToPeer.Collaboration.PEER_PEOPLE_NEAR_ME):System.Net.PeerToPeer.Collaboration.PeerNearMe" Ring="1" />
621         // </SecurityKernel>
622         [System.Security.SecurityCritical]
623         private static void PeerNearMeChangedCallback(object state, bool timedOut)
624         {
625             SafeCollabData eventData = null;
626             int errorCode = 0;
627
628             Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "PeerNearMeChangedCallback() called.");
629
630             while (true){
631                 PeerNearMeChangedEventArgs peerNearMeChangedArgs = null;
632
633                 //
634                 // Get the event data for the fired event
635                 //
636
637                 try{
638                     lock (LockPNMChangedEvent){
639                         if (s_safePeerNearMeChangedEvent.IsInvalid) return;
640                         errorCode = UnsafeCollabNativeMethods.PeerCollabGetEventData(s_safePeerNearMeChangedEvent,
641                                                                                      out eventData);
642                     }
643                     if (errorCode == UnsafeCollabReturnCodes.PEER_S_NO_EVENT_DATA)
644                         break;
645                     else if (errorCode != 0){
646                         Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabGetEventData returned with errorcode {0}", errorCode);
647                         throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetPeerNearMeChangedDataFailed), errorCode);
648                     }
649
650                     PEER_COLLAB_EVENT_DATA ped = (PEER_COLLAB_EVENT_DATA)Marshal.PtrToStructure(eventData.DangerousGetHandle(),
651                                                                                                 typeof(PEER_COLLAB_EVENT_DATA));
652                     if (ped.eventType == PeerCollabEventType.PeopleNearMeChanged){
653                         PEER_EVENT_PEOPLE_NEAR_ME_CHANGED_DATA pnmData = ped.peopleNearMeChangedData;
654                         PeerNearMe peerNearMe = null;
655                         if (pnmData.pPeopleNearMe != IntPtr.Zero){
656                             PEER_PEOPLE_NEAR_ME pnm = (PEER_PEOPLE_NEAR_ME)Marshal.PtrToStructure(pnmData.pPeopleNearMe, typeof(PEER_PEOPLE_NEAR_ME));
657                             peerNearMe = CollaborationHelperFunctions.PEER_PEOPLE_NEAR_METoPeerNearMe(pnm);
658                         }
659
660                         peerNearMeChangedArgs = new PeerNearMeChangedEventArgs(peerNearMe, pnmData.changeType);
661                     }
662                 }
663                 finally{
664                     if (eventData != null) eventData.Dispose();
665                 }
666
667                 //
668                 // Fire the callback with the marshalled event args data
669                 //
670
671                 EventHandler<PeerNearMeChangedEventArgs> handlerCopy = s_peerNearMeChanged;
672
673                 if ((peerNearMeChangedArgs != null) && (handlerCopy != null)){
674                     handlerCopy(null, peerNearMeChangedArgs);
675                     Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Fired the peer near me changed event callback.");
676                 }
677             }
678             Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving PeerNearMeChangedCallback().");
679         }
680
681         // <SecurityKernel Critical="True" Ring="1">
682         // <ReferencesCritical Name="Method: Peer.InternalInviteEndPoint(System.Guid,System.String,System.Byte[],System.Net.PeerToPeer.Collaboration.PeerEndPoint,System.Net.PeerToPeer.Collaboration.PeerContact):System.Net.PeerToPeer.Collaboration.PeerInvitationResponse" Ring="1" />
683         // </SecurityKernel>
684         [System.Security.SecurityCritical]
685         public override PeerInvitationResponse Invite(PeerApplication applicationToInvite, string message,
686                                                       byte[] invitationData)
687         {
688             if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
689
690             PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
691
692             if (applicationToInvite == null)
693                 throw new ArgumentNullException("applicationToInvite");
694             if (applicationToInvite.Id == Guid.Empty)
695                 throw new PeerToPeerException(SR.GetString(SR.Collab_EmptyGuidError));
696             
697             //
698             // We need at least one endpoint to send invitation to
699             //
700             PeerEndPointCollection peerEndPoints = PeerEndPoints;
701
702             if ((peerEndPoints == null) || (peerEndPoints.Count == 0))
703                 throw new PeerToPeerException(SR.GetString(SR.Collab_NoEndpointFound));
704
705             PeerEndPoint peerEndPoint = PeerEndPoints[0];
706
707             PeerInvitationResponse response = InternalInviteEndPoint(applicationToInvite.Id, message, invitationData,
708                                                                      peerEndPoint, null);
709
710             // throw an exception if the response type is ERROR
711             CollaborationHelperFunctions.ThrowIfInvitationResponseInvalid(response);
712             return response;
713         }
714
715         // <SecurityKernel Critical="True" Ring="1">
716         // <ReferencesCritical Name="Method: Peer.get_CurrentApplicationGuid():System.Guid" Ring="1" />
717         // <ReferencesCritical Name="Method: Peer.InternalInviteEndPoint(System.Guid,System.String,System.Byte[],System.Net.PeerToPeer.Collaboration.PeerEndPoint,System.Net.PeerToPeer.Collaboration.PeerContact):System.Net.PeerToPeer.Collaboration.PeerInvitationResponse" Ring="1" />
718         // </SecurityKernel>
719         [System.Security.SecurityCritical]
720         public override PeerInvitationResponse Invite()
721         {
722             if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
723
724             PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
725
726             Guid appGuid = CurrentApplicationGuid;
727
728             if (appGuid.Equals(Guid.Empty))
729                 throw new PeerToPeerException(SR.GetString(SR.Collab_NoGuidForCurrApp));
730             
731             //
732             // We need at least one endpoint to send invitation to
733             //
734             PeerEndPointCollection peerEndPoints = PeerEndPoints;
735
736             if ((peerEndPoints == null) || (peerEndPoints.Count == 0))
737                 throw new PeerToPeerException(SR.GetString(SR.Collab_NoEndpointFound));
738
739             PeerEndPoint peerEndPoint = PeerEndPoints[0];
740
741             PeerInvitationResponse response = InternalInviteEndPoint(appGuid, null, null, peerEndPoint, null);
742
743             // throw an exception if the response type is ERROR
744             CollaborationHelperFunctions.ThrowIfInvitationResponseInvalid(response);
745             return response;
746         }
747
748         // <SecurityKernel Critical="True" Ring="1">
749         // <ReferencesCritical Name="Method: Peer.get_CurrentApplicationGuid():System.Guid" Ring="1" />
750         // <ReferencesCritical Name="Method: Peer.InternalInviteAsync(System.Guid,System.String,System.Byte[],System.Net.PeerToPeer.Collaboration.PeerEndPointCollection,System.Net.PeerToPeer.Collaboration.PeerContact,System.Object):System.Void" Ring="2" />
751         // </SecurityKernel>
752         [System.Security.SecurityCritical]
753         public override void InviteAsync(Object userToken)
754         {
755             if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
756             
757             PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
758             
759             if (userToken == null)
760                 throw new ArgumentException(SR.GetString(SR.NullUserToken));
761
762             Guid appGuid = CurrentApplicationGuid;
763
764             if (appGuid.Equals(Guid.Empty))
765                 throw new PeerToPeerException(SR.GetString(SR.Collab_NoGuidForCurrApp));
766
767             //
768             // We need at least one endpoint to send invitation to
769             //
770             PeerEndPointCollection peerEndPoints = PeerEndPoints;
771
772             if ((peerEndPoints == null) || (peerEndPoints.Count == 0))
773                 throw new PeerToPeerException(SR.GetString(SR.Collab_NoEndpointFound));
774
775             InternalInviteAsync(appGuid, null, null, PeerEndPoints, null, userToken);
776         }
777
778         // <SecurityKernel Critical="True" Ring="2">
779         // <ReferencesCritical Name="Method: Peer.InternalInviteAsync(System.Guid,System.String,System.Byte[],System.Net.PeerToPeer.Collaboration.PeerEndPointCollection,System.Net.PeerToPeer.Collaboration.PeerContact,System.Object):System.Void" Ring="2" />
780         // </SecurityKernel>
781         [System.Security.SecurityCritical]
782         public override void InviteAsync(   PeerApplication applicationToInvite, string message, 
783                                             byte[] invitationData, Object userToken)
784         {
785             if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
786
787             PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
788
789             if (applicationToInvite == null)
790                 throw new ArgumentNullException("applicationToInvite");
791             if (applicationToInvite.Id == Guid.Empty)
792                 throw new PeerToPeerException(SR.GetString(SR.Collab_EmptyGuidError));
793             if (userToken == null)
794                 throw new ArgumentException(SR.GetString(SR.NullUserToken));
795
796             //
797             // We need at least one endpoint to send invitation to
798             //
799             PeerEndPointCollection peerEndPoints = PeerEndPoints;
800
801             if ((peerEndPoints == null) || (peerEndPoints.Count == 0))
802                 throw new PeerToPeerException(SR.GetString(SR.Collab_NoEndpointFound));
803
804             InternalInviteAsync(applicationToInvite.Id, message, invitationData, 
805                                 peerEndPoints, null, userToken);
806         }
807
808         public bool Equals(PeerNearMe other)
809         {
810             if (other == null)
811                 throw new ArgumentNullException("other");
812
813             return other.Id.Equals(Id);
814         }
815
816         public override bool Equals(object obj)
817         {
818             if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
819
820             PeerNearMe comparandPeerNearMe = obj as PeerNearMe;
821             if (comparandPeerNearMe != null){
822                 return Guid.Equals(comparandPeerNearMe.Id, Id);
823             }
824
825             return false;
826         }
827
828         public new static bool Equals(object objA, object objB)
829         {
830             PeerNearMe comparandPeerNearMe1 = objA as PeerNearMe;
831             PeerNearMe comparandPeerNearMe2 = objB as PeerNearMe;
832
833             if ((comparandPeerNearMe1 != null) && (comparandPeerNearMe2 != null)){
834                 return Guid.Equals(comparandPeerNearMe1.Id, comparandPeerNearMe2.Id);
835             }
836
837             return false;
838         }
839
840         public override int GetHashCode()
841         {
842             if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
843
844             return Id.GetHashCode();
845         }
846
847         public override string ToString()
848         {
849             if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
850
851             return Nickname;
852         }
853
854         private bool m_Disposed;
855
856         protected override void Dispose(bool disposing)
857         {
858             if (!m_Disposed){
859                 try{
860                     m_Disposed = true;
861                 }
862                 finally{
863                     base.Dispose(disposing);
864                 }
865             }
866         }
867
868         // <SecurityKernel Critical="True" Ring="0">
869         // <SatisfiesLinkDemand Name="Peer.GetObjectData(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext):System.Void" />
870         // </SecurityKernel>
871         [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.Net.dll is still using pre-v4 security model and needs this demand")]
872         [System.Security.SecurityCritical]
873         [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter, SerializationFormatter = true)]
874         void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
875         {
876             GetObjectData(info, context);
877         }
878
879         /// <summary>
880         /// This is made virtual so that derived types can be implemented correctly
881         /// </summary>
882         // <SecurityKernel Critical="True" Ring="0">
883         // <SatisfiesLinkDemand Name="Peer.GetObjectData(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext):System.Void" />
884         // </SecurityKernel>
885         [System.Security.SecurityCritical]
886         [SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter = true)]
887         protected override void GetObjectData(SerializationInfo info, StreamingContext context)
888         {
889             base.GetObjectData(info, context);
890             info.AddValue("_Id", m_id);
891             info.AddValue("_NickName", m_nickname);
892         }
893
894         //
895         // Tracing information for Peer Near Me
896         //
897         internal void TracePeerNearMe()
898         {
899             Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Contents of the PeerNearMe");
900             Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "\tNickname: {0}", Nickname);
901             Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "\tID: {0}", Id);
902             Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "\tNumber of Endpoints: {0}", PeerEndPoints.Count);
903             if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Verbose)){
904
905                 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "\tEndPoints:");
906                 foreach (PeerEndPoint peerEndPoint in PeerEndPoints)
907                     peerEndPoint.TracePeerEndPoint();
908             }
909         }
910
911
912     }
913
914     //
915     // Manages collection of peer near me classes
916     //
917     [Serializable]
918     public class PeerNearMeCollection : Collection<PeerNearMe>
919     {
920         internal PeerNearMeCollection() { }
921         protected override void SetItem(int index, PeerNearMe item)
922         {
923             // nulls not allowed
924             if (item == null){
925                 throw new ArgumentNullException("item");
926             }
927             base.SetItem(index, item);
928         }
929
930         protected override void InsertItem(int index, PeerNearMe item)
931         {
932             // nulls not allowed
933             if (item == null){
934                 throw new ArgumentNullException("item");
935             }
936             base.InsertItem(index, item);
937         }
938
939         public override string ToString()
940         {
941             bool first = true;
942             StringBuilder builder = new StringBuilder();
943
944             foreach (PeerNearMe peerNearMe in this){
945                 if (!first){
946                     builder.Append(", ");
947                 }
948                 else{
949                     first = false;
950                 }
951                 builder.Append(peerNearMe.ToString());
952             }
953             return builder.ToString();
954         }
955     }
956
957 }