public void Close() { SynchronizeWhenNot(WebSocketClientState.None, () => { _state = WebSocketClientState.Disconnecting; _websocket.Close(CloseStatusCode.Normal, "User invoked close"); }); }
internal WebSocketClient(NetMQSocket streamSocket, byte[] identity) { m_state = WebSocketClientState.Closed; m_streamSocket = streamSocket; m_outgoingMessage = null; Identity = identity; }
public void Close() { // TODO: send close message m_streamSocket.Send(Identity, Identity.Length, true, true); m_streamSocket.Send(""); m_state = WebSocketClientState.Closed; }
public bool Send(byte[] message, bool dontWait, bool more) { int frameSize = 2 + 1 + message.Length; int payloadStartIndex = 2; int payloadLength = message.Length + 1; if (payloadLength > 125) { frameSize += 2; payloadStartIndex += 2; if (payloadLength > ushort.MaxValue) { frameSize += 6; payloadStartIndex += 6; } } byte[] frame = new byte[frameSize]; frame[0] = (byte)0x81; // Text and Final // No mask frame[1] = 0x00; if (payloadLength <= 125) { frame[1] |= (byte)(payloadLength & 127); } else { // TODO: implement } // more byte frame[payloadStartIndex] = (byte)(more ? '1' : '0'); payloadStartIndex++; // payload Buffer.BlockCopy(message, 0, frame, payloadStartIndex, message.Length); try { m_streamSocket.SendMore(Identity, Identity.Length, dontWait); m_streamSocket.Send(frame, frame.Length, dontWait); return(true); } catch (AgainException againException) { return(false); } catch (NetMQException exception) { m_state = WebSocketClientState.Closed; throw exception; } }
public void Close() { // TODO: send close message if (m_streamSocket.TrySendFrame(Identity, Identity.Length, true)) { m_streamSocket.TrySendFrame(""); } m_state = WebSocketClientState.Closed; }
private async Task OnMessage(WebSocketClientState state, string wsMessage) { if (string.IsNullOrWhiteSpace(wsMessage) || wsMessage.Length < 1) { return; } Message msg = Message.Deserialize(wsMessage.Substring(0, wsMessage.Length - 1)); await this.Dispatcher.HandleMessageAsync(state, msg); }
public void Open() { SynchronizeWhen(WebSocketClientState.None, () => { _websocket = new WebSocket(_hostUri.ToString()); _websocket.OnOpen += OnOpen; _websocket.OnClose += OnClose; _websocket.OnMessage += OnMessage; _websocket.OnError += OnError; _state = WebSocketClientState.Connecting; _websocket.ConnectAsync(); }); }
private void OnMessage(object sender, MessageEventArgs e) { if (e.Opcode == OpcodeEnum.Close) { // send close command to the socket try { if (m_streamSocket.TrySendFrame(Identity, Identity.Length, true)) { m_streamSocket.TrySendFrame(""); } } catch (NetMQException) { } m_state = WebSocketClientState.Closed; } else if (e.Opcode == OpcodeEnum.Binary) { if (m_outgoingMessage == null) { m_outgoingMessage = new NetMQMessage(); } m_outgoingMessage.Append(e.Payload); if (!e.More) { if (IncomingMessage != null) { IncomingMessage(this, new NetMQMessageEventArgs(Identity, m_outgoingMessage)); } m_outgoingMessage = null; } } else if (e.Opcode == OpcodeEnum.Ping) { byte[] pong = new byte[2 + e.Payload.Length]; pong[0] = 0x8A; // Pong and Final pong[1] = (byte)(e.Payload.Length & 127); Buffer.BlockCopy(e.Payload, 0, pong, 2, e.Payload.Length); if (m_streamSocket.TrySendFrame(Identity, Identity.Length, true)) { m_streamSocket.TrySendFrame(pong); } } }
private void Synchronize(Action action, Func <bool> predicate = null) { bool stateChanged; lock (_mutex) { WebSocketClientState state = _state; if (predicate == null || predicate()) { action(); } stateChanged = _state != state; } // notify outside lock to avoid deadlock if (stateChanged) { _webSocketClientCallback.OnStateChanged(); } }
internal override Task RunAsync() { this.Server.Start(socket => { socket.OnOpen = () => { WebSocketClientState state = new WebSocketClientState(socket); this.States.AddOrUpdate(socket.ConnectionInfo.Id, state, (_, __) => state); }; socket.OnClose = () => { this.States.Remove(socket.ConnectionInfo.Id, out WebSocketClientState _); }; socket.OnMessage = async wsMsg => { if (this.States.ContainsKey(socket.ConnectionInfo.Id)) { await this.OnMessage(this.States[socket.ConnectionInfo.Id], wsMsg); } }; socket.OnPing = async wsBinaryMsg => { if (this.States.ContainsKey(socket.ConnectionInfo.Id)) { WebSocketClientState state = this.States[socket.ConnectionInfo.Id]; if (state.IsRegistered) { await socket.SendPong(wsBinaryMsg); } } }; }); this.Logger.Nice("Web Socket Server", ConsoleColor.Magenta, $"Running on {this.Server.Location}"); return(Task.CompletedTask); }
public void OnDataReady() { switch (m_state) { case WebSocketClientState.Closed: m_state = WebSocketClientState.Handshake; string clientHandshake = m_streamSocket.ReceiveFrameString(); string[] lines = clientHandshake.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); string key; if (ValidateClientHandshake(lines, out key)) { string acceptKey = GenerateAcceptKey(key); try { if (m_streamSocket.TrySendFrame(Identity, Identity.Length, true) && m_streamSocket.TrySendFrame("HTTP/1.1 101 Switching Protocols\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Accept: " + acceptKey + "\r\n" + "Sec-WebSocket-Protocol: WSNetMQ\r\n\r\n")) { m_decoder = new Decoder(); m_decoder.Message += OnMessage; m_state = WebSocketClientState.Ready; } else { m_state = WebSocketClientState.Closed; } } catch (NetMQException) { m_state = WebSocketClientState.Closed; } } else { m_state = WebSocketClientState.Closed; if (m_streamSocket.TrySendFrame(Identity, Identity.Length, true)) { m_streamSocket.TrySendFrame("HTTP/1.1 400 Bad Request\r\nSec-WebSocket-Version: 13\r\n"); } // invalid request, close the socket and raise closed event if (m_streamSocket.TrySendFrame(Identity, Identity.Length, true)) { m_streamSocket.TrySendFrame(""); } } break; case WebSocketClientState.Ready: byte[] message = m_streamSocket.ReceiveFrameBytes(); m_decoder.Process(message); break; default: throw new ArgumentOutOfRangeException(); } }
public void Disconnect() { if (client == null) return; Debug.Assert(state == WebSocketClientState.Open || state == WebSocketClientState.Handshaking); state = WebSocketClientState.Closing; context.UserContext.Send(DataFrame.CloseResponseFrame); Dispose(); state = WebSocketClientState.Closed; }
/// <summary> /// Begin connecting to a WebSocket server. Upon returning from this method, the server /// will be in the Handshaking state. This means the client is waiting for the handshake /// response from the server. Messages may not be sent until the OnConnected event has fired. /// </summary> public void BeginConnect() { if (state != WebSocketClientState.Closed) throw new InvalidOperationException(); try { state = WebSocketClientState.Connecting; client = new TcpClient(); client.Connect(host, port); state = WebSocketClientState.Handshaking; context = CreateContext(); StartContext(context); } catch (Exception e) { state = WebSocketClientState.Closed; throw e; } }
private void ProcessData(Context context) { if (state == WebSocketClientState.Handshaking) { // Assuming we've read the whole response, and that this response has no payload // Definitely not gaurenteed to be true var someBytes = new byte[context.ReceivedByteCount]; Array.Copy(context.Buffer, someBytes, context.ReceivedByteCount); var authenticated = CheckAuthenticationResponse(someBytes); frameReader = new DataFrameReaderRfc6455(); if (!authenticated) { Disconnect(); } else { state = WebSocketClientState.Open; context.UserContext.OnConnected(); } } else { Debug.Assert(state == WebSocketClientState.Open); frameReader.Append(context.Buffer, context.ReceivedByteCount); foreach (var frameData in frameReader.ReadFrames()) context.UserContext.OnReceive(frameData); } }
private void OnSocketClose() { OnDisconnect(this.context.UserContext); state = WebSocketClientState.Closed; Dispose(); }
// Event Handlers private void OnOpen(object sender, EventArgs e) { Synchronize(() => _state = WebSocketClientState.Connected); _webSocketClientCallback.OnOpen(); }
private void OnClose(object sender, CloseEventArgs e) { Synchronize(() => _state = WebSocketClientState.Disconnected); _webSocketClientCallback.OnClose(); }
private void OnMessage(object sender, MessageEventArgs e) { if (e.Opcode == OpcodeEnum.Close) { // send close command to the socket try { m_streamSocket.SendMore(Identity, Identity.Length, true); m_streamSocket.Send(""); } catch (NetMQException) { } m_state = WebSocketClientState.Closed; } else if (e.Opcode == OpcodeEnum.Binary) { if (m_outgoingMessage == null) { m_outgoingMessage = new NetMQMessage(); } m_outgoingMessage.Append(e.Payload); if (!e.More) { if (IncomingMessage != null) { IncomingMessage(this, new NetMQMessageEventArgs(Identity, m_outgoingMessage)); } m_outgoingMessage = null; } } else if (e.Opcode == OpcodeEnum.Ping) { byte[] pong = new byte[2 + e.Payload.Length]; pong[0] = 0x8A; // Pong and Final pong[1] = (byte)(e.Payload.Length & 127); Buffer.BlockCopy(e.Payload, 0, pong, 2, e.Payload.Length); m_streamSocket.SendMore(Identity, Identity.Length, true); m_streamSocket.Send(pong); } }
public bool Send(byte[] message, bool dontWait, bool more) { int frameSize = 2 + 1 + message.Length; int payloadStartIndex = 2; int payloadLength = message.Length + 1; if (payloadLength > 125) { frameSize += 2; payloadStartIndex += 2; if (payloadLength > ushort.MaxValue) { frameSize += 6; payloadStartIndex += 6; } } byte[] frame = new byte[frameSize]; frame[0] = (byte)0x81; // Text and Final // No mask frame[1] = 0x00; if (payloadLength <= 125) { frame[1] |= (byte)(payloadLength & 127); } else { // TODO: implement } // more byte frame[payloadStartIndex] = (byte)(more ? '1' : '0'); payloadStartIndex++; // payload Buffer.BlockCopy(message, 0, frame, payloadStartIndex, message.Length); try { m_streamSocket.SendMore(Identity, Identity.Length, dontWait); m_streamSocket.Send(frame, frame.Length, dontWait); return true; } catch (AgainException againException) { return false; } catch (NetMQException exception) { m_state = WebSocketClientState.Closed; throw exception; } }
private void SynchronizeWhenNot(WebSocketClientState state, Action action) => Synchronize(action, () => _state != state);
public void OnDataReady() { switch (m_state) { case WebSocketClientState.Closed: m_state = WebSocketClientState.Handshake; string clientHandshake = m_streamSocket.ReceiveString(); string[] lines = clientHandshake.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); string key; if (ValidateClientHandshake(lines, out key)) { string acceptKey = GenerateAcceptKey(key); try { m_streamSocket.SendMore(Identity, Identity.Length, true); m_streamSocket.Send("HTTP/1.1 101 Switching Protocols\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Accept: " + acceptKey + "\r\n" + "Sec-WebSocket-Protocol: WSNetMQ\r\n\r\n"); m_decoder = new Decoder(); m_decoder.Message += OnMessage; m_state = WebSocketClientState.Ready; } catch (NetMQException) { m_state = WebSocketClientState.Closed; } } else { m_state = WebSocketClientState.Closed; try { m_streamSocket.SendMore(Identity, Identity.Length, true); m_streamSocket.Send("HTTP/1.1 400 Bad Request\r\nSec-WebSocket-Version: 13\r\n"); // invalid request, close the socket and raise closed event m_streamSocket.SendMore(Identity, Identity.Length, true); m_streamSocket.Send(""); } catch (NetMQException ex) { } } break; case WebSocketClientState.Ready: byte[] message = m_streamSocket.Receive(); m_decoder.Process(message); break; default: throw new ArgumentOutOfRangeException(); } }