Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
WebSocketBuffer.cs
Go to the documentation of this file.
2using System.Text;
4
6
7internal sealed class WebSocketBuffer : IDisposable
8{
9 private sealed class PayloadReceiveResult
10 {
11 public int Count { get; set; }
12
13 public bool EndOfMessage { get; }
14
16
17 public PayloadReceiveResult(int count, WebSocketMessageType messageType, bool endOfMessage)
18 {
19 if (count < 0)
20 {
21 throw new ArgumentOutOfRangeException("count");
22 }
23 Count = count;
24 EndOfMessage = endOfMessage;
25 MessageType = messageType;
26 }
27 }
28
29 private static readonly int s_PropertyBufferSize = 12 + IntPtr.Size;
30
31 private readonly int _receiveBufferSize;
32
33 private readonly long _startAddress;
34
35 private readonly long _endAddress;
36
38
40
42
44
46
47 private readonly int _sendBufferSize;
48
49 private volatile int _payloadOffset;
50
52
54
56
58
60
61 private int _stateWhenDisposing = int.MinValue;
62
63 private int _sendBufferState;
64
66
68
69 private WebSocketBuffer(ArraySegment<byte> internalBuffer, int receiveBufferSize, int sendBufferSize)
70 {
71 _receiveBufferSize = receiveBufferSize;
72 _sendBufferSize = sendBufferSize;
73 _internalBuffer = internalBuffer;
74 _gcHandle = GCHandle.Alloc(internalBuffer.Array, GCHandleType.Pinned);
75 int num = _receiveBufferSize + _sendBufferSize + 144;
76 _startAddress = Marshal.UnsafeAddrOfPinnedArrayElement(internalBuffer.Array, internalBuffer.Offset).ToInt64();
78 _nativeBuffer = new ArraySegment<byte>(internalBuffer.Array, internalBuffer.Offset, num);
82 }
83
84 internal static WebSocketBuffer CreateServerBuffer(ArraySegment<byte> internalBuffer, int receiveBufferSize)
85 {
86 int nativeSendBufferSize = GetNativeSendBufferSize(16, isServerBuffer: true);
87 return new WebSocketBuffer(internalBuffer, receiveBufferSize, nativeSendBufferSize);
88 }
89
90 public void Dispose(WebSocketState webSocketState)
91 {
92 if (Interlocked.CompareExchange(ref _stateWhenDisposing, (int)webSocketState, int.MinValue) == int.MinValue)
93 {
94 CleanUp();
95 }
96 }
97
98 public void Dispose()
99 {
101 }
102
103 internal global::Interop.WebSocket.Property[] CreateProperties(bool useZeroMaskingKey)
104 {
109 offset += 4;
111 offset += 4;
113 offset += IntPtr.Size;
114 Marshal.WriteInt32(intPtr, offset, useZeroMaskingKey ? 1 : 0);
115 int num = (useZeroMaskingKey ? 4 : 3);
116 global::Interop.WebSocket.Property[] array = new global::Interop.WebSocket.Property[num];
118 array[0] = new global::Interop.WebSocket.Property
119 {
120 Type = WebSocketProtocolComponent.PropertyType.ReceiveBufferSize,
121 PropertySize = 4u,
122 PropertyData = IntPtr.Add(intPtr, offset)
123 };
124 offset += 4;
125 array[1] = new global::Interop.WebSocket.Property
126 {
128 PropertySize = 4u,
129 PropertyData = IntPtr.Add(intPtr, offset)
130 };
131 offset += 4;
132 array[2] = new global::Interop.WebSocket.Property
133 {
135 PropertySize = (uint)_nativeBuffer.Count,
136 PropertyData = IntPtr.Add(intPtr, offset)
137 };
138 offset += IntPtr.Size;
139 if (useZeroMaskingKey)
140 {
141 array[3] = new global::Interop.WebSocket.Property
142 {
144 PropertySize = 4u,
145 PropertyData = IntPtr.Add(intPtr, offset)
146 };
147 }
148 return array;
149 }
150
151 internal void PinSendBuffer(ArraySegment<byte> payload, out bool bufferHasBeenPinned)
152 {
153 bufferHasBeenPinned = false;
155 if (Interlocked.Exchange(ref _sendBufferState, 1) != 0)
156 {
157 throw new AccessViolationException();
158 }
159 _pinnedSendBuffer = payload;
161 bufferHasBeenPinned = true;
164 }
165
167 {
168 return ConvertPinnedSendPayloadToNative(payload.Array, payload.Offset, payload.Count);
169 }
170
179
181 {
182 if (!IsPinnedSendPayloadBuffer(buffer, bufferType))
183 {
184 throw new AccessViolationException();
185 }
186 UnwrapWebSocketBuffer(buffer, bufferType, out var bufferData, out var bufferLength);
187 int num = (int)(bufferData.ToInt64() - _pinnedSendBufferStartAddress);
188 return new ArraySegment<byte>(_pinnedSendBuffer.Array, _pinnedSendBuffer.Offset + num, (int)bufferLength);
189 }
190
191 private bool IsPinnedSendPayloadBuffer(byte[] buffer, int offset, int count)
192 {
193 if (_sendBufferState != 1)
194 {
195 return false;
196 }
198 {
199 return offset + count <= _pinnedSendBuffer.Offset + _pinnedSendBuffer.Count;
200 }
201 return false;
202 }
203
204 internal bool IsPinnedSendPayloadBuffer(global::Interop.WebSocket.Buffer buffer, WebSocketProtocolComponent.BufferType bufferType)
205 {
206 if (_sendBufferState != 1)
207 {
208 return false;
209 }
210 UnwrapWebSocketBuffer(buffer, bufferType, out var bufferData, out var bufferLength);
211 long num = bufferData.ToInt64();
212 long num2 = num + bufferLength;
214 {
215 return num2 <= _pinnedSendBufferEndAddress;
216 }
217 return false;
218 }
219
221 {
222 int num = Interlocked.Exchange(ref _sendBufferState, 0);
223 if (num == 1)
224 {
226 {
228 }
230 }
231 }
232
233 internal void BufferPayload(ArraySegment<byte> payload, int unconsumedDataOffset, WebSocketMessageType messageType, bool endOfMessage)
234 {
236 int count = payload.Count - unconsumedDataOffset;
237 Buffer.BlockCopy(payload.Array, payload.Offset + unconsumedDataOffset, _payloadBuffer.Array, _payloadBuffer.Offset, count);
238 _bufferedPayloadReceiveResult = new PayloadReceiveResult(count, messageType, endOfMessage);
239 }
240
242 {
245 _bufferedPayloadReceiveResult.Count -= num;
249 {
250 _payloadOffset = 0;
252 return false;
253 }
254 _payloadOffset += num;
255 return true;
256 }
257
259 {
261 UnwrapWebSocketBuffer(buffer, bufferType, out var bufferData, out var bufferLength);
262 if (bufferData == IntPtr.Zero)
263 {
265 }
266 if (IsNativeBuffer(bufferData, bufferLength))
267 {
268 return new ArraySegment<byte>(_internalBuffer.Array, GetOffset(bufferData), (int)bufferLength);
269 }
270 throw new AccessViolationException();
271 }
272
273 internal void ConvertCloseBuffer(WebSocketProtocolComponent.Action action, global::Interop.WebSocket.Buffer buffer, out WebSocketCloseStatus closeStatus, out string reason)
274 {
276 closeStatus = (WebSocketCloseStatus)buffer.CloseStatus.CloseStatus;
277 UnwrapWebSocketBuffer(buffer, WebSocketProtocolComponent.BufferType.Close, out var bufferData, out var bufferLength);
278 if (bufferData == IntPtr.Zero)
279 {
280 reason = null;
281 return;
282 }
283 if (IsNativeBuffer(bufferData, bufferLength))
284 {
285 ArraySegment<byte> arraySegment = new ArraySegment<byte>(_internalBuffer.Array, GetOffset(bufferData), (int)bufferLength);
286 reason = Encoding.UTF8.GetString(arraySegment.Array, arraySegment.Offset, arraySegment.Count);
287 return;
288 }
289 throw new AccessViolationException();
290 }
291
292 internal void ValidateNativeBuffers(WebSocketProtocolComponent.Action action, WebSocketProtocolComponent.BufferType bufferType, global::Interop.WebSocket.Buffer[] dataBuffers, uint dataBufferCount)
293 {
295 if (dataBufferCount > dataBuffers.Length)
296 {
297 throw new AccessViolationException();
298 }
299 int num = dataBuffers.Length;
300 bool flag = action == WebSocketProtocolComponent.Action.IndicateSendComplete || action == WebSocketProtocolComponent.Action.SendToNetwork;
301 if (flag)
302 {
303 num = (int)dataBufferCount;
304 }
305 bool flag2 = false;
306 for (int i = 0; i < num; i++)
307 {
308 global::Interop.WebSocket.Buffer buffer = dataBuffers[i];
309 UnwrapWebSocketBuffer(buffer, bufferType, out var bufferData, out var bufferLength);
310 if (!(bufferData == IntPtr.Zero))
311 {
312 flag2 = true;
313 bool flag3 = IsPinnedSendPayloadBuffer(buffer, bufferType);
314 if (bufferLength > GetMaxBufferSize() && (!flag || !flag3))
315 {
316 throw new AccessViolationException();
317 }
318 if (!flag3 && !IsNativeBuffer(bufferData, bufferLength))
319 {
320 throw new AccessViolationException();
321 }
322 }
323 }
324 if (!flag2 && action != 0 && action != WebSocketProtocolComponent.Action.IndicateReceiveComplete)
325 {
326 _ = 2;
327 }
328 }
329
330 private static int GetNativeSendBufferSize(int sendBufferSize, bool isServerBuffer)
331 {
332 if (!isServerBuffer)
333 {
334 return sendBufferSize;
335 }
336 return 16;
337 }
338
339 internal static void UnwrapWebSocketBuffer(global::Interop.WebSocket.Buffer buffer, WebSocketProtocolComponent.BufferType bufferType, out IntPtr bufferData, out uint bufferLength)
340 {
341 bufferData = IntPtr.Zero;
342 bufferLength = 0u;
343 switch (bufferType)
344 {
346 bufferData = buffer.CloseStatus.ReasonData;
347 bufferLength = buffer.CloseStatus.ReasonLength;
348 break;
349 case WebSocketProtocolComponent.BufferType.UTF8Message:
350 case WebSocketProtocolComponent.BufferType.UTF8Fragment:
351 case WebSocketProtocolComponent.BufferType.BinaryMessage:
352 case WebSocketProtocolComponent.BufferType.BinaryFragment:
354 case WebSocketProtocolComponent.BufferType.UnsolicitedPong:
356 bufferData = buffer.Data.BufferData;
357 bufferLength = buffer.Data.BufferLength;
358 break;
359 }
360 }
361
362 private void ThrowIfDisposed()
363 {
364 switch (_stateWhenDisposing)
365 {
366 case int.MinValue:
367 break;
368 case 5:
369 case 6:
371 default:
372 throw new ObjectDisposedException(GetType().FullName);
373 }
374 }
375
376 private int GetOffset(IntPtr pBuffer)
377 {
378 return (int)(pBuffer.ToInt64() - _startAddress + _internalBuffer.Offset);
379 }
380
381 private int GetMaxBufferSize()
382 {
384 }
385
386 internal bool IsInternalBuffer(byte[] buffer, int offset, int count)
387 {
389 {
390 return offset + count <= _nativeBuffer.Offset + _nativeBuffer.Count;
391 }
392 return false;
393 }
394
395 internal IntPtr ToIntPtr(int offset)
396 {
398 }
399
400 private bool IsNativeBuffer(IntPtr pBuffer, uint bufferSize)
401 {
402 long num = pBuffer.ToInt64();
403 long num2 = bufferSize + num;
404 if (num >= _startAddress && num <= _endAddress && num2 >= _startAddress && num2 <= _endAddress)
405 {
406 return true;
407 }
408 return false;
409 }
410
411 private void CleanUp()
412 {
414 {
415 _gcHandle.Free();
416 }
418 }
419
420 internal static ArraySegment<byte> CreateInternalBufferArraySegment(int receiveBufferSize, int sendBufferSize, bool isServerBuffer)
421 {
422 int internalBufferSize = GetInternalBufferSize(receiveBufferSize, sendBufferSize, isServerBuffer);
423 return new ArraySegment<byte>(new byte[internalBufferSize]);
424 }
425
426 internal static void Validate(int count, int receiveBufferSize, int sendBufferSize, bool isServerBuffer)
427 {
428 int internalBufferSize = GetInternalBufferSize(receiveBufferSize, sendBufferSize, isServerBuffer);
429 if (count < internalBufferSize)
430 {
432 }
433 }
434
435 private static int GetInternalBufferSize(int receiveBufferSize, int sendBufferSize, bool isServerBuffer)
436 {
437 int nativeSendBufferSize = GetNativeSendBufferSize(sendBufferSize, isServerBuffer);
438 return 2 * receiveBufferSize + nativeSendBufferSize + 144 + s_PropertyBufferSize;
439 }
440}
static void BlockCopy(Array src, int srcOffset, Array dst, int dstOffset, int count)
Definition Buffer.cs:102
static byte Min(byte val1, byte val2)
Definition Math.cs:912
static byte Max(byte val1, byte val2)
Definition Math.cs:738
PayloadReceiveResult(int count, WebSocketMessageType messageType, bool endOfMessage)
void ValidateNativeBuffers(WebSocketProtocolComponent.Action action, WebSocketProtocolComponent.BufferType bufferType, global::Interop.WebSocket.Buffer[] dataBuffers, uint dataBufferCount)
bool ReceiveFromBufferedPayload(ArraySegment< byte > buffer, out WebSocketReceiveResult receiveResult)
static ArraySegment< byte > CreateInternalBufferArraySegment(int receiveBufferSize, int sendBufferSize, bool isServerBuffer)
static WebSocketBuffer CreateServerBuffer(ArraySegment< byte > internalBuffer, int receiveBufferSize)
bool IsPinnedSendPayloadBuffer(global::Interop.WebSocket.Buffer buffer, WebSocketProtocolComponent.BufferType bufferType)
ArraySegment< byte > ConvertPinnedSendPayloadFromNative(global::Interop.WebSocket.Buffer buffer, WebSocketProtocolComponent.BufferType bufferType)
readonly ArraySegment< byte > _propertyBuffer
void BufferPayload(ArraySegment< byte > payload, int unconsumedDataOffset, WebSocketMessageType messageType, bool endOfMessage)
WebSocketBuffer(ArraySegment< byte > internalBuffer, int receiveBufferSize, int sendBufferSize)
bool IsInternalBuffer(byte[] buffer, int offset, int count)
bool IsPinnedSendPayloadBuffer(byte[] buffer, int offset, int count)
static int GetInternalBufferSize(int receiveBufferSize, int sendBufferSize, bool isServerBuffer)
static void UnwrapWebSocketBuffer(global::Interop.WebSocket.Buffer buffer, WebSocketProtocolComponent.BufferType bufferType, out IntPtr bufferData, out uint bufferLength)
IntPtr ConvertPinnedSendPayloadToNative(byte[] buffer, int offset, int count)
readonly ArraySegment< byte > _internalBuffer
static void Validate(int count, int receiveBufferSize, int sendBufferSize, bool isServerBuffer)
global::Interop.WebSocket.Property[] CreateProperties(bool useZeroMaskingKey)
static int GetNativeSendBufferSize(int sendBufferSize, bool isServerBuffer)
void Dispose(WebSocketState webSocketState)
void ConvertCloseBuffer(WebSocketProtocolComponent.Action action, global::Interop.WebSocket.Buffer buffer, out WebSocketCloseStatus closeStatus, out string reason)
IntPtr ConvertPinnedSendPayloadToNative(ArraySegment< byte > payload)
readonly ArraySegment< byte > _nativeBuffer
void PinSendBuffer(ArraySegment< byte > payload, out bool bufferHasBeenPinned)
volatile PayloadReceiveResult _bufferedPayloadReceiveResult
bool IsNativeBuffer(IntPtr pBuffer, uint bufferSize)
readonly ArraySegment< byte > _payloadBuffer
ArraySegment< byte > ConvertNativeBuffer(WebSocketProtocolComponent.Action action, global::Interop.WebSocket.Buffer buffer, WebSocketProtocolComponent.BufferType bufferType)
static void ValidateBuffer(byte[] buffer, int offset, int count)
static void WriteInt32(object ptr, int ofs, int val)
Definition Marshal.cs:105
static unsafe IntPtr UnsafeAddrOfPinnedArrayElement(Array arr, int index)
Definition Marshal.cs:775
static void WriteIntPtr(IntPtr ptr, int ofs, IntPtr val)
Definition Marshal.cs:1096
static string net_WebSockets_ArgumentOutOfRange_InternalBuffer
Definition SR.cs:164
static string Format(string resourceFormat, object p1)
Definition SR.cs:118
static string net_WebSockets_InvalidState_ClosedOrAborted
Definition SR.cs:154
Definition SR.cs:7
static Encoding UTF8
Definition Encoding.cs:526
static int CompareExchange(ref int location1, int value, int comparand)
static int Exchange(ref int location1, int value)
static ArraySegment< T > Empty
static int Size
Definition IntPtr.cs:21
static IntPtr Add(IntPtr pointer, int offset)
Definition IntPtr.cs:185
unsafe long ToInt64()
Definition IntPtr.cs:128
static readonly IntPtr Zero
Definition IntPtr.cs:18
static GCHandle Alloc(object? value)
Definition GCHandle.cs:81