1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4 namespace System.ServiceModel.Channels
5 {
6     using System.Collections.Generic;
7     using System.ComponentModel;
8     using System.Diagnostics;
9     using System.Globalization;
10     using System.Net;
11     using System.Runtime;
12     using System.Runtime.InteropServices;
13     using System.Runtime.Serialization;
14     using System.ServiceModel;
15     using System.ServiceModel.Description;
16     using System.ServiceModel.Dispatcher;
17     using System.ServiceModel.PeerResolvers;
18     using System.ServiceModel.Security;
19     using System.Threading;
20     using System.Xml;
21 
22     class PeerQuotaHelper
23     {
24         int enqueuedCount = 0;
25         int quota = 64;
26         AutoResetEvent waiter = new AutoResetEvent(false);
27 
PeerQuotaHelper(int limit)28         public PeerQuotaHelper(int limit)
29         {
30             this.quota = limit;
31         }
32 
ReadyToEnqueueItem()33         public void ReadyToEnqueueItem()
34         {
35             int value = Interlocked.Increment(ref enqueuedCount);
36             if (value > quota)
37             {
38                 waiter.WaitOne();
39             }
40         }
41 
ItemDequeued()42         public void ItemDequeued()
43         {
44             int value = Interlocked.Decrement(ref enqueuedCount);
45             Fx.Assert(value >= 0, "queue below empty");
46             if (value >= quota)
47             {
48                 waiter.Set();
49             }
50         }
51 
52     }
53 
54     class PeerNodeConfig
55     {
56         int connectTimeout;
57         MessageEncoder encoder;
58         PeerNodeAddress listenAddress;  // EPR + IP addresses
59         IPAddress listenIPAddress;
60         Uri listenUri;
61         long maxReceivedMessageSize;
62         int minNeighbors;                                             //Neighbor parameters
63         int idealNeighbors;
64         int maxNeighbors;
65         int maxReferrals;
66         int maxReferralCacheSize;
67         int maxResolveAddresses;
68         string meshId;
69         PeerMessagePropagationFilter messagePropagationFilter;
70         ulong nodeId;
71         int port;
72         PeerResolver resolver;
73         int maintainerInterval;
74         TimeSpan maintainerRetryInterval;
75         TimeSpan maintainerTimeout;
76         TimeSpan unregisterTimeout;
77         PeerSecurityManager securityManager;
78         int maxIncomingConcurrentCalls = 128;
79         int maxConcurrentSessions = 64;
80         XmlDictionaryReaderQuotas readerQuotas = new XmlDictionaryReaderQuotas();
81         long maxBufferPoolSize;
82         int maxSendQueueSize = 128;
83 
PeerNodeConfig(string meshId, ulong nodeId, PeerResolver resolver, PeerMessagePropagationFilter messagePropagationFilter, MessageEncoder encoder, Uri listenUri, IPAddress listenIPAddress, int port, long maxReceivedMessageSize, int minNeighbors, int idealNeighbors, int maxNeighbors, int maxReferrals, int connectTimeout, int maintainerInterval, PeerSecurityManager securityManager, XmlDictionaryReaderQuotas readerQuotas, long maxBufferPool, int maxSendQueueSize, int maxReceiveQueueSize)84         public PeerNodeConfig(string meshId, ulong nodeId,
85             PeerResolver resolver,
86             PeerMessagePropagationFilter messagePropagationFilter,
87             MessageEncoder encoder,
88             Uri listenUri, IPAddress listenIPAddress, int port,
89             long maxReceivedMessageSize,
90             int minNeighbors, int idealNeighbors, int maxNeighbors,
91             int maxReferrals,
92             int connectTimeout,
93             int maintainerInterval,
94             PeerSecurityManager securityManager,
95             XmlDictionaryReaderQuotas readerQuotas,
96             long maxBufferPool,
97             int maxSendQueueSize,
98             int maxReceiveQueueSize)
99         {
100             this.connectTimeout = connectTimeout;
101             this.listenIPAddress = listenIPAddress;
102             this.listenUri = listenUri;
103             this.maxReceivedMessageSize = maxReceivedMessageSize;
104             this.minNeighbors = minNeighbors;
105             this.idealNeighbors = idealNeighbors;
106             this.maxNeighbors = maxNeighbors;
107             this.maxReferrals = maxReferrals;
108             this.maxReferralCacheSize = PeerTransportConstants.MaxReferralCacheSize;
109             this.maxResolveAddresses = PeerTransportConstants.MaxResolveAddresses;
110             this.meshId = meshId;
111             this.encoder = encoder;
112             this.messagePropagationFilter = messagePropagationFilter;
113             this.nodeId = nodeId;
114             this.port = port;
115             this.resolver = resolver;
116             this.maintainerInterval = maintainerInterval;
117             this.maintainerRetryInterval = new TimeSpan(PeerTransportConstants.MaintainerRetryInterval * 10000);
118             this.maintainerTimeout = new TimeSpan(PeerTransportConstants.MaintainerTimeout * 10000);
119             this.unregisterTimeout = new TimeSpan(PeerTransportConstants.UnregisterTimeout * 10000);
120             this.securityManager = securityManager;
121             readerQuotas.CopyTo(this.readerQuotas);
122             this.maxBufferPoolSize = maxBufferPool;
123             this.maxIncomingConcurrentCalls = maxReceiveQueueSize;
124             this.maxSendQueueSize = maxSendQueueSize;
125         }
126 
127         internal PeerSecurityManager SecurityManager
128         {
129             get { return securityManager; }
130         }
131 
132         public int ConnectTimeout
133         {
134             get { return connectTimeout; }
135         }
136 
137         public IPAddress ListenIPAddress
138         {
139             get { return listenIPAddress; }
140         }
141 
142         public int ListenerPort
143         {
144             get { return listenAddress.EndpointAddress.Uri.Port; }
145         }
146 
147         public Uri ListenUri
148         {
149             get { return listenUri; }
150         }
151 
152         public int IdealNeighbors
153         {
154             get { return idealNeighbors; }
155         }
156 
157         public int MaintainerInterval
158         {
159             get { return maintainerInterval; }
160         }
161 
162         public TimeSpan MaintainerRetryInterval
163         {
164             get { return maintainerRetryInterval; }
165         }
166 
167         public TimeSpan MaintainerTimeout
168         {
169             get { return maintainerTimeout; }
170         }
171 
172         public long MaxBufferPoolSize
173         {
174             get { return maxBufferPoolSize; }
175         }
176 
177         public long MaxReceivedMessageSize
178         {
179             get { return maxReceivedMessageSize; }
180         }
181 
182         public int MaxNeighbors
183         {
184             get { return maxNeighbors; }
185         }
186 
187         public int MaxReferrals
188         {
189             get { return maxReferrals; }
190         }
191 
192         public int MaxReferralCacheSize
193         {
194             get { return maxReferralCacheSize; }
195         }
196 
197         public int MaxResolveAddresses
198         {
199             get { return maxResolveAddresses; }
200         }
201 
202         public int MaxPendingIncomingCalls
203         {
204             get { return this.maxIncomingConcurrentCalls; }
205         }
206 
207         public int MaxPendingOutgoingCalls
208         {
209             get { return this.maxSendQueueSize; }
210         }
211 
212         public int MaxConcurrentSessions
213         {
214             get { return this.maxConcurrentSessions; }
215         }
216         public int MinNeighbors
217         {
218             get { return minNeighbors; }
219         }
220 
221         public string MeshId
222         {
223             get { return meshId; }
224         }
225 
226         public MessageEncoder MessageEncoder
227         {
228             get { return encoder; }
229         }
230 
231         public PeerMessagePropagationFilter MessagePropagationFilter
232         {
233             get { return messagePropagationFilter; }
234         }
235 
236         public ulong NodeId
237         {
238             get { return nodeId; }
239         }
240 
241         public int Port
242         {
243             get { return port; }
244         }
245 
246         public XmlDictionaryReaderQuotas ReaderQuotas
247         {
248             get { return this.readerQuotas; }
249         }
250 
251         public PeerResolver Resolver
252         {
253             get { return resolver; }
254         }
255 
256         public TimeSpan UnregisterTimeout
257         {
258             get { return unregisterTimeout; }
259         }
260 
261         // Returns the actual address that the node service is listening on.
262         // If retrieving the address in order to send it over the wire, maskScopeId should be true
263         // (scope IDs are not sent over the wire).
GetListenAddress(bool maskScopeId)264         public PeerNodeAddress GetListenAddress(bool maskScopeId)
265         {
266             PeerNodeAddress localAddress = this.listenAddress;
267             return new PeerNodeAddress(localAddress.EndpointAddress, PeerIPHelper.CloneAddresses(localAddress.IPAddresses, maskScopeId));
268         }
269 
SetListenAddress(PeerNodeAddress address)270         public void SetListenAddress(PeerNodeAddress address)
271         {
272             this.listenAddress = address;
273         }
274 
BuildUri(string host, int port, Guid guid)275         static Uri BuildUri(string host, int port, Guid guid)
276         {
277             UriBuilder uriBuilder = new UriBuilder();
278             uriBuilder.Host = host;
279             if (port > 0)
280                 uriBuilder.Port = port;
281             uriBuilder.Path = PeerStrings.KnownServiceUriPrefix + '/' + guid;
282             uriBuilder.Scheme = Uri.UriSchemeNetTcp;
283             TcpChannelListener.FixIpv6Hostname(uriBuilder, uriBuilder.Uri);
284             return uriBuilder.Uri;
285         }
286 
GetSelfUri()287         public Uri GetSelfUri()
288         {
289             Uri uri = null;
290             Guid serviceGuid = Guid.NewGuid();
291 
292             if (this.listenIPAddress == null)
293             {
294                 uri = BuildUri(DnsCache.MachineName, port, serviceGuid);
295             }
296             else
297             {
298                 uri = BuildUri(this.listenIPAddress.ToString(), port, serviceGuid);
299             }
300             return uri;
301         }
302 
GetMeshUri()303         public Uri GetMeshUri()
304         {
305             UriBuilder uriBuilder = new UriBuilder();
306             uriBuilder.Host = this.meshId;
307             uriBuilder.Scheme = PeerStrings.Scheme;
308             return uriBuilder.Uri;
309         }
310     }
311 
312     static class PeerMessageHelpers
313     {
314         // delegates used to call the callback to process an incoming message
CleanupCallback(IPeerNeighbor neighbor, PeerCloseReason reason, Exception exception)315         public delegate void CleanupCallback(IPeerNeighbor neighbor, PeerCloseReason reason, Exception exception);
316 
GetHeaderString(MessageHeaders headers, string name, string ns)317         public static string GetHeaderString(MessageHeaders headers, string name, string ns)
318         {
319             string result = null;
320             int index = headers.FindHeader(name, ns);
321             if (index >= 0)
322             {
323                 using (XmlDictionaryReader reader = headers.GetReaderAtHeader(index))
324                 {
325                     result = reader.ReadElementString();
326                 }
327                 headers.UnderstoodHeaders.Add(headers[index]);
328             }
329             return result;
330         }
331 
GetHeaderUri(MessageHeaders headers, string name, string ns)332         public static Uri GetHeaderUri(MessageHeaders headers, string name, string ns)
333         {
334             Uri result = null;
335             string rawString = GetHeaderString(headers, name, ns);
336             if (rawString != null)
337                 result = new Uri(rawString);
338             return result;
339         }
340 
GetHeaderULong(MessageHeaders headers, int index)341         public static ulong GetHeaderULong(MessageHeaders headers, int index)
342         {
343             ulong result = PeerTransportConstants.MaxHopCount;
344             if (index >= 0)
345             {
346                 using (XmlDictionaryReader reader = headers.GetReaderAtHeader(index))
347                 {
348                     result = XmlConvert.ToUInt64(reader.ReadElementString());
349                 }
350                 headers.UnderstoodHeaders.Add(headers[index]);
351             }
352             return result;
353         }
354 
GetHeaderUniqueId(MessageHeaders headers, string name, string ns)355         public static UniqueId GetHeaderUniqueId(MessageHeaders headers, string name, string ns)
356         {
357             UniqueId result = null;
358             int index = headers.FindHeader(name, ns);
359             if (index >= 0)
360             {
361                 using (XmlDictionaryReader reader = headers.GetReaderAtHeader(index))
362                 {
363                     result = reader.ReadElementContentAsUniqueId();
364                 }
365                 headers.UnderstoodHeaders.Add(headers[index]);
366             }
367             return result;
368         }
369 
370     }
371 
372     static class PeerStrings
373     {
374         public static Dictionary<string, string> protocolActions;
375 
376         // Namespace for infrastructure messages
377         public const string Namespace = "http://schemas.microsoft.com/net/2006/05/peer";
378 
379         // PeerService contract name
380         public const string ServiceContractName = "PeerService";
381 
382         // Infrastructure message actions
383         // PeerConnector
384         public const string ConnectAction = Namespace + "/Connect";
385         public const string WelcomeAction = Namespace + "/Welcome";
386         public const string RefuseAction = Namespace + "/Refuse";
387         public const string DisconnectAction = Namespace + "/Disconnect";
388 
389         // PeerFlooder
390         public const string FloodAction = Namespace + "/Flood";
391         public const string InternalFloodAction = Namespace + "/IntFlood";
392         public const string LinkUtilityAction = Namespace + "/LinkUtility";
393         public const string RequestSecurityTokenAction = "RequestSecurityToken";
394         public const string RequestSecurityTokenResponseAction = "RequestSecurityTokenResponse";
395         public const string HopCountElementName = "Hops";
396         public const string HopCountElementNamespace = Namespace + "/HopCount";
397         public const string PingAction = Namespace + "/Ping";
398 
399         // Uri
400         public const string Scheme = "net.p2p";
401         public const string KnownServiceUriPrefix = "PeerChannelEndpoints";
402         public const string PeerCustomResolver = "PeerCustomResolver";
403 
404         public const string SkipLocalChannels = "SkipLocalChannels";
405         public const string Via = "PeerVia";
406         public const string MessageVerified = "MessageVerified";
407         public const string CacheMiss = "CacheMiss";
408         public const string PeerProperty = "PeerProperty";
409         public const string MessageId = "MessageID";
410 
PeerStrings()411         static PeerStrings()
412         {
413             protocolActions = new Dictionary<string, string>();
414             PopulateProtocolActions();
415         }
416 
PopulateProtocolActions()417         static void PopulateProtocolActions()
418         {
419             protocolActions.Add(PeerStrings.ConnectAction, PeerOperationNames.Connect);
420             protocolActions.Add(PeerStrings.WelcomeAction, PeerOperationNames.Welcome);
421             protocolActions.Add(PeerStrings.RefuseAction, PeerOperationNames.Refuse);
422             protocolActions.Add(PeerStrings.DisconnectAction, PeerOperationNames.Disconnect);
423             protocolActions.Add(PeerStrings.RequestSecurityTokenAction, PeerOperationNames.ProcessRequestSecurityToken);
424             protocolActions.Add(PeerStrings.RequestSecurityTokenResponseAction, PeerOperationNames.RequestSecurityTokenResponse);
425             protocolActions.Add(PeerStrings.LinkUtilityAction, PeerOperationNames.LinkUtility);
426             protocolActions.Add(Addressing10Strings.FaultAction, PeerOperationNames.Fault);
427             protocolActions.Add(PeerStrings.PingAction, PeerOperationNames.Ping);
428         }
429 
FindAction(string action)430         public static string FindAction(string action)
431         {
432             string result = null;
433             protocolActions.TryGetValue(action, out result);
434             return result;
435         }
436 
437 
438     }
439 
440     class PeerOperationNames
441     {
442         public const string Connect = "Connect";
443         public const string Disconnect = "Disconnect";
444         public const string Refuse = "Refuse";
445         public const string Welcome = "Welcome";
446         public const string LinkUtility = "LinkUtility";
447         public const string ProcessRequestSecurityToken = "ProcessRequestSecurityToken";
448         public const string RequestSecurityTokenResponse = "RequestSecurityTokenResponse";
449         public const string Flood = "FloodMessage";
450         public const string Demuxer = "PeerFlooder";
451         public const string PeerVia = "PeerVia";
452         public const string Fault = "Fault";
453         public const string PeerTo = "PeerTo";
454         public const string Ping = "Ping";
455 
456     }
457 
458     class PeerResolverStrings
459     {
460         public const string Namespace = PeerStrings.Namespace + "/resolver";
461         public const string RegisterAction = Namespace + "/Register";
462         public const string RegisterResponseAction = Namespace + "/RegisterResponse";
463         public const string UnregisterAction = Namespace + "/Unregister";
464         public const string ResolveAction = Namespace + "/Resolve";
465         public const string ResolveResponseAction = Namespace + "/ResolveResponse";
466         public const string UpdateAction = Namespace + "/Update";
467         public const string UpdateResponseAction = Namespace + "/UpdateResponse";
468         public const string RefreshAction = Namespace + "/Refresh";
469         public const string RefreshResponseAction = Namespace + "/RefreshResponse";
470         public const string GetServiceSettingsAction = Namespace + "/GetServiceSettings";
471         public const string GetServiceSettingsResponseAction = Namespace + "/GetServiceSettingsResponse";
472     }
473 
474     // constants used by more than one component
475     static class PeerTransportConstants
476     {
477         public const int ConnectTimeout = 60 * 1000;            // 1 minute
478         public const ulong InvalidNodeId = 0;
479         public const int MinNeighbors = 2;
480         public const int IdealNeighbors = 3;
481         public const int MaxResolveAddresses = IdealNeighbors;  // We only to resolve Ideal connections
482 
483         public const int MaxNeighbors = 7;
484         public const int MaxReferrals = 10;
485         public const int MaxReferralCacheSize = 50;             // Cache no more than 50 referrals
486 
487         public const int MaintainerInterval = 5 * 60 * 1000;    // 5 Minutes
488         public const int MaintainerRetryInterval = 10000;       // 10 seconds
489         public const int MaintainerTimeout = 2 * 60 * 1000;     // 2 Minutes
490         public const int UnregisterTimeout = 2 * 60 * 1000;     // 2 Minutes
491 
492         //how long do we want wait before sending each batch of acks?
493         public const int AckTimeout = 30 * 1000;
494 
495         //how many acks do we want max in each ack message?
496         public const uint AckWindow = 32;
497 
498         public const long MinMessageSize = 16384;
499 
500         public const int MinPort = IPEndPoint.MinPort;
501         public const int MaxPort = IPEndPoint.MaxPort;
502         public const ulong MaxHopCount = ulong.MaxValue;
503         public static TimeSpan ForwardInterval = TimeSpan.FromSeconds(10);
504         public static TimeSpan ForwardTimeout = TimeSpan.FromSeconds(60);
505         public static int MaxOutgoingMessages = 128;
506         public const int MessageThreshold = 32;
507     }
508 
509     static class PeerValidateHelper
510     {
ValidateListenIPAddress(IPAddress address)511         public static void ValidateListenIPAddress(IPAddress address)
512         {
513             // null is Okay
514             if (address == null)
515                 return;
516 
517             // If an incorrect IP address is given throw.
518             if (address.Equals(IPAddress.Any) ||
519                 address.Equals(IPAddress.IPv6Any) ||
520                 address.Equals(IPAddress.IPv6None) ||
521                 address.Equals(IPAddress.None) ||
522                 address.Equals(IPAddress.Broadcast) ||
523                 address.IsIPv6Multicast ||
524                 IPAddress.IsLoopback(address))
525             {
526                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
527                     new ArgumentException(SR.GetString(SR.PeerListenIPAddressInvalid, address), "address", null));
528             }
529         }
530 
ValidateMaxMessageSize(long value)531         public static void ValidateMaxMessageSize(long value)
532         {
533             if (value < PeerTransportConstants.MinMessageSize)
534             {
535                 string message = SR.GetString(SR.ArgumentOutOfRange, PeerTransportConstants.MinMessageSize, long.MaxValue);
536                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, message));
537             }
538         }
539 
ValidatePort(int value)540         public static void ValidatePort(int value)
541         {
542             if (value < PeerTransportConstants.MinPort || value > PeerTransportConstants.MaxPort)
543             {
544                 string message = SR.GetString(SR.ArgumentOutOfRange, PeerTransportConstants.MinPort, PeerTransportConstants.MaxPort);
545                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, message));
546             }
547         }
548 
ValidNodeAddress(PeerNodeAddress address)549         public static bool ValidNodeAddress(PeerNodeAddress address)
550         {
551             return (address != null
552                 && address.EndpointAddress != null
553                 && address.EndpointAddress.Uri != null
554                 && address.IPAddresses != null
555                 && address.IPAddresses.Count > 0
556                 && string.Compare(address.EndpointAddress.Uri.Scheme, Uri.UriSchemeNetTcp, StringComparison.OrdinalIgnoreCase) == 0
557                 );
558         }
559 
ValidReferralNodeAddress(PeerNodeAddress address)560         public static bool ValidReferralNodeAddress(PeerNodeAddress address)
561         {
562             bool valid = true;
563             long scopeId = -1;
564 
565             foreach (IPAddress addr in address.IPAddresses)
566             {
567                 if (addr.IsIPv6LinkLocal)
568                 {
569                     if (scopeId == -1)
570                     {
571                         scopeId = addr.ScopeId;
572                     }
573                     else if (scopeId != addr.ScopeId)
574                     {
575                         valid = false;
576                         break;
577                     }
578                 }
579             }
580             return valid;
581         }
582     }
583 
584     // Indicates which side initiated neighbor close
585     enum PeerCloseInitiator
586     {
587         LocalNode,
588         RemoteNode
589     }
590 
591     // Reason for closing a neighbor
592     // WARNING: If you add another enum value, consider whether a corresponding value
593     // should be added to PeerConnector.RefuseReason and PeerConnector.DisconnectReason.
594     // WARNING: Upon adding a new enum value, consider if PeerCloseReasonHelper.IsDefined
595     // should be updated.
596     enum PeerCloseReason
597     {
598         None = 0,               // Reserved value - never serialized used internally.
599         InvalidNeighbor,        // used when protocol violations are detected
600         LeavingMesh,            // Closing because the node is leaving the mesh
601         NotUsefulNeighbor,      // Closing because the neighbor is not useful
602         DuplicateNeighbor,      // The node already has a neighbor session to this node
603         DuplicateNodeId,        // The neighbor has the same node ID as the local node
604         NodeBusy,               // The node has too many neighbor sessions to accept a new session
605         ConnectTimedOut,        // Connect processing timedout
606         Faulted,                // When neighbor faults
607         Closed,                 // When neighbor closes without Disconnect or Refuse
608         InternalFailure,        // Eg: an infrastructure msg send fails and requires closing the channel
609         AuthenticationFailure,  // Eg, when in secure mode, wrong credentials.
610         NodeTooSlow,            //remote neighbor is too slow
611     }
612 
613     // Neighbor event args
614     // EventArgs when a neighbor is closing or closed
615     class PeerNeighborCloseEventArgs : EventArgs
616     {
617         PeerCloseInitiator closeInitiator;
618         Exception exception;
619         PeerCloseReason reason;
620 
PeerNeighborCloseEventArgs(PeerCloseReason reason, PeerCloseInitiator closeInitiator, Exception exception)621         public PeerNeighborCloseEventArgs(PeerCloseReason reason,
622             PeerCloseInitiator closeInitiator, Exception exception)
623         {
624             this.reason = reason;
625             this.closeInitiator = closeInitiator;
626             this.exception = exception;
627         }
628 
629         public PeerCloseInitiator CloseInitiator
630         {
631             get { return this.closeInitiator; }
632         }
633 
634         public Exception Exception
635         {
636             get { return this.exception; }
637         }
638 
639         public PeerCloseReason Reason
640         {
641             get { return this.reason; }
642         }
643     }
644 
645     class PeerExceptionHelper
646     {
ThrowInvalidOperation_InsufficientCryptoSupport(Exception innerException)647         static internal void ThrowInvalidOperation_InsufficientCryptoSupport(Exception innerException)
648         {
649             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InsufficientCryptoSupport), innerException));
650         }
ThrowArgument_InsufficientCredentials(string property)651         static internal void ThrowArgument_InsufficientCredentials(string property)
652         {
653             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.InsufficientCredentials, property)));
654         }
ThrowArgumentOutOfRange_InvalidTransportCredentialType(int value)655         static internal void ThrowArgumentOutOfRange_InvalidTransportCredentialType(int value)
656         {
657             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("CredentialType", value,
658                 SR.GetString(SR.ValueMustBeInRange, PeerTransportCredentialType.Password, PeerTransportCredentialType.Certificate)));
659         }
660 
ThrowArgumentOutOfRange_InvalidSecurityMode(int value)661         static internal void ThrowArgumentOutOfRange_InvalidSecurityMode(int value)
662         {
663             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("Mode", value,
664                 SR.GetString(SR.ValueMustBeInRange, SecurityMode.None, SecurityMode.TransportWithMessageCredential)));
665         }
666 
ThrowInvalidOperation_UnexpectedSecurityTokensDuringHandshake()667         static internal void ThrowInvalidOperation_UnexpectedSecurityTokensDuringHandshake()
668         {
669             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.UnexpectedSecurityTokensDuringHandshake)));
670         }
671 
ThrowArgument_PnrpAddressesExceedLimit()672         static internal void ThrowArgument_PnrpAddressesExceedLimit()
673         {
674             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.PnrpAddressesExceedLimit)));
675         }
ThrowInvalidOperation_PnrpNoClouds()676         static internal void ThrowInvalidOperation_PnrpNoClouds()
677         {
678             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.PnrpNoClouds)));
679         }
ThrowInvalidOperation_PnrpAddressesUnsupported()680         static internal void ThrowInvalidOperation_PnrpAddressesUnsupported()
681         {
682             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.PnrpAddressesUnsupported)));
683         }
ThrowArgument_InsufficientResolverSettings()684         static internal void ThrowArgument_InsufficientResolverSettings()
685         {
686             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.InsufficientResolverSettings)));
687         }
ThrowArgument_MustOverrideInitialize()688         static internal void ThrowArgument_MustOverrideInitialize()
689         {
690             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.MustOverrideInitialize)));
691         }
ThrowArgument_InvalidResolverMode(PeerResolverMode mode)692         static internal void ThrowArgument_InvalidResolverMode(PeerResolverMode mode)
693         {
694             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.InvalidResolverMode, mode)));
695         }
696 
ThrowInvalidOperation_NotValidWhenOpen(string operation)697         static internal void ThrowInvalidOperation_NotValidWhenOpen(string operation)
698         {
699             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.NotValidWhenOpen, operation)));
700         }
701 
ThrowInvalidOperation_NotValidWhenClosed(string operation)702         static internal void ThrowInvalidOperation_NotValidWhenClosed(string operation)
703         {
704             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.NotValidWhenClosed, operation)));
705         }
706 
ThrowInvalidOperation_DuplicatePeerRegistration(string servicepath)707         static internal void ThrowInvalidOperation_DuplicatePeerRegistration(string servicepath)
708         {
709             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.DuplicatePeerRegistration, servicepath)));
710         }
ThrowPnrpError(int errorCode, string cloud)711         static internal void ThrowPnrpError(int errorCode, string cloud)
712         {
713             ThrowPnrpError(errorCode, cloud, true);
714         }
ThrowPnrpError(int errorCode, string cloud, bool trace)715         static internal void ThrowPnrpError(int errorCode, string cloud, bool trace)
716         {
717             throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new System.ServiceModel.Channels.PnrpPeerResolver.PnrpException(errorCode, cloud), trace ? TraceEventType.Error : TraceEventType.Information);
718         }
719 
ThrowInvalidOperation_PeerConflictingPeerNodeSettings(string propertyName)720         static internal void ThrowInvalidOperation_PeerConflictingPeerNodeSettings(string propertyName)
721         {
722             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.PeerConflictingPeerNodeSettings, propertyName)));
723         }
724 
ThrowInvalidOperation_PeerCertGenFailure(Exception innerException)725         static internal void ThrowInvalidOperation_PeerCertGenFailure(Exception innerException)
726         {
727             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.PeerCertGenFailure), innerException));
728         }
ThrowInvalidOperation_ConflictingHeader(string headerName)729         static internal void ThrowInvalidOperation_ConflictingHeader(string headerName)
730         {
731             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.PeerConflictingHeader, headerName, PeerStrings.Namespace)));
732         }
733 
GetLastException()734         public static Exception GetLastException()
735         {
736             return new Win32Exception(Marshal.GetLastWin32Error());
737         }
738 
739     }
740 
741     class PeerBindingPropertyNames
742     {
743         public static readonly string ListenUri = "ListenUri";
744         public static readonly string Port = "Port";
745         public static readonly string MaxReceivedMessageSize = "MaxReceivedMessageSize";
746         public static readonly string Resolver = "Resolver";
747         public static readonly string Security = "Security";
748         public static readonly string SecurityDotMode = "Security.Mode";
749         public static readonly string ListenIPAddress = "ListenIPAddress";
750         public static readonly string Credentials = "Credentials";
751         public static readonly string ResolverSettings = "ResolverSettings";
752         public static readonly string Password = "Password";
753         public static readonly string Certificate = "Certificate";
754         public static readonly string MaxBufferPoolSize = "MaxBufferPoolSize";
755         public static readonly string ReaderQuotasDotArrayLength = "ReaderQuotas.MaxArrayLength";
756         public static readonly string ReaderQuotasDotStringLength = "ReaderQuotas.MaxStringContentLength";
757         public static readonly string ReaderQuotasDotMaxDepth = "ReaderQuotas.MaxDepth";
758         public static readonly string ReaderQuotasDotMaxCharCount = "ReaderQuotas.MaxNameTableCharCount";
759         public static readonly string ReaderQuotasDotMaxBytesPerRead = "ReaderQuotas.MaxBytesPerRead";
760     }
761 
762     class PeerPropertyNames
763     {
764         public static readonly string MessageSenderAuthentication = "Credentials.Peer.MessageSenderAuthentication";
765         public static readonly string Credentials = "SecurityCredentialsManager";
766         public static readonly string Password = "Credentials.Peer.MeshPassword";
767         public static readonly string Certificate = "Credentials.Peer.Certificate";
768         public static readonly string PeerAuthentication = "Credentials.Peer.PeerAuthentication";
769     }
770 
771     class OperationSelector : IDispatchOperationSelector
772     {
773         IPeerNodeMessageHandling messageHandler;
774 
OperationSelector(IPeerNodeMessageHandling messageHandler)775         public OperationSelector(IPeerNodeMessageHandling messageHandler)
776         {
777             this.messageHandler = messageHandler;
778         }
779 
TurnOffSecurityHeader(Message message)780         public static void TurnOffSecurityHeader(Message message)
781         {
782             int i = message.Headers.FindHeader(SecurityJan2004Strings.Security, SecurityJan2004Strings.Namespace);
783             if (i >= 0)
784             {
785                 message.Headers.AddUnderstood(i);
786             }
787         }
788 
SelectOperation(ref Message message)789         public string SelectOperation(ref Message message)
790         {
791 
792             string action = message.Headers.Action;
793             string demux = null;
794             byte[] id = PeerNodeImplementation.DefaultId;
795             string operation = PeerStrings.FindAction(action);
796             Uri via = null;
797             Uri to = null;
798             bool skipped = false;
799             PeerMessageProperty peerProperty = new PeerMessageProperty();
800 
801             if (operation != null)
802                 return operation;
803             try
804             {
805                 demux = PeerMessageHelpers.GetHeaderString(message.Headers, PeerOperationNames.Flood, PeerStrings.Namespace);
806                 via = PeerMessageHelpers.GetHeaderUri(message.Headers, PeerStrings.Via, PeerStrings.Namespace);
807                 to = PeerMessageHelpers.GetHeaderUri(message.Headers, PeerOperationNames.PeerTo, PeerStrings.Namespace);
808             }
809             catch (MessageHeaderException e)
810             {
811                 DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
812                 return PeerOperationNames.Fault;
813             }
814             catch (SerializationException e)
815             {
816                 DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
817                 return PeerOperationNames.Fault;
818             }
819             catch (XmlException e)
820             {
821                 DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
822                 return PeerOperationNames.Fault;
823             }
824             peerProperty.PeerVia = via;
825             peerProperty.PeerTo = to;
826             message.Properties.Add(PeerStrings.PeerProperty, peerProperty);
827             if (demux == PeerOperationNames.Demuxer)
828             {
829                 try
830                 {
831                     if (!this.messageHandler.ValidateIncomingMessage(ref message, via))
832                     {
833                         peerProperty.SkipLocalChannels = true;
834                         skipped = true;
835                         TurnOffSecurityHeader(message);
836                     }
837                     if (this.messageHandler.IsNotSeenBefore(message, out id, out peerProperty.CacheMiss))
838                     {
839                         peerProperty.MessageVerified = true;
840                     }
841                     else
842                     {
843                         if (!skipped)
844                         {
845                             peerProperty.SkipLocalChannels = true;
846                         }
847                     }
848                     //means that the message doesnt contain legal id
849                     if (id == PeerNodeImplementation.DefaultId)
850                         return PeerOperationNames.Fault;
851                 }
852                 catch (MessageHeaderException e)
853                 {
854                     DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
855                     return PeerOperationNames.Fault;
856                 }
857                 catch (SerializationException e)
858                 {
859                     DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
860                     return PeerOperationNames.Fault;
861                 }
862                 catch (XmlException e)
863                 {
864                     DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
865                     return PeerOperationNames.Fault;
866                 }
867                 catch (MessageSecurityException e)
868                 {
869                     if (!e.ReplayDetected)
870                         return PeerOperationNames.Fault;
871                     else
872                         DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
873                 }
874                 return PeerOperationNames.Flood;
875             }
876             else
877                 return null;
878         }
879     }
880 
881     internal class PeerOperationSelectorBehavior : IContractBehavior
882     {
883         IPeerNodeMessageHandling messageHandler;
884 
PeerOperationSelectorBehavior(IPeerNodeMessageHandling messageHandler)885         internal PeerOperationSelectorBehavior(IPeerNodeMessageHandling messageHandler)
886         {
887             this.messageHandler = messageHandler;
888         }
889 
IContractBehavior.AddBindingParameters(ContractDescription description, ServiceEndpoint endpoint, BindingParameterCollection parameters)890         void IContractBehavior.AddBindingParameters(ContractDescription description, ServiceEndpoint endpoint, BindingParameterCollection parameters)
891         {
892         }
893 
IContractBehavior.Validate(ContractDescription description, ServiceEndpoint endpoint)894         void IContractBehavior.Validate(ContractDescription description, ServiceEndpoint endpoint)
895         {
896         }
897 
IContractBehavior.ApplyDispatchBehavior(ContractDescription description, ServiceEndpoint endpoint, DispatchRuntime dispatch)898         void IContractBehavior.ApplyDispatchBehavior(ContractDescription description, ServiceEndpoint endpoint, DispatchRuntime
899         dispatch)
900         {
901             dispatch.OperationSelector = new OperationSelector(this.messageHandler);
902 
903             if (dispatch.ClientRuntime != null)
904             {
905                 dispatch.ClientRuntime.OperationSelector = new OperationSelectorBehavior.MethodInfoOperationSelector(description, MessageDirection.Output);
906             }
907         }
908 
IContractBehavior.ApplyClientBehavior(ContractDescription description, ServiceEndpoint endpoint, ClientRuntime proxy)909         void IContractBehavior.ApplyClientBehavior(ContractDescription description, ServiceEndpoint endpoint, ClientRuntime proxy)
910         {
911             proxy.OperationSelector = new OperationSelectorBehavior.MethodInfoOperationSelector(description, MessageDirection.Input);
912             proxy.CallbackDispatchRuntime.OperationSelector = new OperationSelector(this.messageHandler);
913         }
914 
915     }
916 
917     class PeerDictionaryHeader : DictionaryHeader
918     {
919         string value;
920         XmlDictionaryString name;
921         XmlDictionaryString nameSpace;
922 
923 
924         public override XmlDictionaryString DictionaryName
925         {
926             get { return name; }
927         }
928 
929         public override XmlDictionaryString DictionaryNamespace
930         {
931             get { return nameSpace; }
932         }
933 
PeerDictionaryHeader(XmlDictionaryString name, XmlDictionaryString nameSpace, string value)934         public PeerDictionaryHeader(XmlDictionaryString name, XmlDictionaryString nameSpace, string value)
935         {
936             this.name = name;
937             this.nameSpace = nameSpace;
938             this.value = value;
939         }
940 
941 
942 
PeerDictionaryHeader(XmlDictionaryString name, XmlDictionaryString nameSpace, XmlDictionaryString value)943         public PeerDictionaryHeader(XmlDictionaryString name, XmlDictionaryString nameSpace, XmlDictionaryString value)
944         {
945             this.name = name;
946             this.nameSpace = nameSpace;
947             this.value = value.Value;
948         }
949 
OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)950         protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
951         {
952             writer.WriteString(this.value);
953         }
954 
CreateHopCountHeader(ulong hopcount)955         static internal PeerDictionaryHeader CreateHopCountHeader(ulong hopcount)
956         {
957             return new PeerDictionaryHeader(XD.PeerWireStringsDictionary.HopCount, XD.PeerWireStringsDictionary.HopCountNamespace, hopcount.ToString(CultureInfo.InvariantCulture));
958         }
959 
CreateViaHeader(Uri via)960         static internal PeerDictionaryHeader CreateViaHeader(Uri via)
961         {
962             return new PeerDictionaryHeader(XD.PeerWireStringsDictionary.PeerVia, XD.PeerWireStringsDictionary.Namespace, via.ToString());
963         }
964 
CreateFloodRole()965         static internal PeerDictionaryHeader CreateFloodRole()
966         {
967             return new PeerDictionaryHeader(XD.PeerWireStringsDictionary.FloodAction, XD.PeerWireStringsDictionary.Namespace, XD.PeerWireStringsDictionary.Demuxer);
968         }
969 
CreateToHeader(Uri to)970         static internal PeerDictionaryHeader CreateToHeader(Uri to)
971         {
972             return new PeerDictionaryHeader(XD.PeerWireStringsDictionary.PeerTo, XD.PeerWireStringsDictionary.Namespace, to.ToString());
973         }
CreateMessageIdHeader(System.Xml.UniqueId messageId)974         static internal PeerDictionaryHeader CreateMessageIdHeader(System.Xml.UniqueId messageId)
975         {
976             return new PeerDictionaryHeader(XD.AddressingDictionary.MessageId, XD.PeerWireStringsDictionary.Namespace, messageId.ToString());
977         }
978 
979     }
980 
981     class PeerMessageProperty
982     {
983 
984         public bool MessageVerified;
985         public bool SkipLocalChannels;
986         public Uri PeerVia;
987         public Uri PeerTo;
988         public int CacheMiss;
989     }
990 }
991 
992