public bool CheckHandshake(Context context) { if(context.ReceivedByteCount > 8) { ClientHandshake 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 (Origin != string.Empty) if (handshake.Origin != "http://" + Origin) return false; if (Location != string.Empty) if (handshake.Host != Location + ":" + context.Server.Port.ToString()) return false; // Generate response handshake for the client ServerHandshake serverShake = GenerateResponseHandshake(handshake, context); serverShake.SubProtocol = handshake.SubProtocol; // Send the response handshake SendServerHandshake(serverShake, context); return true; } } return false; }
public static bool CheckHandshake(Context AContext) { if(AContext.ReceivedByteCount > 8) { ClientHandshake AHandshake = new ClientHandshake(new ArraySegment<byte>(AContext.Buffer, AContext.ReceivedByteCount-8, 8), AContext.Header); // See if our header had the required information if (AHandshake.IsValid()) { // Optionally check Origin and Location if they're set. if (Origin != string.Empty) if (AHandshake.Origin != "http://" + Origin) return false; if (Location != string.Empty) if (AHandshake.Host != Location + ":" + AContext.Server.Port.ToString()) return false; // Generate response handshake for the client ServerHandshake ServerShake = GenerateResponseHandshake(AHandshake); // Send the response handshake SendServerHandshake(ServerShake, AContext); return true; } } return false; }
private static string GenerateAccept(string key, Context context) { string rawAnswer = key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; // Create a hash of the rawAnswer and return it SHA1 hasher = SHA1.Create(); return Convert.ToBase64String(hasher.ComputeHash(context.UserContext.Encoding.GetBytes(rawAnswer))); }
/// <summary> /// Fires when a client connects. /// </summary> /// <param name="AConnection">The TCP Connection.</param> protected override void OnRunClient(TcpClient connection) { using (Context context = new Context()) { context.Server = this; context.Connection = connection; context.UserContext.ClientAddress = context.Connection.Client.RemoteEndPoint; context.UserContext.SetOnConnect(DefaultOnConnect); context.UserContext.SetOnDisconnect(DefaultOnDisconnect); context.UserContext.SetOnSend(DefaultOnSend); context.UserContext.SetOnReceive(DefaultOnReceive); context.BufferSize = _defaultBufferSize; context.UserContext.OnConnect(); try { while (context.Connection.Connected) { if (context.ReceiveReady.Wait(TimeOut)) { context.Connection.Client.BeginReceive(context.Buffer, 0, context.Buffer.Length, SocketFlags.None, DoReceive, context); } else { break; } } } catch (Exception e) { Log.Debug("Client Forcefully Disconnected", e); } } }
/// <summary> /// Runs the client. /// Sets up the UserContext. /// Executes in it's own thread. /// Utilizes a semaphore(ReceiveReady) to limit the number of receive events active for this client to 1 at a time. /// </summary> /// <param name="AResult">The A result.</param> private void RunClient(IAsyncResult AResult) { TcpClient AConnection = null; try { if (Listener != null) AConnection = Listener.EndAcceptTcpClient(AResult); } catch (Exception) { Log.Error("[WS_SERVER]: Connection to client failed."); } ConnectReady.Release(); if(AConnection != null) { ClientLock.Wait(); _Clients++; ClientLock.Release(); using (Context AContext = new Context()) //each client has its own context { AContext.Server = this; AContext.Connection = AConnection; AContext.UserContext.ClientAddress = AContext.Connection.Client.RemoteEndPoint; AContext.UserContext.SetOnConnect(DefaultOnConnect); AContext.UserContext.SetOnDisconnect(DefaultOnDisconnect); AContext.UserContext.SetOnSend(DefaultOnSend); AContext.UserContext.SetOnReceive(DefaultOnReceive); AContext.BufferSize = DefaultBufferSize; AContext.UserContext.OnConnect(); try { // message listener, per client while (AContext.Connection.Connected) { if (AContext.ReceiveReady.Wait(TimeOut)) { AContext.Connection.Client.BeginReceive(AContext.Buffer, 0, AContext.Buffer.Length, SocketFlags.None, new AsyncCallback(DoReceive), AContext); } else { break; } } } catch { Log.Info("[WS_SERVER]: Client disconnected 1."); } } ClientLock.Wait(); _Clients--; ClientLock.Release(); } }
/// <summary> /// Attempts to authenticates the specified user context. /// If authentication fails it kills the connection. /// </summary> /// <param name="AContext">The user context.</param> private void Authenticate(Context AContext) { if (AContext.Handler.Authentication.CheckHandshake(AContext)) { AContext.UserContext.Protocol = AContext.Header.Protocol; AContext.UserContext.RequestPath = AContext.Header.RequestPath; AContext.Header = null; AContext.IsSetup = true; } else { AContext.Dispose(); } }
/// <summary> /// Handles the request. /// </summary> /// <param name="AContext">The user context.</param> public override void HandleRequest(Context AContext) { if (AContext.IsSetup) { AContext.UserContext.DataFrame.Append(AContext.Buffer); if (AContext.UserContext.DataFrame.State == DataFrame.DataState.Complete) { switch (AContext.UserContext.DataFrame.Length) { case 1: //Process Command string ACommand = AContext.UserContext.DataFrame.ToString(); if (ACommand == AContext.Server.PingCommand) { SendPingResponse(AContext); AContext.Pings++; } else { AContext.Pings = 0; AContext.UserContext.OnReceive(); } if ((AContext.Pings >= AContext.Server.MaxPingsInSequence) && (AContext.Server.MaxPingsInSequence != 0)) { AContext.Dispose(); } break; default: AContext.Pings = 0; AContext.UserContext.OnReceive(); break; } } else if (AContext.UserContext.DataFrame.State == DataFrame.DataState.Closed) { AContext.UserContext.Send(new byte[0], true); } } else { Authenticate(AContext); } }
private static ServerHandshake GenerateResponseHandshake(ClientHandshake AHandshake, Context AContext) { ServerHandshake AResponseHandshake = new ServerHandshake(); AResponseHandshake.Accept = GenerateAccept(AHandshake.Key, AContext); return AResponseHandshake; }
/// <summary> /// Runs the client. /// Sets up the UserContext. /// Executes in it's own thread. /// Utilizes a semaphore(ReceiveReady) to limit the number of receive events active for this client to 1 at a time. /// </summary> /// <param name="AResult">The A result.</param> private void RunClient(IAsyncResult AResult) { TcpClient AConnection = null; try { if (Listener != null) AConnection = Listener.EndAcceptTcpClient(AResult); } catch (Exception e) { Log.Debug("Connect Failed", e); } ConnectReady.Release(); if(AConnection != null) { ClientLock.Wait(); _Clients++; ClientLock.Release(); using (Context AContext = new Context()) { AContext.Server = this; AContext.Connection = AConnection; AContext.UserContext.ClientAddress = AContext.Connection.Client.RemoteEndPoint; AContext.UserContext.SetOnConnect(DefaultOnConnect); AContext.UserContext.SetOnDisconnect(DefaultOnDisconnect); AContext.UserContext.SetOnSend(DefaultOnSend); AContext.UserContext.SetOnReceive(DefaultOnReceive); AContext.BufferSize = DefaultBufferSize; AContext.UserContext.OnConnect(); try { while (AContext.Connection.Connected) { if (AContext.ReceiveReady.Wait(TimeOut)) { AContext.Connection.Client.BeginReceive(AContext.Buffer, 0, AContext.Buffer.Length, SocketFlags.None, DoReceive, AContext); } else { break; } } } catch (Exception e) { Log.Debug("Client Forcefully Disconnected", e); } } ClientLock.Wait(); _Clients--; ClientLock.Release(); } }
/// <summary> /// Processes the header. /// </summary> /// <param name="context">The user context.</param> public void ProcessHeader(Context context) { string data = context.UserContext.Encoding.GetString(context.Buffer, 0, context.ReceivedByteCount); //Check first to see if this is a flash socket XML request. if (data == "<policy-file-request/>\0") { try { //if it is, we access the Access Policy Server instance to send the appropriate response. context.Server.AccessPolicyServer.SendResponse(context.Connection); } catch { } context.Dispose(); } 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 = Alchemy.Server.Handlers.WebSocket.hybi00.WebSocketHandler.Instance; context.UserContext.DataFrame = new Alchemy.Server.Handlers.WebSocket.hybi00.DataFrame(); break; case Protocol.WebSocketHybi10: context.Handler = Alchemy.Server.Handlers.WebSocket.hybi10.WebSocketHandler.Instance; context.UserContext.DataFrame = new Alchemy.Server.Handlers.WebSocket.hybi10.DataFrame(); break; case Protocol.FlashSocket: context.Handler = Alchemy.Server.Handlers.WebSocket.hybi00.WebSocketHandler.Instance; context.UserContext.DataFrame = new Alchemy.Server.Handlers.WebSocket.hybi00.DataFrame(); 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); } } }
/// <summary> /// Sends the ping response. /// </summary> /// <param name="context">The user context.</param> private static void SendPingResponse(Context context) { context.UserContext.Send(context.Server.PongCommand); }
/// <summary> /// Attempts to authenticates the specified user context. /// If authentication fails it kills the connection. /// </summary> /// <param name="context">The user context.</param> private static void Authenticate(Context context) { if (context.Handler.Authentication.CheckHandshake(context)) { context.UserContext.Protocol = context.Header.Protocol; context.UserContext.RequestPath = context.Header.RequestPath; context.Header = null; context.IsSetup = true; } else { context.Dispose(); } }
/// <summary> /// Initializes a new instance of the <see cref="UserContext"/> class. /// </summary> /// <param name="AContext">The user context.</param> public UserContext(Context AContext) { this.Context = AContext; }
private static ServerHandshake GenerateResponseHandshake(ClientHandshake handshake, Context context) { ServerHandshake responseHandshake = new ServerHandshake(); responseHandshake.Accept = GenerateAccept(handshake.Key, context); return responseHandshake; }
/// <summary> /// Sends the specified data. /// </summary> /// <param name="data">The data.</param> /// <param name="context">The user context.</param> /// <param name="close">if set to <c>true</c> [close].</param> public override void Send(byte[] data, Context context, bool close = false) { byte[] wrappedData = context.UserContext.DataFrame.Wrap(data); AsyncCallback callback = EndSend; if (close) callback = EndSendAndClose; context.SendReady.Wait(); try { context.Connection.Client.BeginSend(wrappedData, 0, wrappedData.Length, SocketFlags.None, callback, context); } catch { context.SendReady.Release(); } }
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 = context.UserContext.Encoding.GetBytes(temp); context.UserContext.SendRaw(handshakeBytes); }
/// <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="AContext">The user context.</param> public override void HandleRequest(Context AContext) { if (AContext.IsSetup) { AContext.Dispose(); } else { ProcessHeader(AContext); } }
private static void SendServerHandshake(ServerHandshake AHandshake, Context AContext) { // generate a byte array representation of the handshake including the answer to the challenge byte[] HandshakeBytes = AContext.UserContext.Encoding.GetBytes(AHandshake.ToString()); Array.Copy(AHandshake.AnswerBytes, 0, HandshakeBytes, HandshakeBytes.Length-16, 16); AContext.UserContext.SendRaw(HandshakeBytes); }
/// <summary> /// Processes the header. /// </summary> /// <param name="AContext">The user context.</param> public void ProcessHeader(Context AContext) { string Data = AContext.UserContext.Encoding.GetString(AContext.Buffer, 0, AContext.ReceivedByteCount); AContext.Header = new Header(Data); switch (AContext.Header.Protocol) { case Protocol.WebSocket: AContext.Handler = WebSocketHandler.Instance; break; default: AContext.Header.Protocol = Protocol.None; break; } if (AContext.Header.Protocol != Protocol.None) { AContext.Handler.HandleRequest(AContext); } else { AContext.UserContext.Send(Response.NotImplemented, true); } }
/// <summary> /// Initializes a new instance of the <see cref="UserContext"/> class. /// </summary> /// <param name="context">The user context.</param> public UserContext(Context AContext) { this.Context = AContext; this.Header = this.Context.Header; }
public abstract void HandleRequest(Context Request);
/// <summary> /// Sends the specified data. /// </summary> /// <param name="Data">The data.</param> /// <param name="AContext">The user context.</param> /// <param name="Close">if set to <c>true</c> [close].</param> public override void Send(byte[] Data, Context AContext, bool Close = false) { byte[] WrappedData = AContext.UserContext.DataFrame.Wrap(Data); AsyncCallback ACallback = EndSend; if (Close) ACallback = EndSendAndClose; AContext.SendReady.Wait(); try { AContext.Connection.Client.BeginSend(WrappedData, 0, WrappedData.Length, SocketFlags.None, ACallback, AContext); } catch { AContext.SendReady.Release(); } }
public abstract void Send(byte[] Data, Context AContext, bool Close = false);
/// <summary> /// Sends the ping response. /// </summary> /// <param name="AContext">The user context.</param> private void SendPingResponse(Context AContext) { AContext.UserContext.Send(AContext.Server.PongCommand); }
/// <summary> /// Sends the specified data. /// </summary> /// <param name="Data">The data.</param> /// <param name="AContext">The user context.</param> /// <param name="Close">if set to <c>true</c> [close].</param> public override void Send(byte[] Data, Context AContext, bool Close = false) { byte[] WrappedData = DataFrame.Wrap(Data); AsyncCallback ACallback = EndSend; if (Close) ACallback = EndSendAndClose; //AContext.SendReady.Wait(); try { AContext.SendReady.Wait(); if (AContext.Connection != null) { AContext.Connection.Client.BeginSend(WrappedData, 0, WrappedData.Length, SocketFlags.None, ACallback, AContext); } } catch { //Console.WriteLine("[WebSocketHandler]: Exception sending"); //AContext.SendReady.Release(); } AContext.SendReady.Release(); }