private async void RttRoutine() { while (Running && !RttToken.IsCancellationRequested) { try { await Task.Delay(RttInterval, RttToken.Token); } catch (Exception) { } if (!RttToken.IsCancellationRequested) { foreach (var keypair in Users) { WebSocketUser user = keypair.Value; if (user.RTT.Sending) { user.RTT.Last = RttInterval; if (user.RTT.Max < RttInterval) { user.RTT.Max = RttInterval; OnRTT?.Invoke(this, new RttEventArgs(user)); } } user.RTT.Sending = true; user.RTT.Sent = DateTime.UtcNow; await user.Writer.WriteCustomPing(); } } } }
private async Task <(bool, string)> InterpretHeader(WebSocketUser user, Stream ns) { string header = await HttpUtils.ReadHeader(ns); Regex getRegex = new Regex(@"^GET(.*)HTTP\/1\.1", RegexOptions.IgnoreCase); Match getRegexMatch = getRegex.Match(header); if (getRegexMatch.Success) { string[] lines = header.Split('\n'); foreach (string line in lines) { if (line.ToLower().StartsWith("user-agent:")) { int index = line.IndexOf(':') + 1; if (index >= line.Length) { break; } user.Meta.UserAgent = line.Substring(index, line.Length - index).Trim(); break; } } await DoHandshake(ns, header); return(true, header); } return(false, header); }
public void RemoveClient(WebSocketUser user, WebSocketDisconnection reason) { try { if (user == null) { return; } user.Disconnected = true; WebSocketUser outer; if (Users.ContainsKey(user.UID)) { Users.TryRemove(user.UID, out outer); } if (user.ListenToken != null) { user.ListenToken.Cancel(); } if (user.Socket != null) { user.Socket.Shutdown(SocketShutdown.Both); } } catch (Exception) { } Logger.DebugWrite("INFO", $"Socket got removed. UID: {user.UID}, Reason: {reason}"); OnDisconnect?.Invoke(this, new DisconnectEventArgs(user, reason)); }
private void OnPongReceived(WebSocketUser user) { if (user.RTT.Sending) { user.RTT.Sending = false; var span = DateTime.UtcNow - user.RTT.Sent; var ms = user.RTT.Last = span.TotalMilliseconds; if (ms < user.RTT.Min || user.RTT.Min == -1) { user.RTT.Min = ms; } if (ms > user.RTT.Max) { user.RTT.Max = ms; } OnRTT?.Invoke(this, new RttEventArgs(user)); //Logger.DebugWrite("INFO", $"RTT Last {user.RTT.Last} / {user.RTT.Min} / {user.RTT.Max}"); } }
public WebSocketWriter(WebSocketUser user) { User = user; Stream = user.Stream; }
private async Task ListenClient(WebSocketUser user) { using (Stream ns = user.Stream) { WebSocketReader reader = new WebSocketReader(); var res = await InterpretHeader(user, ns); if (!(res.Item1)) { RemoveClient(user, WebSocketDisconnection.NoHeader); return; } Logger.DebugWrite("INFO", $"Socket successfully handshaked the update. UID: {user.UID}"); OnHandshake?.Invoke(this, new HandshakeEventArgs(user, res.Item2)); while (Running && !user.ListenToken.IsCancellationRequested) { WebSocketFrame frame = await reader.Read(ns, user); if (frame == null || frame.Opcode == WebSocketOpcode.ConnectionCloseFrame) { RemoveClient(user, WebSocketDisconnection.Disconnect); break; } switch (frame.Opcode) { case WebSocketOpcode.PingFrame: if (frame.Data.Length <= 125) { await user.Writer.WritePong(frame); OnPing?.Invoke(this, new PingEventArgs(frame.Data)); } break; case WebSocketOpcode.PongFrame: OnPong?.Invoke(this, new PongEventArgs(frame.Data)); break; case WebSocketOpcode.BinaryFrame: user.Meta.LastTime.Binary = DateTime.UtcNow; if (RttEnabled && frame.Data.Length == 4 && frame.Data[0] == 26 && frame.Data[1] == 27 && frame.Data[2] == 28 && frame.Data[3] == 29) { OnPongReceived(user); } OnMessage?.Invoke(this, new MessageEventArgs(user, frame)); break; case WebSocketOpcode.TextFrame: user.Meta.LastTime.Text = DateTime.UtcNow; OnMessage?.Invoke(this, new MessageEventArgs(user, frame)); break; } } } }
private async void Listen() { Socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp); Socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false); Socket.Bind(new IPEndPoint(Address, Port)); Socket.Listen(Backlog); Logger.DebugWrite("INFO", $"WebSocket Server is now listening to new connections."); while (Running && !ListenToken.IsCancellationRequested) { Socket socket = null; try { socket = await Socket.AcceptAsync(); } catch (Exception) { continue; } WebSocketUser user = new WebSocketUser() { Socket = socket, Stream = await GetStream(socket), UID = RandomGen.GenRandomUID(Users, 128), Server = this }; if (user.Stream == null) { try { user.Socket.Shutdown(SocketShutdown.Both); } catch (Exception) { } continue; } while (!Users.TryAdd(user.UID, user)) { user.UID = RandomGen.GenRandomUID(Users, 12); } user.Writer = new WebSocketWriter(user); Logger.DebugWrite("INFO", $"New Socket connected to the WebSocket Server. {(user.Socket.RemoteEndPoint as IPEndPoint).Address}, UID: {user.UID}"); OnConnect?.Invoke(this, new ConnectEventArgs(user)); CancellationTokenSource cancel = new CancellationTokenSource(); Task task = new Task(async() => { try { await ListenClient(user); } catch (Exception er) { Logger.DebugWrite("FAILED", "Listen Error: ", er); RemoveClient(user, WebSocketDisconnection.Disconnect); } }, cancel.Token, TaskCreationOptions.LongRunning); task.Start(); user.ListenTask = task; user.ListenToken = cancel; } }
public async Task <WebSocketFrame> Read(Stream stream, WebSocketUser user) { byte first; try { byte[] firstData = new byte[1]; await stream.ReadAsync(firstData, 0, firstData.Length); first = firstData[0]; } catch (Exception) { return(null); } //if (user != null && !WebSocketUtils.IsClientConnected(user)) { // return null; //} try { byte bitFinFlag = 0x80; byte opcodeFlag = 0x0F; bool bitFinSet = (first & bitFinFlag) == bitFinFlag; WebSocketOpcode opcode = (WebSocketOpcode)(first & opcodeFlag); byte bitMaskFlag = 0x80; byte[] secData = new byte[1]; await stream.ReadAsync(secData, 0, secData.Length); byte second = secData[0]; bool bitMaskSet = (second & bitMaskFlag) == bitMaskFlag; ulong length = await ReadLength(stream, second); if (length != 0) { byte[] decoded; if (bitMaskSet) { byte[] key = await WebSocketReaderWriter.Read(stream, 4); byte[] encoded = await WebSocketReaderWriter.Read(stream, length); decoded = new byte[length]; for (int i = 0; i < encoded.Length; i++) { decoded[i] = (byte)(encoded[i] ^ key[i % 4]); } } else { decoded = await WebSocketReaderWriter.Read(stream, length); } WebSocketFrame frame = new WebSocketFrame(opcode, decoded); return(frame); } } catch (Exception er) { Logger.DebugWrite("FAILED", "Error read bytes: ", er); return(null); } return(null); }