/// <summary> /// Handles the main functionality and logica of the application /// </summary> private void Handler() { bool recvRequest = true; string EOL = "\r\n"; string requestPayload = ""; string requestTempLine = ""; List <string> requestLines = new List <string>(); byte[] requestBuffer = new byte[1]; byte[] responseBuffer = new byte[1]; requestLines.Clear(); // Try to get the request headers from the client try { //State 0: Handle Request from Client while (recvRequest) { this._clientSocket.Receive(requestBuffer); string fromByte = ASCIIEncoding.ASCII.GetString(requestBuffer); requestPayload += fromByte; requestTempLine += fromByte; // Format the string headers to a list of headers if (requestTempLine.EndsWith(EOL)) { requestLines.Add(requestTempLine.Trim()); requestTempLine = ""; } // If the request ends with double end of line it has received the headers if (requestPayload.EndsWith(EOL + EOL)) { recvRequest = false; } } string cookie = null; string session = null; string url = null; requestPayload = ""; // Loop through all the HTTP Headers foreach (string line in requestLines) { // Remove Accept-Encoding to display the plain HTML bool addLines = !line.Contains("Accept-Encoding"); // If the line contains a cookie we will check what algorithm is active and react based on that if (line.Contains("Cookie")) { switch (Algoritme.Get()) { case "Cookie Based": cookie = line.Split('=')[1]; break; case "Session Based": session = line.Split('=')[1]; break; } } // Add the HTTP Header to the requestPayload if (addLines) { requestPayload += line; requestPayload += EOL; } } // Determine what server we need to connect to var selectedServer = _server.GetConnectionInfo(cookie, session); // Try to connect to the chosen server try { TcpClient client = new TcpClient(selectedServer[0], Int32.Parse(selectedServer[1])); var stream = client.GetStream(); // Write the request to the server stream.Write(ASCIIEncoding.ASCII.GetBytes(requestPayload), 0, ASCIIEncoding.ASCII.GetBytes(requestPayload).Length); // If the algorithm is cookie based we need to add a cookie to the response headers if (Algoritme.Get() == "Cookie Based") { string response = null; var contentLengthIsAvailable = false; var headersInThePocket = false; int contentLength = 0; StringBuilder responseBytes = null; var i = 0; while (true) { // Read all the bytes from the server stream.Read(responseBuffer, 0, responseBuffer.Length); // Convert these bytes to a string and add these to the response string response += Encoding.ASCII.GetString(responseBuffer); // Check if all the headers are received if (response.EndsWith(EOL + EOL)) { // Add a "Set-Cookie" header to the response headers response = response.Split(new[] { EOL + EOL }, StringSplitOptions.None)[0]; var connectionCookie = selectedServer[0] + ":" + selectedServer[1]; response += EOL + "Set-Cookie: fixed-server=" + Algoritme.CalculateMD5Hash(connectionCookie) + EOL + EOL; var headers = response.Split(':'); // Determine the Content-Length for further reading var contentLengthAvailable = false; foreach (var header in headers) { if (contentLengthAvailable) { contentLength = int.Parse(header.Split('\r')[0]); contentLengthAvailable = false; } if (header.EndsWith("Content-Length")) { contentLengthAvailable = true; } } responseBytes = new StringBuilder(response); headersInThePocket = true; } // Read the body when the headers are in the pocket if (headersInThePocket) { if (contentLength == 0) { // If the response has nog content-length header we will set it on a default contentLength = 2000; } if (i < contentLength) { // As long as the body has not been received we will append the body to our responseBytes responseBytes.Append(Encoding.ASCII.GetString(responseBuffer)); i++; } else { var charResponse = responseBytes.ToString().ToCharArray(0, responseBytes.Length); byte[] test = Encoding.ASCII.GetBytes(charResponse); // Sent the response to the clientSocket _clientSocket.Send(test); // Break out of the while loop as we do not need to receive anymore bytes break; } } } } // If Algorithm "Cookie-Based" has not been selected. We will send everything straight through else { while (stream.Read(responseBuffer, 0, responseBuffer.Length) != 0) { this._clientSocket.Send(responseBuffer); } } // Remove the server from the request for the load Algorithm foreach (var serverRequest in Algoritme.requestPerServer) { if (serverRequest[0] == selectedServer[0]) { Algoritme.requestPerServer.Remove(serverRequest); } } client.Close(); stream.Dispose(); } // When the recommended server cannot be contacted catch (SocketException e) { Console.Write("Server has fallen", e); Handler(); } // Cleanup our socket this._clientSocket.Disconnect(false); this._clientSocket.Dispose(); } catch (Exception e) { Console.WriteLine("Error Occured: " + e.Message); } }
/// <summary> /// Determine what server the server class has to connect to. /// It takes the algorithm and based on that it will choose the server /// </summary> /// <param name="cookie">Cookie if there is any otherwise it is null</param> /// <param name="session">Session if there is any otherwise it is null</param> /// <returns>Server object with connect information</returns> public string[] GetConnectionInfo(string cookie, string session) { int serverChosen = 0; switch (Algoritme.Get()) { case "Random": Random rnd = new Random(); serverChosen = rnd.Next(0, servers.Count); break; case "Round Robin": serverChosen = Algoritme.roundRobinPos; if (Algoritme.roundRobinPos != servers.Count - 1) { Algoritme.roundRobinPos++; } else { Algoritme.roundRobinPos = 0; } break; case "Load": // Chooses the server with the less Load. What is based on the current amount of connections to a server. serverChosen = 0; List <int> requestsServers = new List <int>(); foreach (var serverRequest in Algoritme.requestPerServer) { requestsServers.Add(Int32.Parse(serverRequest[1])); } var i = 0; foreach (var requestsServer in requestsServers) { if (requestsServer == requestsServers.Min()) { serverChosen = i; } i++; } break; case "Cookie Based": var j = 0; foreach (var server in servers) { if (server.ToString().Split('/')[2] == cookie) { serverChosen = j; } j++; } break; case "Session Based": var sessions = Algoritme.sessionsPerServer; // If there is no session set yet it will choose a server based on Round Robin if (session == null) { serverChosen = Algoritme.roundRobinPos; if (Algoritme.roundRobinPos != servers.Count - 1) { Algoritme.roundRobinPos++; } else { Algoritme.roundRobinPos = 0; } } // There is a session else { // Check if the session is already stored in our list of stored sessions var isAlreadyStored = false; object selectedServer = null; foreach (var stringse in Algoritme.sessionsPerServer) { if (session == stringse[0]) { isAlreadyStored = true; selectedServer = stringse[1]; } } if (isAlreadyStored) { // The session is already stored var l = 0; foreach (var server in servers) { if (server == selectedServer) { serverChosen = l; } l++; } } else { // Session is not stored yet // Add new session id to the local storage var k = 0; string[] sessionPerServer = null; if (Algoritme.roundRobinPos != 0) { Algoritme.roundRobinPos--; } else { Algoritme.roundRobinPos = servers.Count - 1; } foreach (var server in servers) { if (k == Algoritme.roundRobinPos) { sessionPerServer = new string[] { session, server.ToString() }; } k++; } serverChosen = Algoritme.roundRobinPos; Algoritme.sessionsPerServer.Add(sessionPerServer); } } break; } // Keep track of the requests for health monitoring HealthMonitor.addConnection(serverChosen); // Return the connectInfo to the server class var connectInfo = GetHostAndPort(servers[serverChosen] as string); return(connectInfo); }