using System; using System.Buffers; using System.IO; using System.Net; using System.Net.Security; using System.Net.Sockets; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Threading.Tasks.Sources; using UMC.Net; namespace UMC.Host { abstract class WebSocket : UMC.Net.MimeRequest, IDisposable { public override bool IsWebSocket => true; public abstract void Dispose(); internal static string GetSecWebSocketAcceptString(string secWebSocketKey) { string s = secWebSocketKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; byte[] bytes = Encoding.UTF8.GetBytes(s); byte[] inArray = System.Security.Cryptography.SHA1.HashData(bytes); return Convert.ToBase64String(inArray); } internal static bool ProcessWebSocketProtocolHeader(string clientSecWebSocketProtocol, out string acceptProtocol) { acceptProtocol = string.Empty; if (string.IsNullOrEmpty(clientSecWebSocketProtocol)) { return false; } string[] array = clientSecWebSocketProtocol.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); if (array.Length > 0) { acceptProtocol = array[0]; } return true; } internal static bool ValidateWebSocketHeaders(NetContext context) { string text = context.Headers["Sec-WebSocket-Version"]; if (string.IsNullOrEmpty(text)) { return false; } if (!string.Equals(text, "13", StringComparison.OrdinalIgnoreCase)) { return false; } string text2 = context.Headers["Sec-WebSocket-Key"]; if (!string.IsNullOrWhiteSpace(text2)) { try { return Convert.FromBase64String(text2).Length == 16; } catch { return false; } } return false; } internal static void AcceptWebSocketAsyncCore(NetContext context, Stream stream) { if (context.Url.AbsolutePath == "/UMC.WS") { var Device = context.Cookies["device"] ?? context.QueryString.Get("device"); if (String.IsNullOrEmpty(Device) == false) { if (ValidateWebSocketHeaders(context) && false) { string secWebSocketKey = context.Headers["Sec-WebSocket-Key"]; string secWebSocketAcceptString = GetSecWebSocketAcceptString(secWebSocketKey); var writer = new Net.TextWriter(stream.Write); writer.Write($"HTTP/1.1 101 {HttpStatusDescription.Get(101)}\r\n"); writer.Write("Connection: Upgrade\r\n"); writer.Write("Upgrade: websocket\r\n"); writer.Write($"Sec-WebSocket-Accept: {secWebSocketAcceptString}\r\n"); writer.Write($"Sec-WebSocket-Protocol: mqtt\r\n"); writer.Write("Server: Apiumc\r\n\r\n"); writer.Flush(); writer.Dispose(); var DeviceId = UMC.Data.Utility.Guid(Device, true).Value; //16384, // context.Tag = WebSocket.CreateFromStream(stream, isServer: true, "mqtt", WebSocket.DefaultKeepAliveInterval); return; } } } context.Error(new ArgumentException("WebSocket")); } } class HttpWebSocket : WebSocket { public byte[] buffer = System.Buffers.ArrayPool.Shared.Rent(0x600); Socket socket; public HttpWebSocket(HttpMime mime, Socket stream) { this.mime = mime; this.socket = stream; SocketAsyncEventArgs eventArgs = new SocketAsyncEventArgs(); eventArgs.SetBuffer(buffer); eventArgs.Completed += Http; if (!this.socket.ReceiveAsync(eventArgs)) { ProcessReceive(eventArgs); } } HttpMime mime; private void Http(object sender, SocketAsyncEventArgs e) { switch (e.LastOperation) { case SocketAsyncOperation.Receive: ProcessReceive(e); break; } } private void ProcessReceive(SocketAsyncEventArgs e) { if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) { try { this.mime.Write(buffer, e.Offset, e.BytesTransferred); if (!socket.ReceiveAsync(e)) { ProcessReceive(e); } } catch { this.Dispose(); } } else { this.Dispose(); } } public override void Receive(byte[] buffer, int offset, int size) { socket.Send(buffer, offset, size, SocketFlags.None); } protected override void Header(byte[] data, int offset, int size) { } public override void Dispose() { this.Dispose(); try { socket.Shutdown(SocketShutdown.Both); } catch { } socket.Close(); System.Buffers.ArrayPool.Shared.Return(buffer); buffer = null; } } }