You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Gateway/Mime/HttpWebSocket.cs

363 lines
11 KiB
C#

2 years ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
2 years ago
using System.IO;
1 year ago
using System.Net.Sockets;
2 years ago
using System.Text;
using UMC.Net;
namespace UMC.Host
{
1 year ago
public class NetWebSocket : UMC.Net.MimeRequest, IDisposable
{
NetWriteData _writer;
Action _close;
Guid _device;
public NetWebSocket(NetWriteData writeData, Guid device, Action close)
{
this._writer = writeData;
this._close = close;
this._device = device;
if (_WebSockets.TryGetValue(device, out var webSocket))
{
webSocket.Dispose();
}
_WebSockets[_device] = this;
}
public static void Send(Guid device, String msg)
{
if (_WebSockets.TryGetValue(device, out var webSocket))
{
webSocket.Send(msg);
};
}
internal static ConcurrentDictionary<Guid, NetWebSocket> _WebSockets = new ConcurrentDictionary<Guid, NetWebSocket>();
1 year ago
byte[] _buffers = Array.Empty<byte>();
int _buferSize = 0;
2 years ago
void Send(String msg)
2 years ago
{
var bs = new List<byte>();
bs.Add(0x81);
var by = System.Text.Encoding.UTF8.GetBytes(msg);
if (by.Length < 126)
{
bs.Add((byte)by.Length);
}
else if (by.Length < UInt16.MaxValue)
{
bs.Add(126);
UInt16 v = (UInt16)by.Length;
var bx = new byte[2];
BitConverter.TryWriteBytes(bx, v);
bs.AddRange(bx);
}
else
{
bs.Add(127);
ulong v = (ulong)by.Length;
var bx = new byte[4];
BitConverter.TryWriteBytes(bx, v);
bs.AddRange(bx);
}
bs.AddRange(by);
this._writer(bs.ToArray(), 0, bs.Count);
2 years ago
}
public override void Receive(byte[] buffer, int offset, int size)
{
if (_buferSize > 0)
{
var len = size + _buferSize;
if (len > _buffers.Length)
{
if (_buffers.Length < len)
{
var bs = System.Buffers.ArrayPool<byte>.Shared.Rent(len);
Array.Copy(_buffers, 0, _buffers, 0, _buferSize);
if (_buffers.Length > 0)
{
System.Buffers.ArrayPool<byte>.Shared.Return(_buffers);
}
_buffers = bs;
};
Array.Copy(buffer, offset, _buffers, _buferSize, size);
_buferSize += size;
Frame(buffer, 0, _buferSize);
}
}
else
{
Frame(buffer, offset, size);
2 years ago
}
}
void Frame(byte[] buffer, int offset, int size)
2 years ago
{
byte len = buffer[offset + 1];
int start = 2;
var isMask = len >> 7 == 1;
len <<= 1;
len >>= 1;
int length = len;//<<= 1;
switch (length)
2 years ago
{
case 126:
start += 2;
length = BitConverter.ToUInt16(buffer, buffer[2]);
break;
case 127:
start += 8;
length = Convert.ToInt32(BitConverter.ToUInt64(buffer, buffer[2]));
break;
2 years ago
}
if (isMask)
2 years ago
{
start += 4;
}
var opcode = buffer[offset];
opcode <<= 4;
opcode >>= 4;
if ((start + length) <= size)
{
if (isMask)
{
var mask = new byte[4];
Array.Copy(buffer, offset + start - 4, mask, 0, 4);
for (uint i = 0; i < length; i++)
{
buffer[offset + start + i] ^= mask[i % 4];
}
//;
switch (opcode)
{
case 0x00:
break;
case 0x01:
case 0x02:
break;
case 0x08:
this.Dispose();
break;
case 0x89:
case 0x09:
// var byt2e = buffer[offset + 1];
buffer[offset + 1] = len;// (byte)(byt2e << 1 >> 1);
buffer[offset] = 0x8a;
Array.Copy(buffer, offset + start, buffer, offset + start - 4, length);
this._writer(buffer, offset, length + start - 4);
break;
case 0x0A:
break;
}
}
else
{
switch (opcode)
{
case 0x00:
break;
case 0x01:
case 0x02:
break;
case 0x08:
this.Dispose();
break;
case 0x89:
case 0x09:
buffer[offset] = 0x8a;
Array.Copy(buffer, offset + start, buffer, offset + start - 4, length);
this._writer(buffer, offset, length + start - 4);
break;
case 0x0A:
break;
}
}
_buferSize = 0;
if (start + length < size)
{
Frame(buffer, offset + start + length, size - start - length);
}
}
else if (_buferSize == 0)
{
if (_buffers.Length < size)
{
if (_buffers.Length > 0)
{
System.Buffers.ArrayPool<byte>.Shared.Return(_buffers);
}
_buffers = System.Buffers.ArrayPool<byte>.Shared.Rent(size);
};
_buferSize = size;
Array.Copy(buffer, offset, _buffers, 0, size);
2 years ago
}
}
protected override void Header(byte[] data, int offset, int size)
{
// throw new NotImplementedException();
}
internal static string GetSecWebSocketAcceptString(string secWebSocketKey)
{//258EAFA5-E914-47DA-95CA-C5AB0DC85B11
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(HttpMimeRequest context)
2 years ago
{
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;
}
public void Dispose()
2 years ago
{
_WebSockets.TryRemove(this._device, out var _);
_close();
2 years ago
if (_buffers.Length > 0)
{
System.Buffers.ArrayPool<byte>.Shared.Return(_buffers);
}
// throw new NotImplementedException();
}
}
2 years ago
abstract class WebSocket : UMC.Net.MimeRequest, IDisposable
{
public override bool IsWebSocket => true;
public abstract void Dispose();
2 years ago
}
1 year ago
class HttpWebSocket : WebSocket
{
public byte[] buffer = System.Buffers.ArrayPool<byte>.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<byte>.Shared.Return(buffer);
buffer = null;
}
}
2 years ago
}