diff options
Diffstat (limited to 'OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs')
-rw-r--r-- | OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs | 87 |
1 files changed, 72 insertions, 15 deletions
diff --git a/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs index ee96b47..c2925e3 100644 --- a/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs | |||
@@ -28,8 +28,10 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.IO; | 30 | using System.IO; |
31 | using System.Net; | ||
31 | using System.Security.Cryptography; | 32 | using System.Security.Cryptography; |
32 | using System.Text; | 33 | using System.Text; |
34 | using System.Threading; | ||
33 | using HttpServer; | 35 | using HttpServer; |
34 | 36 | ||
35 | namespace OpenSim.Framework.Servers.HttpServer | 37 | namespace OpenSim.Framework.Servers.HttpServer |
@@ -75,7 +77,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
75 | /// <summary> | 77 | /// <summary> |
76 | /// This is a regular HTTP Request... This may be removed in the future. | 78 | /// This is a regular HTTP Request... This may be removed in the future. |
77 | /// </summary> | 79 | /// </summary> |
78 | public event RegularHttpRequestDelegate OnRegularHttpRequest; | 80 | // public event RegularHttpRequestDelegate OnRegularHttpRequest; |
79 | 81 | ||
80 | /// <summary> | 82 | /// <summary> |
81 | /// When the upgrade from a HTTP request to a Websocket is completed, this will be fired | 83 | /// When the upgrade from a HTTP request to a Websocket is completed, this will be fired |
@@ -98,6 +100,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
98 | /// </summary> | 100 | /// </summary> |
99 | public ValidateHandshake HandshakeValidateMethodOverride = null; | 101 | public ValidateHandshake HandshakeValidateMethodOverride = null; |
100 | 102 | ||
103 | private ManualResetEvent _receiveDone = new ManualResetEvent(false); | ||
104 | |||
101 | private OSHttpRequest _request; | 105 | private OSHttpRequest _request; |
102 | private HTTPNetworkContext _networkContext; | 106 | private HTTPNetworkContext _networkContext; |
103 | private IHttpClientContext _clientContext; | 107 | private IHttpClientContext _clientContext; |
@@ -109,6 +113,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
109 | private bool _closing; | 113 | private bool _closing; |
110 | private bool _upgraded; | 114 | private bool _upgraded; |
111 | private int _maxPayloadBytes = 41943040; | 115 | private int _maxPayloadBytes = 41943040; |
116 | private int _initialMsgTimeout = 0; | ||
117 | private int _defaultReadTimeout = 10000; | ||
112 | 118 | ||
113 | private const string HandshakeAcceptText = | 119 | private const string HandshakeAcceptText = |
114 | "HTTP/1.1 101 Switching Protocols\r\n" + | 120 | "HTTP/1.1 101 Switching Protocols\r\n" + |
@@ -131,6 +137,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
131 | { | 137 | { |
132 | _request = preq; | 138 | _request = preq; |
133 | _networkContext = pContext.GiveMeTheNetworkStreamIKnowWhatImDoing(); | 139 | _networkContext = pContext.GiveMeTheNetworkStreamIKnowWhatImDoing(); |
140 | _networkContext.Stream.ReadTimeout = _defaultReadTimeout; | ||
134 | _clientContext = pContext; | 141 | _clientContext = pContext; |
135 | _bufferLength = bufferlen; | 142 | _bufferLength = bufferlen; |
136 | _buffer = new byte[_bufferLength]; | 143 | _buffer = new byte[_bufferLength]; |
@@ -206,6 +213,16 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
206 | } | 213 | } |
207 | 214 | ||
208 | /// <summary> | 215 | /// <summary> |
216 | /// Set this to the maximum amount of milliseconds to wait for the first complete message to be sent or received on the websocket after upgrading | ||
217 | /// Default, it waits forever. Use this when your Websocket consuming code opens a connection and waits for a message from the other side to avoid a Denial of Service vector. | ||
218 | /// </summary> | ||
219 | public int InitialMsgTimeout | ||
220 | { | ||
221 | get { return _initialMsgTimeout; } | ||
222 | set { _initialMsgTimeout = value; } | ||
223 | } | ||
224 | |||
225 | /// <summary> | ||
209 | /// This triggers the websocket start the upgrade process | 226 | /// This triggers the websocket start the upgrade process |
210 | /// </summary> | 227 | /// </summary> |
211 | public void HandshakeAndUpgrade() | 228 | public void HandshakeAndUpgrade() |
@@ -245,6 +262,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
245 | string rawaccept = string.Format(HandshakeAcceptText, acceptKey); | 262 | string rawaccept = string.Format(HandshakeAcceptText, acceptKey); |
246 | SendUpgradeSuccess(rawaccept); | 263 | SendUpgradeSuccess(rawaccept); |
247 | 264 | ||
265 | |||
248 | } | 266 | } |
249 | else | 267 | else |
250 | { | 268 | { |
@@ -258,6 +276,10 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
258 | SendUpgradeSuccess(rawaccept); | 276 | SendUpgradeSuccess(rawaccept); |
259 | } | 277 | } |
260 | } | 278 | } |
279 | public IPEndPoint GetRemoteIPEndpoint() | ||
280 | { | ||
281 | return _request.RemoteIPEndPoint; | ||
282 | } | ||
261 | 283 | ||
262 | /// <summary> | 284 | /// <summary> |
263 | /// Generates a handshake response key string based on the client's | 285 | /// Generates a handshake response key string based on the client's |
@@ -290,9 +312,16 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
290 | WebSocketState socketState = new WebSocketState() { ReceivedBytes = new List<byte>(), Header = WebsocketFrameHeader.HeaderDefault(), FrameComplete = true}; | 312 | WebSocketState socketState = new WebSocketState() { ReceivedBytes = new List<byte>(), Header = WebsocketFrameHeader.HeaderDefault(), FrameComplete = true}; |
291 | 313 | ||
292 | byte[] bhandshakeResponse = Encoding.UTF8.GetBytes(pHandshakeResponse); | 314 | byte[] bhandshakeResponse = Encoding.UTF8.GetBytes(pHandshakeResponse); |
315 | |||
316 | |||
317 | |||
318 | |||
293 | try | 319 | try |
294 | { | 320 | { |
295 | 321 | if (_initialMsgTimeout > 0) | |
322 | { | ||
323 | _receiveDone.Reset(); | ||
324 | } | ||
296 | // Begin reading the TCP stream before writing the Upgrade success message to the other side of the stream. | 325 | // Begin reading the TCP stream before writing the Upgrade success message to the other side of the stream. |
297 | _networkContext.Stream.BeginRead(_buffer, 0, _bufferLength, OnReceive, socketState); | 326 | _networkContext.Stream.BeginRead(_buffer, 0, _bufferLength, OnReceive, socketState); |
298 | 327 | ||
@@ -303,16 +332,20 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
303 | UpgradeCompletedDelegate d = OnUpgradeCompleted; | 332 | UpgradeCompletedDelegate d = OnUpgradeCompleted; |
304 | if (d != null) | 333 | if (d != null) |
305 | d(this, new UpgradeCompletedEventArgs()); | 334 | d(this, new UpgradeCompletedEventArgs()); |
335 | if (_initialMsgTimeout > 0) | ||
336 | { | ||
337 | if (!_receiveDone.WaitOne(TimeSpan.FromMilliseconds(_initialMsgTimeout))) | ||
338 | Close(string.Empty); | ||
339 | } | ||
306 | } | 340 | } |
307 | catch (IOException fail) | 341 | catch (IOException) |
308 | { | 342 | { |
309 | Close(string.Empty); | 343 | Close(string.Empty); |
310 | } | 344 | } |
311 | catch (ObjectDisposedException fail) | 345 | catch (ObjectDisposedException) |
312 | { | 346 | { |
313 | Close(string.Empty); | 347 | Close(string.Empty); |
314 | } | 348 | } |
315 | |||
316 | } | 349 | } |
317 | 350 | ||
318 | /// <summary> | 351 | /// <summary> |
@@ -414,8 +447,6 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
414 | _socketState.Header = pheader; | 447 | _socketState.Header = pheader; |
415 | } | 448 | } |
416 | 449 | ||
417 | |||
418 | |||
419 | if (_socketState.FrameComplete) | 450 | if (_socketState.FrameComplete) |
420 | { | 451 | { |
421 | ProcessFrame(_socketState); | 452 | ProcessFrame(_socketState); |
@@ -424,7 +455,6 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
424 | _socketState.ExpectedBytes = 0; | 455 | _socketState.ExpectedBytes = 0; |
425 | 456 | ||
426 | } | 457 | } |
427 | |||
428 | } | 458 | } |
429 | } | 459 | } |
430 | else | 460 | else |
@@ -457,8 +487,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
457 | _socketState.ReceivedBytes.Clear(); | 487 | _socketState.ReceivedBytes.Clear(); |
458 | _socketState.ExpectedBytes = 0; | 488 | _socketState.ExpectedBytes = 0; |
459 | // do some processing | 489 | // do some processing |
460 | } | 490 | } |
461 | |||
462 | } | 491 | } |
463 | } | 492 | } |
464 | if (offset > 0) | 493 | if (offset > 0) |
@@ -477,13 +506,12 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
477 | { | 506 | { |
478 | // We can't read the stream anymore... | 507 | // We can't read the stream anymore... |
479 | } | 508 | } |
480 | |||
481 | } | 509 | } |
482 | catch (IOException fail) | 510 | catch (IOException) |
483 | { | 511 | { |
484 | Close(string.Empty); | 512 | Close(string.Empty); |
485 | } | 513 | } |
486 | catch (ObjectDisposedException fail) | 514 | catch (ObjectDisposedException) |
487 | { | 515 | { |
488 | Close(string.Empty); | 516 | Close(string.Empty); |
489 | } | 517 | } |
@@ -495,6 +523,11 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
495 | /// <param name="message">the string message that is to be sent</param> | 523 | /// <param name="message">the string message that is to be sent</param> |
496 | public void SendMessage(string message) | 524 | public void SendMessage(string message) |
497 | { | 525 | { |
526 | if (_initialMsgTimeout > 0) | ||
527 | { | ||
528 | _receiveDone.Set(); | ||
529 | _initialMsgTimeout = 0; | ||
530 | } | ||
498 | byte[] messagedata = Encoding.UTF8.GetBytes(message); | 531 | byte[] messagedata = Encoding.UTF8.GetBytes(message); |
499 | WebSocketFrame textMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = messagedata }; | 532 | WebSocketFrame textMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = messagedata }; |
500 | textMessageFrame.Header.Opcode = WebSocketReader.OpCode.Text; | 533 | textMessageFrame.Header.Opcode = WebSocketReader.OpCode.Text; |
@@ -505,6 +538,11 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
505 | 538 | ||
506 | public void SendData(byte[] data) | 539 | public void SendData(byte[] data) |
507 | { | 540 | { |
541 | if (_initialMsgTimeout > 0) | ||
542 | { | ||
543 | _receiveDone.Set(); | ||
544 | _initialMsgTimeout = 0; | ||
545 | } | ||
508 | WebSocketFrame dataMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = data}; | 546 | WebSocketFrame dataMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = data}; |
509 | dataMessageFrame.Header.IsEnd = true; | 547 | dataMessageFrame.Header.IsEnd = true; |
510 | dataMessageFrame.Header.Opcode = WebSocketReader.OpCode.Binary; | 548 | dataMessageFrame.Header.Opcode = WebSocketReader.OpCode.Binary; |
@@ -537,6 +575,11 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
537 | /// </summary> | 575 | /// </summary> |
538 | public void SendPingCheck() | 576 | public void SendPingCheck() |
539 | { | 577 | { |
578 | if (_initialMsgTimeout > 0) | ||
579 | { | ||
580 | _receiveDone.Set(); | ||
581 | _initialMsgTimeout = 0; | ||
582 | } | ||
540 | WebSocketFrame pingFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = new byte[0] }; | 583 | WebSocketFrame pingFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = new byte[0] }; |
541 | pingFrame.Header.Opcode = WebSocketReader.OpCode.Ping; | 584 | pingFrame.Header.Opcode = WebSocketReader.OpCode.Ping; |
542 | pingFrame.Header.IsEnd = true; | 585 | pingFrame.Header.IsEnd = true; |
@@ -550,6 +593,11 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
550 | /// <param name="message"></param> | 593 | /// <param name="message"></param> |
551 | public void Close(string message) | 594 | public void Close(string message) |
552 | { | 595 | { |
596 | if (_initialMsgTimeout > 0) | ||
597 | { | ||
598 | _receiveDone.Set(); | ||
599 | _initialMsgTimeout = 0; | ||
600 | } | ||
553 | if (_networkContext == null) | 601 | if (_networkContext == null) |
554 | return; | 602 | return; |
555 | if (_networkContext.Stream != null) | 603 | if (_networkContext.Stream != null) |
@@ -589,7 +637,11 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
589 | WebSocketReader.Mask(psocketState.Header.Mask, unmask); | 637 | WebSocketReader.Mask(psocketState.Header.Mask, unmask); |
590 | psocketState.ReceivedBytes = new List<byte>(unmask); | 638 | psocketState.ReceivedBytes = new List<byte>(unmask); |
591 | } | 639 | } |
592 | 640 | if (psocketState.Header.Opcode != WebSocketReader.OpCode.Continue && _initialMsgTimeout > 0) | |
641 | { | ||
642 | _receiveDone.Set(); | ||
643 | _initialMsgTimeout = 0; | ||
644 | } | ||
593 | switch (psocketState.Header.Opcode) | 645 | switch (psocketState.Header.Opcode) |
594 | { | 646 | { |
595 | case WebSocketReader.OpCode.Ping: | 647 | case WebSocketReader.OpCode.Ping: |
@@ -702,6 +754,11 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
702 | } | 754 | } |
703 | public void Dispose() | 755 | public void Dispose() |
704 | { | 756 | { |
757 | if (_initialMsgTimeout > 0) | ||
758 | { | ||
759 | _receiveDone.Set(); | ||
760 | _initialMsgTimeout = 0; | ||
761 | } | ||
705 | if (_networkContext != null && _networkContext.Stream != null) | 762 | if (_networkContext != null && _networkContext.Stream != null) |
706 | { | 763 | { |
707 | if (_networkContext.Stream.CanWrite) | 764 | if (_networkContext.Stream.CanWrite) |