From 46957684f356527dc8371d6bc334631b28b4bc1c Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Mon, 5 Jun 2017 19:27:51 +0300 Subject: [PATCH] Clients and server limit the number of chat messages included in a message if their byte size exceeds the MTU --- Barotrauma/Source/Networking/ChatMessage.cs | 28 +++++++++++++++++ Barotrauma/Source/Networking/GameClient.cs | 22 +++++++++---- Barotrauma/Source/Networking/GameServer.cs | 34 ++++++++++++--------- 3 files changed, 63 insertions(+), 21 deletions(-) diff --git a/Barotrauma/Source/Networking/ChatMessage.cs b/Barotrauma/Source/Networking/ChatMessage.cs index d527d2a81..fd448eb22 100644 --- a/Barotrauma/Source/Networking/ChatMessage.cs +++ b/Barotrauma/Source/Networking/ChatMessage.cs @@ -196,6 +196,34 @@ namespace Barotrauma.Networking GameMain.Server.SendChatMessage(txt, null, c); } + public int EstimateLengthBytesClient() + { + int length = 1 + //(byte)ServerNetObject.CHAT_MESSAGE + 2 + //(UInt16)NetStateID + Encoding.UTF8.GetBytes(Text).Length + 2; + + return length; + } + + public int EstimateLengthBytesServer(Client c) + { + int length = 1 + //(byte)ServerNetObject.CHAT_MESSAGE + 2 + //(UInt16)NetStateID + 1 + //(byte)Type + Encoding.UTF8.GetBytes(Text).Length + 2; + + if (Sender != null && c.inGame) + { + length += 2; //sender ID (UInt16) + } + else if (SenderName != null) + { + length += Encoding.UTF8.GetBytes(SenderName).Length + 2; + } + + return length; + } + public void ServerWrite(NetOutgoingMessage msg, Client c) { msg.Write((byte)ServerNetObject.CHAT_MESSAGE); diff --git a/Barotrauma/Source/Networking/GameClient.cs b/Barotrauma/Source/Networking/GameClient.cs index 0f35ba280..121601014 100644 --- a/Barotrauma/Source/Networking/GameClient.cs +++ b/Barotrauma/Source/Networking/GameClient.cs @@ -960,6 +960,11 @@ namespace Barotrauma.Networking chatMsgQueue.RemoveAll(cMsg => !NetIdUtils.IdMoreRecent(cMsg.NetStateID, lastSentChatMsgID)); for (int i = 0; i < chatMsgQueue.Count && i < ChatMessage.MaxMessagesPerPacket; i++) { + if (outmsg.LengthBytes + chatMsgQueue[i].EstimateLengthBytesClient() > client.Configuration.MaximumTransmissionUnit - 5) + { + //not enough room in this packet + return; + } chatMsgQueue[i].ClientWrite(outmsg); } outmsg.Write((byte)ClientNetObject.END_OF_MESSAGE); @@ -982,16 +987,21 @@ namespace Barotrauma.Networking outmsg.Write(ChatMessage.LastID); outmsg.Write(entityEventManager.LastReceivedID); - chatMsgQueue.RemoveAll(cMsg => !NetIdUtils.IdMoreRecent(cMsg.NetStateID, lastSentChatMsgID)); - for (int i = 0; i < chatMsgQueue.Count && i < ChatMessage.MaxMessagesPerPacket; i++) - { - chatMsgQueue[i].ClientWrite(outmsg); - } - Character.Controlled?.ClientWrite(outmsg); entityEventManager.Write(outmsg, client.ServerConnection); + chatMsgQueue.RemoveAll(cMsg => !NetIdUtils.IdMoreRecent(cMsg.NetStateID, lastSentChatMsgID)); + for (int i = 0; i < chatMsgQueue.Count && i < ChatMessage.MaxMessagesPerPacket; i++) + { + if (outmsg.LengthBytes + chatMsgQueue[i].EstimateLengthBytesClient() > client.Configuration.MaximumTransmissionUnit - 5) + { + //not enough room in this packet + return; + } + chatMsgQueue[i].ClientWrite(outmsg); + } + outmsg.Write((byte)ClientNetObject.END_OF_MESSAGE); if (outmsg.LengthBytes > client.Configuration.MaximumTransmissionUnit) diff --git a/Barotrauma/Source/Networking/GameServer.cs b/Barotrauma/Source/Networking/GameServer.cs index 32fc800b0..e78821349 100644 --- a/Barotrauma/Source/Networking/GameServer.cs +++ b/Barotrauma/Source/Networking/GameServer.cs @@ -859,14 +859,7 @@ namespace Barotrauma.Networking outmsg.Write((byte)ServerNetObject.SYNC_IDS); outmsg.Write(c.lastSentChatMsgID); //send this to client so they know which chat messages weren't received by the server outmsg.Write(c.lastSentEntityEventID); - - c.chatMsgQueue.RemoveAll(cMsg => !NetIdUtils.IdMoreRecent(cMsg.NetStateID, c.lastRecvChatMsgID)); - for (int i = 0; i < c.chatMsgQueue.Count && i < ChatMessage.MaxMessagesPerPacket; i++) - { - c.chatMsgQueue[i].ServerWrite(outmsg, c); - } - //don't send position updates to characters who are still midround syncing //characters or items spawned mid-round don't necessarily exist at the client's end yet if (!c.NeedsMidRoundSync) @@ -909,6 +902,8 @@ namespace Barotrauma.Networking } entityEventManager.Write(c, outmsg); + + WriteChatMessages(outmsg, c); outmsg.Write((byte)ServerNetObject.END_OF_MESSAGE); @@ -978,15 +973,10 @@ namespace Barotrauma.Networking outmsg.Write(false); outmsg.WritePadBits(); } - - outmsg.Write(c.lastSentChatMsgID); //send this to client so they know which chat messages weren't received by the server - - c.chatMsgQueue.RemoveAll(cMsg => !NetIdUtils.IdMoreRecent(cMsg.NetStateID, c.lastRecvChatMsgID)); - for (int i = 0; i < c.chatMsgQueue.Count && i < ChatMessage.MaxMessagesPerPacket; i++) - { - c.chatMsgQueue[i].ServerWrite(outmsg, c); - } + outmsg.Write(c.lastSentChatMsgID); //send this to client so they know which chat messages weren't received by the server + + WriteChatMessages(outmsg, c); outmsg.Write((byte)ServerNetObject.END_OF_MESSAGE); @@ -1013,6 +1003,20 @@ namespace Barotrauma.Networking } } + private void WriteChatMessages(NetOutgoingMessage outmsg, Client c) + { + c.chatMsgQueue.RemoveAll(cMsg => !NetIdUtils.IdMoreRecent(cMsg.NetStateID, c.lastRecvChatMsgID)); + for (int i = 0; i < c.chatMsgQueue.Count && i < ChatMessage.MaxMessagesPerPacket; i++) + { + if (outmsg.LengthBytes + c.chatMsgQueue[i].EstimateLengthBytesServer(c) > config.MaximumTransmissionUnit - 5) + { + //not enough room in this packet + return; + } + c.chatMsgQueue[i].ServerWrite(outmsg, c); + } + } + public bool StartGameClicked(GUIButton button, object obj) { Submarine selectedSub = null;