/// <summary> /// Logs the memory useage using GC.GetTotalMemory and returns the memory useage /// </summary> /// <param name="p">Process to use to calculate memory</param> public static void LogMemory(Process p) { long mem = +GC.GetTotalMemory(false); if (mem > maxMemoryUseage) { maxMemoryUseage = mem; } Globals_Server.logEvent("GC memory: " + mem); }
/// <summary> /// Send an update to the client- used when the message to be sent requires additional information other than just a response code and some strings /// </summary> /// <param name="message">Message to be sent- can contain any number of details</param> public void Update(ProtoMessage message) { Contract.Requires(message != null); message.ActionType = Actions.Update; if (conn != null) { Globals_Server.logEvent("Update " + this.username + ": " + message.ResponseType.ToString()); Console.WriteLine("Sending update " + message.ResponseType.ToString() + " to " + this.username); Server.SendViaProto(message, conn, alg); } }
/// <summary> /// Updates the client /// </summary> /// <param name="message">The message code to send</param> /// <param name="fields">Additional information to add to the message</param> public void Update(DisplayMessages message, string[] fields = null) { ProtoMessage m = new ProtoMessage(); m.ActionType = Actions.Update; m.ResponseType = message; m.MessageFields = fields; if (conn != null) { Globals_Server.logEvent("Update " + this.username + ": " + message.ToString()); Console.WriteLine("Sending update " + message.ToString() + " to " + this.username); Server.SendViaProto(m, conn, alg); } }
/// <summary> /// Processes a client disconnecting from the server- removes the client as an observer, removes their connection and deletes their CryptoServiceProvider /// </summary> /// <param name="conn">Connection of the client who disconnected</param> private void Disconnect(NetConnection conn) { Contract.Requires(conn != null); lock (ServerLock) { if (clientConnections.ContainsKey(conn)) { Client client = clientConnections[conn]; Globals_Server.logEvent("Client " + client.username + " has disconnected."); Globals_Game.RemoveObserver(client); client.conn = null; clientConnections.Remove(conn); client.alg = null; conn.Disconnect("Disconnect"); } } }
//public static void SendViaProto(global::ProtoMessage.ProtoMessage m, NetConnection conn, bool isPCL, NetEncryption alg = null) //{ // Contract.Requires(m != null && conn != null); // NetOutgoingMessage msg = server.CreateMessage(); // MemoryStream ms = new MemoryStream(); // Serializer.SerializeWithLengthPrefix<global::ProtoMessage.ProtoMessage>(ms, m, PrefixStyle.Fixed32); // msg.Write(ms.GetBuffer()); // if (alg != null) // { // msg.Encrypt(alg); // } // server.SendMessage(msg, conn, NetDeliveryMethod.ReliableOrdered); // server.FlushSendQueue(); //} /// <summary> /// Read a message, get the relevant reply and send to client /// </summary> /// <param name="m">Deserialised message from client</param> /// <param name="connection">Client's connecton</param> public void ProcessMessage(ProtoMessage m, NetConnection connection) { Contract.Requires(connection != null && m != null); Client client; clientConnections.TryGetValue(connection, out client); if (client == null) { NetOutgoingMessage errorMessage = server.CreateMessage("There was a problem with the connection. Please try re-connecting"); server.SendMessage(errorMessage, connection, NetDeliveryMethod.ReliableOrdered); string log = "Connection from peer " + connection.Peer.UniqueIdentifier + " not found in client connections. Timestamp: " + DateTime.Now.ToString(DateTimeFormatInfo.CurrentInfo); Globals_Server.logError(log); return; } var pc = client.myPlayerCharacter; if (pc == null || !pc.isAlive) { NetOutgoingMessage msg = server.CreateMessage("You have no valid PlayerCharacter!"); server.SendMessage(msg, connection, NetDeliveryMethod.ReliableOrdered); server.FlushSendQueue(); } else { Globals_Server.logEvent("From: " + clientConnections[connection].username + ": request = " + m.ActionType.ToString()); ProtoMessage reply = Game.ActionController(m, client); // Set action type to ensure client knows which action invoked response if (reply == null) { ProtoMessage invalid = new ProtoMessage(DisplayMessages.ErrorGenericMessageInvalid); invalid.ActionType = Actions.Update; reply = invalid; } else { reply.ActionType = m.ActionType; } SendViaProto(reply, connection, client.alg); } }
public static void TestRun(bool encrypt = true) { Process currentProcess = Process.GetCurrentProcess(); if (encrypt) { Globals_Server.logEvent("Running test with encryption"); } else { Globals_Server.logEvent("Running test without encryption"); } double LoginTime, RecruitTime, MoveTime, SpyTime; double start = DateTime.Now.TimeOfDay.TotalMilliseconds; byte[] encryptionKey = null; if (encrypt) { encryptionKey = LogInManager.GetRandomSalt(32); } client.LogInAndConnect(Username, Pass, encryptionKey); while (!client.IsConnectedAndLoggedIn()) { Thread.Sleep(0); } LoginTime = DateTime.Now.TimeOfDay.TotalMilliseconds - start; client.RecruitTroops(OwnedArmy.armyID, 70, true); RecruitTime = ProcessNextAction(Actions.RecruitTroops, currentProcess); // Move to another fief client.Move(MyPlayerCharacter.charID, NotOwnedFief.id, null); MoveTime = ProcessNextAction(Actions.TravelTo, currentProcess); // Spy client.SpyOnFief(MyPlayerCharacter.charID, MyPlayerCharacter.location.id); SpyTime = ProcessNextAction(Actions.SpyFief, currentProcess); // Confirm spy Globals_Server.logEvent("Time taken to run test (ms): " + (DateTime.Now.TimeOfDay.TotalMilliseconds - start)); Globals_Server.logEvent("LogIn time: " + LoginTime); Globals_Server.logEvent("Recruit time: " + (RecruitTime)); Globals_Server.logEvent("Travel time: " + MoveTime); Globals_Server.logEvent("Spy time: " + SpyTime); Globals_Server.logEvent("Max memory measured: " + maxMemoryUseage); }
/// <summary> /// Sends a message by serializing with ProtoBufs /// </summary> /// <param name="m">Message to be sent</param> /// <param name="conn">Connection to send across</param> /// <param name="alg">Optional encryption algorithm</param> public static void SendViaProto(ProtoMessage m, NetConnection conn, NetEncryption alg = null) { Contract.Requires(m != null && conn != null); NetOutgoingMessage msg = server.CreateMessage(); MemoryStream ms = new MemoryStream(); Serializer.SerializeWithLengthPrefix <ProtoMessage>(ms, m, PrefixStyle.Fixed32); msg.Write(ms.GetBuffer()); if (alg != null) { msg.Encrypt(alg); } server.SendMessage(msg, conn, NetDeliveryMethod.ReliableOrdered); server.FlushSendQueue(); Globals_Server.logEvent("" + " Sending to: " + clientConnections[conn].username + " | ActionType = " + m.ActionType.ToString() + " | ResponseType = " + m.ResponseType.ToString() + " | " + conn.RemoteEndPoint.ToString() ); }
public void read() { while (client.Status == NetPeerStatus.Running && !ctSource.Token.IsCancellationRequested) { WaitHandle.WaitAny(new WaitHandle[] { client.MessageReceivedEvent, ctSource.Token.WaitHandle }); NetIncomingMessage im; while ((im = client.ReadMessage()) != null && !ctSource.IsCancellationRequested) { switch (im.MessageType) { case NetIncomingMessageType.DebugMessage: case NetIncomingMessageType.ErrorMessage: case NetIncomingMessageType.WarningMessage: case NetIncomingMessageType.VerboseDebugMessage: case NetIncomingMessageType.Data: try { if (alg != null) { im.Decrypt(alg); } MemoryStream ms = new MemoryStream(im.Data); ProtoMessage m = null; try { m = Serializer.DeserializeWithLengthPrefix <ProtoMessage>(ms, PrefixStyle.Fixed32); } catch (Exception e) { // Attempt to read string and add to message queue string s = im.ReadString(); if (!string.IsNullOrWhiteSpace(s)) { Console.WriteLine("CLIENT: Got message: " + s); tClient.stringMessageQueue.Enqueue(s); } } if (m != null) { Console.WriteLine("CLIENT: Got ProtoMessage with ActionType: " + m.ActionType + " and response type: " + m.ResponseType); if (m.ResponseType == DisplayMessages.LogInSuccess) { loggedIn = true; tClient.protobufMessageQueue.Enqueue(m); } else { if (m.ActionType == Actions.Update) { // Don't do anything at the moment for updates } else { tClient.protobufMessageQueue.Enqueue(m); if (m.ActionType == Actions.LogIn && m.ResponseType == DisplayMessages.None) { byte[] key = null; if (ValidateCertificateAndCreateKey(m as ProtoLogIn, out key)) { ComputeAndSendHashAndKey(m as ProtoLogIn, key); } } else { // Attempt to read string and add to message queue string s = im.ReadString(); if (!string.IsNullOrWhiteSpace(s)) { tClient.stringMessageQueue.Enqueue(s); } } } } } } catch (Exception e) { Globals_Server.logError("Error in reading data: " + e.GetType() + " :" + e.Message + "; Stack Trace: " + e.StackTrace); } break; case NetIncomingMessageType.StatusChanged: NetConnectionStatus status = (NetConnectionStatus)im.ReadByte(); Console.WriteLine("CLIENT: Status changed to " + status.ToString()); //MemoryStream ms2 = new MemoryStream(im.SenderConnection.RemoteHailMessage.Data); if (status == NetConnectionStatus.Connected) { if (im.SenderConnection.RemoteHailMessage != null) { try { MemoryStream ms2 = new MemoryStream(im.SenderConnection.RemoteHailMessage.Data); ProtoMessage m = Serializer.DeserializeWithLengthPrefix <ProtoMessage>(ms2, PrefixStyle.Fixed32); if (m != null) { tClient.protobufMessageQueue.Enqueue(m); if (m.ActionType == Actions.LogIn && m.ResponseType == DisplayMessages.None) { byte[] key = null; if (ValidateCertificateAndCreateKey(m as ProtoLogIn, out key)) { if (autoLogIn) { ComputeAndSendHashAndKey(m as ProtoLogIn, key); } } else { Console.WriteLine("Certificate validation failed: Server may be untrusted"); client.Disconnect("Invalid Certificate"); } } } } catch (Exception e) { } } break; } else if (status == NetConnectionStatus.Disconnected) { string reason = im.ReadString(); if (!string.IsNullOrEmpty(reason)) { tClient.stringMessageQueue.Enqueue(reason); } } if (im.SenderConnection.RemoteHailMessage != null && (NetConnectionStatus)im.ReadByte() == NetConnectionStatus.Connected) { } break; case NetIncomingMessageType.ConnectionLatencyUpdated: break; default: break; } client.Recycle(im); } } #if DEBUG Globals_Server.logEvent("Client listening thread ends"); #endif }
/// <summary> /// Initialise the server, and store some test users and clients. /// </summary> private void initialise() { LogInManager.StoreNewUser("helen", "potato"); LogInManager.StoreNewUser("test", "tomato"); NetPeerConfiguration config = new NetPeerConfiguration(app_identifier); config.LocalAddress = NetUtility.Resolve(host_name); config.MaximumConnections = max_connections; config.Port = port; config.SetMessageTypeEnabled(NetIncomingMessageType.ConnectionApproval, true); config.SetMessageTypeEnabled(NetIncomingMessageType.ConnectionLatencyUpdated, false); config.PingInterval = 10f; config.ConnectionTimeout = 100f; config.EnableUPnP = true; //######### server = new NetServer(config); ctSource = new CancellationTokenSource(); server.Start(); try { for (int i = 0; i < 3; i++) { if (server.UPnP.ForwardPort(port, "Designated Listening Port")) { Globals_Server.logEvent("Port forwarded successfully."); break; } else { Globals_Server.logEvent("Port forward FAILED " + i.ToString()); } } } catch (Exception e) { Globals_Server.logEvent(e.ToString()); } Globals_Server.server = server; Globals_Server.logEvent("Server started- host: " + host_name + ", port: " + port + ", appID: " + app_identifier + ", max connections: " + max_connections); Client client = new Client("helen", "Char_158"); Globals_Server.Clients.Add("helen", client); Client client2 = new Client("test", "Char_126"); Globals_Server.Clients.Add("test", client2); String dir = Directory.GetCurrentDirectory(); //dir = dir.Remove(dir.IndexOf("RepairHist_mmo")); String path; if (Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX) { path = Path.Combine(dir, "Certificates"); } else { dir = Directory.GetParent(dir).FullName; dir = Directory.GetParent(dir).FullName; path = Path.Combine(dir, "Certificates"); } LogInManager.InitialiseCertificateAndRSA(path); }
public void Listen() { while (server.Status == NetPeerStatus.Running && !ctSource.Token.IsCancellationRequested) { NetIncomingMessage im; WaitHandle.WaitAny(new WaitHandle[] { server.MessageReceivedEvent, ctSource.Token.WaitHandle }); while ((im = server.ReadMessage()) != null && !ctSource.Token.IsCancellationRequested) { if (im.SenderConnection != null) { Globals_Server.logEvent("Recieved: " + im.MessageType.ToString() + " | " + im.SenderConnection.RemoteEndPoint.ToString()); } else { Globals_Server.logEvent("Recieved: " + im.MessageType.ToString() + " | NULL"); } switch (im.MessageType) { case NetIncomingMessageType.DebugMessage: case NetIncomingMessageType.ErrorMessage: case NetIncomingMessageType.WarningMessage: Globals_Server.logError("Recieved warning message: " + im.ReadString()); break; case NetIncomingMessageType.VerboseDebugMessage: case NetIncomingMessageType.Data: { #if DEBUG //Console.WriteLine("SERVER: recieved data message"); #endif if (!clientConnections.ContainsKey(im.SenderConnection)) { //error im.SenderConnection.Disconnect("Not recognised"); return; } Client c = clientConnections[im.SenderConnection]; if (c.alg != null) { im.Decrypt(c.alg); } ProtoMessage m = null; using (MemoryStream ms = new MemoryStream(im.Data)) { try { m = Serializer.DeserializeWithLengthPrefix <ProtoMessage>(ms, PrefixStyle.Fixed32); } catch (Exception e) { NetOutgoingMessage errorMessage = server.CreateMessage( "Failed to deserialise message. The message may be incorrect, or the decryption may have failed."); if (c.alg != null) { errorMessage.Encrypt(c.alg); } server.SendMessage(errorMessage, im.SenderConnection, NetDeliveryMethod.ReliableOrdered); Globals_Server.logError("Failed to deserialize message for client: " + c.username); } } if (m == null) { string error = "Recieved null message from " + im.SenderEndPoint.ToString(); if (clientConnections.ContainsKey(im.SenderConnection)) { error += ", recognised client " + clientConnections[im.SenderConnection]; } else { error += ", unrecognised client (possible ping)"; } error += ". Data: " + im.ReadString(); Globals_Server.logError(error); break; } if (m.ActionType == Actions.LogIn) { ProtoLogIn login = m as ProtoLogIn; if (login == null) { im.SenderConnection.Disconnect("Received blank login message."); return; } lock (ServerLock) { if (LogInManager.VerifyUser(c.username, login.userSalt)) { if (LogInManager.ProcessLogIn(login, c)) { string log = c.username + " logs in from " + im.SenderEndPoint.ToString(); Globals_Server.logEvent(log); } } else { ProtoMessage reply = new ProtoMessage { ActionType = Actions.LogIn, ResponseType = DisplayMessages.LogInFail }; Server.SendViaProto(reply, c.conn, c.alg); //reply = new ProtoMessage { // ActionType = Actions.Update, // ResponseType = DisplayMessages.Error //}; //Server.SendViaProto(reply, c.conn, c.alg); im.SenderConnection.Disconnect("Authentication Fail"); Globals_Server.logEvent("Wrong Password, disconnecting user."); } } } // temp for testing, should validate connection first else if (clientConnections.ContainsKey(im.SenderConnection)) { if (Globals_Game.IsObserver(c)) { ProcessMessage(m, im.SenderConnection); ProtoClient clientDetails = new ProtoClient(c); clientDetails.ActionType = Actions.Update; clientDetails.ResponseType = DisplayMessages.Success; SendViaProto(clientDetails, im.SenderConnection, c.alg); } else { im.SenderConnection.Disconnect("Not logged in- Disconnecting"); } } } break; case NetIncomingMessageType.StatusChanged: byte stat = im.ReadByte(); NetConnectionStatus status = NetConnectionStatus.None; if (Enum.IsDefined(typeof(NetConnectionStatus), Convert.ToInt32(stat))) { status = (NetConnectionStatus)stat; } else { Globals_Server.logError("Failure to parse byte " + stat + " to NetConnectionStatus for endpoint " + im.ReadIPEndPoint()); } Globals_Server.logEvent("\tStatus is now: " + status); if (status == NetConnectionStatus.Disconnected) { string reason = im.ReadString(); if (reason == null) { reason = "Unknown"; } Globals_Server.logEvent(im.SenderConnection.RemoteEndPoint.ToString() + " has disconnected. Reason: " + reason); if (clientConnections.ContainsKey(im.SenderConnection)) { Disconnect(im.SenderConnection); } } break; case NetIncomingMessageType.ConnectionApproval: { string senderID = im.ReadString(); string text = im.ReadString(); Client client; Globals_Server.Clients.TryGetValue(senderID, out client); if (client != null) { ProtoLogIn logIn; //ProtoMessage logIn; if (!LogInManager.AcceptConnection(client, text, out logIn)) { im.SenderConnection.Deny("User not recognised."); } else { ProtoMessage temp = logIn; NetOutgoingMessage msg = server.CreateMessage(); MemoryStream ms = new MemoryStream(); // Include X509 certificate as bytes for client to validate //Serializer.SerializeWithLengthPrefix<ProtoLogIn>(ms, logIn, PrefixStyle.Fixed32); Serializer.SerializeWithLengthPrefix <ProtoMessage>(ms, temp, PrefixStyle.Fixed32); msg.Write(ms.GetBuffer()); clientConnections.Add(im.SenderConnection, client); client.conn = im.SenderConnection; im.SenderConnection.Approve(msg); //server.FlushSendQueue(); Globals_Server.logEvent("Accepted connection from " + client.username + " | " + senderID + " | " + text); } } else { im.SenderConnection.Deny("Username unrecognised."); } server.FlushSendQueue(); } break; case NetIncomingMessageType.ConnectionLatencyUpdated: Globals_Server.logEvent("LATENCY: Still getting these."); break; default: Globals_Server.logError("Received unrecognised incoming message type: " + im.MessageType); break; } server.Recycle(im); } } Globals_Server.logEvent("Server listening thread exits."); }
/// <summary> /// Selects random adjoining hex (also equal chance to select current hex) /// </summary> /// <returns>Fief to move to (or null)</returns> /// <param name="from">Current fief</param> /// <param name="getOwned">bool indicating whether or not to try to return an owned fief</param> /// <param name="owner">owner, when looking for an owned fief</param> /// <param name="avoid">Fief to avoid (for retreats)</param> public Fief chooseRandomHex(Fief from, bool getOwned = false, PlayerCharacter fiefOwner = null, Fief avoid = null) { // list to store all edges List <TaggedEdge <Fief, string> > choices = new List <TaggedEdge <Fief, string> >(); // list to store all edges to owned fiefs List <TaggedEdge <Fief, string> > ownedChoices = new List <TaggedEdge <Fief, string> >(); // int to use in edge selection int selection = 0; // string to contain chosen move direction Fief goTo = null; //Fief goTo = from; // identify and store all target hexes from source hex foreach (var e in this.myMap.Edges) { bool okToAdd = true; if (e.Source == from) { // no 'avoid' fief specified if (avoid == null) { okToAdd = true; } // if 'avoid' fief specified else { // if is NOT specified 'avoid' fief if (e.Target != avoid) { okToAdd = true; } // if IS specified 'avoid' fief else { okToAdd = false; } } if (okToAdd) { choices.Add(e); // if getOwned, also check for target ownership if (getOwned) { if (e.Target.owner == fiefOwner) { ownedChoices.Add(e); } } } } } // if looking for owned fief, get one if possible if ((getOwned) && (ownedChoices.Count > 0)) { // choose fief by generating random int between 0 and no. of targets selection = Globals_Game.myRand.Next(0, ownedChoices.Count); // get Fief goTo = ownedChoices[selection].Target; } // if ownership not required, choose from all adjoining fiefs else if (choices.Count > 0) { // choose fief by generating random int between 0 and no. of targets selection = Globals_Game.myRand.Next(0, choices.Count); // get Fief goTo = choices[selection].Target; } if (goTo == null) { Globals_Server.logEvent("Random hex method returned a null value for fief."); goTo = from; // BUG: temporary fix is for character or army to stay where they are instead, problematic for retreating armies. } return(goTo); }