Adding reference source for System.Net
[mono.git] / mcs / class / referencesource / System.Net / net / PeerToPeer / Collaboration / CollaborationHelperFunctions.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="CollaborationHelperFunctions.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>                                                                
5 //------------------------------------------------------------------------------
6
7 using System.Security.Permissions;
8
9 namespace System.Net.PeerToPeer.Collaboration
10 {
11     using System;
12     using System.Collections.ObjectModel;
13     using System.Runtime.InteropServices;
14     using System.Net.Mail;
15     using System.Security.Cryptography.X509Certificates;
16     using System.Diagnostics;
17     using System.Threading;
18
19     /// <summary>
20     /// This class contains some of the common functions needed for peer
21     /// collaboration
22     /// </summary>
23     internal static class CollaborationHelperFunctions
24     {
25         private static volatile bool s_Initialized;
26         private static object s_LockInitialized = new object();
27         private const short c_CollabVersion = 0x0001;
28
29         //
30         // Initialise windows collab. This has to be called before any collab operation
31         //
32         // <SecurityKernel Critical="True" Ring="0">
33         // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabStartup(System.Int16):System.Int32" />
34         // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
35         // </SecurityKernel>
36         [System.Security.SecurityCritical]
37         internal static void Initialize()
38         {
39             if (!s_Initialized){
40                 lock (s_LockInitialized){
41                     if (!s_Initialized){
42                         if(!PeerToPeerOSHelper.SupportsP2P)
43                             throw new PlatformNotSupportedException(SR.GetString(SR.P2P_NotAvailable));
44                         int errorCode = UnsafeCollabNativeMethods.PeerCollabStartup(c_CollabVersion);
45                         if (errorCode != 0){
46                             Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabStartup returned with errorcode {0}", errorCode);
47                             throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_StartupFailed), errorCode);
48                         }
49                         s_Initialized = true;
50                     }
51                 }
52             }
53         }
54
55         //
56         // Converts Guid class to GUID structure that we can pass into native
57         //
58         internal static GUID ConvertGuidToGUID(Guid guid)
59         {
60             GUID newGuid = new GUID();
61
62             if (guid != null){
63                 byte[] guidBytes = guid.ToByteArray();
64                 string guidString = guid.ToString();
65
66                 int startVal = 0;
67                 int endVal = guidString.IndexOf('-');
68                 newGuid.data1 = (uint)(Convert.ToUInt32(guidString.Substring(startVal, endVal - startVal), 16));
69                 startVal = endVal + 1;
70                 endVal = guidString.IndexOf('-', endVal + 1);
71                 newGuid.data2 = (ushort)(Convert.ToUInt16(guidString.Substring(startVal, endVal - startVal), 16));
72                 startVal = endVal + 1;
73                 endVal = guidString.IndexOf('-', endVal + 1);
74                 newGuid.data3 = (ushort)(Convert.ToUInt16(guidString.Substring(startVal, endVal - startVal), 16));
75                 newGuid.data4 = guidBytes[8];
76                 newGuid.data5 = guidBytes[9];
77                 newGuid.data6 = guidBytes[10];
78                 newGuid.data7 = guidBytes[11];
79                 newGuid.data8 = guidBytes[12];
80                 newGuid.data9 = guidBytes[13];
81                 newGuid.data10 = guidBytes[14];
82                 newGuid.data11 = guidBytes[15];
83             }
84             return newGuid;
85         }
86
87         //
88         // Converts native GUID structure to managed Guid class
89         //
90         internal static Guid ConvertGUIDToGuid(GUID guid)
91         {
92             byte[] bytes = new byte[8];
93             bytes[0] = guid.data4;
94             bytes[1] = guid.data5;
95             bytes[2] = guid.data6;
96             bytes[3] = guid.data7;
97             bytes[4] = guid.data8;
98             bytes[5] = guid.data9;
99             bytes[6] = guid.data10;
100             bytes[7] = guid.data11;
101
102             return new Guid((int)guid.data1, (short)guid.data2, (short)guid.data3, bytes);
103         }
104
105         //
106         // Converts native PEER_CONTACT to PeerContact class
107         //
108         // <SecurityKernel Critical="True" Ring="1">
109         // <ReferencesCritical Name="Method: ConvertPEER_CONTACTToPeerContact(PEER_CONTACT, Boolean):PeerContact" Ring="1" />
110         // </SecurityKernel>
111         [System.Security.SecurityCritical]
112         internal static PeerContact ConvertPEER_CONTACTToPeerContact(PEER_CONTACT pc)
113         {
114             return ConvertPEER_CONTACTToPeerContact(pc, false);
115         }
116
117         // <SecurityKernel Critical="True" Ring="0">
118         // <SatisfiesLinkDemand Name="Marshal.Copy(System.IntPtr,System.Byte[],System.Int32,System.Int32):System.Void" />
119         // <SatisfiesLinkDemand Name="SafeHandle.get_IsInvalid():System.Boolean" />
120         // <SatisfiesLinkDemand Name="Marshal.GetLastWin32Error():System.Int32" />
121         // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
122         // <SatisfiesLinkDemand Name="X509Store..ctor(System.IntPtr)" />
123         // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
124         // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.CertOpenStore(System.IntPtr,System.UInt32,System.IntPtr,System.UInt32,System.Net.PeerToPeer.Collaboration.PEER_DATA&):System.Net.PeerToPeer.Collaboration.SafeCertStore" />
125         // <ReferencesCritical Name="Local certHandle of type: SafeCertStore" Ring="1" />
126         // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
127         // <ReferencesCritical Name="Method: PeerContact..ctor()" Ring="2" />
128         // <ReferencesCritical Name="Method: MyContact..ctor()" Ring="3" />
129         // </SecurityKernel>
130         [System.Security.SecurityCritical]
131         internal static PeerContact ConvertPEER_CONTACTToPeerContact(PEER_CONTACT pc, bool isMyContact)
132         {
133             PeerContact peerContact = (isMyContact ? new MyContact(): new PeerContact());
134             peerContact.PeerName = new PeerName(pc.pwzPeerName);
135             peerContact.DisplayName = pc.pwzDisplayName;
136             peerContact.Nickname = pc.pwzNickname;
137             peerContact.EmailAddress = (pc.pwzEmailAddress != null) ? new MailAddress(pc.pwzEmailAddress) : null;
138             if(!isMyContact) 
139                 peerContact.SubscribeAllowed = pc.WatcherPermissions;
140             peerContact.IsSubscribed = (isMyContact ? true : pc.fWatch);
141             byte[] data = null;
142
143             if (pc.credentials.cbData != 0){
144                 data = new byte[pc.credentials.cbData];
145                 Marshal.Copy(pc.credentials.pbData, data, 0, (int)pc.credentials.cbData);
146             }
147
148             if (data != null){
149
150                 SafeCertStore certHandle = UnsafeCollabNativeMethods.CertOpenStore(new IntPtr(/*CERT_STORE_PROV_PKCS7*/ 5),
151                                                     0x00000001/*X509_ASN_ENCODING*/| 0x00010000/*PKCS_7_ASN_ENCODING*/,
152                                                     IntPtr.Zero,
153                                                     0x00000001/*CERT_STORE_NO_CRYPT_RELEASE_FLAG*/,
154                                                     ref pc.credentials);
155
156                 if (certHandle == null || certHandle.IsInvalid){
157                     int win32ErrorCode = Marshal.GetLastWin32Error();
158                     throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_CredentialsError), win32ErrorCode);
159                 }
160                 try{
161                     X509Store certStore = new X509Store(certHandle.DangerousGetHandle());
162                     peerContact.Credentials = new X509Certificate2(certStore.Certificates[0]);
163                 }
164                 finally{
165                     if(certHandle != null) certHandle.Dispose();
166                 }
167             }
168
169             return peerContact;
170         }
171
172         // <SecurityKernel Critical="True" Ring="0">
173         // <SatisfiesLinkDemand Name="SafeHandle.get_IsInvalid():System.Boolean" />
174         // <SatisfiesLinkDemand Name="Marshal.GetLastWin32Error():System.Int32" />
175         // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
176         // <SatisfiesLinkDemand Name="X509Store..ctor(System.IntPtr)" />
177         // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
178         // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.CertOpenStore(System.IntPtr,System.UInt32,System.IntPtr,System.UInt32,System.IntPtr):System.Net.PeerToPeer.Collaboration.SafeCertStore" />
179         // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.CertSaveStore(System.Net.PeerToPeer.Collaboration.SafeCertStore,System.UInt32,System.UInt32,System.UInt32,System.Net.PeerToPeer.Collaboration.PEER_DATA&,System.UInt32):System.Boolean" />
180         // <ReferencesCritical Name="Local certHandle of type: SafeCertStore" Ring="1" />
181         // <ReferencesCritical Name="Parameter safeCredentials of type: SafeCollabMemory" Ring="1" />
182         // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
183         // <ReferencesCritical Name="Method: SafeCollabMemory..ctor(System.Int32)" Ring="1" />
184         // </SecurityKernel>
185         [System.Security.SecurityCritical]
186         internal static PEER_CONTACT ConvertPeerContactToPEER_CONTACT(PeerContact peerContact, ref SafeCollabMemory safeCredentials)
187         {
188             PEER_CONTACT pc = new PEER_CONTACT();
189
190             pc.pwzDisplayName = peerContact.DisplayName;
191             pc.pwzEmailAddress = (peerContact.EmailAddress == null) ? null : peerContact.EmailAddress.ToString();
192             pc.pwzNickname = peerContact.Nickname;
193             pc.pwzPeerName = peerContact.PeerName.ToString();
194             pc.fWatch = peerContact.IsSubscribed;
195             pc.WatcherPermissions = peerContact.SubscribeAllowed;
196             PEER_DATA pd = new PEER_DATA();
197
198             if (peerContact.Credentials != null){
199                 SafeCertStore certHandle = UnsafeCollabNativeMethods.CertOpenStore(new IntPtr(/*CERT_STORE_PROV_MEMORY*/ 2),
200                                     0,
201                                     IntPtr.Zero,
202                                     0x00002000/*CERT_STORE_CREATE_NEW_FLAG*/ | 0x00000001/*CERT_STORE_NO_CRYPT_RELEASE_FLAG*/,
203                                     IntPtr.Zero);
204                 
205                 if (certHandle == null || certHandle.IsInvalid){
206                     int win32ErrorCode = Marshal.GetLastWin32Error();
207                     throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_CredentialsError), win32ErrorCode);
208                 }
209                 
210                 try{
211                     X509Store certStore = new X509Store(certHandle.DangerousGetHandle());
212                     certStore.Add(peerContact.Credentials as X509Certificate2);
213                     bool returnCode = UnsafeCollabNativeMethods.CertSaveStore(certHandle,
214                                                      0x00000001/*X509_ASN_ENCODING*/| 0x00010000/*PKCS_7_ASN_ENCODING*/,
215                                                      2 /*CERT_STORE_SAVE_AS_STORE*/,
216                                                      2, /*CERT_STORE_SAVE_TO_MEMORY*/
217                                                      ref pd,
218                                                      0);
219                     
220                     if ((pd.cbData != 0) && (returnCode)){
221                         safeCredentials = new SafeCollabMemory((int)pd.cbData);
222                         pd.pbData = safeCredentials.DangerousGetHandle();
223                         returnCode = UnsafeCollabNativeMethods.CertSaveStore(certHandle,
224                                                      0x00000001/*X509_ASN_ENCODING*/| 0x00010000/*PKCS_7_ASN_ENCODING*/,
225                                                      2 /*CERT_STORE_SAVE_AS_STORE*/,
226                                                      2, /*CERT_STORE_SAVE_TO_MEMORY*/
227                                                      ref pd,// Clean up memory from here;
228                                                      0);
229
230                     }
231                     else{
232                         pd.cbData = 0;
233                         pd.pbData = IntPtr.Zero;
234                     }
235                 }
236                 finally{
237                     if (certHandle != null) certHandle.Dispose();
238                 }
239             }
240             else{
241                 pd.cbData = 0;
242                 pd.pbData = IntPtr.Zero;
243             }
244             pc.credentials = pd;
245
246             return pc;
247
248         }
249
250         //
251         // Converts address bytes to a SOCKADDR_IN6 that can be passed into
252         // native
253         //
254         internal static void ByteArrayToSin6Addr(byte[] addrBytes, ref SOCKADDR_IN6 sin6)
255         {
256             sin6.sin6_addr0 = addrBytes[0];
257             sin6.sin6_addr1 = addrBytes[1];
258             sin6.sin6_addr2 = addrBytes[2];
259             sin6.sin6_addr3 = addrBytes[3];
260             sin6.sin6_addr4 = addrBytes[4];
261             sin6.sin6_addr5 = addrBytes[5];
262             sin6.sin6_addr6 = addrBytes[6];
263             sin6.sin6_addr7 = addrBytes[7];
264             sin6.sin6_addr8 = addrBytes[8];
265             sin6.sin6_addr9 = addrBytes[9];
266             sin6.sin6_addr10 = addrBytes[10];
267             sin6.sin6_addr11 = addrBytes[11];
268             sin6.sin6_addr12 = addrBytes[12];
269             sin6.sin6_addr13 = addrBytes[13];
270             sin6.sin6_addr14 = addrBytes[14];
271             sin6.sin6_addr15 = addrBytes[15];
272         }
273
274         //
275         // Converts native structure PEER_PEOPLE_NEAR_ME to managed PeerNearMe class
276         //
277         // <SecurityKernel Critical="True" Ring="0">
278         // <SatisfiesLinkDemand Name="Marshal.PtrToStringUni(System.IntPtr):System.String" />
279         // <ReferencesCritical Name="Method: ConvertPEER_ENDPOINTToPeerEndPoint(PEER_ENDPOINT):PeerEndPoint" Ring="1" />
280         // </SecurityKernel>
281         [System.Security.SecurityCritical]
282         internal static PeerNearMe PEER_PEOPLE_NEAR_METoPeerNearMe(PEER_PEOPLE_NEAR_ME ppnm)
283         {
284             PeerNearMe peerNearMe = new PeerNearMe();
285             peerNearMe.Id = CollaborationHelperFunctions.ConvertGUIDToGuid(ppnm.id);
286             peerNearMe.Nickname = Marshal.PtrToStringUni(ppnm.pwzNickname); ;
287
288             PEER_ENDPOINT pe = ppnm.endpoint;
289             PeerEndPoint peerEP = ConvertPEER_ENDPOINTToPeerEndPoint(pe);
290             peerNearMe.PeerEndPoints.Add(peerEP);
291             
292             return peerNearMe;
293         }
294
295         //
296         // Converts native PEER_OBJECT structure into PeerObject class
297         //
298         // <SecurityKernel Critical="True" Ring="0">
299         // <SatisfiesLinkDemand Name="Marshal.Copy(System.IntPtr,System.Byte[],System.Int32,System.Int32):System.Void" />
300         // </SecurityKernel>
301         [System.Security.SecurityCritical]
302         internal static PeerObject ConvertPEER_OBJECTToPeerObject(PEER_OBJECT po)
303         {
304             byte[] data = null;
305
306             if (po.data.cbData != 0){
307                 data = new byte[po.data.cbData];
308                 Marshal.Copy(po.data.pbData, data, 0, (int)po.data.cbData);
309             }
310
311             return new PeerObject(ConvertGUIDToGuid(po.guid), data, (PeerScope)po.dwPublicationScope);
312         }
313
314         //
315         // Converts native PEER_APPLICATION structure into PeerApplication class
316         //
317  
318         // <SecurityKernel Critical="True" Ring="0">
319         // <SatisfiesLinkDemand Name="Marshal.Copy(System.IntPtr,System.Byte[],System.Int32,System.Int32):System.Void" />
320         // <SatisfiesLinkDemand Name="Marshal.PtrToStringUni(System.IntPtr):System.String" />
321         // </SecurityKernel>
322         [System.Security.SecurityCritical]
323         internal static PeerApplication ConvertPEER_APPLICATIONToPeerApplication(PEER_APPLICATION pa)
324         {
325             byte[] data = null;
326
327             if (pa.data.cbData != 0){
328                 data = new byte[pa.data.cbData];
329                 Marshal.Copy(pa.data.pbData, data, 0, (int)pa.data.cbData);
330             }
331
332             return new PeerApplication( ConvertGUIDToGuid(pa.guid),
333                                         Marshal.PtrToStringUni(pa.pwzDescription),
334                                         data,
335                                         null, null, PeerScope.None);
336         }
337
338         //
339         // Converts native PEER_ENDPOINT structure into PeerEndPoint class
340         //
341         
342         // <SecurityKernel Critical="True" Ring="0">
343         // <SatisfiesLinkDemand Name="Marshal.PtrToStringUni(System.IntPtr):System.String" />
344         // </SecurityKernel>
345         [System.Security.SecurityCritical]
346         internal static PeerEndPoint ConvertPEER_ENDPOINTToPeerEndPoint(PEER_ENDPOINT pe)
347         {
348
349             byte[] addrBytes = new byte[]{  pe.peerAddress.sin6.sin6_addr0, pe.peerAddress.sin6.sin6_addr1, 
350                                             pe.peerAddress.sin6.sin6_addr2, pe.peerAddress.sin6.sin6_addr3, 
351                                             pe.peerAddress.sin6.sin6_addr4, pe.peerAddress.sin6.sin6_addr5,
352                                             pe.peerAddress.sin6.sin6_addr6, pe.peerAddress.sin6.sin6_addr7, 
353                                             pe.peerAddress.sin6.sin6_addr8, pe.peerAddress.sin6.sin6_addr9, 
354                                             pe.peerAddress.sin6.sin6_addr10, pe.peerAddress.sin6.sin6_addr11, 
355                                             pe.peerAddress.sin6.sin6_addr12, pe.peerAddress.sin6.sin6_addr13, 
356                                             pe.peerAddress.sin6.sin6_addr14, pe.peerAddress.sin6.sin6_addr15};
357             IPAddress IPAddr = new IPAddress(addrBytes, (long)pe.peerAddress.sin6.sin6_scope_id);
358             ushort port;
359             unchecked{
360                 port = (ushort)IPAddress.NetworkToHostOrder((short)pe.peerAddress.sin6.sin6_port);
361             }
362             IPEndPoint IPEndPt = new IPEndPoint(IPAddr, port);
363
364             return new PeerEndPoint(IPEndPt, Marshal.PtrToStringUni(pe.pwzEndpointName));
365         }
366
367         //
368         // Converts IPEndpoint class into native PEER_ADDRESS structure
369         //
370         internal static PEER_ADDRESS ConvertIPEndpointToPEER_ADDRESS(IPEndPoint endPoint)
371         {
372             PEER_ADDRESS pa = new PEER_ADDRESS();
373             SOCKADDR_IN6 sin = new SOCKADDR_IN6();
374             sin.sin6_family = (ushort)endPoint.AddressFamily;
375             sin.sin6_flowinfo = 0; // 
376             unchecked{
377                 sin.sin6_port = (ushort)IPAddress.HostToNetworkOrder((short)endPoint.Port);
378             }
379             sin.sin6_scope_id = (uint)endPoint.Address.ScopeId;
380             CollaborationHelperFunctions.ByteArrayToSin6Addr(endPoint.Address.GetAddressBytes(), ref sin);
381             pa.dwSize = 32;
382             pa.sin6 = sin;
383             return pa;
384         }
385
386         //
387         // Cleans up the registered handle and the wait event. Called under lock from events.
388         //
389         // <SecurityKernel Critical="True" Ring="0">
390         // <SatisfiesLinkDemand Name="SafeHandle.get_IsInvalid():System.Boolean" />
391         // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
392         // <ReferencesCritical Name="Parameter safeEvent of type: SafeCollabEvent" Ring="1" />
393         // </SecurityKernel>
394         [System.Security.SecurityCritical]
395         [SecurityPermissionAttribute(SecurityAction.LinkDemand, UnmanagedCode = true)]
396         internal static void CleanEventVars(ref RegisteredWaitHandle waitHandle,
397                                             ref SafeCollabEvent safeEvent,
398                                             ref AutoResetEvent firedEvent)
399         {
400             if (waitHandle != null){
401                 waitHandle.Unregister(null);
402                 waitHandle = null;
403             }
404
405             if ((safeEvent != null) && (!safeEvent.IsInvalid)){
406                 safeEvent.Dispose();
407             }
408
409             if (firedEvent != null){
410                 firedEvent.Close();
411                 firedEvent = null;
412             }
413         }
414
415         // <SecurityKernel Critical="True" Ring="0">
416         // <SatisfiesLinkDemand Name="WaitHandle.get_SafeWaitHandle():Microsoft.Win32.SafeHandles.SafeWaitHandle" />
417         // <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" />
418         // <ReferencesCritical Name="Parameter safePresenceChangedEvent of type: SafeCollabEvent" Ring="1" />
419         // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
420         // </SecurityKernel>
421         [System.Security.SecurityCritical]
422         internal static void AddMyPresenceChanged(EventHandler<PresenceChangedEventArgs> callback,
423                                                         ref EventHandler<PresenceChangedEventArgs> presenceChanged,
424                                                         object lockPresenceChangedEvent,
425                                                         ref RegisteredWaitHandle regPresenceChangedWaitHandle,
426                                                         ref AutoResetEvent presenceChangedEvent,
427                                                         ref SafeCollabEvent safePresenceChangedEvent,
428                                                         WaitOrTimerCallback PresenceChangedCallback)
429         {
430             //
431             // Register a wait handle if one has not been registered already
432             //
433             lock (lockPresenceChangedEvent){
434                 if (presenceChanged == null){
435
436                     presenceChangedEvent = new AutoResetEvent(false);
437
438                     //
439                     // Register callback with a wait handle
440                     //
441
442                     regPresenceChangedWaitHandle = ThreadPool.RegisterWaitForSingleObject(presenceChangedEvent, //Event that triggers the callback
443                                             PresenceChangedCallback, //callback to be called 
444                                             null, //state to be passed
445                                             -1,   //Timeout - aplicable only for timers
446                                             false //call us everytime the event is set
447                                             );
448                     PEER_COLLAB_EVENT_REGISTRATION pcer = new PEER_COLLAB_EVENT_REGISTRATION();
449                     pcer.eventType = PeerCollabEventType.MyPresenceChanged;
450                     pcer.pInstance = IntPtr.Zero;
451
452
453                     //
454                     // Register event with collab
455                     //
456
457                     int errorCode = UnsafeCollabNativeMethods.PeerCollabRegisterEvent(
458                                                                         presenceChangedEvent.SafeWaitHandle,
459                                                                         1,
460                                                                         ref pcer,
461                                                                         out safePresenceChangedEvent);
462                     if (errorCode != 0){
463                         Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabRegisterEvent returned with errorcode {0}", errorCode);
464                         throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_PresenceChangedRegFailed), errorCode);
465                     }
466                 }
467                 presenceChanged += callback;
468             }
469
470             Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "AddMyPresenceChanged() successful.");
471         }
472
473         // <SecurityKernel Critical="True" Ring="0">
474         // <SatisfiesLinkDemand Name="WaitHandle.get_SafeWaitHandle():Microsoft.Win32.SafeHandles.SafeWaitHandle" />
475         // <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" />
476         // <ReferencesCritical Name="Parameter safeAppChangedEvent of type: SafeCollabEvent" Ring="1" />
477         // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
478         // </SecurityKernel>
479         [System.Security.SecurityCritical]
480         internal static void AddMyApplicationChanged(EventHandler<ApplicationChangedEventArgs> callback,
481                                                 ref EventHandler<ApplicationChangedEventArgs> applicationChanged,
482                                                 object lockAppChangedEvent,
483                                                 ref RegisteredWaitHandle regAppChangedWaitHandle,
484                                                 ref AutoResetEvent appChangedEvent,
485                                                 ref SafeCollabEvent safeAppChangedEvent,
486                                                 WaitOrTimerCallback ApplicationChangedCallback)
487         {
488             //
489             // Register a wait handle if one has not been registered already
490             //
491             lock (lockAppChangedEvent){
492                 if (applicationChanged == null){
493
494                     appChangedEvent = new AutoResetEvent(false);
495
496                     //
497                     // Register callback with a wait handle
498                     //
499
500                     regAppChangedWaitHandle = ThreadPool.RegisterWaitForSingleObject(appChangedEvent, //Event that triggers the callback
501                                             ApplicationChangedCallback, //callback to be called 
502                                             null, //state to be passed
503                                             -1,   //Timeout - aplicable only for timers
504                                             false //call us everytime the event is set
505                                             );
506                     PEER_COLLAB_EVENT_REGISTRATION pcer = new PEER_COLLAB_EVENT_REGISTRATION();
507
508                     pcer.eventType = PeerCollabEventType.MyApplicationChanged;
509                     pcer.pInstance = IntPtr.Zero;
510
511                     //
512                     // Register event with collab
513                     //
514
515                     int errorCode = UnsafeCollabNativeMethods.PeerCollabRegisterEvent(
516                                                                         appChangedEvent.SafeWaitHandle,
517                                                                         1,
518                                                                         ref pcer,
519                                                                         out safeAppChangedEvent);
520                     if (errorCode != 0){
521                         Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabRegisterEvent returned with errorcode {0}", errorCode);
522                         throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_ApplicationChangedRegFailed), errorCode);
523                     }
524                 }
525                 applicationChanged += callback;
526             }
527             
528                 Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "AddApplicationChanged() successful.");
529         }
530
531         // <SecurityKernel Critical="True" Ring="0">
532         // <SatisfiesLinkDemand Name="WaitHandle.get_SafeWaitHandle():Microsoft.Win32.SafeHandles.SafeWaitHandle" />
533         // <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" />
534         // <ReferencesCritical Name="Parameter safeObjChangedEvent of type: SafeCollabEvent" Ring="1" />
535         // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
536         // </SecurityKernel>
537         [System.Security.SecurityCritical]
538         internal static void AddMyObjectChanged(EventHandler<ObjectChangedEventArgs> callback,
539                                         ref EventHandler<ObjectChangedEventArgs> objectChanged,
540                                         object lockObjChangedEvent,
541                                         ref RegisteredWaitHandle regObjChangedWaitHandle,
542                                         ref AutoResetEvent objChangedEvent,
543                                         ref SafeCollabEvent safeObjChangedEvent,
544                                         WaitOrTimerCallback ObjectChangedCallback)
545         {
546             //
547             // Register a wait handle if one has not been registered already
548             //
549             lock (lockObjChangedEvent){
550                 if (objectChanged == null){
551
552                     objChangedEvent = new AutoResetEvent(false);
553
554                     //
555                     // Register callback with a wait handle
556                     //
557
558                     regObjChangedWaitHandle = ThreadPool.RegisterWaitForSingleObject(objChangedEvent, //Event that triggers the callback
559                                             ObjectChangedCallback, //callback to be called 
560                                             null, //state to be passed
561                                             -1,   //Timeout - aplicable only for timers
562                                             false //call us everytime the event is set
563                                             );
564
565                     PEER_COLLAB_EVENT_REGISTRATION pcer = new PEER_COLLAB_EVENT_REGISTRATION();
566                     pcer.eventType = PeerCollabEventType.MyObjectChanged;
567                     pcer.pInstance = IntPtr.Zero;
568
569
570                     //
571                     // Register event with collab
572                     //
573
574                     int errorCode = UnsafeCollabNativeMethods.PeerCollabRegisterEvent(
575                                                                         objChangedEvent.SafeWaitHandle,
576                                                                         1,
577                                                                         ref pcer,
578                                                                         out safeObjChangedEvent);
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_ObjectChangedRegFailed), errorCode);
582                     }
583                 }
584                 objectChanged += callback;
585             }
586
587             Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "AddObjectChanged() successful.");
588
589         }
590
591         internal static void ThrowIfInvitationResponseInvalid(PeerInvitationResponse response)
592         {
593             // throw an exception if the response from the native API was PEER_INVITATION_RESPONSE_ERROR
594             if (response.PeerInvitationResponseType < PeerInvitationResponseType.Declined ||
595                 response.PeerInvitationResponseType > PeerInvitationResponseType.Expired)
596             {
597                 throw new PeerToPeerException(SR.GetString(SR.Collab_InviteFailed));
598             }
599         }
600     }
601 }