Fixed an error with server responses.

This commit is contained in:
2019-07-23 18:23:03 +03:00
parent 8c875c4278
commit a1934fdf34
12 changed files with 169 additions and 89 deletions
+1 -7
View File
@@ -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);
}
}
}
}
+4 -3
View File
@@ -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();
}
+4 -1
View File
@@ -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
+4
View File
@@ -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<string, string> 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());
@@ -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
{
/// <summary>
/// Simple module that returns status code 404.
/// </summary>
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;
}
}
}
@@ -19,6 +19,6 @@ namespace MTSC.Common.Http.ServerModules
/// <param name="client">Client data.</param>
/// <param name="request">Request message.</param>
/// <returns>True if no other module should handle the received request.</returns>
bool HandleRequest(IHandler handler, ClientStruct client, HttpMessage request);
bool HandleRequest(HttpHandler handler, ClientData client, HttpMessage request);
}
}
+1 -12
View File
@@ -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)
+6 -6
View File
@@ -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;
}
+7 -7
View File
@@ -24,7 +24,7 @@ namespace MTSC.Server.Handlers
public ClientState ClientState = ClientState.Initial;
}
#region Fields
private Dictionary<ClientStruct, AdditionalData> additionalData;
private Dictionary<ClientData, AdditionalData> additionalData;
private RSACryptoServiceProvider rsa;
private string privateKey, publicKey;
#endregion
@@ -38,7 +38,7 @@ namespace MTSC.Server.Handlers
/// <param name="server">Server object managed by the handler.</param>
public EncryptionHandler(RSACryptoServiceProvider rsa)
{
additionalData = new Dictionary<ClientStruct, AdditionalData>();
additionalData = new Dictionary<ClientData, AdditionalData>();
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.
/// </summary>
/// <param name="client">Client to be removed.</param>
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
/// </summary>
/// <param name="client">New client connection.</param>
/// <returns>False if an error occurred.</returns>
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
/// <param name="client">Client connection.</param>
/// <param name="message">Received message.</param>
/// <returns>True if no other handler should handle current message.</returns>
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
/// <param name="client">Client connection.</param>
/// <param name="message">Message to be processed.</param>
/// <returns>True if no other handlers should perform operations on current message.</returns>
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
/// <param name="client">Client object.</param>
/// <param name="message">Message to be processed.</param>
/// <returns>True if no other handler should process this message.</returns>
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)
{
+13 -9
View File
@@ -14,6 +14,7 @@ namespace MTSC.Server.Handlers
{
#region Fields
List<IHttpModule> httpModules = new List<IHttpModule>();
Queue<Tuple<ClientData,HttpMessage>> messageQueue = new Queue<Tuple<ClientData, HttpMessage>>();
#endregion
#region Constructors
public HttpHandler()
@@ -36,10 +37,9 @@ namespace MTSC.Server.Handlers
/// Send a response back to the client.
/// </summary>
/// <param name="response">Message containing the response.</param>
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<ClientData, HttpMessage>(client, response));
}
#endregion
#region Interface Implementation
@@ -47,7 +47,7 @@ namespace MTSC.Server.Handlers
/// Handler interface implementation.
/// </summary>
/// <param name="client"></param>
void IHandler.ClientRemoved(Server server, ClientStruct client)
void IHandler.ClientRemoved(Server server, ClientData client)
{
}
@@ -56,7 +56,7 @@ namespace MTSC.Server.Handlers
/// </summary>
/// <param name="client"></param>
/// <returns></returns>
bool IHandler.HandleClient(Server server, ClientStruct client)
bool IHandler.HandleClient(Server server, ClientData client)
{
return false;
}
@@ -66,7 +66,7 @@ namespace MTSC.Server.Handlers
/// <param name="client"></param>
/// <param name="message"></param>
/// <returns></returns>
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
/// <param name="client"></param>
/// <param name="message"></param>
/// <returns></returns>
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
/// <param name="client"></param>
/// <param name="message"></param>
/// <returns></returns>
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
/// </summary>
void IHandler.Tick(Server server)
{
while(messageQueue.Count > 0)
{
Tuple<ClientData, HttpMessage> tuple = messageQueue.Dequeue();
server.QueueMessage(tuple.Item1, tuple.Item2.GetResponse());
}
}
#endregion
}
+5 -5
View File
@@ -16,7 +16,7 @@ namespace MTSC.Server.Handlers
/// <param name="client">Client to be handled.</param>
/// <param name="server">Server calling the handler.</param>
/// <returns>True if the handler processed the client.</returns>
bool HandleClient(Server server, ClientStruct client);
bool HandleClient(Server server, ClientData client);
/// <summary>
/// Handles a message before sending.
/// </summary>
@@ -24,7 +24,7 @@ namespace MTSC.Server.Handlers
/// <param name="message">Message to be processed.</param>
/// <param name="server">Server calling the handler.</param>
/// <returns>True if no other handler should handle this message.</returns>
bool HandleSendMessage(Server server, ClientStruct client, ref Message message);
bool HandleSendMessage(Server server, ClientData client, ref Message message);
/// <summary>
/// Called before the message handling.
/// Perform here any processing of the message.
@@ -33,20 +33,20 @@ namespace MTSC.Server.Handlers
/// <param name="message">Message to be preprocessed.</param>
/// <param name="server">Server calling the handler.</param>
/// <returns>True if the message has been preprocessed and no other handler should handle it anymore.</returns>
bool PreHandleReceivedMessage(Server server, ClientStruct client, ref Message message);
bool PreHandleReceivedMessage(Server server, ClientData client, ref Message message);
/// <summary>
/// Handles the received message.
/// </summary>
/// <param name="message">Message to be handled.</param>
/// <param name="server">Server calling the handler.</param>
/// <returns>True if the message has been handled, false if the message has not been handled.</returns>
bool HandleReceivedMessage(Server server, ClientStruct client, Message message);
bool HandleReceivedMessage(Server server, ClientData client, Message message);
/// <summary>
/// Handles the removal of a client from the server.
/// </summary>
/// <param name="client">Client about to be removed.</param>
/// <param name="server">Server calling the handler.</param>
void ClientRemoved(Server server, ClientStruct client);
void ClientRemoved(Server server, ClientData client);
/// <summary>
/// Method performs regular operations onto the server.
/// </summary>
+88 -38
View File
@@ -23,12 +23,12 @@ namespace MTSC.Server
X509Certificate2 certificate;
TcpListener listener;
int port = 50;
List<ClientStruct> toRemove = new List<ClientStruct>();
List<ClientStruct> clients = new List<ClientStruct>();
List<ClientData> toRemove = new List<ClientData>();
List<ClientData> clients = new List<ClientData>();
List<IHandler> handlers = new List<IHandler>();
List<ILogger> loggers = new List<ILogger>();
List<IExceptionHandler> exceptionHandlers = new List<IExceptionHandler>();
Queue<Tuple<ClientStruct, byte[]>> messageQueue = new Queue<Tuple<ClientStruct, byte[]>>();
Queue<Tuple<ClientData, byte[]>> messageQueue = new Queue<Tuple<ClientData, byte[]>>();
#endregion
#region Properties
/// <summary>
@@ -42,7 +42,7 @@ namespace MTSC.Server
/// <summary>
/// List of clients currently connected to the server.
/// </summary>
public List<ClientStruct> Clients { get => clients; set => clients = value; }
public List<ClientData> Clients { get => clients; set => clients = value; }
#endregion
#region Constructors
/// <summary>
@@ -117,9 +117,9 @@ namespace MTSC.Server
/// </summary>
/// <param name="target">Target client.</param>
/// <param name="message">Message to be sent.</param>
public void QueueMessage(ClientStruct target, byte[] message)
public void QueueMessage(ClientData target, byte[] message)
{
messageQueue.Enqueue(new Tuple<ClientStruct, byte[]>(target, message));
messageQueue.Enqueue(new Tuple<ClientData, byte[]>(target, message));
}
/// <summary>
/// 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<ClientStruct, byte[]> 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<ClientData, byte[]> 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();
}
}
/// <summary>
@@ -304,14 +354,14 @@ namespace MTSC.Server
/// <summary>
/// Structure containing client information.
/// </summary>
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;