Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
WebSocketProtocolComponent.cs
Go to the documentation of this file.
2
4
5internal static class WebSocketProtocolComponent
6{
15
16 internal enum BufferType : uint
17 {
18 None = 0u,
19 UTF8Message = 2147483648u,
20 UTF8Fragment = 2147483649u,
21 BinaryMessage = 2147483650u,
22 BinaryFragment = 2147483651u,
23 Close = 2147483652u,
24 PingPong = 2147483653u,
25 UnsolicitedPong = 2147483654u
26 }
27
37
38 internal enum ActionQueue
39 {
40 Send = 1,
42 }
43
44 private static readonly string s_dummyWebsocketKeyBase64;
45
46 private static readonly IntPtr s_webSocketDllHandle;
47
48 private static readonly string s_supportedVersion;
49
50 private static readonly global::Interop.WebSocket.HttpHeader[] s_initialClientRequestHeaders;
51
52 private static readonly global::Interop.WebSocket.HttpHeader[] s_ServerFakeRequestHeaders;
53
54 internal static string SupportedVersion
55 {
56 get
57 {
58 if (!IsSupported)
59 {
61 }
62 return s_supportedVersion;
63 }
64 }
65
66 internal static bool IsSupported => s_webSocketDllHandle != IntPtr.Zero;
67
69 {
71 s_initialClientRequestHeaders = new global::Interop.WebSocket.HttpHeader[2]
72 {
73 new global::Interop.WebSocket.HttpHeader
74 {
75 Name = "Connection",
76 NameLength = (uint)"Connection".Length,
77 Value = "Upgrade",
78 ValueLength = (uint)"Upgrade".Length
79 },
80 new global::Interop.WebSocket.HttpHeader
81 {
82 Name = "Upgrade",
83 NameLength = (uint)"Upgrade".Length,
84 Value = "websocket",
85 ValueLength = (uint)"websocket".Length
86 }
87 };
88 s_webSocketDllHandle = global::Interop.Kernel32.LoadLibraryEx("websocket.dll", IntPtr.Zero, 0);
90 {
92 s_ServerFakeRequestHeaders = new global::Interop.WebSocket.HttpHeader[5]
93 {
94 new global::Interop.WebSocket.HttpHeader
95 {
96 Name = "Connection",
97 NameLength = (uint)"Connection".Length,
98 Value = "Upgrade",
99 ValueLength = (uint)"Upgrade".Length
100 },
101 new global::Interop.WebSocket.HttpHeader
102 {
103 Name = "Upgrade",
104 NameLength = (uint)"Upgrade".Length,
105 Value = "websocket",
106 ValueLength = (uint)"websocket".Length
107 },
108 new global::Interop.WebSocket.HttpHeader
109 {
110 Name = "Host",
111 NameLength = (uint)"Host".Length,
112 Value = string.Empty,
113 ValueLength = 0u
114 },
115 new global::Interop.WebSocket.HttpHeader
116 {
117 Name = "Sec-WebSocket-Version",
118 NameLength = (uint)"Sec-WebSocket-Version".Length,
119 Value = s_supportedVersion,
120 ValueLength = (uint)s_supportedVersion.Length
121 },
122 new global::Interop.WebSocket.HttpHeader
123 {
124 Name = "Sec-WebSocket-Key",
125 NameLength = (uint)"Sec-WebSocket-Key".Length,
127 ValueLength = (uint)s_dummyWebsocketKeyBase64.Length
128 }
129 };
130 }
131 }
132
133 internal static string GetSupportedVersion()
134 {
135 if (!IsSupported)
136 {
138 }
139 SafeWebSocketHandle webSocketHandle = null;
140 try
141 {
142 int errorCode = global::Interop.WebSocket.WebSocketCreateClientHandle(null, 0u, out webSocketHandle);
143 ThrowOnError(errorCode);
144 if (webSocketHandle == null || webSocketHandle.IsInvalid)
145 {
147 }
148 errorCode = global::Interop.WebSocket.WebSocketBeginClientHandshake(webSocketHandle, IntPtr.Zero, 0u, IntPtr.Zero, 0u, s_initialClientRequestHeaders, (uint)s_initialClientRequestHeaders.Length, out var additionalHeadersPtr, out var additionalHeaderCount);
149 ThrowOnError(errorCode);
150 global::Interop.WebSocket.HttpHeader[] array = MarshalHttpHeaders(additionalHeadersPtr, (int)additionalHeaderCount);
151 string result = null;
152 global::Interop.WebSocket.HttpHeader[] array2 = array;
153 for (int i = 0; i < array2.Length; i++)
154 {
155 global::Interop.WebSocket.HttpHeader httpHeader = array2[i];
156 if (string.Equals(httpHeader.Name, "Sec-WebSocket-Version", StringComparison.OrdinalIgnoreCase))
157 {
158 result = httpHeader.Value;
159 break;
160 }
161 }
162 return result;
163 }
164 finally
165 {
166 webSocketHandle?.Dispose();
167 }
168 }
169
170 internal static void WebSocketCreateServerHandle(global::Interop.WebSocket.Property[] properties, int propertyCount, out SafeWebSocketHandle webSocketHandle)
171 {
172 if (!IsSupported)
173 {
175 }
176 int errorCode = global::Interop.WebSocket.WebSocketCreateServerHandle(properties, (uint)propertyCount, out webSocketHandle);
177 ThrowOnError(errorCode);
178 if (webSocketHandle == null || webSocketHandle.IsInvalid)
179 {
181 }
182 errorCode = global::Interop.WebSocket.WebSocketBeginServerHandshake(webSocketHandle, IntPtr.Zero, IntPtr.Zero, 0u, s_ServerFakeRequestHeaders, (uint)s_ServerFakeRequestHeaders.Length, out var _, out var _);
183 ThrowOnError(errorCode);
184 errorCode = global::Interop.WebSocket.WebSocketEndServerHandshake(webSocketHandle);
185 ThrowOnError(errorCode);
186 }
187
188 internal static void WebSocketAbortHandle(SafeHandle webSocketHandle)
189 {
190 global::Interop.WebSocket.WebSocketAbortHandle(webSocketHandle);
191 DrainActionQueue(webSocketHandle, ActionQueue.Send);
192 DrainActionQueue(webSocketHandle, ActionQueue.Receive);
193 }
194
195 internal static void WebSocketDeleteHandle(IntPtr webSocketPtr)
196 {
197 global::Interop.WebSocket.WebSocketDeleteHandle(webSocketPtr);
198 }
199
200 internal static void WebSocketSend(WebSocketBase webSocket, BufferType bufferType, global::Interop.WebSocket.Buffer buffer)
201 {
203 int errorCode;
204 try
205 {
206 errorCode = global::Interop.WebSocket.WebSocketSend_Raw(webSocket.SessionHandle, bufferType, ref buffer, IntPtr.Zero);
207 }
208 catch (ObjectDisposedException innerException)
209 {
210 throw ConvertObjectDisposedException(webSocket, innerException);
211 }
212 ThrowOnError(errorCode);
213 }
214
215 internal static void WebSocketSendWithoutBody(WebSocketBase webSocket, BufferType bufferType)
216 {
218 int errorCode;
219 try
220 {
221 errorCode = global::Interop.WebSocket.WebSocketSendWithoutBody_Raw(webSocket.SessionHandle, bufferType, IntPtr.Zero, IntPtr.Zero);
222 }
223 catch (ObjectDisposedException innerException)
224 {
225 throw ConvertObjectDisposedException(webSocket, innerException);
226 }
227 ThrowOnError(errorCode);
228 }
229
230 internal static void WebSocketReceive(WebSocketBase webSocket)
231 {
233 int errorCode;
234 try
235 {
236 errorCode = global::Interop.WebSocket.WebSocketReceive(webSocket.SessionHandle, IntPtr.Zero, IntPtr.Zero);
237 }
238 catch (ObjectDisposedException innerException)
239 {
240 throw ConvertObjectDisposedException(webSocket, innerException);
241 }
242 ThrowOnError(errorCode);
243 }
244
245 internal static void WebSocketGetAction(WebSocketBase webSocket, ActionQueue actionQueue, global::Interop.WebSocket.Buffer[] dataBuffers, ref uint dataBufferCount, out Action action, out BufferType bufferType, out IntPtr actionContext)
246 {
247 action = Action.NoAction;
248 bufferType = BufferType.None;
249 actionContext = IntPtr.Zero;
251 int errorCode;
252 try
253 {
254 errorCode = global::Interop.WebSocket.WebSocketGetAction(webSocket.SessionHandle, actionQueue, dataBuffers, ref dataBufferCount, out action, out bufferType, out var _, out actionContext);
255 }
256 catch (ObjectDisposedException innerException)
257 {
258 throw ConvertObjectDisposedException(webSocket, innerException);
259 }
260 ThrowOnError(errorCode);
261 webSocket.ValidateNativeBuffers(action, bufferType, dataBuffers, dataBufferCount);
262 }
263
264 internal static void WebSocketCompleteAction(WebSocketBase webSocket, IntPtr actionContext, int bytesTransferred)
265 {
266 if (webSocket.SessionHandle.IsClosed)
267 {
268 return;
269 }
270 try
271 {
272 global::Interop.WebSocket.WebSocketCompleteAction(webSocket.SessionHandle, actionContext, (uint)bytesTransferred);
273 }
275 {
276 }
277 }
278
279 private static void DrainActionQueue(SafeHandle webSocketHandle, ActionQueue actionQueue)
280 {
281 while (true)
282 {
283 global::Interop.WebSocket.Buffer[] dataBuffers = new global::Interop.WebSocket.Buffer[1];
284 uint dataBufferCount = 1u;
286 BufferType bufferType;
287 IntPtr applicationContext;
288 IntPtr actionContext;
289 int hr = global::Interop.WebSocket.WebSocketGetAction(webSocketHandle, actionQueue, dataBuffers, ref dataBufferCount, out action, out bufferType, out applicationContext, out actionContext);
290 if (!Succeeded(hr) || action == Action.NoAction)
291 {
292 break;
293 }
294 global::Interop.WebSocket.WebSocketCompleteAction(webSocketHandle, actionContext, 0u);
295 }
296 }
297
298 private static void MarshalAndVerifyHttpHeader(IntPtr httpHeaderPtr, ref global::Interop.WebSocket.HttpHeader httpHeader)
299 {
300 IntPtr intPtr = Marshal.ReadIntPtr(httpHeaderPtr);
301 IntPtr ptr = IntPtr.Add(httpHeaderPtr, IntPtr.Size);
302 int num = Marshal.ReadInt32(ptr);
303 if (intPtr != IntPtr.Zero)
304 {
305 httpHeader.Name = Marshal.PtrToStringAnsi(intPtr, num);
306 }
307 if ((httpHeader.Name == null && num != 0) || (httpHeader.Name != null && num != httpHeader.Name.Length))
308 {
309 throw new AccessViolationException();
310 }
311 int offset = 2 * IntPtr.Size;
312 int offset2 = 3 * IntPtr.Size;
313 IntPtr ptr2 = Marshal.ReadIntPtr(IntPtr.Add(httpHeaderPtr, offset));
314 ptr = IntPtr.Add(httpHeaderPtr, offset2);
315 num = Marshal.ReadInt32(ptr);
316 httpHeader.Value = Marshal.PtrToStringAnsi(ptr2, num);
317 if ((httpHeader.Value == null && num != 0) || (httpHeader.Value != null && num != httpHeader.Value.Length))
318 {
319 throw new AccessViolationException();
320 }
321 }
322
323 private static global::Interop.WebSocket.HttpHeader[] MarshalHttpHeaders(IntPtr nativeHeadersPtr, int nativeHeaderCount)
324 {
325 global::Interop.WebSocket.HttpHeader[] array = new global::Interop.WebSocket.HttpHeader[nativeHeaderCount];
326 int num = 4 * IntPtr.Size;
327 for (int i = 0; i < nativeHeaderCount; i++)
328 {
329 int offset = num * i;
330 IntPtr httpHeaderPtr = IntPtr.Add(nativeHeadersPtr, offset);
331 MarshalAndVerifyHttpHeader(httpHeaderPtr, ref array[i]);
332 }
333 return array;
334 }
335
336 public static bool Succeeded(int hr)
337 {
338 return hr >= 0;
339 }
340
341 private static void ThrowOnError(int errorCode)
342 {
343 if (Succeeded(errorCode))
344 {
345 return;
346 }
347 throw new WebSocketException(errorCode);
348 }
349
350 private static void ThrowIfSessionHandleClosed(WebSocketBase webSocket)
351 {
352 if (webSocket.SessionHandle.IsClosed)
353 {
354 throw new WebSocketException(WebSocketError.InvalidState, System.SR.Format(System.SR.net_WebSockets_InvalidState_ClosedOrAborted, webSocket.GetType().FullName, webSocket.State));
355 }
356 }
357
359 {
360 return new WebSocketException(WebSocketError.InvalidState, System.SR.Format(System.SR.net_WebSockets_InvalidState_ClosedOrAborted, webSocket.GetType().FullName, webSocket.State), innerException);
361 }
362}
static string ToBase64String(byte[] inArray)
Definition Convert.cs:2675
static void ThrowPlatformNotSupportedException_WSPC()
void ValidateNativeBuffers(WebSocketProtocolComponent.Action action, WebSocketProtocolComponent.BufferType bufferType, global::Interop.WebSocket.Buffer[] dataBuffers, uint dataBufferCount)
static void DrainActionQueue(SafeHandle webSocketHandle, ActionQueue actionQueue)
static readonly global::Interop.WebSocket.HttpHeader[] s_initialClientRequestHeaders
static WebSocketException ConvertObjectDisposedException(WebSocketBase webSocket, ObjectDisposedException innerException)
static void WebSocketSend(WebSocketBase webSocket, BufferType bufferType, global::Interop.WebSocket.Buffer buffer)
static void WebSocketGetAction(WebSocketBase webSocket, ActionQueue actionQueue, global::Interop.WebSocket.Buffer[] dataBuffers, ref uint dataBufferCount, out Action action, out BufferType bufferType, out IntPtr actionContext)
static void MarshalAndVerifyHttpHeader(IntPtr httpHeaderPtr, ref global::Interop.WebSocket.HttpHeader httpHeader)
static global::Interop.WebSocket.HttpHeader[] MarshalHttpHeaders(IntPtr nativeHeadersPtr, int nativeHeaderCount)
static void WebSocketAbortHandle(SafeHandle webSocketHandle)
static void ThrowIfSessionHandleClosed(WebSocketBase webSocket)
static void WebSocketSendWithoutBody(WebSocketBase webSocket, BufferType bufferType)
static void WebSocketCompleteAction(WebSocketBase webSocket, IntPtr actionContext, int bytesTransferred)
static readonly global::Interop.WebSocket.HttpHeader[] s_ServerFakeRequestHeaders
static void WebSocketCreateServerHandle(global::Interop.WebSocket.Property[] properties, int propertyCount, out SafeWebSocketHandle webSocketHandle)
static IntPtr ReadIntPtr(object ptr, int ofs)
Definition Marshal.cs:976
static int ReadInt32(object ptr, int ofs)
Definition Marshal.cs:59
static unsafe? string PtrToStringAnsi(IntPtr ptr)
Definition Marshal.cs:630
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 int Size
Definition IntPtr.cs:21
static IntPtr Add(IntPtr pointer, int offset)
Definition IntPtr.cs:185
static readonly IntPtr Zero
Definition IntPtr.cs:18