Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
WebSocketHttpListenerDuplexStream.cs
Go to the documentation of this file.
2using System.IO;
8
10
11internal sealed class WebSocketHttpListenerDuplexStream : Stream, WebSocketBase.IWebSocketStream
12{
14 {
16 {
17 None,
18 Receive,
19 Send
20 }
21
22 private int _operating;
23
24 private bool _disposeCalled;
25
27
29
30 private byte[] _buffer;
31
33
34 private int _count;
35
36 private int _offset;
37
38 private int _bytesTransferred;
39
41
42 private global::Interop.HttpApi.HTTP_DATA_CHUNK[] _dataChunks;
43
45
46 private ushort _dataChunkCount;
47
49
50 private bool _shouldCloseOutput;
51
52 private readonly WebSocketBase _webSocket;
53
55
57
58 public byte[] Buffer => _buffer;
59
61 {
62 get
63 {
64 return _bufferList;
65 }
66 set
67 {
69 }
70 }
71
73
74 public int Offset => _offset;
75
76 public int Count => _count;
77
79
80 public ushort EntityChunkCount
81 {
82 get
83 {
84 if (_dataChunks == null)
85 {
86 return 0;
87 }
88 return _dataChunkCount;
89 }
90 }
91
93
95 {
96 get
97 {
98 if (_dataChunks == null)
99 {
100 return IntPtr.Zero;
101 }
103 }
104 }
105
107
109
111 {
112 add
113 {
115 }
116 remove
117 {
119 }
120 }
121
127
129 {
130 this.m_Completed?.Invoke(e._currentStream, e);
131 }
132
134 {
135 _bufferList = null;
136 _buffer = null;
137 _shouldCloseOutput = true;
138 }
139
140 public void Dispose()
141 {
142 _disposeCalled = true;
144 {
145 GC.SuppressFinalize(this);
146 }
147 }
148
150 {
152 _ptrNativeOverlapped = boundHandle.AllocateNativeOverlapped(CompletionPortCallback, null, null);
153 }
154
155 private unsafe void FreeOverlapped(bool checkForShutdown)
156 {
158 {
159 if (_ptrNativeOverlapped != null)
160 {
163 }
165 {
167 _dataChunks = null;
168 }
169 }
170 }
171
186
187 internal void StartOperationReceive()
188 {
190 }
191
197
198 public void SetBuffer(byte[] buffer, int offset, int count)
199 {
200 _buffer = buffer;
201 _offset = offset;
202 _count = count;
203 }
204
205 private void UpdateDataChunk()
206 {
207 if (_dataChunks == null)
208 {
209 _dataChunks = new global::Interop.HttpApi.HTTP_DATA_CHUNK[2];
211 _dataChunks[0] = default(global::Interop.HttpApi.HTTP_DATA_CHUNK);
212 _dataChunks[0].DataChunkType = global::Interop.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
213 _dataChunks[1] = default(global::Interop.HttpApi.HTTP_DATA_CHUNK);
214 _dataChunks[1].DataChunkType = global::Interop.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
215 }
216 if (_buffer != null)
217 {
219 UpdateDataChunk(1, null, 0, 0);
220 _dataChunkCount = 1;
221 }
222 else if (_bufferList != null)
223 {
226 _dataChunkCount = 2;
227 }
228 else
229 {
230 _dataChunks = null;
231 }
232 }
233
234 private unsafe void UpdateDataChunk(int index, byte[] buffer, int offset, int count)
235 {
236 if (buffer == null)
237 {
238 _dataChunks[index].pBuffer = null;
239 _dataChunks[index].BufferLength = 0u;
240 return;
241 }
243 {
244 _dataChunks[index].pBuffer = (byte*)(void*)_webSocket.InternalBuffer.ToIntPtr(offset);
245 }
246 else
247 {
249 }
250 _dataChunks[index].BufferLength = (uint)count;
251 }
252
253 internal void Complete()
254 {
257 if (_disposeCalled)
258 {
259 Dispose();
260 }
261 }
262
268
270 {
272 if (System.Net.NetEventSource.Log.IsEnabled())
273 {
274 string text = ((_completedOperation == HttpListenerAsyncOperation.Receive) ? "ReadAsyncFast" : "WriteAsyncFast");
275 System.Net.NetEventSource.Error(_currentStream, $"{text} {exception}", "FinishOperationFailure");
276 }
277 Complete();
278 OnCompleted(this);
279 }
280
282 {
284 if (System.Net.NetEventSource.Log.IsEnabled())
285 {
286 if (_buffer != null && System.Net.NetEventSource.Log.IsEnabled())
287 {
288 string memberName = ((_completedOperation == HttpListenerAsyncOperation.Receive) ? "ReadAsyncFast" : "WriteAsyncFast");
290 }
291 else if (_bufferList != null)
292 {
294 {
295 System.Net.NetEventSource.DumpBuffer(this, buffer.Array, buffer.Offset, buffer.Count, "WriteAsyncFast");
296 }
297 }
298 }
300 {
302 }
303 Complete();
304 OnCompleted(this);
305 }
306
308 {
309 if (errorCode == 0 || errorCode == 38)
310 {
312 }
313 else
314 {
316 }
317 }
318 }
319
321
323
325
326 private static readonly Action<object> s_OnCancel = OnCancel;
327
329
331
333
334 private bool _inOpaqueMode;
335
337
339
341
343
345
346 private int _cleanedUp;
347
348 public override bool CanRead => _inputStream.CanRead;
349
350 public override bool CanSeek => false;
351
352 public override bool CanTimeout
353 {
354 get
355 {
357 {
359 }
360 return false;
361 }
362 }
363
364 public override bool CanWrite => _outputStream.CanWrite;
365
366 public override long Length
367 {
368 get
369 {
371 }
372 }
373
374 public override long Position
375 {
376 get
377 {
379 }
380 set
381 {
383 }
384 }
385
386 public bool SupportsMultipleWrite => true;
387
389 {
390 _inputStream = inputStream;
392 _context = context;
393 if (System.Net.NetEventSource.Log.IsEnabled())
394 {
395 System.Net.NetEventSource.Associate(inputStream, this, ".ctor");
397 }
398 }
399
400 public override int Read(byte[] buffer, int offset, int count)
401 {
403 }
404
410
412 {
414 int result = 0;
415 try
416 {
417 if (cancellationToken.CanBeCanceled)
418 {
420 }
421 if (!_inOpaqueMode)
422 {
423 result = await _inputStream.ReadAsync(buffer, offset, count, cancellationToken).SuppressContextFlow();
424 }
425 else
426 {
430 {
431 if (_readEventArgs.Exception != null)
432 {
434 }
436 }
437 else
438 {
439 result = await _readTaskCompletionSource.Task.SuppressContextFlow();
440 }
441 }
442 }
443 catch (Exception arg)
444 {
446 {
447 cancellationToken.ThrowIfCancellationRequested();
448 }
449 throw;
450 }
451 finally
452 {
454 }
455 return result;
456 }
457
459 {
461 eventArgs.StartOperationReceive();
462 uint num = 0u;
463 bool flag = false;
464 try
465 {
467 {
468 eventArgs.FinishOperationSuccess(0, syncCompletion: true);
469 return false;
470 }
471 uint num2 = 0u;
472 int offset = eventArgs.Offset;
473 int count = eventArgs.Count;
475 {
478 {
479 eventArgs.FinishOperationSuccess(eventArgs.Count, syncCompletion: true);
480 return false;
481 }
482 }
483 if (num2 != 0)
484 {
485 offset += (int)num2;
486 count -= (int)num2;
487 if (count > 131072)
488 {
489 count = 131072;
490 }
491 eventArgs.SetBuffer(eventArgs.Buffer, offset, count);
492 }
493 else if (count > 131072)
494 {
495 count = 131072;
496 eventArgs.SetBuffer(eventArgs.Buffer, offset, count);
497 }
498 uint flags = 0u;
499 uint bytesReturned = 0u;
500 num = global::Interop.HttpApi.HttpReceiveRequestEntityBody(_inputStream.InternalHttpContext.RequestQueueHandle, _inputStream.InternalHttpContext.RequestId, flags, (void*)_webSocket.InternalBuffer.ToIntPtr(eventArgs.Offset), (uint)eventArgs.Count, out bytesReturned, eventArgs.NativeOverlapped);
501 if (num != 0 && num != 997 && num != 38)
502 {
503 throw new HttpListenerException((int)num);
504 }
506 {
507 eventArgs.FinishOperationSuccess((int)bytesReturned, syncCompletion: true);
508 return false;
509 }
510 if (num == 38)
511 {
512 eventArgs.FinishOperationSuccess(0, syncCompletion: true);
513 return false;
514 }
515 return true;
516 }
517 catch (Exception exception)
518 {
522 return true;
523 }
524 }
525
526 public override int ReadByte()
527 {
528 return _inputStream.ReadByte();
529 }
530
531 public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
532 {
533 return _inputStream.BeginRead(buffer, offset, count, callback, state);
534 }
535
536 public override int EndRead(IAsyncResult asyncResult)
537 {
539 }
540
550
552 {
554 try
555 {
556 if (cancellationToken.CanBeCanceled)
557 {
559 }
561 _writeEventArgs.SetBuffer(null, 0, 0);
562 _writeEventArgs.BufferList = sendBuffers;
564 {
565 await _writeTaskCompletionSource.Task.SuppressContextFlow();
566 }
567 }
568 catch (Exception arg)
569 {
571 {
572 cancellationToken.ThrowIfCancellationRequested();
573 }
574 throw;
575 }
576 finally
577 {
579 }
580 }
581
582 public override void Write(byte[] buffer, int offset, int count)
583 {
585 }
586
592
594 {
596 try
597 {
598 if (cancellationToken.CanBeCanceled)
599 {
601 }
602 if (!_inOpaqueMode)
603 {
605 return;
606 }
608 _writeEventArgs.BufferList = null;
611 {
612 await _writeTaskCompletionSource.Task.SuppressContextFlow();
613 }
614 }
615 catch (Exception arg)
616 {
618 {
619 cancellationToken.ThrowIfCancellationRequested();
620 }
621 throw;
622 }
623 finally
624 {
626 }
627 }
628
630 {
631 global::Interop.HttpApi.HTTP_FLAGS hTTP_FLAGS = global::Interop.HttpApi.HTTP_FLAGS.NONE;
633 eventArgs.StartOperationSend();
634 bool flag = false;
635 try
636 {
637 if (_outputStream.Closed || (eventArgs.Buffer != null && eventArgs.Count == 0))
638 {
639 eventArgs.FinishOperationSuccess(eventArgs.Count, syncCompletion: true);
640 return false;
641 }
642 if (eventArgs.ShouldCloseOutput)
643 {
644 hTTP_FLAGS |= global::Interop.HttpApi.HTTP_FLAGS.HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY;
645 }
646 else
647 {
648 hTTP_FLAGS |= global::Interop.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
649 hTTP_FLAGS |= global::Interop.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA;
650 }
651 Unsafe.SkipInit(out uint bytesTransferred);
652 uint num = global::Interop.HttpApi.HttpSendResponseEntityBody(_outputStream.InternalHttpContext.RequestQueueHandle, _outputStream.InternalHttpContext.RequestId, (uint)hTTP_FLAGS, eventArgs.EntityChunkCount, (global::Interop.HttpApi.HTTP_DATA_CHUNK*)(void*)eventArgs.EntityChunks, &bytesTransferred, Microsoft.Win32.SafeHandles.SafeLocalAllocHandle.Zero, 0u, eventArgs.NativeOverlapped, null);
653 if (num != 0 && num != 997)
654 {
655 throw new HttpListenerException((int)num);
656 }
658 {
659 eventArgs.FinishOperationSuccess((int)bytesTransferred, syncCompletion: true);
660 return false;
661 }
662 return true;
663 }
664 catch (Exception exception)
665 {
669 return true;
670 }
671 }
672
673 public override void WriteByte(byte value)
674 {
676 }
677
678 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
679 {
680 return _outputStream.BeginWrite(buffer, offset, count, callback, state);
681 }
682
683 public override void EndWrite(IAsyncResult asyncResult)
684 {
686 }
687
688 public override void Flush()
689 {
691 }
692
697
698 public override long Seek(long offset, SeekOrigin origin)
699 {
701 }
702
703 public override void SetLength(long value)
704 {
706 }
707
709 {
710 await Task.Yield();
712 try
713 {
714 if (cancellationToken.CanBeCanceled)
715 {
717 }
721 {
722 await _writeTaskCompletionSource.Task.SuppressContextFlow();
723 }
724 }
725 catch (Exception arg)
726 {
728 {
729 throw;
730 }
731 cancellationToken.ThrowIfCancellationRequested();
732 }
733 finally
734 {
736 }
737 }
738
739 protected override void Dispose(bool disposing)
740 {
742 {
743 if (_readTaskCompletionSource != null)
744 {
746 }
748 if (_readEventArgs != null)
749 {
751 }
752 if (_writeEventArgs != null)
753 {
755 }
756 try
757 {
759 }
760 finally
761 {
763 }
764 }
765 }
766
767 public void Abort()
768 {
769 OnCancel(this);
770 }
771
772 private static bool CanHandleException(Exception error)
773 {
775 {
776 return error is IOException;
777 }
778 return true;
779 }
780
781 private static void OnCancel(object state)
782 {
784 try
785 {
786 webSocketHttpListenerDuplexStream._outputStream.SetClosedFlag();
787 webSocketHttpListenerDuplexStream._context.Abort();
788 }
789 catch
790 {
791 }
792 webSocketHttpListenerDuplexStream._readTaskCompletionSource?.TrySetCanceled();
793 webSocketHttpListenerDuplexStream._writeTaskCompletionSource?.TrySetCanceled();
794 }
795
797 {
798 if (_inOpaqueMode)
799 {
800 throw new InvalidOperationException();
801 }
803 _inOpaqueMode = true;
805 _readEventArgs.Completed += s_OnReadCompleted;
807 _writeEventArgs.Completed += s_OnWriteCompleted;
808 if (System.Net.NetEventSource.Log.IsEnabled())
809 {
810 System.Net.NetEventSource.Associate(this, webSocket, "SwitchToOpaqueMode");
811 }
812 }
813
814 private static void OnWriteCompleted(object sender, HttpListenerAsyncEventArgs eventArgs)
815 {
817 if (eventArgs.Exception != null)
818 {
819 currentStream._writeTaskCompletionSource.TrySetException(eventArgs.Exception);
820 }
821 else
822 {
823 currentStream._writeTaskCompletionSource.TrySetResult();
824 }
825 }
826
827 private static void OnReadCompleted(object sender, HttpListenerAsyncEventArgs eventArgs)
828 {
830 if (eventArgs.Exception != null)
831 {
832 currentStream._readTaskCompletionSource.TrySetException(eventArgs.Exception);
833 }
834 else
835 {
836 currentStream._readTaskCompletionSource.TrySetResult(eventArgs.BytesTransferred);
837 }
838 }
839}
static readonly Microsoft.Win32.SafeHandles.SafeLocalAllocHandle Zero
static bool HasShutdownStarted
static void SuppressFinalize(object obj)
Definition GC.cs:202
Definition GC.cs:8
virtual int ReadByte()
Definition Stream.cs:994
virtual bool CanTimeout
Definition Stream.cs:498
virtual void Close()
Definition Stream.cs:644
Task WriteAsync(byte[] buffer, int offset, int count)
Definition Stream.cs:914
Task< int > ReadAsync(byte[] buffer, int offset, int count)
Definition Stream.cs:762
virtual void WriteByte(byte value)
Definition Stream.cs:1020
ThreadPoolBoundHandle RequestQueueBoundHandle
static readonly bool SkipIOCPCallbackOnSuccess
override int Read(byte[] buffer, int offset, int count)
override int EndRead(IAsyncResult asyncResult)
uint GetChunks(byte[] buffer, int offset, int size)
override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
HttpListenerContext InternalHttpContext
override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
override void Write(byte[] buffer, int offset, int count)
HttpListenerContext InternalHttpContext
override Task FlushAsync(CancellationToken cancellationToken)
override void EndWrite(IAsyncResult asyncResult)
static readonly System.Net.NetEventSource Log
static void Error(object thisOrContextObject, FormattableString formattableString, [CallerMemberName] string memberName=null)
static void Associate(object first, object second, [CallerMemberName] string memberName=null)
static void DumpBuffer(object thisOrContextObject, byte[] buffer, int offset, int count, [CallerMemberName] string memberName=null)
bool IsInternalBuffer(byte[] buffer, int offset, int count)
IntPtr ConvertPinnedSendPayloadToNative(ArraySegment< byte > payload)
void StartOperationCommon(WebSocketHttpListenerDuplexStream currentStream, ThreadPoolBoundHandle boundHandle)
unsafe void CompletionPortCallback(uint errorCode, uint numBytes, NativeOverlapped *nativeOverlapped)
HttpListenerAsyncEventArgs(WebSocketBase webSocket, WebSocketHttpListenerDuplexStream stream)
async Task< int > ReadAsyncCore(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
override Task FlushAsync(CancellationToken cancellationToken)
async Task MultipleWriteAsyncCore(IList< ArraySegment< byte > > sendBuffers, CancellationToken cancellationToken)
override void Write(byte[] buffer, int offset, int count)
static void OnReadCompleted(object sender, HttpListenerAsyncEventArgs eventArgs)
override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
static void OnWriteCompleted(object sender, HttpListenerAsyncEventArgs eventArgs)
async Task WriteAsyncCore(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
unsafe bool ReadAsyncFast(HttpListenerAsyncEventArgs eventArgs)
Task MultipleWriteAsync(IList< ArraySegment< byte > > sendBuffers, CancellationToken cancellationToken)
override Task< int > ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
static readonly EventHandler< HttpListenerAsyncEventArgs > s_OnWriteCompleted
override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
static readonly EventHandler< HttpListenerAsyncEventArgs > s_OnReadCompleted
async Task CloseNetworkConnectionAsync(CancellationToken cancellationToken)
WebSocketHttpListenerDuplexStream(HttpRequestStream inputStream, HttpResponseStream outputStream, HttpListenerContext context)
unsafe bool WriteAsyncFast(HttpListenerAsyncEventArgs eventArgs)
override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
static void ValidateBuffer(byte[] buffer, int offset, int count)
static unsafe IntPtr UnsafeAddrOfPinnedArrayElement(Array arr, int index)
Definition Marshal.cs:775
static string net_noseek
Definition SR.cs:114
Definition SR.cs:7
static int CompareExchange(ref int location1, int value, int comparand)
static int Exchange(ref int location1, int value)
static YieldAwaitable Yield()
Definition Task.cs:2220
unsafe void FreeNativeOverlapped(NativeOverlapped *overlapped)
static readonly IntPtr Zero
Definition IntPtr.cs:18
static GCHandle Alloc(object? value)
Definition GCHandle.cs:81