protected override bool CheckAuthentication(Context context) { if (context.ReceivedByteCount > 8) { var handshake = new ClientHandshake(context.Header); // See if our header had the required information if (handshake.IsValid()) { // Optionally check Origin and Location if they're set. if (!String.IsNullOrEmpty(Origin)) { if (handshake.Origin != "http://" + Origin) { return false; } } if (!String.IsNullOrEmpty(Destination)) { if (handshake.Host != Destination + ":" + context.Server.Port) { return false; } } // Generate response handshake for the client var serverShake = GenerateResponseHandshake(handshake, context.Server); // Send the response handshake SendServerHandshake(serverShake, context); return true; } } return false; }
private static void SendServerHandshake(ServerHandshake handshake, Context context) { // generate a byte array representation of the handshake including the answer to the challenge string temp = handshake.ToString(); byte[] handshakeBytes = Encoding.UTF8.GetBytes(temp); context.UserContext.Send(handshakeBytes, true); }
private static void SendServerHandshake(ServerHandshake handshake, Context context) { // generate a byte array representation of the handshake including the answer to the challenge byte[] handshakeBytes = Encoding.UTF8.GetBytes(handshake.ToString()); Array.Copy(handshake.AnswerBytes, 0, handshakeBytes, handshakeBytes.Length - 16, 16); context.UserContext.Send(handshakeBytes, true); }
/// <summary> /// Handles the initial request. /// Attempts to process the header that should have been sent. /// Otherwise, through magic and wizardry, the client gets disconnected. /// </summary> /// <param name="context">The user context.</param> public virtual void HandleRequest(Context context) { if (context.IsSetup) { context.Disconnect(); } else { ProcessHeader(context); } }
/// <summary> /// Attempts to authenticates the specified user context. /// If authentication fails it kills the connection. /// </summary> /// <param name="context">The user context.</param> public void Authenticate(Context context) { if (CheckAuthentication(context)) { context.UserContext.Protocol = context.Header.Protocol; context.UserContext.RequestPath = context.Header.RequestPath; context.Header = null; context.IsSetup = true; context.UserContext.OnConnected(); } else { context.Disconnect(); } }
/// <summary> /// Handles the request. /// </summary> /// <param name="context">The user context.</param> public override void HandleRequest(Context context) { if (context.IsSetup) { context.UserContext.DataFrame.Append(context.Buffer, true); if (context.UserContext.DataFrame.Length <= context.MaxFrameSize) { switch (context.UserContext.DataFrame.State) { case DataFrame.DataState.Complete: context.UserContext.OnReceive(); break; case DataFrame.DataState.Closed: DataFrame closeFrame = context.UserContext.DataFrame.CreateInstance(); closeFrame.State = DataFrame.DataState.Closed; closeFrame.Append(new byte[] { 0x8 }, true); context.UserContext.Send(closeFrame, false, true); break; case DataFrame.DataState.Ping: context.UserContext.DataFrame.State = DataFrame.DataState.Complete; DataFrame dataFrame = context.UserContext.DataFrame.CreateInstance(); dataFrame.State = DataFrame.DataState.Pong; List<ArraySegment<byte>> pingData = context.UserContext.DataFrame.AsRaw(); foreach (var item in pingData) { dataFrame.Append(item.Array); } context.UserContext.Send(dataFrame); break; case DataFrame.DataState.Pong: context.UserContext.DataFrame.State = DataFrame.DataState.Complete; break; } } else { context.Disconnect(); //Disconnect if over MaxFrameSize } } else { Authentication.Authenticate(context); } }
/// <summary> /// Processes the header. /// </summary> /// <param name="context">The user context.</param> public void ProcessHeader(Context context) { string data = Encoding.UTF8.GetString(context.Buffer, 0, context.ReceivedByteCount); //Check first to see if this is a flash socket XML request. if (data == "<policy-file-request/>\0") { //if it is, we access the Access Policy Server instance to send the appropriate response. context.Server.AccessPolicyServer.SendResponse(context.Connection); context.Disconnect(); } else //If it isn't, process http/websocket header as normal. { context.Header = new Header(data); switch (context.Header.Protocol) { case Protocol.WebSocketHybi00: context.Handler.UnregisterContext(context); context.Handler = WebSocket.hybi00.Handler.Instance; context.UserContext.DataFrame = new WebSocket.hybi00.DataFrame(); context.Handler.RegisterContext(context); break; case Protocol.WebSocketRFC6455: context.Handler.UnregisterContext(context); context.Handler = WebSocket.rfc6455.Handler.Instance; context.UserContext.DataFrame = new WebSocket.rfc6455.DataFrame(); context.Handler.RegisterContext(context); break; default: context.Header.Protocol = Protocol.None; break; } if (context.Header.Protocol != Protocol.None) { context.Handler.HandleRequest(context); } else { context.UserContext.Send(Response.NotImplemented, true, true); } } }
protected override bool CheckAuthentication(Context context) { if (context.ReceivedByteCount > 8) { var handshake = new ClientHandshake(new ArraySegment<byte>(context.Buffer, context.ReceivedByteCount - 8, 8), context.Header); // See if our header had the required information if (handshake.IsValid()) { // Optionally check Origin and Location if they're set. if (!String.IsNullOrEmpty(Origin)) { var expectedOrigin = Origin; if (!Origin.Contains("://")) { expectedOrigin = "http://" + Origin; } if (!handshake.Origin.Equals(expectedOrigin, StringComparison.InvariantCultureIgnoreCase)) { return false; } } if (!String.IsNullOrEmpty(Destination)) { if (handshake.Host != Destination + ":" + context.Server.Port) { return false; } } // Generate response handshake for the client var serverShake = GenerateResponseHandshake(handshake, context.Server); // Send the response handshake SendServerHandshake(serverShake, context); return true; } } return false; }
/// <summary> /// Fires when a client connects. /// </summary> /// <param name="result">null</param> protected void OnRunClient(IAsyncResult result) { bool connectError = false; try { _client.EndConnect(result); } catch { Disconnect(); connectError = true; } using (_context = new Context(null, _client)) { _context = new Context(null, _client); _context.BufferSize = 512; _context.UserContext.DataFrame = new DataFrame(); _context.UserContext.SetOnConnect(OnConnect); _context.UserContext.SetOnConnected(OnConnected); _context.UserContext.SetOnDisconnect(OnDisconnect); _context.UserContext.SetOnSend(OnSend); _context.UserContext.SetOnReceive(OnReceive); _context.UserContext.OnConnect(); if (connectError) { _context.UserContext.OnDisconnect(); return; } lock (ContextMapping) { ContextMapping[_context] = this; } lock (NewClients) { NewClients.Enqueue(_context); } } }
private void StartReceive(Context _context) { try { if (!_context.ReceiveEventArgs_StartAsync()) { ReceiveEventArgs_Completed(_context.Connection.Client, _context.ReceiveEventArgs); } } catch (OperationCanceledException) { } catch (SocketException ex) { //logger.Error("SocketException in StartReceive", ex); _context.UserContext.LatestException = ex; _context.Disconnect(); } }
private void SetupContext(Context context) { _context.ReceiveEventArgs.UserToken = _context; _context.ReceiveEventArgs.Completed += ReceiveEventArgs_Completed; _context.ReceiveEventArgs.SetBuffer(_context.Buffer, 0, _context.Buffer.Length); if (_context.Connection != null && _context.Connection.Connected) { _context.ReceiveReady.Wait(); // mjb /* if (!_context.Connection.Client.ReceiveAsync(_context.ReceiveEventArgs)) { ReceiveEventArgs_Completed(_context.Connection.Client, _context.ReceiveEventArgs); } */ if (_context.SslStream != null) { ReceiveWorker rw = new ReceiveWorker() { webSocketClient = this, context = _context }; Thread tw = new Thread(rw.Receive); tw.Start(); } else { if (!_context.Connection.Client.ReceiveAsync(_context.ReceiveEventArgs)) { ReceiveEventArgs_Completed(_context.Connection.Client, _context.ReceiveEventArgs); } } if (!IsAuthenticated) { Authenticate(); } } }
///<summary> /// Starts the asynchronous connection process. /// User callbacks are: OnConnected() when successful - or OnDisconnect() in case of failure. /// UserContext.Data will contain the data object passed here. /// Timeout is defined by the TCP stack. ///</summary> public void BeginConnect(object data) { if (_client != null) return; _context = new Context(null, null); _context.BufferSize = 512; _context.UserContext.DataFrame = new DataFrame(); _context.UserContext.SetOnConnect(OnConnect); _context.UserContext.SetOnConnected(OnConnected); _context.UserContext.SetOnDisconnect(OnDisconnect); _context.UserContext.SetOnSend(OnSend); _context.UserContext.SetOnReceive(OnReceive); _context.UserContext.Data = data; try { ReadyState = ReadyStates.CONNECTING; _context.UserContext.OnConnect(); _client = new TcpClient(); _context.Connection = _client; _connecting = true; _client.BeginConnect(_host, _port, OnClientConnected, null); } catch (Exception ex) { Disconnect(); _context.UserContext.LatestException = ex; _context.UserContext.OnDisconnect(); } }
/// <summary> /// Fires when a client connects. /// </summary> /// <param name="data">The TCP Connection.</param> protected override void OnRunClient(object data) { var connection = (TcpClient)data; using (var context = new Context(this, connection)) { context.UserContext.ClientAddress = context.Connection.Client.RemoteEndPoint; context.UserContext.SetOnConnect(OnConnect); context.UserContext.SetOnConnected(OnConnected); context.UserContext.SetOnDisconnect(OnDisconnect); context.UserContext.SetOnSend(OnSend); context.UserContext.SetOnReceive(OnReceive); context.BufferSize = BufferSize; context.UserContext.OnConnect(); while (context.Connected) { if (context.ReceiveReady.Wait(TimeOut)) { try { context.Connection.Client.BeginReceive(context.Buffer, 0, context.Buffer.Length, SocketFlags.None, DoReceive, context); } catch (SocketException) { break; } } else { break; } } } }
private void SetupContext(Context _context) { _context.ReceiveEventArgs.UserToken = _context; _context.ReceiveEventArgs.Completed += ReceiveEventArgs_Completed; _context.ReceiveEventArgs.SetBuffer(_context.Buffer, 0, _context.Buffer.Length); StartReceive(_context); }
/// <summary> /// Initializes a new instance of the <see cref="UserContext"/> class. /// </summary> /// <param name="context">The user context.</param> public UserContext(Context context) { Context = context; UniqueKey = Guid.NewGuid().ToString("N"); }
/// <summary> /// Initializes a new instance of the <see cref="UserContext"/> class. /// </summary> /// <param name="context">The user context.</param> public UserContext(Context context) { Context = context; }
private void SetupContext(Context context) { _context.ReceiveEventArgs.UserToken = _context; _context.ReceiveEventArgs.Completed += ReceiveEventArgs_Completed; _context.ReceiveEventArgs.SetBuffer(_context.Buffer, 0, _context.Buffer.Length); if (_context.Connection != null && _context.Connection.Connected) { _context.ReceiveReady.Wait(); if (!_context.Connection.Client.ReceiveAsync(_context.ReceiveEventArgs)) { ReceiveEventArgs_Completed(_context.Connection.Client, _context.ReceiveEventArgs); } if (!IsAuthenticated) { Authenticate(); } } }
private bool CheckAuthenticationResponse(Context context) { var receivedData = context.UserContext.DataFrame.ToString(); var header = new Header(receivedData); var handshake = new ServerHandshake(header); if (Authentication.GenerateAccept(_handshake.Key) != handshake.Accept) return false; if (SubProtocols != null) { if (header.SubProtocols == null) { return false; } foreach (var s in SubProtocols) { if (header.SubProtocols.Contains(s) && String.IsNullOrEmpty(CurrentProtocol)) { CurrentProtocol = s; } } if(String.IsNullOrEmpty(CurrentProtocol)) { return false; } } ReadyState = ReadyStates.OPEN; IsAuthenticated = true; _connecting = false; context.UserContext.OnConnected(); return true; }
private void StartReceive(Context _context) { if (_context.ReceiveReady.Wait(TimeOut)) { try { if (!_context.Connection.Client.ReceiveAsync(_context.ReceiveEventArgs)) { ReceiveEventArgs_Completed(_context.Connection.Client, _context.ReceiveEventArgs); } } catch { //logger.Error("SocketException in ReceieveAsync", ex); _context.Disconnect(); } } else { //logger.Error("Timeout waiting for ReceiveReady"); _context.Disconnect(); } }
private void StartReceive(Context _context) { if (_context.ReceiveReady.Wait(TimeOut)) { try { // mjb /* if (!_context.Connection.Client.ReceiveAsync(_context.ReceiveEventArgs)) { ReceiveEventArgs_Completed(_context.Connection.Client, _context.ReceiveEventArgs); } */ if (_context.SslStream != null) { ReceiveWorker rw = new ReceiveWorker() { context = _context }; Thread tw = new Thread(rw.Receive); tw.Start(); } else { if (!_context.Connection.Client.ReceiveAsync(_context.ReceiveEventArgs)) { ReceiveEventArgs_Completed(_context.Connection.Client, _context.ReceiveEventArgs); } } } catch (SocketException ex) { //logger.Error("SocketException in ReceieveAsync", ex); _context.Disconnect(); } } else { //logger.Error("Timeout waiting for ReceiveReady"); _context.Disconnect(); } }
private void ReceiveData(Context context) { if (!IsAuthenticated) { var someBytes = new byte[context.ReceivedByteCount]; Array.Copy(context.Buffer, 0, someBytes, 0, context.ReceivedByteCount); context.UserContext.DataFrame.Append(someBytes); var authenticated = CheckAuthenticationResponse(context); context.UserContext.DataFrame.Reset(); if (!authenticated) { Disconnect(); } } else { context.UserContext.DataFrame.Append(context.Buffer, true); if (context.UserContext.DataFrame.State == Handlers.WebSocket.DataFrame.DataState.Complete) { context.UserContext.OnReceive(); context.UserContext.DataFrame.Reset(); } } }
/// <summary> /// Fires when a client connects. /// </summary> /// <param name="result">null</param> protected void OnRunClient(IAsyncResult result) { try { _client.EndConnect(result); } catch (Exception) { Disconnect(); OnFailedConnection(null); return; } using (_context = new Context(null, _client)) { _context.BufferSize = 512; _context.UserContext.DataFrame = new DataFrame(); _context.UserContext.SetOnConnect(OnConnect); _context.UserContext.SetOnConnected(OnConnected); _context.UserContext.SetOnDisconnect(OnDisconnect); _context.UserContext.SetOnSend(OnSend); _context.UserContext.SetOnReceive(OnReceive); _context.UserContext.OnConnect(); while (_context.Connection.Connected) { _context.ReceiveReady.Wait(); try { _context.Connection.Client.BeginReceive(_context.Buffer, 0, _context.Buffer.Length, SocketFlags.None, DoReceive, _context); } catch (Exception) { break; } if (!IsAuthenticated) { Authenticate(); } } } Disconnect(); }
/// <summary> /// Handles the request. /// </summary> /// <param name="context">The user context.</param> public override void HandleRequest(Context context) { int count = 0; if (context.IsSetup) { int remaining = context.ReceivedByteCount; while (remaining > 0) { count++; // add bytes to existing or empty frame int readCount = context.UserContext.DataFrame.Append(context.Buffer, remaining, true); if (readCount <= 0) { break; // partial header } else if (context.UserContext.DataFrame.Length >= context.MaxFrameSize) { context.Disconnect(); //Disconnect if over MaxFrameSize break; } else { switch (context.UserContext.DataFrame.State) { case DataFrame.DataState.Complete: context.UserContext.OnReceive(); break; case DataFrame.DataState.Closed: context.UserContext.DataFrame.State = DataFrame.DataState.Complete; // see http://stackoverflow.com/questions/17176827/websocket-close-packet, DataState.Closed is only set by rfc6455 var closeFrame = new byte[] { 0x88, 0x00 }; context.UserContext.Send(closeFrame, raw:true, close:true); break; case DataFrame.DataState.Ping: context.UserContext.DataFrame.State = DataFrame.DataState.Complete; DataFrame dataFrame = context.UserContext.DataFrame.CreateInstance(); dataFrame.State = DataFrame.DataState.Pong; List<ArraySegment<byte>> pingData = context.UserContext.DataFrame.AsRaw(); foreach (var item in pingData) { dataFrame.Append(item.Array); } context.UserContext.Send(dataFrame); break; case DataFrame.DataState.Pong: context.UserContext.DataFrame.State = DataFrame.DataState.Complete; break; } remaining -= readCount; // process rest of received bytes if (remaining > 0) { context.Reset(); // starts new message when DataState.Complete // move remaining bytes to beginning of array Array.Copy(context.Buffer, readCount, context.Buffer, 0, remaining); } } } } else { Authentication.Authenticate(context); } }
/// <summary> /// Sends the specified data. /// </summary> /// <param name="dataFrame">The data.</param> /// <param name="context">The user context.</param> /// <param name="raw">whether or not to send raw data</param> /// <param name="close">if set to <c>true</c> [close].</param> public void Send(DataFrame dataFrame, Context context, bool raw = false, bool close = false) { if (context.Connected) { AsyncCallback callback = EndSend; if (close) { callback = EndSendAndClose; } context.SendReady.Wait(); try { List<ArraySegment<byte>> data = raw ? dataFrame.AsRaw() : dataFrame.AsFrame(); context.Connection.Client.BeginSend(data, SocketFlags.None, callback, context); } catch { context.Disconnect(); } } }
/// <summary> /// Fires when a client connects. /// </summary> /// <param name="data">The TCP Connection.</param> protected override void OnRunClient(object data) { var connection = (TcpClient)data; var context = new Context(this, connection); context.UserContext.ClientAddress = context.Connection.Client.RemoteEndPoint; context.UserContext.SetOnConnect(OnConnect); context.UserContext.SetOnConnected(OnConnected); context.UserContext.SetOnDisconnect(OnDisconnect); context.UserContext.SetOnSend(OnSend); context.UserContext.SetOnReceive(OnReceive); context.BufferSize = BufferSize; context.UserContext.OnConnect(); if (context.Connected) { lock (ContextMapping) { ContextMapping[context] = this; } ContextQueue.Enqueue(context); } }
/// <summary> /// Sends the specified data. /// </summary> /// <param name="dataFrame">The data.</param> /// <param name="context">The user context.</param> /// <param name="raw">whether or not to send raw data</param> /// <param name="close">if set to <c>true</c> [close].</param> public void Send(DataFrame dataFrame, Context context, bool raw = false, bool close = false) { if (context.Connected) { HandlerMessage message = new HandlerMessage { DataFrame = dataFrame, Context = context, IsRaw = raw, DoClose = close }; MessageQueue.Enqueue(message); } }
private void StartReceive(Context _context) { if (!_context.Connected) return; try { if (_context.ReceiveReady.Wait(TimeOut, cancellation.Token)) { try { if (!_context.Connection.Client.ReceiveAsync(_context.ReceiveEventArgs)) { ReceiveEventArgs_Completed(_context.Connection.Client, _context.ReceiveEventArgs); } } catch (SocketException ex) { //logger.Error("SocketException in ReceieveAsync", ex); _context.Disconnect(); } } else { //logger.Error("Timeout waiting for ReceiveReady"); _context.Disconnect(); } } catch (OperationCanceledException) { } }
public void UnregisterContext(Context context) { context.SendEventArgs.Completed -= SendEventArgs_Completed; }
protected abstract bool CheckAuthentication(Context context);
private void ReceiveData(Context context) { if (!IsAuthenticated) { var someBytes = new byte[context.ReceivedByteCount]; Array.Copy(context.Buffer, 0, someBytes, 0, context.ReceivedByteCount); context.UserContext.DataFrame.Append(someBytes); var authenticated = CheckAuthenticationResponse(context); context.UserContext.DataFrame.Reset(); if (!authenticated) { Disconnect(); _context.UserContext.LatestException = new Exception("could not authenticate web socket server"); _context.UserContext.OnDisconnect(); } } else { int remaining = context.ReceivedByteCount; while (remaining > 0) { // add bytes to existing or empty frame int readCount = context.UserContext.DataFrame.Append(context.Buffer, remaining, true); if (readCount <= 0) { break; // partial header } else if (context.UserContext.DataFrame.State == Handlers.WebSocket.DataFrame.DataState.Complete) { // pass frame to user code and start new frame context.UserContext.OnReceive(); context.UserContext.DataFrame.Reset(); } remaining -= readCount; // process rest of received bytes if (remaining > 0) { // move remaining bytes to beginning of array Array.Copy(context.Buffer, readCount, context.Buffer, 0, remaining); } } } }