Welcome to mirror list, hosted at ThFree Co, Russian Federation.

PeerName.cs « PeerToPeer « net « System.Net « referencesource « class « mcs - github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: e4c8f05b975ae73f14ca46570edd8a07c6e98769 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
//------------------------------------------------------------------------------
// <copyright file="PeerName.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
namespace System.Net.PeerToPeer
{

    using System;
    using System.Globalization;
    using System.Collections.Generic;
    using System.Text;
    using System.Threading;
    using System.Text.RegularExpressions;
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System.Runtime.Serialization;
    using System.Security.Permissions;
    using Microsoft.Win32;
    /// <remarks>
    /// The PeerName class represents the native PeerName construct.
    /// </remarks>
    [Serializable]
    public class PeerName : ISerializable, IEquatable<PeerName>
    {
        //===================================================
        //constants
        //===================================================
        private const int PEER_MAX_CLASSIFIER_LENGTH = 149;
        private const int SECURE_AUTHORITY_LENGTH = 40;
        private const int INSECURE_AUTHORITY_LENGTH = 1;
        private const int PEER_MAX_PEERNAME_LENGTH = SECURE_AUTHORITY_LENGTH + 1 + PEER_MAX_CLASSIFIER_LENGTH;
        private const string PEERNAME_UNSECURED_AUTHORITY = "0";

        //===================================================
        //private member variables
        //===================================================
        private string m_PeerName;
        private string m_Authority;
        private string m_Classifier;
        private string m_PeerHostName;

        // ===================================================
        //     Constructors
        // ===================================================

        static PeerName()
        {
            //-------------------------------------------------
            //Check for the availability of the simpler PNRP APIs
            //-------------------------------------------------
            if (!PeerToPeerOSHelper.SupportsP2P)
            {
                throw new PlatformNotSupportedException(SR.GetString(SR.P2P_NotAvailable));
            }
        }

        /// <summary>
        /// We use this constructor to create an PeerName 
        /// for internal implementation
        /// </summary>
        private PeerName(string peerName, string authority, string classifier) {
            m_PeerName = peerName;
            m_Classifier = classifier;
            m_Authority = authority;
        }

