public static void SendDMPModMessageToAll(ClientObject excludeClient, string modName, byte[] messageData, bool highPriority) { ServerMessage newMessage = new ServerMessage(); newMessage.type = ServerMessageType.MOD_DATA; using (MessageWriter mw = new MessageWriter()) { mw.Write<string>(modName); mw.Write<byte[]>(messageData); newMessage.data = mw.GetMessageBytes(); } ClientHandler.SendToAll(excludeClient, newMessage, highPriority); }
public override void OnMessageReceived(ClientObject client, ClientMessage message) { if (!client.authenticated) { //Only handle authenticated messages return; } if (message.type == ClientMessageType.SCENARIO_DATA) { HandleScenarioMessage(client, message); message.handled = true; } }
//Fire OnClientDisconnect public static void FireOnClientDisconnect(ClientObject client) { foreach (var plugin in loadedPlugins) { try { plugin.OnClientDisconnect(client); } catch (Exception e) { Type type = plugin.GetType(); DarkLog.Debug("Error thrown in OnClientDisconnect event for " + type.FullName + " (" + type.Assembly.FullName + "), Exception: " + e); } } }
public void OnMessageReceived(ClientObject client, ClientMessage message) { if (message.type == ClientMessageType.CHAT_MESSAGE) { using (MessageReader mr = new MessageReader(message.data, false)) { ChatMessageType messageType = (ChatMessageType)mr.Read<int>(); string fromPlayer = mr.Read<string>(); if (messageType == ChatMessageType.CHANNEL_MESSAGE) { string channel = mr.Read<string>(); string umessage = mr.Read<string>(); ircClient.Channels["#" + channel].SendMessage(String.Format("{0} -> {1}", fromPlayer, umessage)); } } } }
private void SendCKANFileToClient(ClientObject client) { using (MessageWriter mw = new MessageWriter()) { mw.Write<int>(CKAN_PROTOCOL_VERSION); if (!File.Exists(ckanFile)) { mw.Write<bool>(false); byte[] sendData = mw.GetMessageBytes(); DMPModInterface.SendDMPModMessageToClient(client, "DMPCkanPlugin", sendData, false); return; } mw.Write<bool>(true); mw.Write<string>(File.ReadAllText(ckanFile)); } DarkLog.Debug("Sent CKAN file to " + client.playerName); }
public static void SendDMPModMessageToClient(ClientObject client, string modName, byte[] messageData, bool highPriority) { if (modName == null) { //Now that's just being silly :) return; } if (messageData == null) { DarkLog.Debug(modName + " attemped to send a null message"); return; } ServerMessage newMessage = new ServerMessage(); newMessage.type = ServerMessageType.MOD_DATA; using (MessageWriter mw = new MessageWriter()) { mw.Write<string>(modName); mw.Write<byte[]>(messageData); newMessage.data = mw.GetMessageBytes(); } ClientHandler.SendToClient(client, newMessage , highPriority); }
//Receive message data (PROTOCOL 1): //int ckan protocol version //int ckan request type: //1: CKAN metadata file //Send message data (PROTOCOL 1): //int ckan protocol version //bool ckan available (true/false) //if ckan available: UTF-8 string (ckan export data) private void OnCKANRequest(ClientObject client, byte[] messageData) { using (MessageReader mr = new MessageReader(messageData)) { int clientProtocol = mr.Read<int>(); if (clientProtocol != CKAN_PROTOCOL_VERSION) { DarkLog.Error("Client " + client.playerName + " connected with CKAN protocol " + clientProtocol + ", server version: " + CKAN_PROTOCOL_VERSION); return; } int requestType = mr.Read<int>(); switch (requestType) { case 1: SendCKANFileToClient(client); break; default: DarkLog.Error("Unknown CKAN request type: " + requestType); break; } } }
//Fire OnMessageReceived public static void FireOnMessageReceived(ClientObject client, ClientMessage message) { bool handledByAny = false; foreach (var plugin in loadedPlugins) { try { plugin.OnMessageReceived(client, message); //prevent plugins from unhandling other plugin's handled requests if (message.handled) { handledByAny = true; } } catch (Exception e) { Type type = plugin.GetType(); DarkLog.Debug("Error thrown in OnMessageReceived event for " + type.FullName + " (" + type.Assembly.FullName + "), Exception: " + e); } } message.handled = handledByAny; }
private static void SendSetSubspace(ClientObject client) { if (!Settings.settingsStore.keepTickingWhileOffline && clients.Count == 1) { DarkLog.Debug("Reverting server time to last player connection"); long currentTime = DateTime.UtcNow.Ticks; foreach (KeyValuePair<int, Subspace> subspace in subspaces) { subspace.Value.serverClock = currentTime; subspace.Value.subspaceSpeed = 1f; SaveLatestSubspace(); } } int targetSubspace = -1; if (Settings.settingsStore.sendPlayerToLatestSubspace || !playerSubspace.ContainsKey(client.playerName)) { DarkLog.Debug("Sending " + client.playerName + " to the latest subspace " + targetSubspace); targetSubspace = GetLatestSubspace(); } else { DarkLog.Debug("Sending " + client.playerName + " to the previous subspace " + targetSubspace); targetSubspace = playerSubspace[client.playerName]; } client.subspace = targetSubspace; ServerMessage newMessage = new ServerMessage(); newMessage.type = ServerMessageType.SET_SUBSPACE; using (MessageWriter mw = new MessageWriter()) { mw.Write<int>(targetSubspace); newMessage.data = mw.GetMessageBytes(); } SendToClient(client, newMessage, true); }
private static void SendAllSubspaces(ClientObject client) { //Send all the locks. foreach (KeyValuePair<int, Subspace> subspace in subspaces) { ServerMessage newMessage = new ServerMessage(); newMessage.type = ServerMessageType.WARP_CONTROL; using (MessageWriter mw = new MessageWriter()) { mw.Write<int>((int)WarpMessageType.NEW_SUBSPACE); mw.Write<string>(""); mw.Write<int>(subspace.Key); mw.Write<long>(subspace.Value.serverClock); mw.Write<double>(subspace.Value.planetTime); mw.Write<float>(subspace.Value.subspaceSpeed); newMessage.data = mw.GetMessageBytes(); } SendToClient(client, newMessage, true); } //Tell the player "when" everyone is. foreach (ClientObject otherClient in clients) { if (otherClient.authenticated && (otherClient.playerName != client.playerName)) { ServerMessage newMessage = new ServerMessage(); newMessage.type = ServerMessageType.WARP_CONTROL; using (MessageWriter mw = new MessageWriter()) { mw.Write<int>((int)WarpMessageType.CHANGE_SUBSPACE); mw.Write<string>(otherClient.playerName); mw.Write<int>(otherClient.subspace); newMessage.data = mw.GetMessageBytes(); } SendToClient(client, newMessage, true); } } }
private static void SendScenarioModules(ClientObject client) { int numberOfScenarioModules = Directory.GetFiles(Path.Combine(Server.universeDirectory, "Scenarios", client.playerName)).Length; int currentScenarioModule = 0; string[] scenarioNames = new string[numberOfScenarioModules]; byte[][] scenarioDataArray = new byte[numberOfScenarioModules][]; foreach (string file in Directory.GetFiles(Path.Combine(Server.universeDirectory, "Scenarios", client.playerName))) { //Remove the .txt part for the name scenarioNames[currentScenarioModule] = Path.GetFileNameWithoutExtension(file); scenarioDataArray[currentScenarioModule] = File.ReadAllBytes(file); currentScenarioModule++; } ServerMessage newMessage = new ServerMessage(); newMessage.type = ServerMessageType.SCENARIO_DATA; using (MessageWriter mw = new MessageWriter()) { mw.Write<string[]>(scenarioNames); foreach (byte[] scenarioData in scenarioDataArray) { mw.Write<byte[]>(scenarioData); } newMessage.data = mw.GetMessageBytes(); } SendToClient(client, newMessage, true); }
private static void DisconnectClient(ClientObject client) { lock (client.disconnectLock) { if (client.connectionStatus != ConnectionStatus.DISCONNECTED) { DMPPluginHandler.FireOnClientDisconnect(client); if (client.playerName != null) { if (playerChatChannels.ContainsKey(client.playerName)) { playerChatChannels.Remove(client.playerName); } if (playerDownloadedScreenshotIndex.ContainsKey(client.playerName)) { playerDownloadedScreenshotIndex.Remove(client.playerName); } if (playerUploadedScreenshotIndex.ContainsKey(client.playerName)) { playerUploadedScreenshotIndex.Remove(client.playerName); } if (playerWatchScreenshot.ContainsKey(client.playerName)) { playerWatchScreenshot.Remove(client.playerName); } } client.connectionStatus = ConnectionStatus.DISCONNECTED; if (client.authenticated) { ServerMessage newMessage = new ServerMessage(); newMessage.type = ServerMessageType.PLAYER_DISCONNECT; using (MessageWriter mw = new MessageWriter()) { mw.Write<string>(client.playerName); newMessage.data = mw.GetMessageBytes(); } SendToAll(client, newMessage, true); lockSystem.ReleasePlayerLocks(client.playerName); } deleteClients.Enqueue(client); try { if (client.connection != null) { client.connection.GetStream().Close(); client.connection.Close(); } } catch (Exception e) { DarkLog.Debug("Error closing client connection: " + e.Message); } Server.lastPlayerActivity = Server.serverClock.ElapsedMilliseconds; } } }
public virtual void OnClientAuthenticated(ClientObject client) { }
private static void SplitAndRewriteMessage(ClientObject client, ref ServerMessage message) { if (message == null) { return; } if (message.data == null) { return; } if (message.data.Length > Common.SPLIT_MESSAGE_LENGTH) { ServerMessage newSplitMessage = new ServerMessage(); newSplitMessage.type = ServerMessageType.SPLIT_MESSAGE; int splitBytesLeft = message.data.Length; using (MessageWriter mw = new MessageWriter()) { mw.Write<int>((int)message.type); mw.Write<int>(message.data.Length); byte[] firstSplit = new byte[Common.SPLIT_MESSAGE_LENGTH]; Array.Copy(message.data, 0, firstSplit, 0, Common.SPLIT_MESSAGE_LENGTH); mw.Write<byte[]>(firstSplit); splitBytesLeft -= Common.SPLIT_MESSAGE_LENGTH; newSplitMessage.data = mw.GetMessageBytes(); //SPLIT_MESSAGE adds a 12 byte header. client.bytesQueuedOut += 12; client.sendMessageQueueSplit.Enqueue(newSplitMessage); } while (splitBytesLeft > 0) { ServerMessage currentSplitMessage = new ServerMessage(); currentSplitMessage.type = ServerMessageType.SPLIT_MESSAGE; currentSplitMessage.data = new byte[Math.Min(splitBytesLeft, Common.SPLIT_MESSAGE_LENGTH)]; Array.Copy(message.data, message.data.Length - splitBytesLeft, currentSplitMessage.data, 0, currentSplitMessage.data.Length); splitBytesLeft -= currentSplitMessage.data.Length; //Add the SPLIT_MESSAGE header to the out queue count. client.bytesQueuedOut += 12; client.sendMessageQueueSplit.Enqueue(currentSplitMessage); } client.sendMessageQueueSplit.TryDequeue(out message); } }
private static void StartReceivingIncomingMessages(ClientObject client) { client.lastReceiveTime = Server.serverClock.ElapsedMilliseconds; //Allocate byte for header client.receiveMessage = new ClientMessage(); client.receiveMessage.data = new byte[8]; client.receiveMessageBytesLeft = client.receiveMessage.data.Length; try { client.connection.GetStream().BeginRead(client.receiveMessage.data, client.receiveMessage.data.Length - client.receiveMessageBytesLeft, client.receiveMessageBytesLeft, new AsyncCallback(ReceiveCallback), client); } catch (Exception e) { HandleDisconnectException("Start Receive", client, e); } }
private static void SendConnectionEnd(ClientObject client, string reason) { ServerMessage newMessage = new ServerMessage(); newMessage.type = ServerMessageType.CONNECTION_END; using (MessageWriter mw = new MessageWriter()) { mw.Write<string>(reason); newMessage.data = mw.GetMessageBytes(); } SendToClient(client, newMessage, true); }
private static void StartSendingOutgoingMessages(ClientObject client) { Thread clientSendThread = new Thread(new ParameterizedThreadStart(SendOutgoingMessages)); clientSendThread.IsBackground = true; clientSendThread.Start(client); }
private static void SendVessel(ClientObject client, byte[] vesselData) { ServerMessage newMessage = new ServerMessage(); newMessage.type = ServerMessageType.VESSEL_PROTO; using (MessageWriter mw = new MessageWriter()) { mw.Write<double>(0); mw.Write<byte[]>(vesselData); newMessage.data = mw.GetMessageBytes(); } SendToClient(client, newMessage, false); }
private static void SendMotdReply(ClientObject client) { ServerMessage newMessage = new ServerMessage(); newMessage.type = ServerMessageType.MOTD_REPLY; string newMotd = Settings.settingsStore.serverMotd; newMotd = newMotd.Replace("%name%", client.playerName); newMotd = newMotd.Replace(@"\n", Environment.NewLine); using (MessageWriter mw = new MessageWriter()) { mw.Write<string>(newMotd); newMessage.data = mw.GetMessageBytes(); } SendToClient(client, newMessage, true); }
private static void SendKerbal(ClientObject client, string kerbalName, byte[] kerbalData) { ServerMessage newMessage = new ServerMessage(); newMessage.type = ServerMessageType.KERBAL_REPLY; using (MessageWriter mw = new MessageWriter()) { //Send the vessel with a send time of 0 so it instantly loads on the client. mw.Write<double>(0); mw.Write<string>(kerbalName); mw.Write<byte[]>(kerbalData); newMessage.data = mw.GetMessageBytes(); } SendToClient(client, newMessage, false); }
private static void SendAllReportedSkewRates(ClientObject client) { foreach (ClientObject otherClient in clients) { if (otherClient.authenticated) { if (otherClient != client) { ServerMessage newMessage = new ServerMessage(); newMessage.type = ServerMessageType.WARP_CONTROL; using (MessageWriter mw = new MessageWriter()) { mw.Write<int>((int)WarpMessageType.REPORT_RATE); mw.Write<string>(otherClient.playerName); mw.Write<float>(otherClient.subspace); mw.Write<float>(otherClient.subspaceRate); newMessage.data = mw.GetMessageBytes(); } SendToClient(client, newMessage, true); } } } }
public virtual void OnClientDisconnect(ClientObject client) { }
public virtual void OnMessageSent(ClientObject client, ServerMessage messageData) { }
public virtual void OnMessageReceived(ClientObject client, ClientMessage messageData) { }
private static void SendVesselList(ClientObject client) { ServerMessage newMessage = new ServerMessage(); newMessage.type = ServerMessageType.VESSEL_LIST; string[] vesselFiles = Directory.GetFiles(Path.Combine(Server.universeDirectory, "Vessels")); string[] vesselObjects = new string[vesselFiles.Length]; for (int i = 0; i < vesselFiles.Length; i++) { vesselObjects[i] = Common.CalculateSHA256Hash(vesselFiles[i]); } using (MessageWriter mw = new MessageWriter()) { mw.Write<string[]>(vesselObjects); newMessage.data = mw.GetMessageBytes(); } SendToClient(client, newMessage, false); }
private static void SendKerbalsComplete(ClientObject client) { ServerMessage newMessage = new ServerMessage(); newMessage.type = ServerMessageType.KERBAL_COMPLETE; SendToClient(client, newMessage, false); //Send vessel list needed for sync to the client SendVesselList(client); }
public void SendUnordered(ClientObject client, IMessage aMessage) { m_server.SendTo(aMessage, client.Id, GameServer.SendType.KUnordered); }
private static void SendVesselsComplete(ClientObject client) { ServerMessage newMessage = new ServerMessage(); newMessage.type = ServerMessageType.VESSEL_COMPLETE; SendToClient(client, newMessage, false); }
public void SendUnreliable(ClientObject client, IMessage aMessage) { m_server.SendTo(aMessage, client.Id, GameServer.SendType.KUnreliable); }
private static void SetupClient(TcpClient newClientConnection) { ClientObject newClientObject = new ClientObject(); newClientObject.subspace = GetLatestSubspace(); newClientObject.playerStatus = new PlayerStatus(); newClientObject.connectionStatus = ConnectionStatus.CONNECTED; newClientObject.endpoint = newClientConnection.Client.RemoteEndPoint.ToString(); newClientObject.ipAddress = (newClientConnection.Client.RemoteEndPoint as IPEndPoint).Address; //Keep the connection reference newClientObject.connection = newClientConnection; StartReceivingIncomingMessages(newClientObject); StartSendingOutgoingMessages(newClientObject); DMPPluginHandler.FireOnClientConnect(newClientObject); SendHandshakeChallange(newClientObject); addClients.Enqueue(newClientObject); }
private static void SendNetworkMessage(ClientObject client, ServerMessage message) { //Write the send times down in SYNC_TIME_REPLY packets if (message.type == ServerMessageType.SYNC_TIME_REPLY) { try { using (MessageWriter mw = new MessageWriter()) { using (MessageReader mr = new MessageReader(message.data)) { client.bytesQueuedOut += 8; //Client send time mw.Write <long>(mr.Read <long>()); //Server receive time mw.Write <long>(mr.Read <long>()); //Server send time mw.Write <long>(DateTime.UtcNow.Ticks); message.data = mw.GetMessageBytes(); } } } catch (Exception e) { DarkLog.Debug("Error rewriting SYNC_TIME packet, Exception " + e); } } //Continue sending byte[] messageBytes = Common.PrependNetworkFrame((int)message.type, message.data); client.lastSendTime = Server.serverClock.ElapsedMilliseconds; client.bytesQueuedOut -= messageBytes.Length; client.bytesSent += messageBytes.Length; if (client.connectionStatus == ConnectionStatus.CONNECTED) { try { client.connection.GetStream().Write(messageBytes, 0, messageBytes.Length); } catch (Exception e) { HandleDisconnectException("Send Network Message", client, e); return; } } DMPPluginHandler.FireOnMessageSent(client, message); if (message.type == ServerMessageType.CONNECTION_END) { using (MessageReader mr = new MessageReader(message.data)) { string reason = mr.Read <string>(); DarkLog.Normal("Disconnecting client " + client.playerName + ", sent CONNECTION_END (" + reason + ") to endpoint " + client.endpoint); client.disconnectClient = true; DisconnectClient(client); } } if (message.type == ServerMessageType.HANDSHAKE_REPLY) { using (MessageReader mr = new MessageReader(message.data)) { int response = mr.Read <int>(); string reason = mr.Read <string>(); if (response != 0) { DarkLog.Normal("Disconnecting client " + client.playerName + ", sent HANDSHAKE_REPLY (" + reason + ") to endpoint " + client.endpoint); client.disconnectClient = true; DisconnectClient(client); } } } }
private static void CheckHeartBeat(ClientObject client) { long currentTime = Server.serverClock.ElapsedMilliseconds; if ((currentTime - client.lastReceiveTime) > Common.CONNECTION_TIMEOUT) { //Heartbeat timeout DarkLog.Normal("Disconnecting client " + client.playerName + ", endpoint " + client.endpoint + ", Connection timed out"); DisconnectClient(client); } else { if (client.sendMessageQueueHigh.Count == 0 && client.sendMessageQueueSplit.Count == 0 && client.sendMessageQueueLow.Count == 0) { if ((currentTime - client.lastSendTime) > Common.HEART_BEAT_INTERVAL) { SendHeartBeat(client); } } } }
private static void ReceiveCallback(IAsyncResult ar) { ClientObject client = (ClientObject)ar.AsyncState; int bytesRead = 0; try { bytesRead = client.connection.GetStream().EndRead(ar); } catch (Exception e) { HandleDisconnectException("ReceiveCallback", client, e); return; } if (bytesRead == 0) { DarkLog.Normal("Disconnected " + client.endpoint); DisconnectClient(client); return; } client.bytesReceived += bytesRead; client.receiveMessageBytesLeft -= bytesRead; if (client.receiveMessageBytesLeft == 0) { //We either have the header or the message data, let's do something if (!client.isReceivingMessage) { //We have the header using (MessageReader mr = new MessageReader(client.receiveMessage.data)) { int messageType = mr.Read <int>(); int messageLength = mr.Read <int>(); if (messageType < 0 || messageType > (Enum.GetNames(typeof(ClientMessageType)).Length - 1)) { //Malformed message, most likely from a non DMP-client. Messages.ConnectionEnd.SendConnectionEnd(client, "Invalid DMP message. Disconnected."); DarkLog.Normal("Invalid DMP message from " + client.endpoint); //Returning from ReceiveCallback will break the receive loop and stop processing any further messages. return; } client.receiveMessage.type = (ClientMessageType)messageType; if (messageLength == 0) { //Null message, handle it. client.receiveMessage.data = null; HandleMessage(client, client.receiveMessage); client.receiveMessage.type = 0; client.receiveMessage.data = new byte[8]; client.receiveMessageBytesLeft = client.receiveMessage.data.Length; } else { if (messageLength > 0 && messageLength < Common.MAX_MESSAGE_SIZE) { client.isReceivingMessage = true; client.receiveMessage.data = new byte[messageLength]; client.receiveMessageBytesLeft = client.receiveMessage.data.Length; } else { //Malformed message, most likely from a non DMP-client. Messages.ConnectionEnd.SendConnectionEnd(client, "Invalid DMP message. Disconnected."); DarkLog.Normal("Invalid DMP message from " + client.endpoint); //Returning from ReceiveCallback will break the receive loop and stop processing any further messages. return; } } } } else { //We have the message data to a non-null message, handle it client.isReceivingMessage = false; #if !DEBUG try { #endif HandleMessage(client, client.receiveMessage); #if !DEBUG } catch (Exception e) { HandleDisconnectException("ReceiveCallback", client, e); return; } #endif client.receiveMessage.type = 0; client.receiveMessage.data = new byte[8]; client.receiveMessageBytesLeft = client.receiveMessage.data.Length; } } if (client.connectionStatus == ConnectionStatus.CONNECTED) { client.lastReceiveTime = Server.serverClock.ElapsedMilliseconds; try { client.connection.GetStream().BeginRead(client.receiveMessage.data, client.receiveMessage.data.Length - client.receiveMessageBytesLeft, client.receiveMessageBytesLeft, new AsyncCallback(ReceiveCallback), client); } catch (Exception e) { HandleDisconnectException("ReceiveCallback", client, e); return; } } }
private static void SendOutgoingMessages(ClientObject client) { while (client.connectionStatus == ConnectionStatus.CONNECTED) { ServerMessage message = null; if (message == null && client.sendMessageQueueHigh.Count > 0) { client.sendMessageQueueHigh.TryDequeue(out message); } //Don't send low or split during server shutdown. if (Server.serverRunning) { if (message == null && client.sendMessageQueueSplit.Count > 0) { client.sendMessageQueueSplit.TryDequeue(out message); } if (message == null && client.sendMessageQueueLow.Count > 0) { client.sendMessageQueueLow.TryDequeue(out message); //Splits large messages to higher priority messages can get into the queue faster SplitAndRewriteMessage(client, ref message); } } if (message != null) { SendNetworkMessage(client, message); } else { //Give the chance for the thread to terminate client.sendEvent.WaitOne(1000); } } }
internal static void HandleMessage(ClientObject client, ClientMessage message) { //Prevent plugins from dodging SPLIT_MESSAGE. If they are modified, every split message will be broken. if (message.type != ClientMessageType.SPLIT_MESSAGE) { DMPPluginHandler.FireOnMessageReceived(client, message); if (message.handled) { //a plugin has handled this message and requested suppression of the default DMP behavior return; } } //Clients can only send HEARTBEATS, HANDSHAKE_REQUEST or CONNECTION_END's until they are authenticated. if (!client.authenticated && !(message.type == ClientMessageType.HEARTBEAT || message.type == ClientMessageType.HANDSHAKE_RESPONSE || message.type == ClientMessageType.CONNECTION_END)) { Messages.ConnectionEnd.SendConnectionEnd(client, "You must authenticate before attempting to send a " + message.type.ToString() + " message"); return; } #if !DEBUG try { #endif switch (message.type) { case ClientMessageType.HEARTBEAT: //Don't do anything for heartbeats, they just keep the connection alive break; case ClientMessageType.HANDSHAKE_RESPONSE: Messages.Handshake.HandleHandshakeResponse(client, message.data); break; case ClientMessageType.CHAT_MESSAGE: Messages.Chat.HandleChatMessage(client, message.data); break; case ClientMessageType.PLAYER_STATUS: Messages.PlayerStatus.HandlePlayerStatus(client, message.data); break; case ClientMessageType.PLAYER_COLOR: Messages.PlayerColor.HandlePlayerColor(client, message.data); break; case ClientMessageType.GROUP: Messages.GroupMessage.HandleMessage(client, message.data); break; case ClientMessageType.SCENARIO_DATA: Messages.ScenarioData.HandleScenarioModuleData(client, message.data); break; case ClientMessageType.SYNC_TIME_REQUEST: Messages.SyncTimeRequest.HandleSyncTimeRequest(client, message.data); break; case ClientMessageType.KERBALS_REQUEST: Messages.KerbalsRequest.HandleKerbalsRequest(client); break; case ClientMessageType.KERBAL_PROTO: Messages.KerbalProto.HandleKerbalProto(client, message.data); break; case ClientMessageType.VESSELS_REQUEST: Messages.VesselRequest.HandleVesselsRequest(client, message.data); break; case ClientMessageType.VESSEL_PROTO: Messages.VesselProto.HandleVesselProto(client, message.data); break; case ClientMessageType.VESSEL_UPDATE: Messages.VesselUpdate.HandleVesselUpdate(client, message.data); break; case ClientMessageType.VESSEL_REMOVE: Messages.VesselRemove.HandleVesselRemoval(client, message.data); break; case ClientMessageType.PERMISSION: Messages.PermissionMessage.HandleMessage(client, message.data); break; case ClientMessageType.CRAFT_LIBRARY: Messages.CraftLibrary.HandleCraftLibrary(client, message.data); break; case ClientMessageType.SCREENSHOT_LIBRARY: Messages.ScreenshotLibrary.HandleScreenshotLibrary(client, message.data); break; case ClientMessageType.FLAG_SYNC: Messages.FlagSync.HandleFlagSync(client, message.data); break; case ClientMessageType.PING_REQUEST: Messages.PingRequest.HandlePingRequest(client, message.data); break; case ClientMessageType.MOTD_REQUEST: Messages.MotdRequest.HandleMotdRequest(client); break; case ClientMessageType.WARP_CONTROL: Messages.WarpControl.HandleWarpControl(client, message.data); break; case ClientMessageType.LOCK_SYSTEM: Messages.LockSystem.HandleLockSystemMessage(client, message.data); break; case ClientMessageType.MOD_DATA: Messages.ModData.HandleModDataMessage(client, message.data); break; case ClientMessageType.KERBAL_REMOVE: Messages.VesselRemove.HandleKerbalRemoval(client, message.data); break; case ClientMessageType.SPLIT_MESSAGE: Messages.SplitMessage.HandleSplitMessage(client, message.data); break; case ClientMessageType.CONNECTION_END: Messages.ConnectionEnd.HandleConnectionEnd(client, message.data); break; case ClientMessageType.MODPACK_DATA: Messages.Modpack.HandleModpackMessage(client, message.data); break; default: DarkLog.Debug("Unhandled message type " + message.type); Messages.ConnectionEnd.SendConnectionEnd(client, "Unhandled message type " + message.type); #if DEBUG throw new NotImplementedException("Message type not implemented"); #else break; #endif } #if !DEBUG } catch (Exception e) { DarkLog.Debug("Error handling " + message.type + " from " + client.playerName + ", exception: " + e); Messages.ConnectionEnd.SendConnectionEnd(client, "Server failed to process " + message.type + " message"); } #endif }
private static void SendNetworkMessage(ClientObject client, ServerMessage message) { //Write the send times down in SYNC_TIME_REPLY packets if (message.type == ServerMessageType.SYNC_TIME_REPLY) { try { using (MessageWriter mw = new MessageWriter()) { using (MessageReader mr = new MessageReader(message.data, false)) { client.bytesQueuedOut += 8; //Client send time mw.Write<long>(mr.Read<long>()); //Server receive time mw.Write<long>(mr.Read<long>()); //Server send time mw.Write<long>(DateTime.UtcNow.Ticks); message.data = mw.GetMessageBytes(); } } } catch (Exception e) { DarkLog.Debug("Error rewriting SYNC_TIME packet, Exception " + e); } } //Continue sending byte[] messageBytes; using (MessageWriter mw = new MessageWriter((int)message.type)) { if (message.data != null) { mw.Write<byte[]>(message.data); } messageBytes = mw.GetMessageBytes(); } client.lastSendTime = Server.serverClock.ElapsedMilliseconds; client.bytesQueuedOut -= messageBytes.Length; client.bytesSent += messageBytes.Length; if (client.connectionStatus == ConnectionStatus.CONNECTED) { try { client.connection.GetStream().Write(messageBytes, 0, messageBytes.Length); } catch (Exception e) { HandleDisconnectException("Send Network Message", client, e); return; } } if (message.type == ServerMessageType.CONNECTION_END) { using (MessageReader mr = new MessageReader(message.data, false)) { string reason = mr.Read<string>(); DarkLog.Normal("Disconnecting client " + client.playerName + ", sent CONNECTION_END (" + reason + ") to endpoint " + client.endpoint); client.disconnectClient = true; DisconnectClient(client); } } if (message.type == ServerMessageType.HANDSHAKE_REPLY) { using (MessageReader mr = new MessageReader(message.data, false)) { int response = mr.Read<int>(); string reason = mr.Read<string>(); if (response != 0) { DarkLog.Normal("Disconnecting client " + client.playerName + ", sent HANDSHAKE_REPLY (" + reason + ") to endpoint " + client.endpoint); client.disconnectClient = true; DisconnectClient(client); } } } }
public static void SendToClient(ClientObject client, ServerMessage message, bool highPriority) { //Because we dodge the queue, we need to lock it up again... lock (client.sendLock) { if (message == null) { return; } //All messages have an 8 byte header client.bytesQueuedOut += 8; if (message.data != null) { //Count the payload if we have one. client.bytesQueuedOut += message.data.Length; } if (highPriority) { client.sendMessageQueueHigh.Enqueue(message); } else { client.sendMessageQueueLow.Enqueue(message); //If we need to optimize if (client.bytesQueuedOut > OPTIMIZE_QUEUE_LIMIT) { //And we haven't optimized in the last 5 seconds long currentTime = DateTime.UtcNow.Ticks; long optimizedBytes = 0; if ((currentTime - client.lastQueueOptimizeTime) > 50000000) { client.lastQueueOptimizeTime = currentTime; DarkLog.Debug("Optimizing " + client.playerName + " (" + client.bytesQueuedOut + " bytes queued)"); //Create a temporary filter list List <ServerMessage> oldClientMessagesToSend = new List <ServerMessage>(); List <ServerMessage> newClientMessagesToSend = new List <ServerMessage>(); //Steal all the messages from the queue and put them into a list ServerMessage stealMessage = null; while (client.sendMessageQueueLow.TryDequeue(out stealMessage)) { oldClientMessagesToSend.Add(stealMessage); } //Clear the client send queue List <string> seenProtovesselUpdates = new List <string>(); List <string> seenPositionUpdates = new List <string>(); //Iterate backwards over the list oldClientMessagesToSend.Reverse(); foreach (ServerMessage currentMessage in oldClientMessagesToSend) { if (currentMessage.type != ServerMessageType.VESSEL_PROTO && currentMessage.type != ServerMessageType.VESSEL_UPDATE) { //Message isn't proto or position, don't skip it. newClientMessagesToSend.Add(currentMessage); } else { //Message is proto or position if (currentMessage.type == ServerMessageType.VESSEL_PROTO) { using (MessageReader mr = new MessageReader(currentMessage.data)) { //Don't care about the send time, it's already the latest in the queue. mr.Read <double>(); string vesselID = mr.Read <string>(); if (!seenProtovesselUpdates.Contains(vesselID)) { seenProtovesselUpdates.Add(vesselID); newClientMessagesToSend.Add(currentMessage); } else { optimizedBytes += 8 + currentMessage.data.Length; } } } if (currentMessage.type == ServerMessageType.VESSEL_UPDATE) { using (MessageReader mr = new MessageReader(currentMessage.data)) { //Don't care about the send time, it's already the latest in the queue. mr.Read <double>(); string vesselID = mr.Read <string>(); if (!seenPositionUpdates.Contains(vesselID)) { seenPositionUpdates.Add(vesselID); newClientMessagesToSend.Add(currentMessage); } else { //8 byte message header plus payload optimizedBytes += 8 + currentMessage.data.Length; } } } } } //Flip it back to the right order newClientMessagesToSend.Reverse(); foreach (ServerMessage putBackMessage in newClientMessagesToSend) { client.sendMessageQueueLow.Enqueue(putBackMessage); } float optimizeTime = (DateTime.UtcNow.Ticks - currentTime) / 10000f; client.bytesQueuedOut -= optimizedBytes; DarkLog.Debug("Optimized " + optimizedBytes + " bytes in " + Math.Round(optimizeTime, 3) + " ms."); } } } client.sendEvent.Set(); } }
private static void HandleDisconnectException(string location, ClientObject client, Exception e) { lock (client.disconnectLock) { if (!client.disconnectClient && client.connectionStatus != ConnectionStatus.DISCONNECTED) { if (e.InnerException != null) { DarkLog.Normal("Client " + client.playerName + " disconnected in " + location + ", endpoint " + client.endpoint + ", error: " + e.Message + " (" + e.InnerException.Message + ")"); } else { DarkLog.Normal("Client " + client.playerName + " disconnected in " + location + ", endpoint " + client.endpoint + ", error: " + e.Message); } } DisconnectClient(client); } }
public static bool ClientConnected(ClientObject client) { return(clients.Contains(client)); }
private static void HandleMessage(ClientObject client, ClientMessage message) { //Prevent plugins from dodging SPLIT_MESSAGE. If they are modified, every split message will be broken. if (message.type != ClientMessageType.SPLIT_MESSAGE) { DMPPluginHandler.FireOnMessageReceived(client, message); if (message.handled) { //a plugin has handled this message and requested suppression of the default DMP behavior return; } } //Clients can only send HEARTBEATS, HANDSHAKE_REQUEST or CONNECTION_END's until they are authenticated. if (!client.authenticated && !(message.type == ClientMessageType.HEARTBEAT || message.type == ClientMessageType.HANDSHAKE_RESPONSE || message.type == ClientMessageType.CONNECTION_END)) { SendConnectionEnd(client, "You must authenticate before attempting to send a " + message.type.ToString() + " message"); return; } try { switch (message.type) { case ClientMessageType.HEARTBEAT: //Don't do anything for heartbeats, they just keep the connection alive break; case ClientMessageType.HANDSHAKE_RESPONSE: HandleHandshakeResponse(client, message.data); break; case ClientMessageType.CHAT_MESSAGE: HandleChatMessage(client, message.data); break; case ClientMessageType.PLAYER_STATUS: HandlePlayerStatus(client, message.data); break; case ClientMessageType.PLAYER_COLOR: HandlePlayerColor(client, message.data); break; case ClientMessageType.SCENARIO_DATA: HandleScenarioModuleData(client, message.data); break; case ClientMessageType.SYNC_TIME_REQUEST: HandleSyncTimeRequest(client, message.data); break; case ClientMessageType.KERBALS_REQUEST: HandleKerbalsRequest(client); break; case ClientMessageType.KERBAL_PROTO: HandleKerbalProto(client, message.data); break; case ClientMessageType.VESSELS_REQUEST: HandleVesselsRequest(client, message.data); break; case ClientMessageType.VESSEL_PROTO: HandleVesselProto(client, message.data); break; case ClientMessageType.VESSEL_UPDATE: HandleVesselUpdate(client, message.data); break; case ClientMessageType.VESSEL_REMOVE: HandleVesselRemoval(client, message.data); break; case ClientMessageType.CRAFT_LIBRARY: HandleCraftLibrary(client, message.data); break; case ClientMessageType.SCREENSHOT_LIBRARY: HandleScreenshotLibrary(client, message.data); break; case ClientMessageType.FLAG_SYNC: HandleFlagSync(client, message.data); break; case ClientMessageType.PING_REQUEST: HandlePingRequest(client, message.data); break; case ClientMessageType.MOTD_REQUEST: HandleMotdRequest(client); break; case ClientMessageType.WARP_CONTROL: HandleWarpControl(client, message.data); break; case ClientMessageType.LOCK_SYSTEM: HandleLockSystemMessage(client, message.data); break; case ClientMessageType.MOD_DATA: HandleModDataMessage(client, message.data); break; case ClientMessageType.SPLIT_MESSAGE: HandleSplitMessage(client, message.data); break; case ClientMessageType.CONNECTION_END: HandleConnectionEnd(client, message.data); break; default: DarkLog.Debug("Unhandled message type " + message.type); SendConnectionEnd(client, "Unhandled message type " + message.type); break; } } catch (Exception e) { DarkLog.Debug("Error handling " + message.type + " from " + client.playerName + ", exception: " + e); SendConnectionEnd(client, "Server failed to process " + message.type + " message"); } }
private static void SendAllPlayerStatus(ClientObject client) { foreach (ClientObject otherClient in clients) { if (otherClient.authenticated) { if (otherClient != client) { ServerMessage newMessage = new ServerMessage(); newMessage.type = ServerMessageType.PLAYER_STATUS; using (MessageWriter mw = new MessageWriter()) { mw.Write<string>(otherClient.playerName); mw.Write<string>(otherClient.playerStatus.vesselText); mw.Write<string>(otherClient.playerStatus.statusText); newMessage.data = mw.GetMessageBytes(); } SendToClient(client, newMessage, true); } } } }