1 // <copyright>
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 // </copyright>
4 
5 namespace System.ServiceModel.Channels
6 {
7     using System;
8     using System.ComponentModel;
9     using System.Net.WebSockets;
10     using System.Runtime;
11     using System.Threading;
12 
13     public sealed class WebSocketTransportSettings : IEquatable<WebSocketTransportSettings>
14     {
15         public const string ConnectionOpenedAction = "http://schemas.microsoft.com/2011/02/session/onopen";
16         public const string BinaryMessageReceivedAction = "http://schemas.microsoft.com/2011/02/websockets/onbinarymessage";
17         public const string TextMessageReceivedAction = "http://schemas.microsoft.com/2011/02/websockets/ontextmessage";
18         public const string SoapContentTypeHeader = "soap-content-type";
19         public const string BinaryEncoderTransferModeHeader = "microsoft-binary-transfer-mode";
20         internal const string WebSocketMethod = "WEBSOCKET";
21         internal const string SoapSubProtocol = "soap";
22         internal const string TransportUsageMethodName = "TransportUsage";
23 
24         WebSocketTransportUsage transportUsage;
25         bool createNotificationOnConnection;
26         TimeSpan keepAliveInterval;
27         string subProtocol;
28         bool disablePayloadMasking;
29         int maxPendingConnections;
30 
WebSocketTransportSettings()31         public WebSocketTransportSettings()
32         {
33             this.transportUsage = WebSocketDefaults.TransportUsage;
34             this.createNotificationOnConnection = WebSocketDefaults.CreateNotificationOnConnection;
35             this.keepAliveInterval = WebSocketDefaults.DefaultKeepAliveInterval;
36             this.subProtocol = WebSocketDefaults.SubProtocol;
37             this.disablePayloadMasking = WebSocketDefaults.DisablePayloadMasking;
38             this.maxPendingConnections = WebSocketDefaults.DefaultMaxPendingConnections;
39         }
40 
WebSocketTransportSettings(WebSocketTransportSettings settings)41         WebSocketTransportSettings(WebSocketTransportSettings settings)
42         {
43             Fx.Assert(settings != null, "settings should not be null.");
44             this.TransportUsage = settings.TransportUsage;
45             this.SubProtocol = settings.SubProtocol;
46             this.KeepAliveInterval = settings.KeepAliveInterval;
47             this.DisablePayloadMasking = settings.DisablePayloadMasking;
48             this.CreateNotificationOnConnection = settings.CreateNotificationOnConnection;
49             this.MaxPendingConnections = settings.MaxPendingConnections;
50         }
51 
52         [DefaultValue(WebSocketDefaults.TransportUsage)]
53         public WebSocketTransportUsage TransportUsage
54         {
55             get
56             {
57                 return this.transportUsage;
58             }
59 
60             set
61             {
62                 WebSocketTransportUsageHelper.Validate(value);
63                 this.transportUsage = value;
64             }
65         }
66 
67         [DefaultValue(WebSocketDefaults.CreateNotificationOnConnection)]
68         public bool CreateNotificationOnConnection
69         {
70             get
71             {
72                 return this.createNotificationOnConnection;
73             }
74 
75             set
76             {
77                 this.createNotificationOnConnection = value;
78             }
79         }
80 
81         [DefaultValue(typeof(TimeSpan), WebSocketDefaults.DefaultKeepAliveIntervalString)]
82         public TimeSpan KeepAliveInterval
83         {
84             get
85             {
86                 return this.keepAliveInterval;
87             }
88 
89             set
90             {
91                 if (value < TimeSpan.Zero && value != Timeout.InfiniteTimeSpan)
92                 {
93                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(
94                                 "value",
95                                 value,
96                                 SR.GetString(SR.SFxTimeoutOutOfRange0)));
97                 }
98 
99                 if (TimeoutHelper.IsTooLarge(value))
100                 {
101                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(
102                                             "value",
103                                             value,
104                                             SR.GetString(SR.SFxTimeoutOutOfRangeTooBig)));
105                 }
106 
107                 this.keepAliveInterval = value;
108             }
109         }
110 
111         [DefaultValue(WebSocketDefaults.SubProtocol)]
112         public string SubProtocol
113         {
114             get
115             {
116                 return this.subProtocol;
117             }
118 
119             set
120             {
121                 if (value != null)
122                 {
123                     if (value == string.Empty)
124                     {
125                         throw FxTrace.Exception.Argument("value", SR.GetString(SR.WebSocketInvalidProtocolEmptySubprotocolString));
126                     }
127 
128                     if (value.Split(WebSocketHelper.ProtocolSeparators).Length > 1)
129                     {
130                         throw FxTrace.Exception.Argument("value", SR.GetString(SR.WebSocketInvalidProtocolContainsMultipleSubProtocolString, value));
131                     }
132 
133                     string invalidChar;
134                     if (WebSocketHelper.IsSubProtocolInvalid(value, out invalidChar))
135                     {
136                         throw FxTrace.Exception.Argument("value", SR.GetString(SR.WebSocketInvalidProtocolInvalidCharInProtocolString, value, invalidChar));
137                     }
138                 }
139 
140                 this.subProtocol = value;
141             }
142         }
143 
144         [DefaultValue(WebSocketDefaults.DisablePayloadMasking)]
145         public bool DisablePayloadMasking
146         {
147             get
148             {
149                 return this.disablePayloadMasking;
150             }
151 
152             set
153             {
154                 this.disablePayloadMasking = value;
155             }
156         }
157 
158         [DefaultValue(WebSocketDefaults.DefaultMaxPendingConnections)]
159         public int MaxPendingConnections
160         {
161             get
162             {
163                 return this.maxPendingConnections;
164             }
165 
166             set
167             {
168                 if (value < 0)
169                 {
170                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(
171                         "value",
172                         value,
173                         SR.GetString(SR.ValueMustBePositive)));
174                 }
175 
176                 this.maxPendingConnections = value;
177             }
178         }
179 
Equals(WebSocketTransportSettings other)180         public bool Equals(WebSocketTransportSettings other)
181         {
182             if (other == null)
183             {
184                 return false;
185             }
186 
187             return this.TransportUsage == other.TransportUsage
188                 && this.CreateNotificationOnConnection == other.CreateNotificationOnConnection
189                 && this.KeepAliveInterval == other.KeepAliveInterval
190                 && this.DisablePayloadMasking == other.DisablePayloadMasking
191                 && StringComparer.OrdinalIgnoreCase.Compare(this.SubProtocol, other.SubProtocol) == 0
192                 && this.MaxPendingConnections == other.MaxPendingConnections;
193         }
194 
Equals(object obj)195         public override bool Equals(object obj)
196         {
197             if (obj == null)
198             {
199                 return base.Equals(obj);
200             }
201 
202             WebSocketTransportSettings settings = obj as WebSocketTransportSettings;
203             return this.Equals(settings);
204         }
205 
GetHashCode()206         public override int GetHashCode()
207         {
208             int hashcode = this.TransportUsage.GetHashCode()
209                         ^ this.CreateNotificationOnConnection.GetHashCode()
210                         ^ this.KeepAliveInterval.GetHashCode()
211                         ^ this.DisablePayloadMasking.GetHashCode()
212                         ^ this.MaxPendingConnections.GetHashCode();
213             if (this.SubProtocol != null)
214             {
215                 hashcode ^= this.SubProtocol.ToLowerInvariant().GetHashCode();
216             }
217 
218             return hashcode;
219         }
220 
Clone()221         internal WebSocketTransportSettings Clone()
222         {
223             return new WebSocketTransportSettings(this);
224         }
225 
GetEffectiveKeepAliveInterval()226         internal TimeSpan GetEffectiveKeepAliveInterval()
227         {
228             return this.keepAliveInterval == TimeSpan.Zero ? WebSocket.DefaultKeepAliveInterval : this.keepAliveInterval;
229         }
230     }
231 }
232