From 81486772f63e3c9db30a6ddb250a194da90566f7 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Sat, 9 Oct 2021 11:55:31 -0700 Subject: [PATCH] fix: Fixes networking (#822) * Fixes wepoll to be POSIX compliant. --- .../Helpers/PacketTestUtilities.cs | 18 +--- .../Packets/Outgoing/LightPacketTests.cs | 2 +- Projects/Server/Network/NetState/NetState.cs | 14 ++-- Projects/Server/Network/NetworkSocket.cs | 77 ------------------ .../Server/Network/PollGroup/EPollGroup.cs | 61 ++++++-------- .../Network/PollGroup/KQueuePollGroup.cs | 31 +++---- .../Server/Network/PollGroup/PollGroup.cs | 8 +- Projects/Server/Network/TcpServer.cs | 2 +- Projects/Server/wepoll.dll | Bin 21504 -> 21504 bytes Projects/UOContent/Misc/ServerList.cs | 8 +- 10 files changed, 60 insertions(+), 161 deletions(-) delete mode 100644 Projects/Server/Network/NetworkSocket.cs diff --git a/Projects/Server.Tests/Helpers/PacketTestUtilities.cs b/Projects/Server.Tests/Helpers/PacketTestUtilities.cs index b90c457e9..afcbc6423 100644 --- a/Projects/Server.Tests/Helpers/PacketTestUtilities.cs +++ b/Projects/Server.Tests/Helpers/PacketTestUtilities.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; using System.Net.Sockets; -using Moq; using Server.Network; namespace Server.Tests.Network @@ -11,18 +9,8 @@ namespace Server.Tests.Network public static Span Compile(this Packet p) => p.Compile(false, out var length).AsSpan(0, length); - public static NetState CreateTestNetState() - { - var socket = new Mock(); - socket - .Setup(s => s.SendAsync(It.IsAny>>(), SocketFlags.None)) - .ReturnsAsync(() => 0); - - socket - .Setup(s => s.ReceiveAsync(It.IsAny>>(), SocketFlags.None)) - .ReturnsAsync(() => 0); - - return new NetState(socket.Object); - } + public static NetState CreateTestNetState() => new( + new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) + ); } } diff --git a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/LightPacketTests.cs b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/LightPacketTests.cs index 36e79adf9..a6eb94b47 100644 --- a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/LightPacketTests.cs +++ b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/LightPacketTests.cs @@ -9,7 +9,7 @@ namespace Server.Tests.Network [Fact] public void TestGlobalLightLevel() { - byte lightLevel = 5; + const byte lightLevel = 5; var expected = new GlobalLightLevel(lightLevel).Compile(); var ns = PacketTestUtilities.CreateTestNetState(); diff --git a/Projects/Server/Network/NetState/NetState.cs b/Projects/Server/Network/NetState/NetState.cs index 136b84320..a1104a6f8 100755 --- a/Projects/Server/Network/NetState/NetState.cs +++ b/Projects/Server/Network/NetState/NetState.cs @@ -48,7 +48,7 @@ namespace Server.Network private const int MenuCap = 512; private const int PacketPerSecondThreshold = 3000; - private static NetState[] _polledStates = new NetState[2048]; + private static GCHandle[] _polledStates = new GCHandle[2048]; private static readonly IPollGroup _pollGroup = PollGroup.Create(); private static readonly Queue FlushPending = new(2048); private static readonly Queue FlushedPartials = new(2048); @@ -101,7 +101,7 @@ namespace Server.Network Timer.DelayCall(TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1.5), CheckAllAlive); } - public NetState(ISocket connection) + public NetState(Socket connection) { Connection = connection; Seeded = false; @@ -130,7 +130,7 @@ namespace Server.Network try { - _pollGroup.Add(this); + _pollGroup.Add(connection, _handle); } catch (Exception ex) { @@ -171,7 +171,7 @@ namespace Server.Network public Pipe SendPipe { get; } - public ISocket Connection { get; } + public Socket Connection { get; } public bool CompressionEnabled { get; set; } @@ -885,8 +885,8 @@ namespace Server.Network { for (int i = 0; i < count; i++) { - _polledStates[i].HandleReceive(); - _polledStates[i] = null; + (_polledStates[i].Target as NetState)?.HandleReceive(); + _polledStates[i] = default; } } @@ -1032,7 +1032,7 @@ namespace Server.Network TcpServer.Instances.Remove(this); try { - _pollGroup.Remove(this); + _pollGroup.Remove(Connection); } catch (Exception ex) { diff --git a/Projects/Server/Network/NetworkSocket.cs b/Projects/Server/Network/NetworkSocket.cs deleted file mode 100644 index f762ba1cf..000000000 --- a/Projects/Server/Network/NetworkSocket.cs +++ /dev/null @@ -1,77 +0,0 @@ -/************************************************************************* - * ModernUO * - * Copyright 2019-2020 - ModernUO Development Team * - * Email: hi@modernuo.com * - * File: NetworkSocket.cs * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * (at your option) any later version. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - *************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Net; -using System.Net.Sockets; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; - -namespace Server.Network -{ - public class NetworkSocket : ISocket - { - private readonly Socket _connection; - - public Socket Connection - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _connection; - } - - public IntPtr Handle - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _connection.Handle; - } - - public EndPoint LocalEndPoint - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _connection.LocalEndPoint; - } - - public EndPoint RemoteEndPoint - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _connection.RemoteEndPoint; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public NetworkSocket(Socket connection) => _connection = connection; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Task SendAsync(IList> buffers, SocketFlags flags) => - _connection.SendAsync(buffers, flags); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int Send(IList> buffers, SocketFlags flags) => _connection.Send(buffers, flags); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Task ReceiveAsync(IList> buffers, SocketFlags flags) => - _connection.ReceiveAsync(buffers, flags); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int Receive(IList> buffers, SocketFlags flags) => - _connection.Receive(buffers, flags); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Shutdown(SocketShutdown how) => _connection.Shutdown(how); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Close() => _connection.Close(); - } -} diff --git a/Projects/Server/Network/PollGroup/EPollGroup.cs b/Projects/Server/Network/PollGroup/EPollGroup.cs index 60b8d594f..bc51526e8 100755 --- a/Projects/Server/Network/PollGroup/EPollGroup.cs +++ b/Projects/Server/Network/PollGroup/EPollGroup.cs @@ -14,6 +14,7 @@ *************************************************************************/ using System; +using System.Net.Sockets; using System.Runtime.InteropServices; namespace Server.Network @@ -53,23 +54,20 @@ namespace Server.Network EPOLL_CTL_MOD = 3, } - [StructLayout(LayoutKind.Explicit)] + [StructLayout(LayoutKind.Explicit, Size = 8)] private struct epoll_data { [FieldOffset(0)] public int fd; - [FieldOffset(0)] public IntPtr ptr; - [FieldOffset(0)] public uint u32; - [FieldOffset(0)] public ulong u64; } - [StructLayout(LayoutKind.Explicit)] + [StructLayout(LayoutKind.Explicit, Pack = 4)] private struct epoll_event { [FieldOffset(0)] @@ -109,10 +107,12 @@ namespace Server.Network } private readonly int _epHndle; + private readonly bool _isWindows; public EPollGroup() { - _epHndle = Core.IsWindows ? Windows.epoll_create1(epoll_flags.NONE) : Linux.epoll_create1(epoll_flags.NONE); + _isWindows = Core.IsWindows; + _epHndle = _isWindows ? Windows.epoll_create1(epoll_flags.NONE) : Linux.epoll_create1(epoll_flags.NONE); if (_epHndle == 0) { @@ -122,7 +122,7 @@ namespace Server.Network public void Dispose() { - if (Core.IsWindows) + if (_isWindows) { Windows.epoll_close(_epHndle); } @@ -132,18 +132,18 @@ namespace Server.Network } } - public void Add(NetState state) + public void Add(Socket socket, GCHandle handle) { var ev = new epoll_event { events = epoll_events.EPOLLIN | epoll_events.EPOLLERR }; - ev.data.ptr = (IntPtr)state._handle; + ev.data.ptr = (IntPtr)handle; - var rc = Core.IsWindows ? - Windows.epoll_ctl(_epHndle, epoll_op.EPOLL_CTL_ADD, (int)state.Connection.Handle, ref ev) : - Linux.epoll_ctl(_epHndle, epoll_op.EPOLL_CTL_ADD, (int)state.Connection.Handle, ref ev); + var rc = _isWindows ? + Windows.epoll_ctl(_epHndle, epoll_op.EPOLL_CTL_ADD, (int)socket.Handle, ref ev) : + Linux.epoll_ctl(_epHndle, epoll_op.EPOLL_CTL_ADD, (int)socket.Handle, ref ev); if (rc != 0) @@ -152,17 +152,13 @@ namespace Server.Network } } - public void Remove(NetState state) + public void Remove(Socket socket) { - var ev = new epoll_event - { - events = epoll_events.EPOLLIN | epoll_events.EPOLLERR, - }; - ev.data.ptr = (IntPtr)state._handle; + var ev = new epoll_event { events = epoll_events.EPOLLIN | epoll_events.EPOLLERR }; - var rc = Core.IsWindows ? - Windows.epoll_ctl(_epHndle, epoll_op.EPOLL_CTL_DEL, (int)state.Connection.Handle, ref ev) : - Linux.epoll_ctl(_epHndle, epoll_op.EPOLL_CTL_DEL, (int)state.Connection.Handle, ref ev); + var rc = _isWindows ? + Windows.epoll_ctl(_epHndle, epoll_op.EPOLL_CTL_DEL, (int)socket.Handle, ref ev) : + Linux.epoll_ctl(_epHndle, epoll_op.EPOLL_CTL_DEL, (int)socket.Handle, ref ev); if (rc != 0) { @@ -172,36 +168,29 @@ namespace Server.Network private epoll_event[] _events = new epoll_event[2048]; - public int Poll(ref NetState[] states) + public int Poll(ref GCHandle[] handles) { - if (states.Length > _events.Length) + if (handles.Length > _events.Length) { - var newLength = Math.Max(states.Length, _events.Length + (_events.Length >> 2)); + var newLength = Math.Max(handles.Length, _events.Length + (_events.Length >> 2)); _events = new epoll_event[newLength]; } - var rc = Core.IsWindows ? - Windows.epoll_wait(_epHndle, _events, states.Length, 0) : - Linux.epoll_wait(_epHndle, _events, states.Length, 0); + var rc = _isWindows ? + Windows.epoll_wait(_epHndle, _events, handles.Length, 0) : + Linux.epoll_wait(_epHndle, _events, handles.Length, 0); if (rc <= 0) { return rc; } - int count = 0; - for (int i = 0; i < rc; i++) { - if (((GCHandle)_events[i].data.ptr).Target is not NetState state) - { - continue; - } - - states[count++] = state; + handles[i] = (GCHandle)_events[i].data.ptr; } - return count; + return rc; } } diff --git a/Projects/Server/Network/PollGroup/KQueuePollGroup.cs b/Projects/Server/Network/PollGroup/KQueuePollGroup.cs index 41466b968..278e88406 100644 --- a/Projects/Server/Network/PollGroup/KQueuePollGroup.cs +++ b/Projects/Server/Network/PollGroup/KQueuePollGroup.cs @@ -15,6 +15,7 @@ using System; using System.IO; +using System.Net.Sockets; using System.Runtime.InteropServices; namespace Server.Network @@ -181,14 +182,14 @@ namespace Server.Network Marshal.FreeHGlobal(_zeroTimeoutPtr); } - public void Add(NetState state) + public void Add(Socket socket, GCHandle handle) { var rc = BSD.kevent( _kqueueHndle, - state.Connection.Handle, + socket.Handle, kqueue_filter.READ | kqueue_filter.WRITE, kqueue_flags.ADD | kqueue_flags.CLEAR, - udata: (IntPtr)state._handle + udata: (IntPtr)handle ); if (rc != 0) @@ -197,14 +198,13 @@ namespace Server.Network } } - public void Remove(NetState state) + public void Remove(Socket socket) { var rc = BSD.kevent( _kqueueHndle, - state.Connection.Handle, + socket.Handle, kqueue_filter.READ | kqueue_filter.WRITE, - kqueue_flags.DELETE, - udata: (IntPtr)state._handle + kqueue_flags.DELETE ); if (rc != 0) @@ -215,11 +215,11 @@ namespace Server.Network private kevent[] _events = new kevent[2048]; - public int Poll(ref NetState[] states) + public int Poll(ref GCHandle[] handles) { - if (states.Length > _events.Length) + if (handles.Length > _events.Length) { - var newLength = Math.Max(states.Length, _events.Length + (_events.Length >> 2)); + var newLength = Math.Max(handles.Length, _events.Length + (_events.Length >> 2)); _events = new kevent[newLength]; } @@ -230,19 +230,12 @@ namespace Server.Network return rc; } - int count = 0; - for (int i = 0; i < rc; i++) { - if (((GCHandle)_events[i].udata).Target is not NetState state) - { - continue; - } - - states[count++] = state; + handles[i] = (GCHandle)_events[i].udata; } - return count; + return rc; } } } diff --git a/Projects/Server/Network/PollGroup/PollGroup.cs b/Projects/Server/Network/PollGroup/PollGroup.cs index 9089f871b..0fa4fa875 100644 --- a/Projects/Server/Network/PollGroup/PollGroup.cs +++ b/Projects/Server/Network/PollGroup/PollGroup.cs @@ -14,14 +14,16 @@ *************************************************************************/ using System; +using System.Net.Sockets; +using System.Runtime.InteropServices; namespace Server.Network { public interface IPollGroup : IDisposable { - void Add(NetState state); - void Remove(NetState state); - int Poll(ref NetState[] states); + void Add(Socket sock, GCHandle handle); + void Remove(Socket sock); + int Poll(ref GCHandle[] handles); } public static class PollGroup diff --git a/Projects/Server/Network/TcpServer.cs b/Projects/Server/Network/TcpServer.cs index 428c40cf9..a9b9f1955 100644 --- a/Projects/Server/Network/TcpServer.cs +++ b/Projects/Server/Network/TcpServer.cs @@ -196,7 +196,7 @@ namespace Server.Network } else { - var ns = new NetState(new NetworkSocket(socket)); + var ns = new NetState(socket); _connectedQueue.Enqueue(ns); } } diff --git a/Projects/Server/wepoll.dll b/Projects/Server/wepoll.dll index d3f207d746070b8b0b540ca110c5a6822f10accb..f9383691d3ce8f8c96fb244c0d4908fe4bbbd484 100644 GIT binary patch delta 6532 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 i+B4eUXzy+BZ@1f%}j`^j1!hZo5*3@?Z delta 6454 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 diff --git a/Projects/UOContent/Misc/ServerList.cs b/Projects/UOContent/Misc/ServerList.cs index 33e33d2af..031f44bc8 100644 --- a/Projects/UOContent/Misc/ServerList.cs +++ b/Projects/UOContent/Misc/ServerList.cs @@ -68,7 +68,11 @@ namespace Server.Misc { var ns = e.State; - var ipep = (IPEndPoint)ns.Connection.LocalEndPoint; + var ipep = (IPEndPoint)ns.Connection?.LocalEndPoint; + if (ipep == null) + { + return; + } var localAddress = ipep.Address; var localPort = ipep.Port; @@ -76,7 +80,7 @@ namespace Server.Misc if (IsPrivateNetwork(localAddress)) { ipep = (IPEndPoint)ns.Connection.RemoteEndPoint; - if (!IsPrivateNetwork(ipep.Address) && _publicAddress != null) + if (ipep == null || !IsPrivateNetwork(ipep.Address) && _publicAddress != null) { localAddress = _publicAddress; }