diff --git a/MTSC-TestClient/Program.cs b/MTSC-TestClient/Program.cs index 1eef162..c7f7710 100644 --- a/MTSC-TestClient/Program.cs +++ b/MTSC-TestClient/Program.cs @@ -10,20 +10,14 @@ namespace MTSC_TestClient static void Main(string[] args) { Client client = new Client(true); - BroadcastHandler broadcastHandler = new BroadcastHandler(); client .SetServerAddress("127.0.0.1") .SetPort(555) .AddHandler(new EncryptionHandler()) - .AddHandler(broadcastHandler) + //.AddHandler(new BroadcastHandler()) .AddLogger(new ConsoleLogger()) .AddLogger(new DebugConsoleLogger()) .Connect(); - while (true) - { - string line = Console.ReadLine(); - broadcastHandler.Broadcast(client, line); - } } } } diff --git a/MTSC-TestServer/Program.cs b/MTSC-TestServer/Program.cs index 51ace0a..e199c2b 100644 --- a/MTSC-TestServer/Program.cs +++ b/MTSC-TestServer/Program.cs @@ -1,4 +1,5 @@ -using MTSC.Exceptions; +using MTSC.Common.Http.ServerModules; +using MTSC.Exceptions; using MTSC.Logging; using MTSC.Server; using MTSC.Server.Handlers; @@ -22,8 +23,8 @@ namespace MTSC_TestServer .AddLogger(new ConsoleLogger()) .AddLogger(new DebugConsoleLogger()) .AddExceptionHandler(new ExceptionConsoleLogger()) - .AddHandler(new BroadcastHandler()) - .AddHandler(new HttpHandler()) + //.AddHandler(new BroadcastHandler()) + .AddHandler(new HttpHandler().AddHttpModule(new Http404Module())) .Run(); } diff --git a/MTSC/Client/Client.cs b/MTSC/Client/Client.cs index ab3d08e..a234692 100644 --- a/MTSC/Client/Client.cs +++ b/MTSC/Client/Client.cs @@ -177,7 +177,9 @@ namespace MTSC.Client } catch(Exception e) { - foreach(IExceptionHandler exceptionHandler in exceptionHandlers) + LogDebug("Exception: " + e.Message); + LogDebug("Stacktrace: " + e.StackTrace); + foreach (IExceptionHandler exceptionHandler in exceptionHandlers) { exceptionHandler.HandleException(e); } @@ -278,6 +280,7 @@ namespace MTSC.Client exceptionHandler.HandleException(e); } } + Thread.Sleep(33); } } #endregion diff --git a/MTSC/Common/Http/HttpMessage.cs b/MTSC/Common/Http/HttpMessage.cs index eaf7968..14387e9 100644 --- a/MTSC/Common/Http/HttpMessage.cs +++ b/MTSC/Common/Http/HttpMessage.cs @@ -322,6 +322,10 @@ namespace MTSC.Common.Http { StringBuilder responseString = new StringBuilder(); responseString.Append(HTTPVER).Append(SP).Append((int)this.StatusCode).Append(SP).Append(this.StatusCode.ToString()).Append(CRLF); + foreach (KeyValuePair header in headers) + { + responseString.Append(header.Key).Append(':').Append(SP).Append(header.Value).Append(CRLF); + } responseString.Append(CRLF); byte[] response = new byte[responseString.Length + (Body == null ? 0 : Body.Length)]; byte[] responseBytes = ASCIIEncoding.ASCII.GetBytes(responseString.ToString()); diff --git a/MTSC/Common/Http/ServerModules/Http404Module.cs b/MTSC/Common/Http/ServerModules/Http404Module.cs new file mode 100644 index 0000000..6a2ea43 --- /dev/null +++ b/MTSC/Common/Http/ServerModules/Http404Module.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Text; +using MTSC.Server; +using MTSC.Server.Handlers; + +namespace MTSC.Common.Http.ServerModules +{ + /// + /// Simple module that returns status code 404. + /// + public class Http404Module : IHttpModule + { + bool IHttpModule.HandleRequest(HttpHandler handler, ClientData client, HttpMessage request) + { + if(request.Method == HttpMessage.MethodEnum.Get) + { + HttpMessage response = new HttpMessage(); + if (request.ContainsHeader(HttpMessage.GeneralHeadersEnum.Connection) && + request[HttpMessage.GeneralHeadersEnum.Connection] == "Keep-Alive") + { + response[HttpMessage.GeneralHeadersEnum.Connection] = "Keep-Alive"; + } + else + { + client.ToBeRemoved = true; + } + response.StatusCode = HttpMessage.StatusCodes.NotFound; + response[HttpMessage.GeneralHeadersEnum.Date] = DateTime.Now.ToString(); + handler.SendResponse(client, response); + } + return false; + } + } +} diff --git a/MTSC/Common/Http/ServerModules/IHttpModule.cs b/MTSC/Common/Http/ServerModules/IHttpModule.cs index 5b160e7..9d09904 100644 --- a/MTSC/Common/Http/ServerModules/IHttpModule.cs +++ b/MTSC/Common/Http/ServerModules/IHttpModule.cs @@ -19,6 +19,6 @@ namespace MTSC.Common.Http.ServerModules /// Client data. /// Request message. /// True if no other module should handle the received request. - bool HandleRequest(IHandler handler, ClientStruct client, HttpMessage request); + bool HandleRequest(HttpHandler handler, ClientData client, HttpMessage request); } } diff --git a/MTSC/CommunicationPrimitives.cs b/MTSC/CommunicationPrimitives.cs index 7fd661a..5620221 100644 --- a/MTSC/CommunicationPrimitives.cs +++ b/MTSC/CommunicationPrimitives.cs @@ -46,18 +46,7 @@ namespace MTSC { stream = client.GetStream(); } - byte[] messageBuffer = new byte[4 + message.MessageLength]; - byte[] lengthBuffer = BitConverter.GetBytes(message.MessageLength); - uint length = message.MessageLength; - messageBuffer[0] = lengthBuffer[0]; - messageBuffer[1] = lengthBuffer[1]; - messageBuffer[2] = lengthBuffer[2]; - messageBuffer[3] = lengthBuffer[3]; - if (message.MessageLength > 0) - { - Array.Copy(message.MessageBytes, 0, messageBuffer, 4, length); - } - stream.Write(messageBuffer, 0, messageBuffer.Length); + stream.Write(message.MessageBytes, 0, (int)message.MessageLength); } public static Message BuildMessage(byte[] msgData) diff --git a/MTSC/Server/Handlers/BroadcastHandler.cs b/MTSC/Server/Handlers/BroadcastHandler.cs index 7042d42..c5873cf 100644 --- a/MTSC/Server/Handlers/BroadcastHandler.cs +++ b/MTSC/Server/Handlers/BroadcastHandler.cs @@ -14,33 +14,33 @@ namespace MTSC.Server.Handlers } - void IHandler.ClientRemoved(Server server, ClientStruct client) + void IHandler.ClientRemoved(Server server, ClientData client) { } - bool IHandler.HandleClient(Server server, ClientStruct client) + bool IHandler.HandleClient(Server server, ClientData client) { return false; } - bool IHandler.HandleReceivedMessage(Server server, ClientStruct client, Message message) + bool IHandler.HandleReceivedMessage(Server server, ClientData client, Message message) { server.LogDebug("Broadcast: " + UnicodeEncoding.Unicode.GetString(message.MessageBytes)); server.LogDebug("From: " + client.TcpClient.Client.RemoteEndPoint.ToString()); - foreach(ClientStruct clientStruct in server.Clients) + foreach(ClientData clientStruct in server.Clients) { server.QueueMessage(clientStruct, message.MessageBytes); } return false; } - bool IHandler.HandleSendMessage(Server server, ClientStruct client, ref Message message) + bool IHandler.HandleSendMessage(Server server, ClientData client, ref Message message) { return false; } - bool IHandler.PreHandleReceivedMessage(Server server, ClientStruct client, ref Message message) + bool IHandler.PreHandleReceivedMessage(Server server, ClientData client, ref Message message) { return false; } diff --git a/MTSC/Server/Handlers/EncryptionHandler.cs b/MTSC/Server/Handlers/EncryptionHandler.cs index d240bc9..d97d174 100644 --- a/MTSC/Server/Handlers/EncryptionHandler.cs +++ b/MTSC/Server/Handlers/EncryptionHandler.cs @@ -24,7 +24,7 @@ namespace MTSC.Server.Handlers public ClientState ClientState = ClientState.Initial; } #region Fields - private Dictionary additionalData; + private Dictionary additionalData; private RSACryptoServiceProvider rsa; private string privateKey, publicKey; #endregion @@ -38,7 +38,7 @@ namespace MTSC.Server.Handlers /// Server object managed by the handler. public EncryptionHandler(RSACryptoServiceProvider rsa) { - additionalData = new Dictionary(); + additionalData = new Dictionary(); this.rsa = rsa; privateKey = HelperFunctions.ToXmlString(rsa, true); publicKey = HelperFunctions.ToXmlString(rsa, false); @@ -123,7 +123,7 @@ namespace MTSC.Server.Handlers /// Called when a client is being removed. /// /// Client to be removed. - void IHandler.ClientRemoved(Server server, ClientStruct client) + void IHandler.ClientRemoved(Server server, ClientData client) { additionalData.Remove(client); } @@ -132,7 +132,7 @@ namespace MTSC.Server.Handlers /// /// New client connection. /// False if an error occurred. - bool IHandler.HandleClient(Server server, ClientStruct client) + bool IHandler.HandleClient(Server server, ClientData client) { additionalData.Add(client, new AdditionalData()); return false; @@ -143,7 +143,7 @@ namespace MTSC.Server.Handlers /// Client connection. /// Received message. /// True if no other handler should handle current message. - bool IHandler.HandleReceivedMessage(Server server, ClientStruct client, Message message) + bool IHandler.HandleReceivedMessage(Server server, ClientData client, Message message) { if (additionalData[client].ClientState == ClientState.Initial || additionalData[client].ClientState == ClientState.Negotiating) { @@ -180,7 +180,7 @@ namespace MTSC.Server.Handlers /// Client connection. /// Message to be processed. /// True if no other handlers should perform operations on current message. - bool IHandler.PreHandleReceivedMessage(Server server, ClientStruct client, ref Message message) + bool IHandler.PreHandleReceivedMessage(Server server, ClientData client, ref Message message) { if (additionalData[client].ClientState == ClientState.Encrypted) { @@ -213,7 +213,7 @@ namespace MTSC.Server.Handlers /// Client object. /// Message to be processed. /// True if no other handler should process this message. - bool IHandler.HandleSendMessage(Server server, ClientStruct client, ref Message message) + bool IHandler.HandleSendMessage(Server server, ClientData client, ref Message message) { if (additionalData[client].ClientState == ClientState.Encrypted) { diff --git a/MTSC/Server/Handlers/HttpHandler.cs b/MTSC/Server/Handlers/HttpHandler.cs index 45c1662..234e5f1 100644 --- a/MTSC/Server/Handlers/HttpHandler.cs +++ b/MTSC/Server/Handlers/HttpHandler.cs @@ -14,6 +14,7 @@ namespace MTSC.Server.Handlers { #region Fields List httpModules = new List(); + Queue> messageQueue = new Queue>(); #endregion #region Constructors public HttpHandler() @@ -36,10 +37,9 @@ namespace MTSC.Server.Handlers /// Send a response back to the client. /// /// Message containing the response. - public void SendResponse(Server server, ClientStruct client, HttpMessage response) + public void SendResponse(ClientData client, HttpMessage response) { - byte[] responseBytes = response.GetResponse(); - server.QueueMessage(client, responseBytes); + messageQueue.Enqueue(new Tuple(client, response)); } #endregion #region Interface Implementation @@ -47,7 +47,7 @@ namespace MTSC.Server.Handlers /// Handler interface implementation. /// /// - void IHandler.ClientRemoved(Server server, ClientStruct client) + void IHandler.ClientRemoved(Server server, ClientData client) { } @@ -56,7 +56,7 @@ namespace MTSC.Server.Handlers /// /// /// - bool IHandler.HandleClient(Server server, ClientStruct client) + bool IHandler.HandleClient(Server server, ClientData client) { return false; } @@ -66,7 +66,7 @@ namespace MTSC.Server.Handlers /// /// /// - bool IHandler.HandleReceivedMessage(Server server, ClientStruct client, Message message) + bool IHandler.HandleReceivedMessage(Server server, ClientData client, Message message) { HttpMessage httpMessage = new HttpMessage(); httpMessage.ParseRequest(message.MessageBytes); @@ -85,7 +85,7 @@ namespace MTSC.Server.Handlers /// /// /// - bool IHandler.HandleSendMessage(Server server, ClientStruct client, ref Message message) + bool IHandler.HandleSendMessage(Server server, ClientData client, ref Message message) { return false; } @@ -95,7 +95,7 @@ namespace MTSC.Server.Handlers /// /// /// - bool IHandler.PreHandleReceivedMessage(Server server, ClientStruct client, ref Message message) + bool IHandler.PreHandleReceivedMessage(Server server, ClientData client, ref Message message) { return false; } @@ -104,7 +104,11 @@ namespace MTSC.Server.Handlers /// void IHandler.Tick(Server server) { - + while(messageQueue.Count > 0) + { + Tuple tuple = messageQueue.Dequeue(); + server.QueueMessage(tuple.Item1, tuple.Item2.GetResponse()); + } } #endregion } diff --git a/MTSC/Server/Handlers/IHandler.cs b/MTSC/Server/Handlers/IHandler.cs index ed0a46b..c6802e0 100644 --- a/MTSC/Server/Handlers/IHandler.cs +++ b/MTSC/Server/Handlers/IHandler.cs @@ -16,7 +16,7 @@ namespace MTSC.Server.Handlers /// Client to be handled. /// Server calling the handler. /// True if the handler processed the client. - bool HandleClient(Server server, ClientStruct client); + bool HandleClient(Server server, ClientData client); /// /// Handles a message before sending. /// @@ -24,7 +24,7 @@ namespace MTSC.Server.Handlers /// Message to be processed. /// Server calling the handler. /// True if no other handler should handle this message. - bool HandleSendMessage(Server server, ClientStruct client, ref Message message); + bool HandleSendMessage(Server server, ClientData client, ref Message message); /// /// Called before the message handling. /// Perform here any processing of the message. @@ -33,20 +33,20 @@ namespace MTSC.Server.Handlers /// Message to be preprocessed. /// Server calling the handler. /// True if the message has been preprocessed and no other handler should handle it anymore. - bool PreHandleReceivedMessage(Server server, ClientStruct client, ref Message message); + bool PreHandleReceivedMessage(Server server, ClientData client, ref Message message); /// /// Handles the received message. /// /// Message to be handled. /// Server calling the handler. /// True if the message has been handled, false if the message has not been handled. - bool HandleReceivedMessage(Server server, ClientStruct client, Message message); + bool HandleReceivedMessage(Server server, ClientData client, Message message); /// /// Handles the removal of a client from the server. /// /// Client about to be removed. /// Server calling the handler. - void ClientRemoved(Server server, ClientStruct client); + void ClientRemoved(Server server, ClientData client); /// /// Method performs regular operations onto the server. /// diff --git a/MTSC/Server/Server.cs b/MTSC/Server/Server.cs index ed1c69e..de36f33 100644 --- a/MTSC/Server/Server.cs +++ b/MTSC/Server/Server.cs @@ -23,12 +23,12 @@ namespace MTSC.Server X509Certificate2 certificate; TcpListener listener; int port = 50; - List toRemove = new List(); - List clients = new List(); + List toRemove = new List(); + List clients = new List(); List handlers = new List(); List loggers = new List(); List exceptionHandlers = new List(); - Queue> messageQueue = new Queue>(); + Queue> messageQueue = new Queue>(); #endregion #region Properties /// @@ -42,7 +42,7 @@ namespace MTSC.Server /// /// List of clients currently connected to the server. /// - public List Clients { get => clients; set => clients = value; } + public List Clients { get => clients; set => clients = value; } #endregion #region Constructors /// @@ -117,9 +117,9 @@ namespace MTSC.Server /// /// Target client. /// Message to be sent. - public void QueueMessage(ClientStruct target, byte[] message) + public void QueueMessage(ClientData target, byte[] message) { - messageQueue.Enqueue(new Tuple(target, message)); + messageQueue.Enqueue(new Tuple(target, message)); } /// /// Adds a message to be logged by the associated loggers. @@ -156,20 +156,43 @@ namespace MTSC.Server while (running) { /* - * Check if there are messages queued to be sent. + * Check the client states. If a client is disconnected, + * remove it from the list of clients. */ - if(messageQueue.Count > 0) + try { - Tuple queuedOrder = messageQueue.Dequeue(); - Message sendMessage = CommunicationPrimitives.BuildMessage(queuedOrder.Item2); - for(int i = handlers.Count - 1; i >= 0; i--) + foreach (ClientData client in clients) { - IHandler handler = handlers[i]; - handler.HandleSendMessage(this, queuedOrder.Item1, ref sendMessage); + if (!client.TcpClient.Connected || client.ToBeRemoved) + { + toRemove.Add(client); + } + } + foreach (ClientData client in toRemove) + { + foreach (IHandler handler in handlers) + { + handler.ClientRemoved(this, client); + } + LogDebug("Client removed: " + client.TcpClient.Client.RemoteEndPoint.ToString()); + client.SslStream?.Dispose(); + client.TcpClient?.Dispose(); + clients.Remove(client); + } + toRemove.Clear(); + } + catch (Exception e) + { + LogDebug("Exception: " + e.Message); + LogDebug("Stacktrace: " + e.StackTrace); + foreach (IExceptionHandler exceptionHandler in exceptionHandlers) + { + if (exceptionHandler.HandleException(e)) + { + break; + } } - CommunicationPrimitives.SendMessage(queuedOrder.Item1.TcpClient, sendMessage, queuedOrder.Item1.SslStream); } - /* * Check if the server has any pending connections. * If it has a new connection, process it. @@ -179,7 +202,7 @@ namespace MTSC.Server if (listener.Pending()) { TcpClient tcpClient = listener.AcceptTcpClient(); - ClientStruct clientStruct = new ClientStruct(tcpClient); + ClientData clientStruct = new ClientData(tcpClient); if (certificate != null) { SslStream sslStream = new SslStream(tcpClient.GetStream(), true, new RemoteCertificateValidationCallback((o, c, ch, po) => { @@ -238,10 +261,6 @@ namespace MTSC.Server } } } - else - { - Thread.Sleep(100); - } } catch(Exception e) { @@ -256,28 +275,59 @@ namespace MTSC.Server } } }); + foreach(IHandler handler in handlers) + { + try + { + handler.Tick(this); + } + catch(Exception e) + { + LogDebug("Exception: " + e.Message); + LogDebug("Stacktrace: " + e.StackTrace); + foreach (IExceptionHandler exceptionHandler in exceptionHandlers) + { + if (exceptionHandler.HandleException(e)) + { + break; + } + } + } + } /* - * Check the client states. If a client is disconnected, - * remove it from the list of clients. + * Check if there are messages queued to be sent. */ - foreach(ClientStruct client in clients) + if (messageQueue.Count == 0) { - if (!client.TcpClient.Connected || client.ToBeRemoved) + Thread.Sleep(33); + } + else + { + try { - toRemove.Add(client); + Tuple queuedOrder = messageQueue.Dequeue(); + Message sendMessage = CommunicationPrimitives.BuildMessage(queuedOrder.Item2); + for (int i = handlers.Count - 1; i >= 0; i--) + { + IHandler handler = handlers[i]; + ClientData client = queuedOrder.Item1; + handler.HandleSendMessage(this, client, ref sendMessage); + } + CommunicationPrimitives.SendMessage(queuedOrder.Item1.TcpClient, sendMessage, queuedOrder.Item1.SslStream); + } + catch (Exception e) + { + LogDebug("Exception: " + e.Message); + LogDebug("Stacktrace: " + e.StackTrace); + foreach (IExceptionHandler exceptionHandler in exceptionHandlers) + { + if (exceptionHandler.HandleException(e)) + { + break; + } + } } } - foreach(ClientStruct client in toRemove) - { - foreach(IHandler handler in handlers) - { - handler.ClientRemoved(this, client); - } - client.SslStream?.Dispose(); - client.TcpClient?.Dispose(); - clients.Remove(client); - } - toRemove.Clear(); } } /// @@ -304,14 +354,14 @@ namespace MTSC.Server /// /// Structure containing client information. /// - public struct ClientStruct + public class ClientData { public TcpClient TcpClient; public DateTime LastMessageTime; public bool ToBeRemoved; public SslStream SslStream; - public ClientStruct(TcpClient client) + public ClientData(TcpClient client) { this.TcpClient = client; this.LastMessageTime = DateTime.Now;