diff --git a/TShockAPI/Net/DisconnectMsg.cs b/TShockAPI/Net/DisconnectMsg.cs new file mode 100644 index 00000000..e838280e --- /dev/null +++ b/TShockAPI/Net/DisconnectMsg.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Microsoft.Xna.Framework; +using TerrariaAPI; +using XNAHelpers; + +namespace TShockAPI.Net +{ + class DisconnectMsg : BaseMsg + { + public override PacketTypes ID + { + get + { + return PacketTypes.Disconnect; + } + } + public string Reason {get;set;} + public override void Pack(Stream stream) + { + stream.WriteBytes(Encoding.ASCII.GetBytes(Reason)); + } + } +} diff --git a/TShockAPI/PacketBufferer.cs b/TShockAPI/PacketBufferer.cs index 4778e9dd..cd19f6ed 100644 --- a/TShockAPI/PacketBufferer.cs +++ b/TShockAPI/PacketBufferer.cs @@ -110,22 +110,18 @@ namespace TShockAPI if (socket == null || !socket.active) return false; - if (!socket.tcpClient.Client.Poll(0, SelectMode.SelectWrite)) + if (buffers[socket.whoAmI].Count < 1) return false; byte[] buff = buffers[socket.whoAmI].GetBytes(BytesPerUpdate); if (buff == null) return false; - - socket.tcpClient.Client.Send(buff); - return true; - } - catch (ObjectDisposedException) - { - } - catch (SocketException) - { + if (SendBytes(socket, buff)) + { + buffers[socket.whoAmI].Pop(buff.Length); + return true; + } } catch (Exception e) { @@ -140,12 +136,16 @@ namespace TShockAPI buffers[socket.whoAmI] = new PacketBuffer(); } - public void SendBytes(ServerSock socket, byte[] buffer) + public bool SendBytes(ServerSock socket, byte[] buffer) { - SendBytes(socket, buffer, 0, buffer.Length); + return SendBytes(socket, buffer, 0, buffer.Length); + } + public void BufferBytes(ServerSock socket, byte[] buffer) + { + BufferBytes(socket, buffer, 0, buffer.Length); } - public void SendBytes(ServerSock socket, byte[] buffer, int offset, int count) + public void BufferBytes(ServerSock socket, byte[] buffer, int offset, int count) { lock (buffers[socket.whoAmI]) { @@ -164,10 +164,29 @@ namespace TShockAPI } } + public bool SendBytes(ServerSock socket, byte[] buffer, int offset, int count) + { + try + { + if (socket.tcpClient.Client != null && socket.tcpClient.Client.Poll(0, SelectMode.SelectWrite)) + { + socket.tcpClient.Client.Send(buffer, offset, count, SocketFlags.None); + return true; + } + } + catch (ObjectDisposedException) + { + } + catch (SocketException) + { + } + return false; + } + void ServerHooks_SendBytes(ServerSock socket, byte[] buffer, int offset, int count, HandledEventArgs e) { e.Handled = true; - SendBytes(socket, buffer, offset, count); + BufferBytes(socket, buffer, offset, count); } #if DEBUG_NET static int Compress(byte[] buffer, int offset, int count) @@ -195,9 +214,16 @@ namespace TShockAPI var ret = new byte[Math.Min(max, this.Count)]; this.CopyTo(0, ret, 0, ret.Length); - this.RemoveRange(0, ret.Length); return ret; } } + + public void Pop(int count) + { + lock (this) + { + this.RemoveRange(0, count); + } + } } } diff --git a/TShockAPI/Properties/AssemblyInfo.cs b/TShockAPI/Properties/AssemblyInfo.cs index b57720cb..529c736f 100644 --- a/TShockAPI/Properties/AssemblyInfo.cs +++ b/TShockAPI/Properties/AssemblyInfo.cs @@ -36,5 +36,5 @@ using System.Runtime.InteropServices; // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.2.7.0817")] -[assembly: AssemblyFileVersion("3.2.7.0817")] +[assembly: AssemblyVersion("3.2.8.0818")] +[assembly: AssemblyFileVersion("3.2.8.0818")] diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs index a59fbc57..e63b65bb 100644 --- a/TShockAPI/TSPlayer.cs +++ b/TShockAPI/TSPlayer.cs @@ -156,7 +156,6 @@ namespace TShockAPI public virtual void Disconnect(string reason) { SendData(PacketTypes.Disconnect, reason); - Flush(); } public virtual void Flush() diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 397a7ab7..9e0e258b 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -40,6 +40,7 @@ using Terraria; using TerrariaAPI; using TerrariaAPI.Hooks; using TShockAPI.DB; +using TShockAPI.Net; namespace TShockAPI { @@ -179,6 +180,7 @@ namespace TShockAPI ServerHooks.Chat += OnChat; ServerHooks.Command += ServerHooks_OnCommand; NetHooks.GetData += OnGetData; + NetHooks.SendData += NetHooks_SendData; NetHooks.GreetPlayer += OnGreetPlayer; NpcHooks.StrikeNpc += NpcHooks_OnStrikeNpc; @@ -212,6 +214,7 @@ namespace TShockAPI ServerHooks.Chat -= OnChat; ServerHooks.Command -= ServerHooks_OnCommand; NetHooks.GetData -= OnGetData; + NetHooks.SendData -= NetHooks_SendData; NetHooks.GreetPlayer -= OnGreetPlayer; NpcHooks.StrikeNpc -= NpcHooks_OnStrikeNpc; if (File.Exists(Path.Combine(SavePath, "tshock.pid"))) @@ -556,6 +559,9 @@ namespace TShockAPI return; PacketTypes type = e.MsgID; + + Debug.WriteLine("Recv: {0:X}: {2} ({1:XX})", e.Msg.whoAmI, (byte)type, type); + var player = Players[e.Msg.whoAmI]; if (player == null) { @@ -569,7 +575,7 @@ namespace TShockAPI return; } - //Debug.WriteLine("Recv: {0:X} ({2}): {3} ({1:XX})", player.Index, (byte)type, player.TPlayer.dead ? "dead " : "alive", type); + // Stop accepting updates from player as this player is going to be kicked/banned during OnUpdate (different thread so can produce race conditions) if ((Config.BanKillTileAbusers || Config.KickKillTileAbusers) && @@ -656,10 +662,20 @@ namespace TShockAPI { if (PacketBuffer != null) { - PacketBuffer.SendBytes(client, bytes); + PacketBuffer.BufferBytes(client, bytes); return true; } + return SendBytesBufferless(client,bytes); + } + /// + /// Send bytes to a client ignoring the packet buffer + /// + /// socket to send to + /// bytes to send + /// False on exception + public static bool SendBytesBufferless(ServerSock client, byte[] bytes) + { try { if (client.tcpClient.Connected) @@ -668,11 +684,44 @@ namespace TShockAPI } catch (Exception ex) { + Log.Warn("This is a normal exception"); Log.Warn(ex.ToString()); } return false; } + void NetHooks_SendData(SendDataEventArgs e) + { + if (e.MsgID == PacketTypes.Disconnect) + { + Action senddisconnect = (sock, str) => + { + if (sock == null || !sock.active) + return; + using (var ms = new MemoryStream()) + { + new DisconnectMsg {Reason = str}.PackFull(ms); + SendBytesBufferless(sock, ms.ToArray()); + } + }; + + if (e.remoteClient != -1) + { + senddisconnect(Netplay.serverSock[e.remoteClient], e.text); + } + else + { + for (int i = 0; i < Netplay.serverSock.Length; i++) + { + if (e.ignoreClient != -1 && e.ignoreClient == i) + continue; + + senddisconnect(Netplay.serverSock[i], e.text); + } + } + } + } + private void OnSaveWorld(bool resettime, HandledEventArgs e) { Tools.Broadcast("Saving world. Momentary lag might result from this.", Color.Red); diff --git a/TShockAPI/TShockAPI.csproj b/TShockAPI/TShockAPI.csproj index 08f1fb60..9f680956 100644 --- a/TShockAPI/TShockAPI.csproj +++ b/TShockAPI/TShockAPI.csproj @@ -112,6 +112,7 @@ + @@ -180,7 +181,7 @@ - +