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 d3f207d74..f9383691d 100644 Binary files a/Projects/Server/wepoll.dll and b/Projects/Server/wepoll.dll differ 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; }