        /// <summary>
        /// This constructor is to create a peername from an 
        /// arbitrary string. The Identity is not necessarily 
        /// the same as the current user
        /// </summary>
        /// <param name="peerName">string form of the peer name</param>
        /// <remarks>
        ///     1. We assume that the peername is already normalized according to the 
        ///         Unicode rules
        ///     2. The PeerName given has nothig to do with the default Identity
        ///         It is just a way to create a PeerName instance given a string
        /// </remarks>
        public PeerName(string remotePeerName)
        {
            //-------------------------------------------------
            //Check arguments
            //-------------------------------------------------
            if (remotePeerName == null)
                throw new ArgumentNullException("remotePeerName");

            //-------------------------------------------------
            //Check PeerName format
            //NOTE: Currentlt thre is no native API to check
            //the format of the PeerName string. The 
            //StrongParsePeerName implements the logic
            //-------------------------------------------------
            string authority;
            string classifier;
            if (!StrongParsePeerName(remotePeerName, out authority, out classifier))
            {
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "PeerName string {0} failed the check for a valid peer name", remotePeerName);
                throw new ArgumentException(SR.GetString(SR.Pnrp_InvalidPeerName), "remotePeerName");
            }
            //authrority would have been lower cased
            //so we must ste the m_PeerName to authority + classifier
            if (classifier != null)
                m_PeerName = authority + "." + classifier;
            else
                m_PeerName = authority;
            m_Authority = authority;
            m_Classifier = classifier;
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "PeerName instance created - PeerName {0} Authority {1} Classfier {2}", m_PeerName, m_Authority, ((m_Classifier == null)? "null" : m_Classifier));
        }

        /// <summary>
        /// Given a classifier creates a secured or unsecured name
        /// </summary>
        /// <param name="classifier"></param>
        /// <param name="secured"></param>
        // <SecurityKernel Critical="True" Ring="0">
        // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
        // <CallsSuppressUnmanagedCode Name="UnsafeP2PNativeMethods.PeerCreatePeerName(System.String,System.String,System.Net.PeerToPeer.SafePeerData&):System.Int32" />
        // <CallsSuppressUnmanagedCode Name="UnsafeP2PNativeMethods.PeerIdentityGetDefault(System.Net.PeerToPeer.SafePeerData&):System.Int32" />
        // <ReferencesCritical Name="Local shNewPeerName of type: SafePeerData" Ring="1" />
        // <ReferencesCritical Name="Local shDefaultIdentity of type: SafePeerData" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // <ReferencesCritical Name="Method: SafePeerData.get_UnicodeString():System.String" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public PeerName(string classifier, PeerNameType peerNameType)
        {
            //-------------------------------------------------
            //Check arguments
            //-------------------------------------------------
            if ((classifier == null || classifier.Length == 0)&& 
                peerNameType == PeerNameType.Unsecured)
            {
                throw new ArgumentNullException("classifier");
            }
            if (classifier != null && classifier.Length > PEER_MAX_CLASSIFIER_LENGTH)
            {
                throw new ArgumentException(SR.GetString(SR.Pnrp_InvalidClassifier), "classifier");
            }
			//--------------------------------------------------
			//Normalize using NFC
			//--------------------------------------------------
            if (classifier != null && classifier.Length > 0)
            {
                classifier = classifier.Normalize(NormalizationForm.FormC);
            }
            //-------------------------------------------------
            //call the helper to create the PeerName
            //-------------------------------------------------
            Int32 result;
            SafePeerData shNewPeerName = null;
            SafePeerData shDefaultIdentity = null;
            try
            {
                if (peerNameType == PeerNameType.Unsecured)
                {
                    result = UnsafeP2PNativeMethods.PeerCreatePeerName((string)null, classifier, out shNewPeerName);
                    if (result != 0)
                    {
                        throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Pnrp_CouldNotCreateUnsecuredPeerName), result);
                    }
                    m_Authority = PEERNAME_UNSECURED_AUTHORITY;
                }
                else
                {
                    result = UnsafeP2PNativeMethods.PeerIdentityGetDefault(out shDefaultIdentity);
                    if (result != 0)
                    {
                        throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Pnrp_CouldNotGetDefaultIdentity), result);
                    }
                    m_Authority = shDefaultIdentity.UnicodeString;              
                    //}

                    result = UnsafeP2PNativeMethods.PeerCreatePeerName(m_Authority, classifier, out shNewPeerName);
                    if (result != 0)
                    {
                        throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Pnrp_CouldNotCreateSecuredPeerName), result);
                    }
                }
                m_PeerName = shNewPeerName.UnicodeString;
                m_Classifier = classifier;
            }
            finally
            {
                if (shNewPeerName != null) shNewPeerName.Dispose();
                if (shDefaultIdentity != null) shDefaultIdentity.Dispose();
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "PeerName instance created - PeerName {0} Authority {1} Classfier {2}", m_PeerName, m_Authority, m_Classifier);
        }

        /// <summary>
        /// Given a peerHostName string [the dns safe version of the PeerName]
        /// Get the PeerName for it
        /// </summary>
        /// <param name="peerHostName">string form (dns safe form) of the peer name</param>
        /// <returns>a PeerName instance</returns>
        // <SecurityKernel Critical="True" Ring="0">
        // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
        // <CallsSuppressUnmanagedCode Name="UnsafeP2PNativeMethods.PeerHostNameToPeerName(System.String,System.Net.PeerToPeer.SafePeerData&):System.Int32" />
        // <ReferencesCritical Name="Local shPeerName of type: SafePeerData" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // <ReferencesCritical Name="Method: SafePeerData.get_UnicodeString():System.String" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public static PeerName CreateFromPeerHostName(string peerHostName)
        {
            //-------------------------------------------------
            //Check arguments
            //-------------------------------------------------
            if (peerHostName == null)
                throw new ArgumentNullException("peerHostName");
            if (peerHostName.Length == 0)
                throw new ArgumentException(SR.GetString(SR.Pnrp_InvalidPeerHostName), "peerHostName");

            Int32 result;
            SafePeerData shPeerName = null;
            string peerName = null;
            try
            {
                result = UnsafeP2PNativeMethods.PeerHostNameToPeerName(peerHostName, out shPeerName);
                if (result != 0)
                {
                    throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Pnrp_CouldNotGetPeerNameFromPeerHostName), result);
                }
                peerName = shPeerName.UnicodeString;
            }
            finally
            {
                if (shPeerName != null) shPeerName.Dispose();
            }

            string authority;
            string classifier;
            WeakParsePeerName(peerName, out authority, out classifier);
            PeerName p = new PeerName(peerName, authority, classifier);
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "PeerName created from PeerHostName - PeerHostName {0} to PeerName PeerName {1} Authority {2} Classfier {3}", peerHostName, peerName, authority, classifier);
            return p; 
        }
          
        /// <summary>
        /// Given a PeerName, change the classifier. 
        /// This is simply replacing the classifier, but we will
        /// let the native APIs do the right thing since they
        /// might change the concept in future
        /// </summary>
        /// <param name="peerName">a PeerName instance</param>
        /// <param name="classifier">a new classfier string</param>
        /// <returns></returns>
        // <SecurityKernel Critical="True" Ring="0">
        // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
        // <CallsSuppressUnmanagedCode Name="UnsafeP2PNativeMethods.PeerCreatePeerName(System.String,System.String,System.Net.PeerToPeer.SafePeerData&):System.Int32" />
        // <ReferencesCritical Name="Local shNewPeerName of type: SafePeerData" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // <ReferencesCritical Name="Method: SafePeerData.get_UnicodeString():System.String" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public static PeerName CreateRelativePeerName(
                                        PeerName peerName,
                                        string classifier)
        {
            //-------------------------------------------------
            //Check arguments
            //-------------------------------------------------
            if (peerName == null)
            {
                throw new ArgumentNullException("peerName", SR.GetString(SR.Pnrp_PeerNameCantBeNull));
            }
            if (!peerName.IsSecured && (classifier == null || classifier.Length == 0))
            {
                throw new ArgumentException(SR.GetString(SR.Pnrp_InvalidClassifier), "classifier");
            }
            if (classifier != null && classifier.Length > PEER_MAX_CLASSIFIER_LENGTH)
            {
                throw new ArgumentException(SR.GetString(SR.Pnrp_InvalidClassifier), "classifier");
            }

			//--------------------------------------------------
			//Normalize using NFC
			//--------------------------------------------------
            if (classifier != null && classifier.Length > 0)
            {
                classifier = classifier.Normalize(NormalizationForm.FormC);
            }

            Int32 result;
            SafePeerData shNewPeerName = null;
            string newPeerName = null;
            try
            {
                //Here there is change made on the native side 
                //when passing secured peer names, it takes string of the form [40hexdigits].claasisifer and a newclassifier 
                //returns [40hexdigits.newclassifier]
                //But for unsecured peer names it does not take 0.clasfier and newclassfier to return 0.newclassfier. 
                //It expects NULL as the first param. To satisfy this broken finctionality, we are passing null if the 
                //peer name is unsecured. 
                result = UnsafeP2PNativeMethods.PeerCreatePeerName(peerName.IsSecured? peerName.m_PeerName : null, classifier, out shNewPeerName);
                if (result != 0)
                {
                    throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Pnrp_CouldNotCreateRelativePeerName), result);
                }
                newPeerName = shNewPeerName.UnicodeString;
            }
            finally
            {
                if (shNewPeerName != null) shNewPeerName.Dispose();
            }

            string authority;
            string newClassifier;
            WeakParsePeerName(newPeerName, out authority, out newClassifier);
            PeerName p = new PeerName(newPeerName, authority, newClassifier);
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "A new PeerName created from existing PeerName with a new classfier. Existing PeerName {0} Classifier {1} New PeerName {2}", peerName, classifier, p);
            return p; 
        }

        /// <summary>
        /// Friendly string
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return m_PeerName;
        }

        /// <summary>
        /// Notionb of equals is based on same peer name string content
        /// </summary>
        /// <param name="comparand"></param>
        /// <returns></returns>
        public bool Equals(PeerName other)
        {
            if(other == null) return false;
            return string.Compare(other.m_PeerName, m_PeerName, StringComparison.Ordinal) == 0;
        }

        public override bool Equals(object obj)
        {
            if (obj == null) return false;
            PeerName other = obj as PeerName;
            if (other == null) return false;
            return Equals(other);
      
        }
        /// <summary>
        /// Hash code comes from m_PeerName since the others are just components of this
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return m_PeerName.GetHashCode();
        }

        /// <summary>
        /// Authroity
        /// </summary>
        public string Authority
        {
            get
            {
                return m_Authority;
            }
        }
        /// <summary>
        /// Classifier
        /// </summary>
        public string Classifier
        {
            get
            {
                return m_Classifier;
            }
        }

        /// <summary>
        /// A DNS Safe version of the Peer Name
        /// </summary>
        public string PeerHostName
        {
            // <SecurityKernel Critical="True" Ring="0">
            // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
            // <CallsSuppressUnmanagedCode Name="UnsafeP2PNativeMethods.PeerNameToPeerHostName(System.String,System.Net.PeerToPeer.SafePeerData&):System.Int32" />
            // <ReferencesCritical Name="Local shPeerHostName of type: SafePeerData" Ring="1" />
            // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
            // <ReferencesCritical Name="Method: SafePeerData.get_UnicodeString():System.String" Ring="1" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            get
            {
                if (m_PeerHostName == null)
                {
                    Int32 result;
                    SafePeerData shPeerHostName = null;
                    try
                    {
						//This API gives HRESULT > 0 for success instead of S_OK == 0
						//WINDOWS OS 

                        result = UnsafeP2PNativeMethods.PeerNameToPeerHostName( m_PeerName, out shPeerHostName);
                        if (result < 0)
                        {
                            throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Pnrp_CouldNotGetPeerHostNameFromPeerName), result);
                        }
                        m_PeerHostName = shPeerHostName.UnicodeString;
                    }
                    finally
                    {
                        if (shPeerHostName != null) shPeerHostName.Dispose();
                    }
                }
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "PeerHostName created for PeerName PeerHostName {0} PeerName {1}", m_PeerHostName, this);
                return m_PeerHostName;
            }
        }

        /// <summary>
        /// Basically if the authority == 0 or not [unsecured or secured respectively]
        /// </summary>
        public bool IsSecured
        {
            get
            {
                return m_Authority != PEERNAME_UNSECURED_AUTHORITY;
            }
        }


        // ===================================================
        // Private methods
        // ===================================================
        /// <summary>
        /// I have considered using regular expressions. However, the regular expressions offer 
        /// poor performance and or startup cost. Really there is no substiture for custom 
        /// parsing logic. I decided to write this piece of code to parse the peername for now 
        /// - [....] 6/6/2005
        /// </summary>
        /// <param name="peerName"></param>
        /// <param name="authority"></param>
        /// <param name="classifier"></param>
        /// <returns></returns>
        private static bool StrongParsePeerName(string peerName, out string authority, out string classifier)
        {
            authority = null;
            classifier = null;
            
            //Rule 0. The max length must not be exeeded
            if (peerName == null ||
                peerName.Length == 0 ||
                peerName.Length > PEER_MAX_PEERNAME_LENGTH) return false;

            //Rule 1. The length of the string must be at least 3
            //as in 0.C for unsecured PeerName with classifier "C"
            if (peerName.Length < 3) return false;

            string tempAuthority = null;
            int IndexOfPeriod = peerName.IndexOf('.');
            if (IndexOfPeriod == 0) return false;
            if (IndexOfPeriod < 0)
            {
                //Rule 2. Secure PeerNames can have just the authority 
                //or Authority. or Authority.Classifier
                //if there is no period, we have to treat the entire string as the authority
                tempAuthority = peerName;
            }
            else if (IndexOfPeriod == peerName.Length - 1)
            {
                //May be this is of the form Authority.
                tempAuthority = peerName.Substring(0, peerName.Length - 1);
            }
            else
            {
                //Rule 2B. Unsecure peer names must have a classifier
                //There must be a period separating the authority and classifier
                //and must not be the first character and it must not be the last character
                tempAuthority = peerName.Substring(0, IndexOfPeriod);
            }

            //Rule 3. Authority is either SECURE_AUTHORITY_LENGTH hex characters or "0"
            if (tempAuthority.Length != SECURE_AUTHORITY_LENGTH &&
                tempAuthority.Length != INSECURE_AUTHORITY_LENGTH) return false;

            //Rule 4. If it is length 1 it must be 0
            if (tempAuthority.Length == INSECURE_AUTHORITY_LENGTH && tempAuthority != PEERNAME_UNSECURED_AUTHORITY)
                return false;

            //Rule 5. the authority must be 40 hex characters
            if(tempAuthority.Length == SECURE_AUTHORITY_LENGTH)
            {
                foreach (char c in tempAuthority)
                {
                    if (!IsHexDigit(c)) return false;
                }
            }
            //Rule 6. The maximum length of the classfier is PEER_MAX_CLASSIFIER_LENGTH
            string tempClassifier = null;
            if (IndexOfPeriod != peerName.Length - 1 && IndexOfPeriod > 0)
            {
                tempClassifier = peerName.Substring(IndexOfPeriod + 1);
            }
            if (tempClassifier != null && tempClassifier.Length > PEER_MAX_CLASSIFIER_LENGTH) return false;

            //Finish
            authority = tempAuthority.ToLower(CultureInfo.InvariantCulture); //Safe for Hex digits
            classifier = tempClassifier;
            return true;
        }
        private static bool IsHexDigit(char character)
        {
            return ((character >= '0') && (character <= '9'))
                || ((character >= 'A') && (character <= 'F'))
                || ((character >= 'a') && (character <= 'f'));
        }

        /// <summary>
        /// WARNING: Don't call this unless you are sure that 
        /// the PeerName is a valid string. This is invoked only when 
        /// we are sure that the peername is valid and we need to components
        /// </summary>
        /// <param name="peerName">in: peerName to parse</param>
        /// <param name="authority">out: parsed authority value</param>
        /// <param name="classifier">out: parsed classfier value</param>
        /// <returns>none</returns>
        private static void WeakParsePeerName(string peerName, out string authority, out string classifier)
        {
            authority = null;
            classifier = null;
            int indexOfPeriod = peerName.IndexOf('.');
            if (indexOfPeriod < 0)
            {
                authority = peerName;
            }
            else if (indexOfPeriod == peerName.Length - 1)
            {
                //May be this is of the form Authority.
                authority = peerName.Substring(0, peerName.Length - 1);
            }
            else
            {
                authority = peerName.Substring(0, indexOfPeriod);
            }

            if (indexOfPeriod != peerName.Length - 1 && indexOfPeriod > 0)
            {
                classifier = peerName.Substring(indexOfPeriod + 1);
            }
            authority = authority.ToLower(CultureInfo.InvariantCulture); //safe for hex strings
        }

        /// <summary>
        /// Constructor to enable serialization 
        /// </summary>
        /// <param name="serializationInfo"></param>
        /// <param name="streamingContext"></param>
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
        protected PeerName(SerializationInfo info, StreamingContext context)
        {
            if (info == null)
            {
                throw new ArgumentNullException("info");
            }
            m_PeerName = info.GetString("_PeerName");
            m_Authority = info.GetString("_Authority");
            m_Classifier = info.GetString("_Classifier");
        }


        // <SecurityKernel Critical="True" Ring="0">
        // <SatisfiesLinkDemand Name="GetObjectData(SerializationInfo, StreamingContext):Void" />
        // </SecurityKernel>
        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.Net.dll is still using pre-v4 security model and needs this demand")]
        [System.Security.SecurityCritical]
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter, SerializationFormatter = true)]
        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
            GetObjectData(info, context);
        }

        /// <summary>
        /// This is made virtual so that derived types can be implemented correctly
        /// </summary>
        /// <param name="serializationInfo"></param>
        /// <param name="streamingContext"></param>
        [SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter = true)]
        protected virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("_PeerName", m_PeerName);
            info.AddValue("_Authority", m_Authority);
            info.AddValue("_Classifier", m_Classifier);
        }
		
    }
}