diff --git a/.gitignore b/.gitignore index 19f99345f..e4e6742f0 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ /Distribution/Logs /Distribution/Backups /Distribution/Saves +/Distribution/docs /Distribution/System.IO.Pipelines.dll /Distribution/libdrng.dll /Distribution/zlib.dll @@ -12,21 +13,17 @@ /Distribution/System.Runtime.CompilerServices.Unsafe.dll # LibUv Dependencies +/Distribution/libuv.dylib /Distribution/libuv.dll +/Distribution/libuv.so /Distribution/Microsoft.AspNetCore.Connections.Abstractions.dll /Distribution/Microsoft.AspNetCore.Http.Features.dll +/Distribution/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.dll /Distribution/Microsoft.Extensions.Configuration.Abstractions.dll -/Distribution/Microsoft.Extensions.Configuration.Binder.dll -/Distribution/Microsoft.Extensions.Configuration.dll /Distribution/Microsoft.Extensions.DependencyInjection.Abstractions.dll -/Distribution/Microsoft.Extensions.DependencyInjection.dll /Distribution/Microsoft.Extensions.FileProviders.Abstractions.dll /Distribution/Microsoft.Extensions.Hosting.Abstractions.dll /Distribution/Microsoft.Extensions.Logging.Abstractions.dll -/Distribution/Microsoft.Extensions.Logging.Configuration.dll -/Distribution/Microsoft.Extensions.Logging.Console.dll -/Distribution/Microsoft.Extensions.Logging.dll -/Distribution/Microsoft.Extensions.Options.ConfigurationExtensions.dll /Distribution/Microsoft.Extensions.Options.dll /Distribution/Microsoft.Extensions.Primitives.dll diff --git a/Projects/Scripts/Accounting/IPLimiter.cs b/Projects/Scripts/Accounting/IPLimiter.cs index 072ed9148..5e0cbf7c0 100644 --- a/Projects/Scripts/Accounting/IPLimiter.cs +++ b/Projects/Scripts/Accounting/IPLimiter.cs @@ -30,7 +30,7 @@ namespace Server.Misc if (!Enabled || IsExempt(ourAddress)) return true; - List netStates = NetState.Instances; + List netStates = TcpServer.Instances; int count = 0; @@ -50,4 +50,4 @@ namespace Server.Misc return true; } } -} \ No newline at end of file +} diff --git a/Projects/Scripts/Commands/Generic/Implementors/IPAddressCommandImplementor.cs b/Projects/Scripts/Commands/Generic/Implementors/IPAddressCommandImplementor.cs index d0d6f1bbe..927867b50 100644 --- a/Projects/Scripts/Commands/Generic/Implementors/IPAddressCommandImplementor.cs +++ b/Projects/Scripts/Commands/Generic/Implementors/IPAddressCommandImplementor.cs @@ -36,7 +36,7 @@ namespace Server.Commands.Generic List list = new List(); List addresses = new List(); - List states = NetState.Instances; + List states = TcpServer.Instances; for (int i = 0; i < states.Count; ++i) { @@ -60,4 +60,4 @@ namespace Server.Commands.Generic } } } -} \ No newline at end of file +} diff --git a/Projects/Scripts/Commands/Generic/Implementors/OnlineCommandImplementor.cs b/Projects/Scripts/Commands/Generic/Implementors/OnlineCommandImplementor.cs index 4d538f36e..2f80acea7 100644 --- a/Projects/Scripts/Commands/Generic/Implementors/OnlineCommandImplementor.cs +++ b/Projects/Scripts/Commands/Generic/Implementors/OnlineCommandImplementor.cs @@ -34,7 +34,7 @@ namespace Server.Commands.Generic List list = new List(); - List states = NetState.Instances; + List states = TcpServer.Instances; for (int i = 0; i < states.Count; ++i) { @@ -61,4 +61,4 @@ namespace Server.Commands.Generic } } } -} \ No newline at end of file +} diff --git a/Projects/Scripts/Commands/Handlers.cs b/Projects/Scripts/Commands/Handlers.cs index 723dfb2eb..f1540b499 100644 --- a/Projects/Scripts/Commands/Handlers.cs +++ b/Projects/Scripts/Commands/Handlers.cs @@ -671,7 +671,7 @@ namespace Server.Commands public static void BroadcastMessage(AccessLevel ac, int hue, string message) { - foreach (NetState state in NetState.Instances) + foreach (NetState state in TcpServer.Instances) { Mobile m = state.Mobile; @@ -743,7 +743,7 @@ namespace Server.Commands [Description("View some stats about the server.")] public static void Stats_OnCommand(CommandEventArgs e) { - e.Mobile.SendMessage("Open Connections: {0}", NetState.Instances.Count); + e.Mobile.SendMessage("Open Connections: {0}", TcpServer.Instances.Count); e.Mobile.SendMessage("Mobiles: {0}", World.Mobiles.Count); e.Mobile.SendMessage("Items: {0}", World.Items.Count); } diff --git a/Projects/Scripts/Engines/Help/PageQueue.cs b/Projects/Scripts/Engines/Help/PageQueue.cs index fa934094a..bce872da8 100644 --- a/Projects/Scripts/Engines/Help/PageQueue.cs +++ b/Projects/Scripts/Engines/Help/PageQueue.cs @@ -212,7 +212,7 @@ namespace Server.Engines.Help bool isStaffOnline = false; - foreach (NetState ns in NetState.Instances) + foreach (NetState ns in TcpServer.Instances) { Mobile m = ns.Mobile; diff --git a/Projects/Scripts/Gumps/AdminGump.cs b/Projects/Scripts/Gumps/AdminGump.cs index a9d63360d..5742830db 100644 --- a/Projects/Scripts/Gumps/AdminGump.cs +++ b/Projects/Scripts/Gumps/AdminGump.cs @@ -133,7 +133,7 @@ namespace Server.Gumps AddLabel(150, 170, LabelHue, Firewall.List.Count.ToString()); AddLabel(20, 190, LabelHue, "Clients:"); - AddLabel(150, 190, LabelHue, NetState.Instances.Count.ToString()); + AddLabel(150, 190, LabelHue, TcpServer.Instances.Count.ToString()); AddLabel(20, 210, LabelHue, "Mobiles:"); AddLabel(150, 210, LabelHue, World.Mobiles.Count.ToString()); @@ -380,7 +380,7 @@ namespace Server.Gumps { if (m_List == null) { - List states = NetState.Instances.ToList(); + List states = TcpServer.Instances; states.Sort(NetStateComparer.Instance); m_List = states.ToList(); @@ -1932,7 +1932,7 @@ namespace Server.Gumps if (level > AccessLevel.Player) { - List clients = NetState.Instances; + List clients = TcpServer.Instances; int count = 0; for (int i = 0; i < clients.Count; ++i) @@ -2020,7 +2020,7 @@ namespace Server.Gumps } else { - List instances = NetState.Instances; + List instances = TcpServer.Instances; for (int i = 0; i < instances.Count; ++i) { diff --git a/Projects/Scripts/Gumps/WhoGump.cs b/Projects/Scripts/Gumps/WhoGump.cs index 85263057b..098c4f41d 100644 --- a/Projects/Scripts/Gumps/WhoGump.cs +++ b/Projects/Scripts/Gumps/WhoGump.cs @@ -112,7 +112,7 @@ namespace Server.Gumps string filter = string.IsNullOrWhiteSpace(rawFilter) ? null : rawFilter.Trim().ToLower(); List list = new List(); - List states = NetState.Instances; + List states = TcpServer.Instances; for ( int i = 0; i < states.Count; ++i ) { diff --git a/Projects/Scripts/Misc/CrashGuard.cs b/Projects/Scripts/Misc/CrashGuard.cs index 7ab2e9743..26d9e31bb 100644 --- a/Projects/Scripts/Misc/CrashGuard.cs +++ b/Projects/Scripts/Misc/CrashGuard.cs @@ -202,7 +202,7 @@ namespace Server.Misc try { - List states = NetState.Instances; + List states = TcpServer.Instances; op.WriteLine("- Count: {0}", states.Count); diff --git a/Projects/Scripts/Misc/FoodDecay.cs b/Projects/Scripts/Misc/FoodDecay.cs index 4b3d44d52..e5afa1b2b 100644 --- a/Projects/Scripts/Misc/FoodDecay.cs +++ b/Projects/Scripts/Misc/FoodDecay.cs @@ -19,7 +19,7 @@ namespace Server.Misc public static void FoodDecay() { - foreach (NetState state in NetState.Instances) + foreach (NetState state in TcpServer.Instances) { HungerDecay(state.Mobile); ThirstDecay(state.Mobile); diff --git a/Projects/Scripts/Misc/LightCycle.cs b/Projects/Scripts/Misc/LightCycle.cs index 90155d0fa..0df950d41 100644 --- a/Projects/Scripts/Misc/LightCycle.cs +++ b/Projects/Scripts/Misc/LightCycle.cs @@ -20,9 +20,9 @@ namespace Server { m_LevelOverride = value; - for (int i = 0; i < NetState.Instances.Count; ++i) + for (int i = 0; i < TcpServer.Instances.Count; ++i) { - NetState ns = NetState.Instances[i]; + NetState ns = TcpServer.Instances[i]; Mobile m = ns.Mobile; m?.CheckLightLevels(false); @@ -69,12 +69,12 @@ namespace Server Clock.GetTime(from.Map, from.X, from.Y, out int hours, out int minutes); /* OSI times: - * + * * Midnight -> 3:59 AM : Night * 4:00 AM -> 11:59 PM : Day - * + * * RunUO times: - * + * * 10:00 PM -> 11:59 PM : Scale to night * Midnight -> 3:59 AM : Night * 4:00 AM -> 5:59 AM : Scale to day @@ -102,9 +102,9 @@ namespace Server protected override void OnTick() { - for (int i = 0; i < NetState.Instances.Count; ++i) + for (int i = 0; i < TcpServer.Instances.Count; ++i) { - NetState ns = NetState.Instances[i]; + NetState ns = TcpServer.Instances[i]; Mobile m = ns.Mobile; m?.CheckLightLevels(false); @@ -130,4 +130,4 @@ namespace Server } } } -} \ No newline at end of file +} diff --git a/Projects/Scripts/Misc/LoginStats.cs b/Projects/Scripts/Misc/LoginStats.cs index 69985c921..8b6ca8614 100644 --- a/Projects/Scripts/Misc/LoginStats.cs +++ b/Projects/Scripts/Misc/LoginStats.cs @@ -12,7 +12,7 @@ namespace Server.Misc private static void EventSink_Login(LoginEventArgs args) { - int userCount = NetState.Instances.Count; + int userCount = TcpServer.Instances.Count; int itemCount = World.Items.Count; int mobileCount = World.Mobiles.Count; @@ -27,4 +27,4 @@ namespace Server.Misc mobileCount, mobileCount == 1 ? "" : "s"); } } -} \ No newline at end of file +} diff --git a/Projects/Scripts/Misc/ServerList.cs b/Projects/Scripts/Misc/ServerList.cs index 87fe8d846..e2a1c6141 100644 --- a/Projects/Scripts/Misc/ServerList.cs +++ b/Projects/Scripts/Misc/ServerList.cs @@ -9,7 +9,7 @@ using Server.Network; namespace Server.Misc { - public class ServerList + public static class ServerList { /* * The default setting for Address, a value of 'null', will use your local IP address. If all of your local IP addresses diff --git a/Projects/Scripts/Misc/SocketOptions.cs b/Projects/Scripts/Misc/SocketOptions.cs index 3a59aac2c..3aa4b1d41 100644 --- a/Projects/Scripts/Misc/SocketOptions.cs +++ b/Projects/Scripts/Misc/SocketOptions.cs @@ -1,4 +1,5 @@ using System.Net; +using Server.Network; namespace Server { @@ -15,8 +16,7 @@ namespace Server public static void RegisterListeners() { - for (int i = 0; i < m_ListenerEndPoints.Length; i++) - Core.MessagePump.AddListener(m_ListenerEndPoints[i]); + TcpServer.Listeners.AddRange(m_ListenerEndPoints); } } } diff --git a/Projects/Scripts/Misc/VendorGenerator.cs b/Projects/Scripts/Misc/VendorGenerator.cs index 3e450fe0f..b04fe173f 100644 --- a/Projects/Scripts/Misc/VendorGenerator.cs +++ b/Projects/Scripts/Misc/VendorGenerator.cs @@ -316,10 +316,7 @@ namespace Server private static void ProcessDisplayCase(Map map, StaticTile[] tiles, int x, int y) { - ShopFlags flags = ShopFlags.None; - - for (int i = 0; i < tiles.Length; ++i) - flags |= ProcessDisplayedItem(tiles[i].ID); + ShopFlags flags = tiles.Aggregate(ShopFlags.None, (current, t) => current | ProcessDisplayedItem(t.ID)); if (flags != ShopFlags.None) { diff --git a/Projects/Scripts/Misc/Weather.cs b/Projects/Scripts/Misc/Weather.cs index 58071654e..86fa57e24 100644 --- a/Projects/Scripts/Misc/Weather.cs +++ b/Projects/Scripts/Misc/Weather.cs @@ -263,7 +263,7 @@ namespace Server.Misc else type = 2; - List states = NetState.Instances; + List states = TcpServer.Instances; Packet weatherPacket = null; diff --git a/Projects/Scripts/Misc/WebStatus.cs b/Projects/Scripts/Misc/WebStatus.cs index f0ada5366..961ec3c4d 100644 --- a/Projects/Scripts/Misc/WebStatus.cs +++ b/Projects/Scripts/Misc/WebStatus.cs @@ -119,7 +119,7 @@ namespace Server.Misc int index = 0; - foreach (Mobile m in NetState.Instances.Where(state => state.Mobile != null).Select(state => state.Mobile)) + foreach (Mobile m in TcpServer.Instances.Where(state => state.Mobile != null).Select(state => state.Mobile)) { ++index; @@ -181,4 +181,4 @@ namespace Server.Misc } } } -} \ No newline at end of file +} diff --git a/Projects/Scripts/Scripts.csproj b/Projects/Scripts/Scripts.csproj index 5707e931e..670d74678 100644 --- a/Projects/Scripts/Scripts.csproj +++ b/Projects/Scripts/Scripts.csproj @@ -36,6 +36,8 @@ - + + + diff --git a/Projects/Scripts/SpecialSystems/Engines/PreventInaccess.cs b/Projects/Scripts/SpecialSystems/Engines/PreventInaccess.cs index fcde69079..9e25a137f 100644 --- a/Projects/Scripts/SpecialSystems/Engines/PreventInaccess.cs +++ b/Projects/Scripts/SpecialSystems/Engines/PreventInaccess.cs @@ -41,7 +41,7 @@ namespace Server.Misc { Mobile from = e.Mobile; - if (from?.AccessLevel < AccessLevel.Counselor) + if (from == null || from.AccessLevel < AccessLevel.Counselor) return; if (HasDisconnected(from)) diff --git a/Projects/Server/AggressorInfo.cs b/Projects/Server/AggressorInfo.cs index a8706ca85..69ce600fe 100644 --- a/Projects/Server/AggressorInfo.cs +++ b/Projects/Server/AggressorInfo.cs @@ -27,7 +27,7 @@ namespace Server { public class AggressorInfo { - private static Queue m_Pool = new Queue(); + private static readonly Queue m_Pool = new Queue(); private Mobile m_Attacker, m_Defender; private bool m_CanReportMurder; private bool m_CriminalAggression; diff --git a/Projects/Server/ApplicationLifetime.cs b/Projects/Server/ApplicationLifetime.cs deleted file mode 100644 index 314cdcdea..000000000 --- a/Projects/Server/ApplicationLifetime.cs +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Threading; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; - -namespace Microsoft.AspNetCore.Hosting -{ - /// - /// Allows consumers to perform cleanup during a graceful shutdown. - /// - internal class ApplicationLifetime : IHostApplicationLifetime - { - private readonly CancellationTokenSource _startedSource = new CancellationTokenSource(); - private readonly CancellationTokenSource _stoppingSource = new CancellationTokenSource(); - private readonly CancellationTokenSource _stoppedSource = new CancellationTokenSource(); - private readonly ILogger _logger; - - public ApplicationLifetime(ILogger logger) => _logger = logger; - - /// - /// Triggered when the application host has fully started and is about to wait - /// for a graceful shutdown. - /// - public CancellationToken ApplicationStarted => _startedSource.Token; - - /// - /// Triggered when the application host is performing a graceful shutdown. - /// Request may still be in flight. Shutdown will block until this event completes. - /// - public CancellationToken ApplicationStopping => _stoppingSource.Token; - - /// - /// Triggered when the application host is performing a graceful shutdown. - /// All requests should be complete at this point. Shutdown will block - /// until this event completes. - /// - public CancellationToken ApplicationStopped => _stoppedSource.Token; - - /// - /// Signals the ApplicationStopping event and blocks until it completes. - /// - public void StopApplication() - { - // Lock on CTS to synchronize multiple calls to StopApplication. This guarantees that the first call - // to StopApplication and its callbacks run to completion before subsequent calls to StopApplication, - // which will no-op since the first call already requested cancellation, get a chance to execute. - lock (_stoppingSource) - { - try - { - ExecuteHandlers(_stoppingSource); - } - catch (Exception) - { - /* _logger.ApplicationError(LoggerEventIds.ApplicationStoppingException, - "An error occurred stopping the application", - ex);*/ - } - } - } - - /// - /// Signals the ApplicationStarted event and blocks until it completes. - /// - public void NotifyStarted() - { - try - { - ExecuteHandlers(_startedSource); - } - catch (Exception) - { - /* _logger.ApplicationError(LoggerEventIds.ApplicationStartupException, - "An error occurred starting the application", - ex);*/ - } - } - - /// - /// Signals the ApplicationStopped event and blocks until it completes. - /// - public void NotifyStopped() - { - try - { - ExecuteHandlers(_stoppedSource); - } - catch (Exception) - { - /* _logger.ApplicationError(LoggerEventIds.ApplicationStoppedException, - "An error occurred stopping the application", - ex);*/ - } - } - - private void ExecuteHandlers(CancellationTokenSource cancel) - { - // Noop if this is already cancelled - if (cancel.IsCancellationRequested) return; - - // Run the cancellation token callbacks - cancel.Cancel(false); - } - } -} diff --git a/Projects/Server/Assemblies/libuv.dll b/Projects/Server/Assemblies/libuv.dll deleted file mode 100644 index d744f343d..000000000 Binary files a/Projects/Server/Assemblies/libuv.dll and /dev/null differ diff --git a/Projects/Server/AssemblyHandler.cs b/Projects/Server/AssemblyHandler.cs index a206f4450..31bba7e48 100644 --- a/Projects/Server/AssemblyHandler.cs +++ b/Projects/Server/AssemblyHandler.cs @@ -29,7 +29,7 @@ namespace Server { public static class AssemblyHandler { - private static Dictionary m_TypeCaches = new Dictionary(); + private static readonly Dictionary m_TypeCaches = new Dictionary(); private static TypeCache m_NullCache; public static Assembly[] Assemblies { get; set; } @@ -85,10 +85,7 @@ namespace Server List types = new List(); if(ignoreCase) name = name.ToLower(); - for (int i = 0; i < Assemblies.Length; i++) - { - types.AddRange(GetTypeCache(Assemblies[i])[name]); - } + for (int i = 0; i < Assemblies.Length; i++) types.AddRange(GetTypeCache(Assemblies[i])[name]); if (types.Count == 0) types.AddRange(GetTypeCache(Core.Assembly)[name]); return types; @@ -107,15 +104,12 @@ namespace Server public class TypeCache { - private Dictionary m_NameMap = new Dictionary(); - private Type[] m_Types; - public IEnumerable Types { get => m_Types; } - public IEnumerable Names { get => m_NameMap.Keys; } + private readonly Dictionary m_NameMap = new Dictionary(); + private readonly Type[] m_Types; + public IEnumerable Types => m_Types; + public IEnumerable Names => m_NameMap.Keys; - public IEnumerable this[string name] - { - get => m_NameMap.TryGetValue(name, out int[] value) ? value.Select(x => m_Types[x]) : new Type[0]; - } + public IEnumerable this[string name] => m_NameMap.TryGetValue(name, out int[] value) ? value.Select(x => m_Types[x]) : new Type[0]; public TypeCache(Assembly asm) { diff --git a/Projects/Server/Body.cs b/Projects/Server/Body.cs index 998378129..b20101b14 100644 --- a/Projects/Server/Body.cs +++ b/Projects/Server/Body.cs @@ -35,7 +35,7 @@ namespace Server public struct Body { - private static BodyType[] m_Types; + private static readonly BodyType[] m_Types; static Body() { diff --git a/Projects/Server/Buffers/DiagnosticPoolBlock.cs b/Projects/Server/Buffers/DiagnosticPoolBlock.cs index 9623596f8..62da1dc84 100644 --- a/Projects/Server/Buffers/DiagnosticPoolBlock.cs +++ b/Projects/Server/Buffers/DiagnosticPoolBlock.cs @@ -20,7 +20,7 @@ namespace System.Buffers private readonly IMemoryOwner _memoryOwner; private MemoryHandle? _memoryHandle; - private Memory _memory; + private readonly Memory _memory; private readonly object _syncObj = new object(); private bool _isDisposed; diff --git a/Projects/Server/Buffers/MemoryPoolFactory.cs b/Projects/Server/Buffers/MemoryPoolFactory.cs index f8a3f37c5..b8eb87903 100644 --- a/Projects/Server/Buffers/MemoryPoolFactory.cs +++ b/Projects/Server/Buffers/MemoryPoolFactory.cs @@ -5,15 +5,7 @@ namespace System.Buffers { public static class SlabMemoryPoolFactory { - public static MemoryPool Create() - { -#if DEBUG - return new DiagnosticMemoryPool(CreateSlabMemoryPool()); -#else - return CreateSlabMemoryPool(); -#endif - } - + public static MemoryPool Create() => CreateSlabMemoryPool(); public static MemoryPool CreateSlabMemoryPool() => new SlabMemoryPool(); } } diff --git a/Projects/Server/ContextMenus/OpenBackpackEntry.cs b/Projects/Server/ContextMenus/OpenBackpackEntry.cs index 547fabff8..7664bf43e 100644 --- a/Projects/Server/ContextMenus/OpenBackpackEntry.cs +++ b/Projects/Server/ContextMenus/OpenBackpackEntry.cs @@ -22,7 +22,7 @@ namespace Server.ContextMenus { public class OpenBackpackEntry : ContextMenuEntry { - private Mobile m_Mobile; + private readonly Mobile m_Mobile; public OpenBackpackEntry(Mobile m) : base(6145) => m_Mobile = m; diff --git a/Projects/Server/ContextMenus/PaperdollEntry.cs b/Projects/Server/ContextMenus/PaperdollEntry.cs index 12aee25ab..717c12fd5 100644 --- a/Projects/Server/ContextMenus/PaperdollEntry.cs +++ b/Projects/Server/ContextMenus/PaperdollEntry.cs @@ -22,7 +22,7 @@ namespace Server.ContextMenus { public class PaperdollEntry : ContextMenuEntry { - private Mobile m_Mobile; + private readonly Mobile m_Mobile; public PaperdollEntry(Mobile m) : base(6123, 18) => m_Mobile = m; diff --git a/Projects/Server/Diagnostics/BaseProfile.cs b/Projects/Server/Diagnostics/BaseProfile.cs index bbc7804a5..086042ade 100644 --- a/Projects/Server/Diagnostics/BaseProfile.cs +++ b/Projects/Server/Diagnostics/BaseProfile.cs @@ -27,7 +27,7 @@ namespace Server.Diagnostics { public abstract class BaseProfile { - private Stopwatch _stopwatch; + private readonly Stopwatch _stopwatch; protected BaseProfile(string name) { diff --git a/Projects/Server/Diagnostics/GumpProfile.cs b/Projects/Server/Diagnostics/GumpProfile.cs index b8ac1c7cb..190ba1327 100644 --- a/Projects/Server/Diagnostics/GumpProfile.cs +++ b/Projects/Server/Diagnostics/GumpProfile.cs @@ -25,7 +25,7 @@ namespace Server.Diagnostics { public class GumpProfile : BaseProfile { - private static Dictionary _profiles = new Dictionary(); + private static readonly Dictionary _profiles = new Dictionary(); public GumpProfile(Type type) : base(type.FullName) { diff --git a/Projects/Server/Diagnostics/PacketProfile.cs b/Projects/Server/Diagnostics/PacketProfile.cs index 54f349dcf..6f9ee132b 100644 --- a/Projects/Server/Diagnostics/PacketProfile.cs +++ b/Projects/Server/Diagnostics/PacketProfile.cs @@ -53,7 +53,7 @@ namespace Server.Diagnostics public class PacketSendProfile : BasePacketProfile { - private static Dictionary _profiles = new Dictionary(); + private static readonly Dictionary _profiles = new Dictionary(); private long _created; @@ -87,7 +87,7 @@ namespace Server.Diagnostics public class PacketReceiveProfile : BasePacketProfile { - private static Dictionary _profiles = new Dictionary(); + private static readonly Dictionary _profiles = new Dictionary(); public PacketReceiveProfile(int packetId) : base($"0x{packetId:X2}") diff --git a/Projects/Server/Diagnostics/TargetProfile.cs b/Projects/Server/Diagnostics/TargetProfile.cs index 581961a0d..d16312209 100644 --- a/Projects/Server/Diagnostics/TargetProfile.cs +++ b/Projects/Server/Diagnostics/TargetProfile.cs @@ -25,7 +25,7 @@ namespace Server.Diagnostics { public class TargetProfile : BaseProfile { - private static Dictionary _profiles = new Dictionary(); + private static readonly Dictionary _profiles = new Dictionary(); public TargetProfile(Type type) : base(type.FullName) diff --git a/Projects/Server/Diagnostics/TimerProfile.cs b/Projects/Server/Diagnostics/TimerProfile.cs index 2f6f8826c..90c336397 100644 --- a/Projects/Server/Diagnostics/TimerProfile.cs +++ b/Projects/Server/Diagnostics/TimerProfile.cs @@ -25,7 +25,7 @@ namespace Server.Diagnostics { public class TimerProfile : BaseProfile { - private static Dictionary _profiles = new Dictionary(); + private static readonly Dictionary _profiles = new Dictionary(); public TimerProfile(string name) : base(name) diff --git a/Projects/Server/EventSink.cs b/Projects/Server/EventSink.cs index 89a131305..a5a826932 100644 --- a/Projects/Server/EventSink.cs +++ b/Projects/Server/EventSink.cs @@ -196,7 +196,7 @@ namespace Server public class AggressiveActionEventArgs : EventArgs { - private static Queue m_Pool = new Queue(); + private static readonly Queue m_Pool = new Queue(); private AggressiveActionEventArgs(Mobile aggressed, Mobile aggressor, bool criminal) { @@ -512,7 +512,7 @@ namespace Server public class MovementEventArgs : EventArgs { - private static Queue m_Pool = new Queue(); + private static readonly Queue m_Pool = new Queue(); public MovementEventArgs(Mobile mobile, Direction dir) { diff --git a/Projects/Server/Guild.cs b/Projects/Server/Guild.cs index df966e444..55b33fb84 100644 --- a/Projects/Server/Guild.cs +++ b/Projects/Server/Guild.cs @@ -32,7 +32,7 @@ namespace Server.Guilds public abstract class BaseGuild : ISerializable { - private BufferWriter m_SaveBuffer; + private readonly BufferWriter m_SaveBuffer; public BufferWriter SaveBuffer => m_SaveBuffer; private static uint m_NextID = 1; diff --git a/Projects/Server/Gumps/Gump.cs b/Projects/Server/Gumps/Gump.cs index 05718b5dd..f9b94881e 100644 --- a/Projects/Server/Gumps/Gump.cs +++ b/Projects/Server/Gumps/Gump.cs @@ -29,13 +29,13 @@ namespace Server.Gumps { private static uint m_NextSerial = 1; - private static byte[] m_BeginLayout = StringToBuffer("{ "); - private static byte[] m_EndLayout = StringToBuffer(" }"); + private static readonly byte[] m_BeginLayout = StringToBuffer("{ "); + private static readonly byte[] m_EndLayout = StringToBuffer(" }"); - private static byte[] m_NoMove = StringToBuffer("{ nomove }"); - private static byte[] m_NoClose = StringToBuffer("{ noclose }"); - private static byte[] m_NoDispose = StringToBuffer("{ nodispose }"); - private static byte[] m_NoResize = StringToBuffer("{ noresize }"); + private static readonly byte[] m_NoMove = StringToBuffer("{ nomove }"); + private static readonly byte[] m_NoClose = StringToBuffer("{ noclose }"); + private static readonly byte[] m_NoDispose = StringToBuffer("{ nodispose }"); + private static readonly byte[] m_NoResize = StringToBuffer("{ noresize }"); private bool m_Closable = true; private bool m_Disposable = true; @@ -43,7 +43,7 @@ namespace Server.Gumps private bool m_Resizable = true; private uint m_Serial; - private List m_Strings; + private readonly List m_Strings; internal int m_TextEntries, m_Switches; private int m_X, m_Y; diff --git a/Projects/Server/Gumps/GumpAlphaRegion.cs b/Projects/Server/Gumps/GumpAlphaRegion.cs index 20cfefe0d..165d37f98 100644 --- a/Projects/Server/Gumps/GumpAlphaRegion.cs +++ b/Projects/Server/Gumps/GumpAlphaRegion.cs @@ -24,7 +24,7 @@ namespace Server.Gumps { public class GumpAlphaRegion : GumpEntry { - private static byte[] m_LayoutName = Gump.StringToBuffer("checkertrans"); + private static readonly byte[] m_LayoutName = Gump.StringToBuffer("checkertrans"); private int m_Width, m_Height; private int m_X, m_Y; diff --git a/Projects/Server/Gumps/GumpBackground.cs b/Projects/Server/Gumps/GumpBackground.cs index 8016cfe1b..3c96f17f2 100644 --- a/Projects/Server/Gumps/GumpBackground.cs +++ b/Projects/Server/Gumps/GumpBackground.cs @@ -24,7 +24,7 @@ namespace Server.Gumps { public class GumpBackground : GumpEntry { - private static byte[] m_LayoutName = Gump.StringToBuffer("resizepic"); + private static readonly byte[] m_LayoutName = Gump.StringToBuffer("resizepic"); private int m_GumpID; private int m_Width, m_Height; private int m_X, m_Y; diff --git a/Projects/Server/Gumps/GumpButton.cs b/Projects/Server/Gumps/GumpButton.cs index 9186b8e37..dd6c7ec8e 100644 --- a/Projects/Server/Gumps/GumpButton.cs +++ b/Projects/Server/Gumps/GumpButton.cs @@ -30,7 +30,7 @@ namespace Server.Gumps public class GumpButton : GumpEntry { - private static byte[] m_LayoutName = Gump.StringToBuffer("button"); + private static readonly byte[] m_LayoutName = Gump.StringToBuffer("button"); private int m_ButtonID; private int m_ID1, m_ID2; private int m_Param; diff --git a/Projects/Server/Gumps/GumpCheck.cs b/Projects/Server/Gumps/GumpCheck.cs index afc3a54d0..61f47f6db 100644 --- a/Projects/Server/Gumps/GumpCheck.cs +++ b/Projects/Server/Gumps/GumpCheck.cs @@ -24,7 +24,7 @@ namespace Server.Gumps { public class GumpCheck : GumpEntry { - private static byte[] m_LayoutName = Gump.StringToBuffer("checkbox"); + private static readonly byte[] m_LayoutName = Gump.StringToBuffer("checkbox"); private int m_ID1, m_ID2; private bool m_InitialState; private int m_SwitchID; diff --git a/Projects/Server/Gumps/GumpGroup.cs b/Projects/Server/Gumps/GumpGroup.cs index 93418d837..7eb0f154e 100644 --- a/Projects/Server/Gumps/GumpGroup.cs +++ b/Projects/Server/Gumps/GumpGroup.cs @@ -24,7 +24,7 @@ namespace Server.Gumps { public class GumpGroup : GumpEntry { - private static byte[] m_LayoutName = Gump.StringToBuffer("group"); + private static readonly byte[] m_LayoutName = Gump.StringToBuffer("group"); private int m_Group; public GumpGroup(int group) => m_Group = group; diff --git a/Projects/Server/Gumps/GumpHtml.cs b/Projects/Server/Gumps/GumpHtml.cs index 12cd813e4..b70bee5cb 100644 --- a/Projects/Server/Gumps/GumpHtml.cs +++ b/Projects/Server/Gumps/GumpHtml.cs @@ -24,7 +24,7 @@ namespace Server.Gumps { public class GumpHtml : GumpEntry { - private static byte[] m_LayoutName = Gump.StringToBuffer("htmlgump"); + private static readonly byte[] m_LayoutName = Gump.StringToBuffer("htmlgump"); private bool m_Background, m_Scrollbar; private string m_Text; private int m_Width, m_Height; diff --git a/Projects/Server/Gumps/GumpHtmlLocalized.cs b/Projects/Server/Gumps/GumpHtmlLocalized.cs index ad8bf533e..8db25a304 100644 --- a/Projects/Server/Gumps/GumpHtmlLocalized.cs +++ b/Projects/Server/Gumps/GumpHtmlLocalized.cs @@ -31,9 +31,9 @@ namespace Server.Gumps public class GumpHtmlLocalized : GumpEntry { - private static byte[] m_LayoutNamePlain = Gump.StringToBuffer("xmfhtmlgump"); - private static byte[] m_LayoutNameColor = Gump.StringToBuffer("xmfhtmlgumpcolor"); - private static byte[] m_LayoutNameArgs = Gump.StringToBuffer("xmfhtmltok"); + private static readonly byte[] m_LayoutNamePlain = Gump.StringToBuffer("xmfhtmlgump"); + private static readonly byte[] m_LayoutNameColor = Gump.StringToBuffer("xmfhtmlgumpcolor"); + private static readonly byte[] m_LayoutNameArgs = Gump.StringToBuffer("xmfhtmltok"); private string m_Args; private bool m_Background, m_Scrollbar; private int m_Color; diff --git a/Projects/Server/Gumps/GumpImage.cs b/Projects/Server/Gumps/GumpImage.cs index 26d013222..dad0341ce 100644 --- a/Projects/Server/Gumps/GumpImage.cs +++ b/Projects/Server/Gumps/GumpImage.cs @@ -24,8 +24,8 @@ namespace Server.Gumps { public class GumpImage : GumpEntry { - private static byte[] m_LayoutName = Gump.StringToBuffer("gumppic"); - private static byte[] m_HueEquals = Gump.StringToBuffer(" hue="); + private static readonly byte[] m_LayoutName = Gump.StringToBuffer("gumppic"); + private static readonly byte[] m_HueEquals = Gump.StringToBuffer(" hue="); private int m_GumpID; private int m_Hue; private int m_X, m_Y; diff --git a/Projects/Server/Gumps/GumpImageTileButton.cs b/Projects/Server/Gumps/GumpImageTileButton.cs index a7fcfc4c0..37af7c24a 100644 --- a/Projects/Server/Gumps/GumpImageTileButton.cs +++ b/Projects/Server/Gumps/GumpImageTileButton.cs @@ -24,8 +24,8 @@ namespace Server.Gumps { public class GumpImageTileButton : GumpEntry { - private static byte[] m_LayoutName = Gump.StringToBuffer("buttontileart"); - private static byte[] m_LayoutTooltip = Gump.StringToBuffer(" }{ tooltip"); + private static readonly byte[] m_LayoutName = Gump.StringToBuffer("buttontileart"); + private static readonly byte[] m_LayoutTooltip = Gump.StringToBuffer(" }{ tooltip"); private int m_ButtonID; private int m_Height; private int m_Hue; diff --git a/Projects/Server/Gumps/GumpImageTiled.cs b/Projects/Server/Gumps/GumpImageTiled.cs index e090bdf3a..b3b099b82 100644 --- a/Projects/Server/Gumps/GumpImageTiled.cs +++ b/Projects/Server/Gumps/GumpImageTiled.cs @@ -24,7 +24,7 @@ namespace Server.Gumps { public class GumpImageTiled : GumpEntry { - private static byte[] m_LayoutName = Gump.StringToBuffer("gumppictiled"); + private static readonly byte[] m_LayoutName = Gump.StringToBuffer("gumppictiled"); private int m_GumpID; private int m_Width, m_Height; private int m_X, m_Y; diff --git a/Projects/Server/Gumps/GumpItem.cs b/Projects/Server/Gumps/GumpItem.cs index 8420886ea..a43cc4dd0 100644 --- a/Projects/Server/Gumps/GumpItem.cs +++ b/Projects/Server/Gumps/GumpItem.cs @@ -24,8 +24,8 @@ namespace Server.Gumps { public class GumpItem : GumpEntry { - private static byte[] m_LayoutName = Gump.StringToBuffer("tilepic"); - private static byte[] m_LayoutNameHue = Gump.StringToBuffer("tilepichue"); + private static readonly byte[] m_LayoutName = Gump.StringToBuffer("tilepic"); + private static readonly byte[] m_LayoutNameHue = Gump.StringToBuffer("tilepichue"); private int m_Hue; private int m_ItemID; private int m_X, m_Y; diff --git a/Projects/Server/Gumps/GumpItemProperty.cs b/Projects/Server/Gumps/GumpItemProperty.cs index 5ce65e19e..b4b43e9be 100644 --- a/Projects/Server/Gumps/GumpItemProperty.cs +++ b/Projects/Server/Gumps/GumpItemProperty.cs @@ -24,7 +24,7 @@ namespace Server.Gumps { public class GumpItemProperty : GumpEntry { - private static byte[] m_LayoutName = Gump.StringToBuffer("itemproperty"); + private static readonly byte[] m_LayoutName = Gump.StringToBuffer("itemproperty"); private uint m_Serial; public GumpItemProperty(uint serial) => m_Serial = serial; diff --git a/Projects/Server/Gumps/GumpLabel.cs b/Projects/Server/Gumps/GumpLabel.cs index d8a0c3389..623363484 100644 --- a/Projects/Server/Gumps/GumpLabel.cs +++ b/Projects/Server/Gumps/GumpLabel.cs @@ -24,7 +24,7 @@ namespace Server.Gumps { public class GumpLabel : GumpEntry { - private static byte[] m_LayoutName = Gump.StringToBuffer("text"); + private static readonly byte[] m_LayoutName = Gump.StringToBuffer("text"); private int m_Hue; private string m_Text; private int m_X, m_Y; diff --git a/Projects/Server/Gumps/GumpLabelCropped.cs b/Projects/Server/Gumps/GumpLabelCropped.cs index 462968311..cd988ab59 100644 --- a/Projects/Server/Gumps/GumpLabelCropped.cs +++ b/Projects/Server/Gumps/GumpLabelCropped.cs @@ -24,7 +24,7 @@ namespace Server.Gumps { public class GumpLabelCropped : GumpEntry { - private static byte[] m_LayoutName = Gump.StringToBuffer("croppedtext"); + private static readonly byte[] m_LayoutName = Gump.StringToBuffer("croppedtext"); private int m_Hue; private string m_Text; private int m_Width, m_Height; diff --git a/Projects/Server/Gumps/GumpPage.cs b/Projects/Server/Gumps/GumpPage.cs index 8b5479512..7e0ebd9d2 100644 --- a/Projects/Server/Gumps/GumpPage.cs +++ b/Projects/Server/Gumps/GumpPage.cs @@ -24,7 +24,7 @@ namespace Server.Gumps { public class GumpPage : GumpEntry { - private static byte[] m_LayoutName = Gump.StringToBuffer("page"); + private static readonly byte[] m_LayoutName = Gump.StringToBuffer("page"); private int m_Page; public GumpPage(int page) => m_Page = page; diff --git a/Projects/Server/Gumps/GumpRadio.cs b/Projects/Server/Gumps/GumpRadio.cs index 740c3d9b1..153d9b319 100644 --- a/Projects/Server/Gumps/GumpRadio.cs +++ b/Projects/Server/Gumps/GumpRadio.cs @@ -24,7 +24,7 @@ namespace Server.Gumps { public class GumpRadio : GumpEntry { - private static byte[] m_LayoutName = Gump.StringToBuffer("radio"); + private static readonly byte[] m_LayoutName = Gump.StringToBuffer("radio"); private int m_ID1, m_ID2; private bool m_InitialState; private int m_SwitchID; diff --git a/Projects/Server/Gumps/GumpTextEntry.cs b/Projects/Server/Gumps/GumpTextEntry.cs index 8ebd49f83..e364281e2 100644 --- a/Projects/Server/Gumps/GumpTextEntry.cs +++ b/Projects/Server/Gumps/GumpTextEntry.cs @@ -24,7 +24,7 @@ namespace Server.Gumps { public class GumpTextEntry : GumpEntry { - private static byte[] m_LayoutName = Gump.StringToBuffer("textentry"); + private static readonly byte[] m_LayoutName = Gump.StringToBuffer("textentry"); private int m_EntryID; private int m_Hue; private string m_InitialText; diff --git a/Projects/Server/Gumps/GumpTextEntryLimited.cs b/Projects/Server/Gumps/GumpTextEntryLimited.cs index 2b4d983aa..11538ac2b 100644 --- a/Projects/Server/Gumps/GumpTextEntryLimited.cs +++ b/Projects/Server/Gumps/GumpTextEntryLimited.cs @@ -24,7 +24,7 @@ namespace Server.Gumps { public class GumpTextEntryLimited : GumpEntry { - private static byte[] m_LayoutName = Gump.StringToBuffer("textentrylimited"); + private static readonly byte[] m_LayoutName = Gump.StringToBuffer("textentrylimited"); private int m_EntryID; private int m_Hue; private string m_InitialText; diff --git a/Projects/Server/Gumps/GumpTooltip.cs b/Projects/Server/Gumps/GumpTooltip.cs index 2982ebecc..f05672bd8 100644 --- a/Projects/Server/Gumps/GumpTooltip.cs +++ b/Projects/Server/Gumps/GumpTooltip.cs @@ -24,7 +24,7 @@ namespace Server.Gumps { public class GumpTooltip : GumpEntry { - private static byte[] m_LayoutName = Gump.StringToBuffer("tooltip"); + private static readonly byte[] m_LayoutName = Gump.StringToBuffer("tooltip"); private int m_Number; public GumpTooltip(int number) => m_Number = number; diff --git a/Projects/Server/Item.cs b/Projects/Server/Item.cs index 1bf318018..8fc4db6c2 100644 --- a/Projects/Server/Item.cs +++ b/Projects/Server/Item.cs @@ -201,13 +201,13 @@ namespace Server public class Item : IHued, IComparable, ISerializable, ISpawnable, IPropertyListObject { - private BufferWriter m_SaveBuffer; - public BufferWriter SaveBuffer { get { return m_SaveBuffer; } } + private readonly BufferWriter m_SaveBuffer; + public BufferWriter SaveBuffer => m_SaveBuffer; public const int QuestItemHue = 0x4EA; // Hmmmm... "for EA"? public static readonly List EmptyItems = new List(); - private static List m_DeltaQueue = new List(); + private static readonly List m_DeltaQueue = new List(); private static bool _processing; diff --git a/Projects/Server/Items/Container.cs b/Projects/Server/Items/Container.cs index 846cea79d..5bc03a3f2 100644 --- a/Projects/Server/Items/Container.cs +++ b/Projects/Server/Items/Container.cs @@ -36,8 +36,8 @@ namespace Server.Items public class Container : Item { - private static QueuePool m_QueuePool = new QueuePool(QueueRef.Generate, preGenerateCount: 2, maxRefrenceRetention: 5); - private static List m_FindItemsList = new List(); + private static readonly QueuePool m_QueuePool = new QueuePool(QueueRef.Generate, preGenerateCount: 2, maxRefrenceRetention: 5); + private static readonly List m_FindItemsList = new List(); private ContainerData m_ContainerData; @@ -200,7 +200,7 @@ namespace Server.Items public virtual bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight) { - if (m?.AccessLevel < AccessLevel.GameMaster) + if (m == null || m.AccessLevel < AccessLevel.GameMaster) { if (IsDecoContainer) { @@ -735,7 +735,7 @@ namespace Server.Items private class GroupComparer : IComparer { - private CheckItemGroup m_Grouper; + private readonly CheckItemGroup m_Grouper; public GroupComparer(CheckItemGroup grouper) => m_Grouper = grouper; @@ -754,8 +754,8 @@ namespace Server.Items private struct ItemStackEntry { - public Item m_StackItem; - public Item m_DropItem; + public readonly Item m_StackItem; + public readonly Item m_DropItem; public ItemStackEntry(Item stack, Item drop) { @@ -1536,12 +1536,10 @@ namespace Server.Items { var container = queue.Dequeue(); foreach (var item in container.Items) - { if (item is T typedItem && predicate?.Invoke(typedItem) != false) items.Add(typedItem); else if (recurse && item is Container itemContainer) queue.Enqueue(itemContainer); - } } return items; } @@ -1583,7 +1581,7 @@ namespace Server.Items public class ContainerData { - private static Dictionary m_Table; + private static readonly Dictionary m_Table; static ContainerData() { diff --git a/Projects/Server/Kestrel/CorrelationIdGenerator.cs b/Projects/Server/Kestrel/CorrelationIdGenerator.cs deleted file mode 100644 index 1be328db1..000000000 --- a/Projects/Server/Kestrel/CorrelationIdGenerator.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Threading; - -namespace Microsoft.AspNetCore.Connections -{ - public static class CorrelationIdGenerator - { - // Base32 encoding - in ascii sort order for easy text based sorting - private static readonly char[] s_encode32Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUV".ToCharArray(); - - // Seed the _lastConnectionId for this application instance with - // the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001 - // for a roughly increasing _lastId over restarts - private static long _lastId = DateTime.UtcNow.Ticks; - - public static string GetNextId() => GenerateId(Interlocked.Increment(ref _lastId)); - - private static string GenerateId(long id) - { - return string.Create(13, id, (buffer, value) => - { - char[] encode32Chars = s_encode32Chars; - - buffer[12] = encode32Chars[value & 31]; - buffer[11] = encode32Chars[(value >> 5) & 31]; - buffer[10] = encode32Chars[(value >> 10) & 31]; - buffer[9] = encode32Chars[(value >> 15) & 31]; - buffer[8] = encode32Chars[(value >> 20) & 31]; - buffer[7] = encode32Chars[(value >> 25) & 31]; - buffer[6] = encode32Chars[(value >> 30) & 31]; - buffer[5] = encode32Chars[(value >> 35) & 31]; - buffer[4] = encode32Chars[(value >> 40) & 31]; - buffer[3] = encode32Chars[(value >> 45) & 31]; - buffer[2] = encode32Chars[(value >> 50) & 31]; - buffer[1] = encode32Chars[(value >> 55) & 31]; - buffer[0] = encode32Chars[(value >> 60) & 31]; - }); - } - } -} diff --git a/Projects/Server/LibUv/IAsyncDisposable.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/IAsyncDisposable.cs similarity index 76% rename from Projects/Server/LibUv/IAsyncDisposable.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/IAsyncDisposable.cs index 70f4a53a5..f46e09e7f 100644 --- a/Projects/Server/LibUv/IAsyncDisposable.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/IAsyncDisposable.cs @@ -3,7 +3,7 @@ using System.Threading.Tasks; -namespace Libuv +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal { interface IAsyncDisposable { diff --git a/Projects/Server/LibUv/ILibuvTrace.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/ILibuvTrace.cs similarity index 83% rename from Projects/Server/LibUv/ILibuvTrace.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/ILibuvTrace.cs index 371018cd2..29fd48d9e 100644 --- a/Projects/Server/LibUv/ILibuvTrace.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/ILibuvTrace.cs @@ -4,9 +4,9 @@ using System; using Microsoft.Extensions.Logging; -namespace Libuv +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal { - public interface ILibuvTrace : ILogger + internal interface ILibuvTrace : ILogger { void ConnectionRead(string connectionId, int count); diff --git a/Projects/Server/LibUv/LibuvAwaitable.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvAwaitable.cs similarity index 76% rename from Projects/Server/LibUv/LibuvAwaitable.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvAwaitable.cs index efdaeae29..bb8c4e7b5 100644 --- a/Projects/Server/LibUv/LibuvAwaitable.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvAwaitable.cs @@ -5,11 +5,11 @@ using System; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Threading; -using Libuv.Internal; +using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking; -namespace Libuv +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal { - public class LibuvAwaitable : ICriticalNotifyCompletion where TRequest : UvRequest + internal class LibuvAwaitable : ICriticalNotifyCompletion where TRequest : UvRequest { private static readonly Action _callbackCompleted = () => { }; @@ -53,8 +53,7 @@ namespace Libuv { // There should never be a race between IsCompleted and OnCompleted since both operations // should always be on the libuv thread - if (ReferenceEquals(_callback, _callbackCompleted)) - Debug.Fail($"{typeof(LibuvAwaitable)}.{nameof(OnCompleted)} raced with {nameof(IsCompleted)}, scheduling callback."); + if (ReferenceEquals(_callback, _callbackCompleted)) Debug.Fail($"{typeof(LibuvAwaitable)}.{nameof(OnCompleted)} raced with {nameof(IsCompleted)}, scheduling callback."); _callback = continuation; } @@ -65,7 +64,7 @@ namespace Libuv } } - public struct UvWriteResult + internal struct UvWriteResult { public int Status { get; } public UvException Error { get; } diff --git a/Projects/Server/LibUv/LibuvConnection.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvConnection.cs similarity index 90% rename from Projects/Server/LibUv/LibuvConnection.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvConnection.cs index 5839c4d6b..dd9dcecc8 100644 --- a/Projects/Server/LibUv/LibuvConnection.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvConnection.cs @@ -8,19 +8,21 @@ using System.IO.Pipelines; using System.Net; using System.Threading; using System.Threading.Tasks; -using Libuv.Internal; using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking; using Microsoft.Extensions.Logging; -namespace Libuv +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal { - public partial class LibuvConnection : TransportConnection + internal partial class LibuvConnection : TransportConnection { private static readonly int MinAllocBufferSize = SlabMemoryPool.BlockSize / 2; - private static readonly Action _readCallback = ReadCallback; + private static readonly Action _readCallback = + (handle, status, state) => ReadCallback(handle, status, state); - private static readonly Func _allocCallback = AllocCallback; + private static readonly Func _allocCallback = + (handle, suggestedSize, state) => AllocCallback(handle, suggestedSize, state); private readonly UvStreamHandle _socket; private readonly CancellationTokenSource _connectionClosedTokenSource = new CancellationTokenSource(); @@ -243,7 +245,7 @@ namespace Libuv state._waitForConnectionClosedTcs.TrySetResult(null); }, this, - false); + preferLocal: false); } private async Task ApplyBackpressureAsync(ValueTask flushTask) @@ -282,16 +284,18 @@ namespace Libuv // The operation was canceled by the server not the client. No need for additional logs. return new ConnectionAbortedException(uvError.Message, uvError); } - - if (LibuvConstants.IsConnectionReset(uvError.StatusCode)) + else if (LibuvConstants.IsConnectionReset(uvError.StatusCode)) { // Log connection resets at a lower (Debug) level. Log.ConnectionReset(ConnectionId); return new ConnectionResetException(uvError.Message, uvError); } - // This is unexpected. - Log.ConnectionError(ConnectionId, uvError); - return new IOException(uvError.Message, uvError); + else + { + // This is unexpected. + Log.ConnectionError(ConnectionId, uvError); + return new IOException(uvError.Message, uvError); + } } private void CancelConnectionClosedToken() diff --git a/Projects/Server/LibUv/LibuvConnectionListener.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvConnectionListener.cs similarity index 89% rename from Projects/Server/LibUv/LibuvConnectionListener.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvConnectionListener.cs index d04da54c6..99868a0fd 100644 --- a/Projects/Server/LibUv/LibuvConnectionListener.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvConnectionListener.cs @@ -7,15 +7,14 @@ using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; -using Libuv.Internal; using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using Server; -namespace Libuv +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal { - public class LibuvConnectionListener : IConnectionListener + internal class LibuvConnectionListener : IConnectionListener { private readonly List _listeners = new List(); private IAsyncEnumerator _acceptEnumerator; @@ -63,8 +62,7 @@ namespace Libuv var disposeTasks = _listeners.Select(listener => ((IAsyncDisposable)listener).DisposeAsync()).ToArray(); - if (!await WaitAsync(Task.WhenAll(disposeTasks), TimeSpan.FromSeconds(5)).ConfigureAwait(false)) - Log.LogError(0, null, "Disposing listeners failed"); + if (!await WaitAsync(Task.WhenAll(disposeTasks), TimeSpan.FromSeconds(5)).ConfigureAwait(false)) Log.LogError(0, null, "Disposing listeners failed"); } @@ -101,14 +99,9 @@ namespace Libuv } Threads.Clear(); -#if DEBUG && !INNER_LOOP - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); -#endif } - public async Task BindAsync() + internal async Task BindAsync() { // TODO: Move thread management to LibuvTransportFactory // TODO: Split endpoint management from thread management @@ -127,7 +120,7 @@ namespace Libuv } else { - var pipeName = (Core.IsWindows ? @"\\.\pipe\kestrel_" : "/tmp/kestrel_") + Guid.NewGuid().ToString("n"); + var pipeName = (Libuv.IsWindows ? @"\\.\pipe\kestrel_" : "/tmp/kestrel_") + Guid.NewGuid().ToString("n"); var pipeMessage = Guid.NewGuid().ToByteArray(); var listenerPrimary = new ListenerPrimary(TransportContext); @@ -171,7 +164,7 @@ namespace Libuv while (remainingSlots > 0) { // Calling GetAwaiter().GetResult() is safe because we know the task is completed - var (connection, slot) = (await Task.WhenAny(slots)).GetAwaiter().GetResult(); + (var connection, var slot) = (await Task.WhenAny(slots)).GetAwaiter().GetResult(); // If the connection is null then the listener was closed if (connection == null) diff --git a/Projects/Server/LibUv/LibuvConstants.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvConstants.cs similarity index 50% rename from Projects/Server/LibUv/LibuvConstants.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvConstants.cs index bce142a81..5352d5e8d 100644 --- a/Projects/Server/LibUv/LibuvConstants.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvConstants.cs @@ -2,11 +2,11 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Runtime.CompilerServices; -using Server; +using System.Runtime.InteropServices; -namespace Libuv +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal { - public static class LibuvConstants + internal static class LibuvConstants { public const int EOF = -4095; public static readonly int? ECONNRESET = GetECONNRESET(); @@ -22,76 +22,69 @@ namespace Libuv private static int? GetECONNRESET() { - if (Core.IsWindows) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return -4077; - if (Core.IsLinux) + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return -104; - if (Core.IsDarwin) - return -5; + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return -54; return null; } private static int? GetEPIPE() { - if (Core.IsWindows) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return -4047; - if (Core.IsLinux) - return -32; - if (Core.IsDarwin) + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return -32; + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return -32; return null; } private static int? GetENOTCONN() { - if (Core.IsWindows) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return -4053; - if (Core.IsLinux) + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return -107; - if (Core.IsDarwin) - return -57; + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return -57; return null; } private static int? GetEINVAL() { - if (Core.IsWindows) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return -4071; - if (Core.IsLinux) - return -22; - if (Core.IsDarwin) + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return -22; + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return -22; return null; } private static int? GetEADDRINUSE() { - if (Core.IsWindows) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return -4091; - if (Core.IsLinux) + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return -98; - if (Core.IsDarwin) - return -48; + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return -48; return null; } private static int? GetENOTSUP() { - if (Core.IsLinux) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return -95; - if (Core.IsDarwin) - return -45; + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return -45; return null; } private static int? GetECANCELED() { - if (Core.IsWindows) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return -4081; - if (Core.IsLinux) + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return -125; - if (Core.IsDarwin) - return -89; + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return -89; return null; } } diff --git a/Projects/Server/LibUv/LibuvOutputConsumer.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvOutputConsumer.cs similarity index 90% rename from Projects/Server/LibUv/LibuvOutputConsumer.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvOutputConsumer.cs index e9d42ca52..bb0b95831 100644 --- a/Projects/Server/LibUv/LibuvOutputConsumer.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvOutputConsumer.cs @@ -4,11 +4,11 @@ using System; using System.IO.Pipelines; using System.Threading.Tasks; -using Libuv.Internal; +using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking; -namespace Libuv +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal { - public class LibuvOutputConsumer + internal class LibuvOutputConsumer { private readonly LibuvThread _thread; private readonly UvStreamHandle _socket; diff --git a/Projects/Server/LibUv/LibuvThread.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvThread.cs similarity index 88% rename from Projects/Server/LibUv/LibuvThread.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvThread.cs index d57d7f2dc..c2a742a80 100644 --- a/Projects/Server/LibUv/LibuvThread.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvThread.cs @@ -9,13 +9,13 @@ using System.IO.Pipelines; using System.Runtime.ExceptionServices; using System.Threading; using System.Threading.Tasks; -using Libuv.Internal; +using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -namespace Libuv +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal { - public class LibuvThread : PipeScheduler + internal class LibuvThread : PipeScheduler { // maximum times the work queues swapped and are processed in a single pass // as completing a task may immediately have write data to put on the network @@ -35,8 +35,8 @@ namespace Libuv private readonly object _workSync = new object(); private readonly object _closeHandleSync = new object(); private readonly object _startSync = new object(); - private bool _stopImmediate; - private bool _initCompleted; + private bool _stopImmediate = false; + private bool _initCompleted = false; private Exception _closeError; private readonly ILibuvTrace _log; @@ -60,9 +60,9 @@ namespace Libuv #endif #if !DEBUG - // Mark the thread as being as unimportant to keeping the process alive. - // Don't do this for debug builds, so we know if the thread isn't terminating. - _thread.IsBackground = true; + // Mark the thread as being as unimportant to keeping the process alive. + // Don't do this for debug builds, so we know if the thread isn't terminating. + _thread.IsBackground = true; #endif QueueCloseHandle = PostCloseHandle; QueueCloseAsyncHandle = EnqueueCloseHandle; @@ -76,10 +76,6 @@ namespace Libuv public WriteReqPool WriteReqPool { get; } -#if DEBUG - public List Requests { get; } = new List(); -#endif - public Exception FatalError => _closeError; public Action, IntPtr> QueueCloseHandle { get; } @@ -129,18 +125,6 @@ namespace Libuv if (_closeError != null) ExceptionDispatchInfo.Capture(_closeError).Throw(); } -#if DEBUG && !INNER_LOOP - private void CheckUvReqLeaks() - { - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - // Detect leaks in UvRequest objects - foreach (var request in Requests) Debug.Assert(request.Target == null, $"{request.Target?.GetType()} object is still alive."); - } -#endif - private void AllowStop() { _post.Unreference(); @@ -320,11 +304,6 @@ namespace Libuv } WriteReqPool.Dispose(); _threadTcs.SetResult(null); - -#if DEBUG && !INNER_LOOP - // Check for handle leaks after disposing everything - CheckUvReqLeaks(); -#endif } } @@ -406,8 +385,7 @@ namespace Libuv return wasWork; } - private static async Task WaitAsync(Task task, TimeSpan timeout) => - await Task.WhenAny(task, Task.Delay(timeout)).ConfigureAwait(false) == task; + private static async Task WaitAsync(Task task, TimeSpan timeout) => await Task.WhenAny(task, Task.Delay(timeout)).ConfigureAwait(false) == task; public override void Schedule(Action action, object state) { diff --git a/Projects/Server/LibUv/LibuvTrace.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvTrace.cs similarity index 94% rename from Projects/Server/LibUv/LibuvTrace.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvTrace.cs index ebc090316..1d3e2e794 100644 --- a/Projects/Server/LibUv/LibuvTrace.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvTrace.cs @@ -4,9 +4,9 @@ using System; using Microsoft.Extensions.Logging; -namespace Libuv +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal { - public class LibuvTrace : ILibuvTrace + internal class LibuvTrace : ILibuvTrace { // ConnectionRead: Reserved: 3 diff --git a/Projects/Server/LibUv/LibuvTransportContext.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvTransportContext.cs similarity index 74% rename from Projects/Server/LibUv/LibuvTransportContext.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvTransportContext.cs index 730f31eb3..d5f68e1f5 100644 --- a/Projects/Server/LibUv/LibuvTransportContext.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvTransportContext.cs @@ -3,9 +3,9 @@ using Microsoft.Extensions.Hosting; -namespace Libuv +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal { - public class LibuvTransportContext + internal class LibuvTransportContext { public LibuvTransportOptions Options { get; set; } diff --git a/Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvTransportFactory.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvTransportFactory.cs new file mode 100644 index 000000000..6b06c11bc --- /dev/null +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/LibuvTransportFactory.cs @@ -0,0 +1,64 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Connections; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal +{ + internal class LibuvTransportFactory : IConnectionListenerFactory + { + private readonly LibuvTransportContext _baseTransportContext; + + public LibuvTransportFactory( + IOptions options, + IHostApplicationLifetime applicationLifetime, + ILoggerFactory loggerFactory) + { + if (options == null) throw new ArgumentNullException(nameof(options)); + if (applicationLifetime == null) throw new ArgumentNullException(nameof(applicationLifetime)); + if (loggerFactory == null) throw new ArgumentNullException(nameof(loggerFactory)); + + var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv"); + var trace = new LibuvTrace(logger); + + var threadCount = options.Value.ThreadCount; + + if (threadCount <= 0) + throw new ArgumentOutOfRangeException(nameof(threadCount), + threadCount, + "ThreadCount must be positive."); + + if (!LibuvConstants.ECONNRESET.HasValue) trace.LogWarning("Unable to determine ECONNRESET value on this platform."); + + if (!LibuvConstants.EADDRINUSE.HasValue) trace.LogWarning("Unable to determine EADDRINUSE value on this platform."); + + _baseTransportContext = new LibuvTransportContext + { + Options = options.Value, + AppLifetime = applicationLifetime, + Log = trace, + }; + } + + public async ValueTask BindAsync(EndPoint endpoint, CancellationToken cancellationToken = default) + { + var transportContext = new LibuvTransportContext + { + Options = _baseTransportContext.Options, + AppLifetime = _baseTransportContext.AppLifetime, + Log = _baseTransportContext.Log + }; + + var transport = new LibuvConnectionListener(transportContext, endpoint); + await transport.BindAsync(); + return transport; + } + } +} diff --git a/Projects/Server/LibUv/Listener.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Listener.cs similarity index 83% rename from Projects/Server/LibUv/Listener.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/Listener.cs index 4ed799b78..aac5bf3f2 100644 --- a/Projects/Server/LibUv/Listener.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Listener.cs @@ -5,16 +5,16 @@ using System; using System.Net; using System.Net.Sockets; using System.Threading.Tasks; -using Libuv.Internal; using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking; using Microsoft.Extensions.Logging; -namespace Libuv +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal { /// /// Base class for listeners in Kestrel. Listens for incoming connections /// - public class Listener : ListenerContext, IAsyncDisposable + internal class Listener : ListenerContext, IAsyncDisposable { // REVIEW: This needs to be bounded and we need a strategy for what to do when the queue is full private bool _closed; @@ -46,13 +46,17 @@ namespace Libuv /// private UvStreamHandle CreateListenSocket() { - return EndPoint switch + switch (EndPoint) { - IPEndPoint _ => ListenTcp(false), - UnixDomainSocketEndPoint _ => ListenPipe(false), - FileHandleEndPoint _ => ListenHandle(), - _ => throw new NotSupportedException() - }; + case IPEndPoint _: + return ListenTcp(useFileHandle: false); + case UnixDomainSocketEndPoint _: + return ListenPipe(useFileHandle: false); + case FileHandleEndPoint _: + return ListenHandle(); + default: + throw new NotSupportedException(); + } } private UvTcpHandle ListenTcp(bool useFileHandle) @@ -62,7 +66,7 @@ namespace Libuv try { socket.Init(Thread.Loop, Thread.QueueCloseHandle); - socket.NoDelay(true); + socket.NoDelay(TransportContext.Options.NoDelay); if (!useFileHandle) { @@ -117,9 +121,9 @@ namespace Libuv case FileHandleType.Auto: break; case FileHandleType.Tcp: - return ListenTcp(true); + return ListenTcp(useFileHandle: true); case FileHandleType.Pipe: - return ListenPipe(true); + return ListenPipe(useFileHandle: true); default: throw new NotSupportedException(); } @@ -127,7 +131,7 @@ namespace Libuv UvStreamHandle handle; try { - handle = ListenTcp(true); + handle = ListenTcp(useFileHandle: true); EndPoint = new FileHandleEndPoint(handleEndPoint.FileHandle, FileHandleType.Tcp); return handle; } @@ -136,7 +140,7 @@ namespace Libuv Log.LogDebug(0, exception, "Listener.ListenHandle"); } - handle = ListenPipe(true); + handle = ListenPipe(useFileHandle: true); EndPoint = new FileHandleEndPoint(handleEndPoint.FileHandle, FileHandleType.Pipe); return handle; } diff --git a/Projects/Server/LibUv/ListenerContext.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/ListenerContext.cs similarity index 84% rename from Projects/Server/LibUv/ListenerContext.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/ListenerContext.cs index 52b5b9149..32cfd42d8 100644 --- a/Projects/Server/LibUv/ListenerContext.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/ListenerContext.cs @@ -9,13 +9,13 @@ using System.Net.Sockets; using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; -using Libuv.Internal; using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking; using Microsoft.Extensions.Logging; -namespace Libuv +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal { - public class ListenerContext + internal class ListenerContext { // Single reader, single writer queue since all writes happen from the uv thread and reads happen sequentially private readonly Channel _acceptQueue = Channel.CreateUnbounded(new UnboundedChannelOptions @@ -115,7 +115,7 @@ namespace Libuv try { socket.Init(Thread.Loop, Thread.QueueCloseHandle); - socket.NoDelay(true); + socket.NoDelay(TransportContext.Options.NoDelay); } catch { @@ -152,17 +152,14 @@ namespace Libuv { var fileHandleEndPoint = (FileHandleEndPoint)EndPoint; - switch (fileHandleEndPoint.FileHandleType) + return fileHandleEndPoint.FileHandleType switch { - case FileHandleType.Auto: - throw new InvalidOperationException("Cannot accept on a non-specific file handle, listen should be performed first."); - case FileHandleType.Tcp: - return AcceptTcp(); - case FileHandleType.Pipe: - return AcceptPipe(); - default: - throw new NotSupportedException(); - } + FileHandleType.Auto => throw new InvalidOperationException( + "Cannot accept on a non-specific file handle, listen should be performed first."), + FileHandleType.Tcp => (UvStreamHandle)AcceptTcp(), + FileHandleType.Pipe => AcceptPipe(), + _ => throw new NotSupportedException() + }; } } } diff --git a/Projects/Server/LibUv/ListenerPrimary.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/ListenerPrimary.cs similarity index 91% rename from Projects/Server/LibUv/ListenerPrimary.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/ListenerPrimary.cs index da006b7fe..e172ad175 100644 --- a/Projects/Server/LibUv/ListenerPrimary.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/ListenerPrimary.cs @@ -7,19 +7,16 @@ using System.IO; using System.Net; using System.Runtime.InteropServices; using System.Threading.Tasks; -using Libuv.Internal; +using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking; using Microsoft.Extensions.Logging; -using Server; -#pragma warning disable 169 - -namespace Libuv +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal { /// /// A primary listener waits for incoming connections on a specified socket. Incoming /// connections may be passed to a secondary listener to handle. /// - public class ListenerPrimary : Listener + internal class ListenerPrimary : Listener { // The list of pipes that can be dispatched to (where we've confirmed the _pipeMessage) private readonly List _dispatchPipes = new List(); @@ -29,7 +26,7 @@ namespace Libuv private string _pipeName; private byte[] _pipeMessage; private IntPtr _fileCompletionInfoPtr; - private bool _tryDetachFromIOCP = Core.IsWindows; + private bool _tryDetachFromIOCP = PlatformApis.IsWindows; // this message is passed to write2 because it must be non-zero-length, // but it has no other functional significance @@ -151,15 +148,17 @@ namespace Libuv Thread.Loop.Libuv.uv_fileno(handle, ref socket); if (NtSetInformationFile(socket, out statusBlock, _fileCompletionInfoPtr, - (uint)Marshal.SizeOf(), FileReplaceCompletionInformation) == STATUS_INVALID_INFO_CLASS) + (uint)Marshal.SizeOf(), FileReplaceCompletionInformation) == STATUS_INVALID_INFO_CLASS) // Replacing IOCP information is only supported on Windows 8.1 or newer _tryDetachFromIOCP = false; } private struct IO_STATUS_BLOCK { +#pragma warning disable 169 uint status; ulong information; +#pragma warning restore 169 } private struct FILE_COMPLETION_INFORMATION @@ -219,7 +218,7 @@ namespace Libuv { // This is an unexpected immediate termination of the dispatch pipe most likely caused by an // external process scanning the pipe, so don't we don't log it too severely. - // https://github.com/aspnet/AspNetCore/issues/4741 + // https://github.com/dotnet/aspnetcore/issues/4741 dispatchPipe.Dispose(); _bufHandle.Free(); diff --git a/Projects/Server/LibUv/ListenerSecondary.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/ListenerSecondary.cs similarity index 92% rename from Projects/Server/LibUv/ListenerSecondary.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/ListenerSecondary.cs index 4377a4e9c..e741c8c0c 100644 --- a/Projects/Server/LibUv/ListenerSecondary.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/ListenerSecondary.cs @@ -6,16 +6,16 @@ using System.Net; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -using Libuv.Internal; +using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking; using Microsoft.Extensions.Logging; -namespace Libuv +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal { /// /// A secondary listener is delegated requests from a primary listener via a named pipe or /// UNIX domain socket. /// - public class ListenerSecondary : ListenerContext, IAsyncDisposable + internal class ListenerSecondary : ListenerContext, IAsyncDisposable { private string _pipeName; private byte[] _pipeMessage; diff --git a/Projects/Server/LibUv/Internal/LibuvFunctions.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/LibuvFunctions.cs similarity index 78% rename from Projects/Server/LibUv/Internal/LibuvFunctions.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/LibuvFunctions.cs index f215c0ae6..718bdc3cd 100644 --- a/Projects/Server/LibUv/Internal/LibuvFunctions.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/LibuvFunctions.cs @@ -4,14 +4,15 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using Server; -namespace Libuv.Internal +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking { - public class LibuvFunctions + internal class LibuvFunctions { public LibuvFunctions() { + IsWindows = PlatformApis.IsWindows; + _uv_loop_init = NativeMethods.uv_loop_init; _uv_loop_close = NativeMethods.uv_loop_close; _uv_run = NativeMethods.uv_run; @@ -63,6 +64,8 @@ namespace Libuv.Internal { } + public readonly bool IsWindows; + public void ThrowIfErrored(int statusCode) { // Note: method is explicitly small so the success case is easily inlined @@ -83,47 +86,51 @@ namespace Libuv.Internal error = statusCode < 0 ? GetError(statusCode) : null; } - // Note: method marked as NoInlining so it doesn't bloat either of the two preceding functions - // Check and ThrowError and alter their jit heuristics. [MethodImpl(MethodImplOptions.NoInlining)] - private UvException GetError(int statusCode) => - new UvException($"Error {statusCode} {err_name(statusCode)} {strerror(statusCode)}", statusCode); + private UvException GetError(int statusCode) + { + // Note: method marked as NoInlining so it doesn't bloat either of the two preceding functions + // Check and ThrowError and alter their jit heuristics. + var errorName = err_name(statusCode); + var errorDescription = strerror(statusCode); + return new UvException("Error " + statusCode + " " + errorName + " " + errorDescription, statusCode); + } - public Func _uv_loop_init; + protected Func _uv_loop_init; public void loop_init(UvLoopHandle handle) { ThrowIfErrored(_uv_loop_init(handle)); } - public Func _uv_loop_close; + protected Func _uv_loop_close; public void loop_close(UvLoopHandle handle) { - handle.Validate(true); + handle.Validate(closed: true); ThrowIfErrored(_uv_loop_close(handle.InternalGetHandle())); } - public Func _uv_run; + protected Func _uv_run; public void run(UvLoopHandle handle, int mode) { handle.Validate(); ThrowIfErrored(_uv_run(handle, mode)); } - public Action _uv_stop; + protected Action _uv_stop; public void stop(UvLoopHandle handle) { handle.Validate(); _uv_stop(handle); } - public Action _uv_ref; + protected Action _uv_ref; public void @ref(UvHandle handle) { handle.Validate(); _uv_ref(handle); } - public Action _uv_unref; + protected Action _uv_unref; public void unref(UvHandle handle) { handle.Validate(); @@ -131,8 +138,8 @@ namespace Libuv.Internal } [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int uv_fileno_func(UvHandle handle, ref IntPtr socket); - public uv_fileno_func _uv_fileno; + protected delegate int uv_fileno_func(UvHandle handle, ref IntPtr socket); + protected uv_fileno_func _uv_fileno; public void uv_fileno(UvHandle handle, ref IntPtr socket) { handle.Validate(); @@ -141,10 +148,10 @@ namespace Libuv.Internal [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void uv_close_cb(IntPtr handle); - public Action _uv_close; + protected Action _uv_close; public void close(UvHandle handle, uv_close_cb close_cb) { - handle.Validate(true); + handle.Validate(closed: true); _uv_close(handle.InternalGetHandle(), close_cb); } @@ -155,7 +162,7 @@ namespace Libuv.Internal [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void uv_async_cb(IntPtr handle); - public Func _uv_async_init; + protected Func _uv_async_init; public void async_init(UvLoopHandle loop, UvAsyncHandle handle, uv_async_cb cb) { loop.Validate(); @@ -163,19 +170,19 @@ namespace Libuv.Internal ThrowIfErrored(_uv_async_init(loop, handle, cb)); } - public Func _uv_async_send; + protected Func _uv_async_send; public void async_send(UvAsyncHandle handle) { ThrowIfErrored(_uv_async_send(handle)); } - public Func _uv_unsafe_async_send; + protected Func _uv_unsafe_async_send; public void unsafe_async_send(IntPtr handle) { ThrowIfErrored(_uv_unsafe_async_send(handle)); } - public Func _uv_tcp_init; + protected Func _uv_tcp_init; public void tcp_init(UvLoopHandle loop, UvTcpHandle handle) { loop.Validate(); @@ -183,29 +190,29 @@ namespace Libuv.Internal ThrowIfErrored(_uv_tcp_init(loop, handle)); } - public delegate int uv_tcp_bind_func(UvTcpHandle handle, ref SockAddr addr, int flags); - public uv_tcp_bind_func _uv_tcp_bind; + protected delegate int uv_tcp_bind_func(UvTcpHandle handle, ref SockAddr addr, int flags); + protected uv_tcp_bind_func _uv_tcp_bind; public void tcp_bind(UvTcpHandle handle, ref SockAddr addr, int flags) { handle.Validate(); ThrowIfErrored(_uv_tcp_bind(handle, ref addr, flags)); } - public Func _uv_tcp_open; + protected Func _uv_tcp_open; public void tcp_open(UvTcpHandle handle, IntPtr hSocket) { handle.Validate(); ThrowIfErrored(_uv_tcp_open(handle, hSocket)); } - public Func _uv_tcp_nodelay; + protected Func _uv_tcp_nodelay; public void tcp_nodelay(UvTcpHandle handle, bool enable) { handle.Validate(); ThrowIfErrored(_uv_tcp_nodelay(handle, enable ? 1 : 0)); } - public Func _uv_pipe_init; + protected Func _uv_pipe_init; public void pipe_init(UvLoopHandle loop, UvPipeHandle handle, bool ipc) { loop.Validate(); @@ -213,14 +220,14 @@ namespace Libuv.Internal ThrowIfErrored(_uv_pipe_init(loop, handle, ipc ? -1 : 0)); } - public Func _uv_pipe_bind; + protected Func _uv_pipe_bind; public void pipe_bind(UvPipeHandle handle, string name) { handle.Validate(); ThrowIfErrored(_uv_pipe_bind(handle, name)); } - public Func _uv_pipe_open; + protected Func _uv_pipe_open; public void pipe_open(UvPipeHandle handle, IntPtr hSocket) { handle.Validate(); @@ -229,14 +236,14 @@ namespace Libuv.Internal [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void uv_connection_cb(IntPtr server, int status); - public Func _uv_listen; + protected Func _uv_listen; public void listen(UvStreamHandle handle, int backlog, uv_connection_cb cb) { handle.Validate(); ThrowIfErrored(_uv_listen(handle, backlog, cb)); } - public Func _uv_accept; + protected Func _uv_accept; public void accept(UvStreamHandle server, UvStreamHandle client) { server.Validate(); @@ -246,7 +253,7 @@ namespace Libuv.Internal [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void uv_connect_cb(IntPtr req, int status); - public Action _uv_pipe_connect; + protected Action _uv_pipe_connect; public void pipe_connect(UvConnectRequest req, UvPipeHandle handle, string name, uv_connect_cb cb) { req.Validate(); @@ -254,7 +261,7 @@ namespace Libuv.Internal _uv_pipe_connect(req, handle, name, cb); } - public Func _uv_pipe_pending_count; + protected Func _uv_pipe_pending_count; public int pipe_pending_count(UvPipeHandle handle) { handle.Validate(); @@ -265,21 +272,21 @@ namespace Libuv.Internal public delegate void uv_alloc_cb(IntPtr server, int suggested_size, out uv_buf_t buf); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void uv_read_cb(IntPtr server, int nread, ref uv_buf_t buf); - public Func _uv_read_start; + protected Func _uv_read_start; public void read_start(UvStreamHandle handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb) { handle.Validate(); ThrowIfErrored(_uv_read_start(handle, alloc_cb, read_cb)); } - public Func _uv_read_stop; + protected Func _uv_read_stop; public void read_stop(UvStreamHandle handle) { handle.Validate(); ThrowIfErrored(_uv_read_stop(handle)); } - public Func _uv_try_write; + protected Func _uv_try_write; public int try_write(UvStreamHandle handle, uv_buf_t[] bufs, int nbufs) { handle.Validate(); @@ -291,8 +298,8 @@ namespace Libuv.Internal [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void uv_write_cb(IntPtr req, int status); - public unsafe delegate int uv_write_func(UvRequest req, UvStreamHandle handle, uv_buf_t* bufs, int nbufs, uv_write_cb cb); - public uv_write_func _uv_write; + protected unsafe delegate int uv_write_func(UvRequest req, UvStreamHandle handle, uv_buf_t* bufs, int nbufs, uv_write_cb cb); + protected uv_write_func _uv_write; public unsafe void write(UvRequest req, UvStreamHandle handle, uv_buf_t* bufs, int nbufs, uv_write_cb cb) { req.Validate(); @@ -300,8 +307,8 @@ namespace Libuv.Internal ThrowIfErrored(_uv_write(req, handle, bufs, nbufs, cb)); } - public unsafe delegate int uv_write2_func(UvRequest req, UvStreamHandle handle, uv_buf_t* bufs, int nbufs, UvStreamHandle sendHandle, uv_write_cb cb); - public uv_write2_func _uv_write2; + protected unsafe delegate int uv_write2_func(UvRequest req, UvStreamHandle handle, uv_buf_t* bufs, int nbufs, UvStreamHandle sendHandle, uv_write_cb cb); + protected uv_write2_func _uv_write2; public unsafe void write2(UvRequest req, UvStreamHandle handle, uv_buf_t* bufs, int nbufs, UvStreamHandle sendHandle, uv_write_cb cb) { req.Validate(); @@ -309,38 +316,38 @@ namespace Libuv.Internal ThrowIfErrored(_uv_write2(req, handle, bufs, nbufs, sendHandle, cb)); } - public Func _uv_err_name; + protected Func _uv_err_name; public string err_name(int err) { IntPtr ptr = _uv_err_name(err); return ptr == IntPtr.Zero ? null : Marshal.PtrToStringAnsi(ptr); } - public Func _uv_strerror; + protected Func _uv_strerror; public string strerror(int err) { IntPtr ptr = _uv_strerror(err); return ptr == IntPtr.Zero ? null : Marshal.PtrToStringAnsi(ptr); } - public Func _uv_loop_size; + protected Func _uv_loop_size; public int loop_size() => _uv_loop_size(); - public Func _uv_handle_size; + protected Func _uv_handle_size; public int handle_size(HandleType handleType) => _uv_handle_size(handleType); - public Func _uv_req_size; + protected Func _uv_req_size; public int req_size(RequestType reqType) => _uv_req_size(reqType); - public delegate int uv_ip4_addr_func(string ip, int port, out SockAddr addr); - public uv_ip4_addr_func _uv_ip4_addr; + protected delegate int uv_ip4_addr_func(string ip, int port, out SockAddr addr); + protected uv_ip4_addr_func _uv_ip4_addr; public void ip4_addr(string ip, int port, out SockAddr addr, out UvException error) { Check(_uv_ip4_addr(ip, port, out addr), out error); } - public delegate int uv_ip6_addr_func(string ip, int port, out SockAddr addr); - public uv_ip6_addr_func _uv_ip6_addr; + protected delegate int uv_ip6_addr_func(string ip, int port, out SockAddr addr); + protected uv_ip6_addr_func _uv_ip6_addr; public void ip6_addr(string ip, int port, out SockAddr addr, out UvException error) { Check(_uv_ip6_addr(ip, port, out addr), out error); @@ -348,15 +355,15 @@ namespace Libuv.Internal [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void uv_walk_cb(IntPtr handle, IntPtr arg); - public Func _uv_walk; + protected Func _uv_walk; public void walk(UvLoopHandle loop, uv_walk_cb walk_cb, IntPtr arg) { loop.Validate(); _uv_walk(loop, walk_cb, arg); } - public Func _uv_timer_init; - public void timer_init(UvLoopHandle loop, UvTimerHandle handle) + protected Func _uv_timer_init; + public unsafe void timer_init(UvLoopHandle loop, UvTimerHandle handle) { loop.Validate(); handle.Validate(); @@ -365,29 +372,29 @@ namespace Libuv.Internal [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void uv_timer_cb(IntPtr handle); - public Func _uv_timer_start; - public void timer_start(UvTimerHandle handle, uv_timer_cb cb, long timeout, long repeat) + protected Func _uv_timer_start; + public unsafe void timer_start(UvTimerHandle handle, uv_timer_cb cb, long timeout, long repeat) { handle.Validate(); ThrowIfErrored(_uv_timer_start(handle, cb, timeout, repeat)); } - public Func _uv_timer_stop; - public void timer_stop(UvTimerHandle handle) + protected Func _uv_timer_stop; + public unsafe void timer_stop(UvTimerHandle handle) { handle.Validate(); ThrowIfErrored(_uv_timer_stop(handle)); } - public Func _uv_now; - public long now(UvLoopHandle loop) + protected Func _uv_now; + public unsafe long now(UvLoopHandle loop) { loop.Validate(); return _uv_now(loop); } public delegate int uv_tcp_getsockname_func(UvTcpHandle handle, out SockAddr addr, ref int namelen); - public uv_tcp_getsockname_func _uv_tcp_getsockname; + protected uv_tcp_getsockname_func _uv_tcp_getsockname; public void tcp_getsockname(UvTcpHandle handle, out SockAddr addr, ref int namelen) { handle.Validate(); @@ -395,14 +402,14 @@ namespace Libuv.Internal } public delegate int uv_tcp_getpeername_func(UvTcpHandle handle, out SockAddr addr, ref int namelen); - public uv_tcp_getpeername_func _uv_tcp_getpeername; + protected uv_tcp_getpeername_func _uv_tcp_getpeername; public void tcp_getpeername(UvTcpHandle handle, out SockAddr addr, ref int namelen) { handle.Validate(); ThrowIfErrored(_uv_tcp_getpeername(handle, out addr, ref namelen)); } - public uv_buf_t buf_init(IntPtr memory, int len) => new uv_buf_t(memory, len, Core.IsWindows); + public uv_buf_t buf_init(IntPtr memory, int len) => new uv_buf_t(memory, len, IsWindows); public struct uv_buf_t { @@ -417,9 +424,9 @@ namespace Libuv.Internal private readonly IntPtr _field0; private readonly IntPtr _field1; - public uv_buf_t(IntPtr memory, int len, bool windows) + public uv_buf_t(IntPtr memory, int len, bool IsWindows) { - if (windows) + if (IsWindows) { _field0 = (IntPtr)len; _field1 = memory; @@ -581,16 +588,16 @@ namespace Libuv.Internal public static extern int uv_walk(UvLoopHandle loop, uv_walk_cb walk_cb, IntPtr arg); [DllImport("libuv", CallingConvention = CallingConvention.Cdecl)] - public static extern int uv_timer_init(UvLoopHandle loop, UvTimerHandle handle); + public static extern unsafe int uv_timer_init(UvLoopHandle loop, UvTimerHandle handle); [DllImport("libuv", CallingConvention = CallingConvention.Cdecl)] - public static extern int uv_timer_start(UvTimerHandle handle, uv_timer_cb cb, long timeout, long repeat); + public static extern unsafe int uv_timer_start(UvTimerHandle handle, uv_timer_cb cb, long timeout, long repeat); [DllImport("libuv", CallingConvention = CallingConvention.Cdecl)] - public static extern int uv_timer_stop(UvTimerHandle handle); + public static extern unsafe int uv_timer_stop(UvTimerHandle handle); [DllImport("libuv", CallingConvention = CallingConvention.Cdecl)] - public static extern long uv_now(UvLoopHandle loop); + public static extern unsafe long uv_now(UvLoopHandle loop); [DllImport("WS2_32.dll", CallingConvention = CallingConvention.Winapi)] public static extern unsafe int WSAIoctl( diff --git a/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/PlatformApis.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/PlatformApis.cs new file mode 100644 index 000000000..ebf59a240 --- /dev/null +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/PlatformApis.cs @@ -0,0 +1,20 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; + +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking +{ + internal static class PlatformApis + { + public static bool IsWindows { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + + public static bool IsDarwin { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long VolatileRead(ref long value) => IntPtr.Size == 8 ? Volatile.Read(ref value) : Interlocked.Read(ref value); + } +} diff --git a/Projects/Server/LibUv/Internal/SockAddr.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/SockAddr.cs similarity index 78% rename from Projects/Server/LibUv/Internal/SockAddr.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/SockAddr.cs index 09c6e6473..9a01f5be3 100644 --- a/Projects/Server/LibUv/Internal/SockAddr.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/SockAddr.cs @@ -3,20 +3,19 @@ using System.Net; using System.Runtime.InteropServices; -using Server; -namespace Libuv.Internal +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking { [StructLayout(LayoutKind.Sequential)] - public struct SockAddr + internal struct SockAddr { // this type represents native memory occupied by sockaddr struct // https://msdn.microsoft.com/en-us/library/windows/desktop/ms740496(v=vs.85).aspx // although the c/c++ header defines it as a 2-byte short followed by a 14-byte array, // the simplest way to reserve the same size in c# is with four nameless long values - private long _field0; - private long _field1; - private long _field2; + private readonly long _field0; + private readonly long _field1; + private readonly long _field2; private long _field3; public SockAddr(long ignored) => _field0 = _field1 = _field2 = _field3 = 0; @@ -64,30 +63,33 @@ namespace Libuv.Internal var port = ((int)(_field0 & 0x00FF0000) >> 8) | (int)((_field0 & 0xFF000000) >> 24); int family = (int)_field0; - if (Core.IsDarwin) + if (PlatformApis.IsDarwin) // see explanation in example 4 family >>= 8; family &= 0xFF; if (family == 2) + { // AF_INET => IPv4 return new IPEndPoint(new IPAddress((_field0 >> 32) & 0xFFFFFFFF), port); - - if (IsIPv4MappedToIPv6()) + } + else if (IsIPv4MappedToIPv6()) { var ipv4bits = (_field2 >> 32) & 0x00000000FFFFFFFF; return new IPEndPoint(new IPAddress(ipv4bits), port); } - - // otherwise IPv6 - var bytes = new byte[16]; - fixed (byte* b = bytes) + else { - *(long*)b = _field1; - *(long*)(b + 8) = _field2; - } + // otherwise IPv6 + var bytes = new byte[16]; + fixed (byte* b = bytes) + { + *(long*)b = _field1; + *(long*)(b + 8) = _field2; + } - return new IPEndPoint(new IPAddress(bytes, ScopeId), port); + return new IPEndPoint(new IPAddress(bytes, ScopeId), port); + } } public uint ScopeId @@ -100,8 +102,13 @@ namespace Libuv.Internal } } - // If the IPAddress is an IPv4 mapped to IPv6, return the IPv4 representation instead. - // For example [::FFFF:127.0.0.1] will be transform to IPAddress of 127.0.0.1 - private bool IsIPv4MappedToIPv6() => _field1 == 0 && (_field2 & 0xFFFFFFFF) == 0xFFFF0000; + private bool IsIPv4MappedToIPv6() + { + // If the IPAddress is an IPv4 mapped to IPv6, return the IPv4 representation instead. + // For example [::FFFF:127.0.0.1] will be transform to IPAddress of 127.0.0.1 + if (_field1 != 0) return false; + + return (_field2 & 0xFFFFFFFF) == 0xFFFF0000; + } } } diff --git a/Projects/Server/LibUv/Internal/UvAsyncHandle.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvAsyncHandle.cs similarity index 86% rename from Projects/Server/LibUv/Internal/UvAsyncHandle.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvAsyncHandle.cs index f27a179a8..47552037c 100644 --- a/Projects/Server/LibUv/Internal/UvAsyncHandle.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvAsyncHandle.cs @@ -5,13 +5,13 @@ using System; using System.Diagnostics; using System.Threading; -namespace Libuv.Internal +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking { - public class UvAsyncHandle : UvHandle + internal class UvAsyncHandle : UvHandle { - private static readonly LibuvFunctions.uv_close_cb _destroyMemory = handle => DestroyMemory(handle); + private static readonly LibuvFunctions.uv_close_cb _destroyMemory = (handle) => DestroyMemory(handle); - private static readonly LibuvFunctions.uv_async_cb _uv_async_cb = handle => AsyncCb(handle); + private static readonly LibuvFunctions.uv_async_cb _uv_async_cb = (handle) => AsyncCb(handle); private Action _callback; private Action, IntPtr> _queueCloseHandle; @@ -56,7 +56,7 @@ namespace Libuv.Internal { // This can be called from the finalizer. // Ensure the closure doesn't reference "this". - LibuvFunctions uv = _uv; + var uv = _uv; _queueCloseHandle(memory2 => uv.close(memory2, _destroyMemory), memory); uv.unsafe_async_send(memory); } diff --git a/Projects/Server/LibUv/Internal/UvConnectRequest.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvConnectRequest.cs similarity index 86% rename from Projects/Server/LibUv/Internal/UvConnectRequest.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvConnectRequest.cs index cc60539ac..8aa07fc8d 100644 --- a/Projects/Server/LibUv/Internal/UvConnectRequest.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvConnectRequest.cs @@ -4,14 +4,14 @@ using System; using Microsoft.Extensions.Logging; -namespace Libuv.Internal +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking { /// /// Summary description for UvWriteRequest /// - public class UvConnectRequest : UvRequest + internal class UvConnectRequest : UvRequest { - private static readonly LibuvFunctions.uv_connect_cb _uv_connect_cb = UvConnectCb; + private static readonly LibuvFunctions.uv_connect_cb _uv_connect_cb = (req, status) => UvConnectCb(req, status); private Action _callback; private object _state; diff --git a/Projects/Server/LibUv/Internal/UvException.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvException.cs similarity index 70% rename from Projects/Server/LibUv/Internal/UvException.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvException.cs index 3d4e492ef..bdda17954 100644 --- a/Projects/Server/LibUv/Internal/UvException.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvException.cs @@ -3,9 +3,9 @@ using System; -namespace Libuv.Internal +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking { - public class UvException : Exception + internal class UvException : Exception { public UvException(string message, int statusCode) : base(message) => StatusCode = statusCode; diff --git a/Projects/Server/LibUv/Internal/UvHandle.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvHandle.cs similarity index 83% rename from Projects/Server/LibUv/Internal/UvHandle.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvHandle.cs index 888791bcc..4f738819e 100644 --- a/Projects/Server/LibUv/Internal/UvHandle.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvHandle.cs @@ -5,11 +5,11 @@ using System; using System.Diagnostics; using System.Threading; -namespace Libuv.Internal +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking { - public abstract class UvHandle : UvMemory + internal abstract class UvHandle : UvMemory { - private static readonly LibuvFunctions.uv_close_cb _destroyMemory = DestroyMemory; + private static readonly LibuvFunctions.uv_close_cb _destroyMemory = (handle) => DestroyMemory(handle); private Action, IntPtr> _queueCloseHandle; protected UvHandle(ILibuvTrace logger) : base (logger) @@ -28,7 +28,7 @@ namespace Libuv.Internal protected override bool ReleaseHandle() { - IntPtr memory = handle; + var memory = handle; if (memory != IntPtr.Zero) { handle = IntPtr.Zero; @@ -41,7 +41,7 @@ namespace Libuv.Internal { // This can be called from the finalizer. // Ensure the closure doesn't reference "this". - LibuvFunctions uv = _uv; + var uv = _uv; _queueCloseHandle(memory2 => uv.close(memory2, _destroyMemory), memory); } else diff --git a/Projects/Server/LibUv/Internal/UvLoopHandle.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvLoopHandle.cs similarity index 84% rename from Projects/Server/LibUv/Internal/UvLoopHandle.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvLoopHandle.cs index c99c8896f..d24c1fac0 100644 --- a/Projects/Server/LibUv/Internal/UvLoopHandle.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvLoopHandle.cs @@ -4,9 +4,9 @@ using System; using System.Threading; -namespace Libuv.Internal +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking { - public class UvLoopHandle : UvMemory + internal class UvLoopHandle : UvMemory { public UvLoopHandle(ILibuvTrace logger) : base(logger) { diff --git a/Projects/Server/LibUv/Internal/UvMemory.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvMemory.cs similarity index 90% rename from Projects/Server/LibUv/Internal/UvMemory.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvMemory.cs index b5369ab5c..e42e420f8 100644 --- a/Projects/Server/LibUv/Internal/UvMemory.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvMemory.cs @@ -7,12 +7,12 @@ using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading; -namespace Libuv.Internal +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking { /// /// Summary description for UvMemory /// - public abstract class UvMemory : SafeHandle + internal abstract class UvMemory : SafeHandle { protected LibuvFunctions _uv; protected int _threadId; @@ -66,7 +66,6 @@ namespace Libuv.Internal { Debug.Assert(closed || !IsClosed, "Handle is closed"); Debug.Assert(!IsInvalid, "Handle is invalid"); - Debug.Assert(_threadId == Thread.CurrentThread.ManagedThreadId, "ThreadId is incorrect"); } diff --git a/Projects/Server/LibUv/Internal/UvPipeHandle.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvPipeHandle.cs similarity index 83% rename from Projects/Server/LibUv/Internal/UvPipeHandle.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvPipeHandle.cs index 188777209..0ce7aedd3 100644 --- a/Projects/Server/LibUv/Internal/UvPipeHandle.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvPipeHandle.cs @@ -3,9 +3,9 @@ using System; -namespace Libuv.Internal +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking { - public class UvPipeHandle : UvStreamHandle + internal class UvPipeHandle : UvStreamHandle { public UvPipeHandle(ILibuvTrace logger) : base(logger) { diff --git a/Projects/Server/LibUv/Internal/UvRequest.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvRequest.cs similarity index 65% rename from Projects/Server/LibUv/Internal/UvRequest.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvRequest.cs index ed7199ce2..c25a1eecd 100644 --- a/Projects/Server/LibUv/Internal/UvRequest.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvRequest.cs @@ -4,9 +4,9 @@ using System; using System.Runtime.InteropServices; -namespace Libuv.Internal +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking { - public class UvRequest : UvMemory + internal class UvRequest : UvMemory { protected UvRequest(ILibuvTrace logger) : base(logger, GCHandleType.Normal) { @@ -14,11 +14,6 @@ namespace Libuv.Internal public virtual void Init(LibuvThread thread) { -#if DEBUG - // Store weak handles to all UvRequest objects so we can do leak detection - // while running tests - thread.Requests.Add(new WeakReference(this)); -#endif } protected override bool ReleaseHandle() @@ -29,3 +24,4 @@ namespace Libuv.Internal } } } + diff --git a/Projects/Server/LibUv/Internal/UvStreamHandle.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvStreamHandle.cs similarity index 89% rename from Projects/Server/LibUv/Internal/UvStreamHandle.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvStreamHandle.cs index 2edf8253b..eb139c311 100644 --- a/Projects/Server/LibUv/Internal/UvStreamHandle.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvStreamHandle.cs @@ -5,16 +5,14 @@ using System; using System.Runtime.InteropServices; using Microsoft.Extensions.Logging; -namespace Libuv.Internal +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking { - public abstract class UvStreamHandle : UvHandle + internal abstract class UvStreamHandle : UvHandle { - private static readonly LibuvFunctions.uv_connection_cb _uv_connection_cb = UvConnectionCb; + private static readonly LibuvFunctions.uv_connection_cb _uv_connection_cb = (handle, status) => UvConnectionCb(handle, status); // Ref and out lamda params must be explicitly typed - private static readonly LibuvFunctions.uv_alloc_cb _uv_alloc_cb = - (IntPtr handle, int suggested_size, out LibuvFunctions.uv_buf_t buf) => UvAllocCb(handle, suggested_size, out buf); - private static readonly LibuvFunctions.uv_read_cb _uv_read_cb = - (IntPtr handle, int status, ref LibuvFunctions.uv_buf_t buf) => UvReadCb(handle, status, ref buf); + private static readonly LibuvFunctions.uv_alloc_cb _uv_alloc_cb = (IntPtr handle, int suggested_size, out LibuvFunctions.uv_buf_t buf) => UvAllocCb(handle, suggested_size, out buf); + private static readonly LibuvFunctions.uv_read_cb _uv_read_cb = (IntPtr handle, int status, ref LibuvFunctions.uv_buf_t buf) => UvReadCb(handle, status, ref buf); private Action _listenCallback; private object _listenState; diff --git a/Projects/Server/LibUv/Internal/UvTcpHandle.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvTcpHandle.cs similarity index 90% rename from Projects/Server/LibUv/Internal/UvTcpHandle.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvTcpHandle.cs index 745477201..548ec53a0 100644 --- a/Projects/Server/LibUv/Internal/UvTcpHandle.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvTcpHandle.cs @@ -5,9 +5,9 @@ using System; using System.Net; using System.Runtime.InteropServices; -namespace Libuv.Internal +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking { - public class UvTcpHandle : UvStreamHandle + internal class UvTcpHandle : UvStreamHandle { public UvTcpHandle(ILibuvTrace logger) : base(logger) { diff --git a/Projects/Server/LibUv/Internal/UvTimerHandle.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvTimerHandle.cs similarity index 87% rename from Projects/Server/LibUv/Internal/UvTimerHandle.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvTimerHandle.cs index 5fc52af17..f15c8458c 100644 --- a/Projects/Server/LibUv/Internal/UvTimerHandle.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvTimerHandle.cs @@ -4,9 +4,9 @@ using System; using Microsoft.Extensions.Logging; -namespace Libuv.Internal +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking { - public class UvTimerHandle : UvHandle + internal class UvTimerHandle : UvHandle { private static readonly LibuvFunctions.uv_timer_cb _uv_timer_cb = UvTimerCb; diff --git a/Projects/Server/LibUv/Internal/UvWriteReq.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvWriteReq.cs similarity index 84% rename from Projects/Server/LibUv/Internal/UvWriteReq.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvWriteReq.cs index 29b8b4e9f..b3fa47ce6 100644 --- a/Projects/Server/LibUv/Internal/UvWriteReq.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/Networking/UvWriteReq.cs @@ -7,14 +7,14 @@ using System.Collections.Generic; using System.Runtime.InteropServices; using Microsoft.Extensions.Logging; -namespace Libuv.Internal +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking { /// /// Summary description for UvWriteRequest /// - public class UvWriteReq : UvRequest + internal class UvWriteReq : UvRequest { - private static readonly LibuvFunctions.uv_write_cb _uv_write_cb = (ptr, status) => UvWriteCb(ptr, status); + private static readonly LibuvFunctions.uv_write_cb _uv_write_cb = (IntPtr ptr, int status) => UvWriteCb(ptr, status); private IntPtr _bufs; @@ -22,9 +22,9 @@ namespace Libuv.Internal private object _state; private const int BUFFER_COUNT = 4; - private LibuvAwaitable _awaitable = new LibuvAwaitable(); - private List _pins = new List(BUFFER_COUNT + 1); - private List _handles = new List(BUFFER_COUNT + 1); + private readonly LibuvAwaitable _awaitable = new LibuvAwaitable(); + private readonly List _pins = new List(BUFFER_COUNT + 1); + private readonly List _handles = new List(BUFFER_COUNT + 1); public UvWriteReq(ILibuvTrace logger) : base(logger) { @@ -76,9 +76,6 @@ namespace Libuv.Internal nBuffers++; var pBuffers = (LibuvFunctions.uv_buf_t*)_bufs; - if (pBuffers == null) - throw new NullReferenceException(); - if (nBuffers > BUFFER_COUNT) { // create and pin buffer array when it's larger than the pre-allocated one @@ -86,8 +83,6 @@ namespace Libuv.Internal var gcHandle = GCHandle.Alloc(bufArray, GCHandleType.Pinned); _pins.Add(gcHandle); pBuffers = (LibuvFunctions.uv_buf_t*)gcHandle.AddrOfPinnedObject(); - if (pBuffers == null) - throw new NullReferenceException(); } if (nBuffers == 1) @@ -137,7 +132,7 @@ namespace Libuv.Internal Action callback, object state) { - WriteArraySegmentInternal(handle, bufs, null, callback, state); + WriteArraySegmentInternal(handle, bufs, sendHandle: null, callback: callback, state: state); } public void Write2( @@ -154,15 +149,12 @@ namespace Libuv.Internal UvStreamHandle handle, ArraySegment> bufs, UvStreamHandle sendHandle, - Action callback, object state - ) + Action callback, + object state) { try { var pBuffers = (LibuvFunctions.uv_buf_t*)_bufs; - if (pBuffers == null) - throw new NullReferenceException(); - var nBuffers = bufs.Count; if (nBuffers > BUFFER_COUNT) { @@ -171,14 +163,12 @@ namespace Libuv.Internal var gcHandle = GCHandle.Alloc(bufArray, GCHandleType.Pinned); _pins.Add(gcHandle); pBuffers = (LibuvFunctions.uv_buf_t*)gcHandle.AddrOfPinnedObject(); - if (pBuffers == null) - throw new NullReferenceException(); } for (var index = 0; index < nBuffers; index++) { // create and pin each segment being written - var buf = bufs.Array?[bufs.Offset + index] ?? throw new Exception("buffs.Array is null"); + var buf = bufs.Array[bufs.Offset + index]; var gcHandle = GCHandle.Alloc(buf.Array, GCHandleType.Pinned); _pins.Add(gcHandle); diff --git a/Projects/Server/LibUv/WriteReqPool.cs b/Projects/Server/Kestrel/Transport.LIbuv/Internal/WriteReqPool.cs similarity index 84% rename from Projects/Server/LibUv/WriteReqPool.cs rename to Projects/Server/Kestrel/Transport.LIbuv/Internal/WriteReqPool.cs index 745874344..41f76afd7 100644 --- a/Projects/Server/LibUv/WriteReqPool.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/Internal/WriteReqPool.cs @@ -3,11 +3,11 @@ using System; using System.Collections.Generic; -using Libuv.Internal; +using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking; -namespace Libuv +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal { - public class WriteReqPool + internal class WriteReqPool { private const int _maxPooledWriteReqs = 1024; diff --git a/Projects/Server/LibUv/LibuvTransportOptions.cs b/Projects/Server/Kestrel/Transport.LIbuv/LibuvTransportOptions.cs similarity index 66% rename from Projects/Server/LibUv/LibuvTransportOptions.cs rename to Projects/Server/Kestrel/Transport.LIbuv/LibuvTransportOptions.cs index 9de07cc83..7ea005700 100644 --- a/Projects/Server/LibUv/LibuvTransportOptions.cs +++ b/Projects/Server/Kestrel/Transport.LIbuv/LibuvTransportOptions.cs @@ -4,7 +4,7 @@ using System; using System.Buffers; -namespace Libuv +namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv { /// /// Provides programmatic configuration of Libuv transport features. @@ -19,6 +19,14 @@ namespace Libuv /// public int ThreadCount { get; set; } = ProcessorThreadCount; + /// + /// Set to false to enable Nagle's algorithm for all connections. + /// + /// + /// Defaults to true. + /// + public bool NoDelay { get; set; } = true; + /// /// The maximum length of the pending connection queue. /// @@ -39,12 +47,19 @@ namespace Libuv { // Actual core count would be a better number // rather than logical cores which includes hyper-threaded cores. - // Divide by 2 for hyper-threading, and good defaults (still need threads for the game thread). + // Divide by 2 for hyper-threading, and good defaults (still need threads to do webserving). var threadCount = Environment.ProcessorCount >> 1; - // Receive Side Scaling RSS Processor count currently maxes out at 16 - // would be better to check the NIC's current hardware queues; but xplat... - return threadCount < 1 ? 1 : threadCount > 16 ? 16 : threadCount; + if (threadCount < 1) + // Ensure shifted value is at least one + return 1; + + if (threadCount > 16) + // Receive Side Scaling RSS Processor count currently maxes out at 16 + // would be better to check the NIC's current hardware queues; but xplat... + return 16; + + return threadCount; } } } diff --git a/Projects/Server/Kestrel/Transport.LIbuv/WebHostBuilderLibuvExtensions.cs b/Projects/Server/Kestrel/Transport.LIbuv/WebHostBuilderLibuvExtensions.cs new file mode 100644 index 000000000..242695bb3 --- /dev/null +++ b/Projects/Server/Kestrel/Transport.LIbuv/WebHostBuilderLibuvExtensions.cs @@ -0,0 +1,51 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv; +using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal; +using Microsoft.Extensions.DependencyInjection; + +namespace Microsoft.AspNetCore.Hosting +{ + public static class WebHostBuilderLibuvExtensions + { + /// + /// Specify Libuv as the transport to be used by Kestrel. + /// + /// + /// The Microsoft.AspNetCore.Hosting.IWebHostBuilder to configure. + /// + /// + /// The Microsoft.AspNetCore.Hosting.IWebHostBuilder. + /// + public static IWebHostBuilder UseLibuv(this IWebHostBuilder hostBuilder) + { + return hostBuilder.ConfigureServices(services => + { + services.AddSingleton(); + }); + } + + /// + /// Specify Libuv as the transport to be used by Kestrel. + /// + /// + /// The Microsoft.AspNetCore.Hosting.IWebHostBuilder to configure. + /// + /// + /// A callback to configure Libuv options. + /// + /// + /// The Microsoft.AspNetCore.Hosting.IWebHostBuilder. + /// + public static IWebHostBuilder UseLibuv(this IWebHostBuilder hostBuilder, Action configureOptions) + { + return hostBuilder.UseLibuv().ConfigureServices(services => + { + services.Configure(configureOptions); + }); + } + } +} diff --git a/Projects/Server/Kestrel/TransportConnection.FeatureCollection.cs b/Projects/Server/Kestrel/TransportConnection.FeatureCollection.cs deleted file mode 100644 index 70033b7c9..000000000 --- a/Projects/Server/Kestrel/TransportConnection.FeatureCollection.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Buffers; -using System.Collections.Generic; -using System.IO.Pipelines; -using System.Threading; -using Microsoft.AspNetCore.Connections.Features; - -namespace Microsoft.AspNetCore.Connections -{ - public partial class TransportConnection : IConnectionIdFeature, - IConnectionTransportFeature, - IConnectionItemsFeature, - IMemoryPoolFeature, - IConnectionLifetimeFeature - { - // NOTE: When feature interfaces are added to or removed from this TransportConnection class implementation, - // then the list of `features` in the generated code project MUST also be updated. - // See also: tools/CodeGenerator/TransportConnectionFeatureCollection.cs - - MemoryPool IMemoryPoolFeature.MemoryPool => MemoryPool; - - IDuplexPipe IConnectionTransportFeature.Transport - { - get => Transport; - set => Transport = value; - } - - IDictionary IConnectionItemsFeature.Items - { - get => Items; - set => Items = value; - } - - CancellationToken IConnectionLifetimeFeature.ConnectionClosed - { - get => ConnectionClosed; - set => ConnectionClosed = value; - } - - void IConnectionLifetimeFeature.Abort() => Abort(new ConnectionAbortedException("The connection was aborted by the application via IConnectionLifetimeFeature.Abort().")); - } -} diff --git a/Projects/Server/Kestrel/TransportConnection.Generated.cs b/Projects/Server/Kestrel/TransportConnection.Generated.cs deleted file mode 100644 index eb6f2ba25..000000000 --- a/Projects/Server/Kestrel/TransportConnection.Generated.cs +++ /dev/null @@ -1,248 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections; -using System.Collections.Generic; - -using Microsoft.AspNetCore.Connections.Features; -using Microsoft.AspNetCore.Http.Features; - -namespace Microsoft.AspNetCore.Connections -{ - public partial class TransportConnection : IFeatureCollection - { - private static readonly Type IConnectionIdFeatureType = typeof(IConnectionIdFeature); - private static readonly Type IConnectionTransportFeatureType = typeof(IConnectionTransportFeature); - private static readonly Type IConnectionItemsFeatureType = typeof(IConnectionItemsFeature); - private static readonly Type IMemoryPoolFeatureType = typeof(IMemoryPoolFeature); - private static readonly Type IConnectionLifetimeFeatureType = typeof(IConnectionLifetimeFeature); - - private object _currentIConnectionIdFeature; - private object _currentIConnectionTransportFeature; - private object _currentIConnectionItemsFeature; - private object _currentIMemoryPoolFeature; - private object _currentIConnectionLifetimeFeature; - - private int _featureRevision; - - private List> MaybeExtra; - - private void FastReset() - { - _currentIConnectionIdFeature = this; - _currentIConnectionTransportFeature = this; - _currentIConnectionItemsFeature = this; - _currentIMemoryPoolFeature = this; - _currentIConnectionLifetimeFeature = this; - - } - - // Internal for testing - internal void ResetFeatureCollection() - { - FastReset(); - MaybeExtra?.Clear(); - _featureRevision++; - } - - private object ExtraFeatureGet(Type key) - { - if (MaybeExtra == null) - { - return null; - } - for (var i = 0; i < MaybeExtra.Count; i++) - { - var kv = MaybeExtra[i]; - if (kv.Key == key) - { - return kv.Value; - } - } - return null; - } - - private void ExtraFeatureSet(Type key, object value) - { - if (MaybeExtra == null) - { - MaybeExtra = new List>(2); - } - - for (var i = 0; i < MaybeExtra.Count; i++) - { - if (MaybeExtra[i].Key == key) - { - MaybeExtra[i] = new KeyValuePair(key, value); - return; - } - } - MaybeExtra.Add(new KeyValuePair(key, value)); - } - - bool IFeatureCollection.IsReadOnly => false; - - int IFeatureCollection.Revision => _featureRevision; - - object IFeatureCollection.this[Type key] - { - get - { - object feature = null; - if (key == IConnectionIdFeatureType) - { - feature = _currentIConnectionIdFeature; - } - else if (key == IConnectionTransportFeatureType) - { - feature = _currentIConnectionTransportFeature; - } - else if (key == IConnectionItemsFeatureType) - { - feature = _currentIConnectionItemsFeature; - } - else if (key == IMemoryPoolFeatureType) - { - feature = _currentIMemoryPoolFeature; - } - else if (key == IConnectionLifetimeFeatureType) - { - feature = _currentIConnectionLifetimeFeature; - } - else if (MaybeExtra != null) - { - feature = ExtraFeatureGet(key); - } - - return feature; - } - - set - { - _featureRevision++; - - if (key == IConnectionIdFeatureType) - { - _currentIConnectionIdFeature = value; - } - else if (key == IConnectionTransportFeatureType) - { - _currentIConnectionTransportFeature = value; - } - else if (key == IConnectionItemsFeatureType) - { - _currentIConnectionItemsFeature = value; - } - else if (key == IMemoryPoolFeatureType) - { - _currentIMemoryPoolFeature = value; - } - else if (key == IConnectionLifetimeFeatureType) - { - _currentIConnectionLifetimeFeature = value; - } - else - { - ExtraFeatureSet(key, value); - } - } - } - - TFeature IFeatureCollection.Get() - { - TFeature feature = default; - if (typeof(TFeature) == typeof(IConnectionIdFeature)) - { - feature = (TFeature)_currentIConnectionIdFeature; - } - else if (typeof(TFeature) == typeof(IConnectionTransportFeature)) - { - feature = (TFeature)_currentIConnectionTransportFeature; - } - else if (typeof(TFeature) == typeof(IConnectionItemsFeature)) - { - feature = (TFeature)_currentIConnectionItemsFeature; - } - else if (typeof(TFeature) == typeof(IMemoryPoolFeature)) - { - feature = (TFeature)_currentIMemoryPoolFeature; - } - else if (typeof(TFeature) == typeof(IConnectionLifetimeFeature)) - { - feature = (TFeature)_currentIConnectionLifetimeFeature; - } - else if (MaybeExtra != null) - { - feature = (TFeature)(ExtraFeatureGet(typeof(TFeature))); - } - - return feature; - } - - void IFeatureCollection.Set(TFeature feature) - { - _featureRevision++; - if (typeof(TFeature) == typeof(IConnectionIdFeature)) - { - _currentIConnectionIdFeature = feature; - } - else if (typeof(TFeature) == typeof(IConnectionTransportFeature)) - { - _currentIConnectionTransportFeature = feature; - } - else if (typeof(TFeature) == typeof(IConnectionItemsFeature)) - { - _currentIConnectionItemsFeature = feature; - } - else if (typeof(TFeature) == typeof(IMemoryPoolFeature)) - { - _currentIMemoryPoolFeature = feature; - } - else if (typeof(TFeature) == typeof(IConnectionLifetimeFeature)) - { - _currentIConnectionLifetimeFeature = feature; - } - else - { - ExtraFeatureSet(typeof(TFeature), feature); - } - } - - private IEnumerable> FastEnumerable() - { - if (_currentIConnectionIdFeature != null) - { - yield return new KeyValuePair(IConnectionIdFeatureType, _currentIConnectionIdFeature); - } - if (_currentIConnectionTransportFeature != null) - { - yield return new KeyValuePair(IConnectionTransportFeatureType, _currentIConnectionTransportFeature); - } - if (_currentIConnectionItemsFeature != null) - { - yield return new KeyValuePair(IConnectionItemsFeatureType, _currentIConnectionItemsFeature); - } - if (_currentIMemoryPoolFeature != null) - { - yield return new KeyValuePair(IMemoryPoolFeatureType, _currentIMemoryPoolFeature); - } - if (_currentIConnectionLifetimeFeature != null) - { - yield return new KeyValuePair(IConnectionLifetimeFeatureType, _currentIConnectionLifetimeFeature); - } - - if (MaybeExtra != null) - { - foreach (var item in MaybeExtra) - { - yield return item; - } - } - } - - IEnumerator> IEnumerable>.GetEnumerator() => FastEnumerable().GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() => FastEnumerable().GetEnumerator(); - } -} diff --git a/Projects/Server/Kestrel/TransportConnection.cs b/Projects/Server/Kestrel/TransportConnection.cs deleted file mode 100644 index fcd066608..000000000 --- a/Projects/Server/Kestrel/TransportConnection.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Buffers; -using System.Collections.Generic; -using System.IO.Pipelines; -using System.Net; -using System.Threading; -using Microsoft.AspNetCore.Http.Features; - -namespace Microsoft.AspNetCore.Connections -{ - public abstract partial class TransportConnection : ConnectionContext - { - private IDictionary _items; - private string _connectionId; - - public TransportConnection() - { - FastReset(); - } - - public override EndPoint LocalEndPoint { get; set; } - public override EndPoint RemoteEndPoint { get; set; } - - public override string ConnectionId - { - get => _connectionId ??= CorrelationIdGenerator.GetNextId(); - set => _connectionId = value; - } - - public override IFeatureCollection Features => this; - - public virtual MemoryPool MemoryPool { get; } - - public override IDuplexPipe Transport { get; set; } - - public IDuplexPipe Application { get; set; } - - public override IDictionary Items - { - get => _items ??= new ConnectionItems(); - set => _items = value; - } - - public override CancellationToken ConnectionClosed { get; set; } - - // DO NOT remove this override to ConnectionContext.Abort. Doing so would cause - // any TransportConnection that does not override Abort or calls base.Abort - // to stack overflow when IConnectionLifetimeFeature.Abort() is called. - // That said, all derived types should override this method should override - // this implementation of Abort because canceling pending output reads is not - // sufficient to abort the connection if there is backpressure. - public override void Abort(ConnectionAbortedException abortReason) - { - Application.Input.CancelPendingRead(); - } - } -} diff --git a/Projects/Server/KeywordList.cs b/Projects/Server/KeywordList.cs index a51a296b6..a96e6d995 100644 --- a/Projects/Server/KeywordList.cs +++ b/Projects/Server/KeywordList.cs @@ -22,7 +22,7 @@ namespace Server { public class KeywordList { - private static int[] m_EmptyInts = new int[0]; + private static readonly int[] m_EmptyInts = new int[0]; private int[] m_Keywords; public KeywordList() diff --git a/Projects/Server/Main.cs b/Projects/Server/Main.cs index 25a9b2d16..c91fb518b 100644 --- a/Projects/Server/Main.cs +++ b/Projects/Server/Main.cs @@ -29,6 +29,9 @@ using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Server.Network; namespace Server @@ -56,7 +59,7 @@ namespace Server * GetTickCount and GetTickCount64 have poor resolution. * GetTickCount64 is unavailable on Windows XP and Windows Server 2003. * Stopwatch.GetTimestamp() (QueryPerformanceCounter) is high resolution, but - * somewhat expensive to call because of its defference to DateTime.Now, + * somewhat expensive to call because of its difference to DateTime.Now, * which is why Stopwatch has been used to verify HRT before calling GetTimestamp(), * enabling the usage of DateTime.UtcNow instead. */ @@ -80,8 +83,6 @@ namespace Server private static readonly Type[] m_SerialTypeArray = { typeof(Serial) }; - public static MessagePump MessagePump{ get; set; } - public static bool Profiling { get => m_Profiling; @@ -265,9 +266,7 @@ namespace Server { try { - Task.WhenAll( - MessagePump.Listeners.Select(listener => listener.Dispose()) - ).Wait(); + // Close all listeners } catch { @@ -444,9 +443,6 @@ namespace Server AssemblyHandler.Invoke("Initialize"); - // Start accepting new connections - MessagePump = new MessagePump(); - AssemblyHandler.Invoke("RegisterListeners"); timerThread.Start(); @@ -454,10 +450,18 @@ namespace Server foreach (Map m in Map.AllMaps) m.Tiles.Force(); - NetState.Initialize(); - EventSink.InvokeServerStarted(); + // Start net socket server + var host = TcpServer.CreateWebHostBuilder(new string[0]).Build(); + var life = host.Services.GetRequiredService(); + life.ApplicationStopping.Register(() => { Kill(); }); + + host.Run(); + } + + public static void RunEventLoop(IMessagePumpService messagePumpService) + { try { long last = TickCount; @@ -477,7 +481,7 @@ namespace Server ); Timer.Slice(); - MessagePump.DoWork(); + messagePumpService.DoWork(); NetState.ProcessDisposedQueue(); diff --git a/Projects/Server/Map.cs b/Projects/Server/Map.cs index ce21385e6..4751ee7f2 100644 --- a/Projects/Server/Map.cs +++ b/Projects/Server/Map.cs @@ -262,16 +262,17 @@ namespace Server private static readonly List _EmptyFixItems = new List(); private Region m_DefaultRegion; - private int m_FileIndex; + private readonly int m_FileIndex; private string m_Name; - private Sector[][] m_Sectors; + private readonly Sector[][] m_Sectors; - private int m_SectorsWidth, m_SectorsHeight; + private readonly int m_SectorsWidth; + private readonly int m_SectorsHeight; private TileMatrix m_Tiles; - private object tileLock = new object(); + private readonly object tileLock = new object(); public Map(int mapID, int mapIndex, int fileIndex, int width, int height, int season, string name, MapRules rules) { diff --git a/Projects/Server/Menus/ItemListMenu.cs b/Projects/Server/Menus/ItemListMenu.cs index 8fc57a153..fe014949e 100644 --- a/Projects/Server/Menus/ItemListMenu.cs +++ b/Projects/Server/Menus/ItemListMenu.cs @@ -41,7 +41,7 @@ namespace Server.Menus.ItemLists public class ItemListMenu : IMenu { private static int m_NextSerial; - private int m_Serial; + private readonly int m_Serial; public ItemListMenu(string question, ItemListEntry[] entries) { diff --git a/Projects/Server/Menus/QuestionMenu.cs b/Projects/Server/Menus/QuestionMenu.cs index 0fe6a5aa2..2d403f537 100644 --- a/Projects/Server/Menus/QuestionMenu.cs +++ b/Projects/Server/Menus/QuestionMenu.cs @@ -25,7 +25,7 @@ namespace Server.Menus.Questions public class QuestionMenu : IMenu { private static int m_NextSerial; - private int m_Serial; + private readonly int m_Serial; public QuestionMenu(string question, string[] answers) { diff --git a/Projects/Server/Mobile.cs b/Projects/Server/Mobile.cs index ec0a5e42a..bc75d05fc 100644 --- a/Projects/Server/Mobile.cs +++ b/Projects/Server/Mobile.cs @@ -56,7 +56,7 @@ namespace Server public class TimedSkillMod : SkillMod { - private DateTime m_Expire; + private readonly DateTime m_Expire; public TimedSkillMod(SkillName skill, bool relative, double value, TimeSpan delay) : this(skill, relative, value, DateTime.UtcNow + delay) @@ -64,21 +64,16 @@ namespace Server } public TimedSkillMod(SkillName skill, bool relative, double value, DateTime expire) - : base(skill, relative, value) - { + : base(skill, relative, value) => m_Expire = expire; - } - public override bool CheckCondition() - { - return DateTime.UtcNow < m_Expire; - } + public override bool CheckCondition() => DateTime.UtcNow < m_Expire; } public class EquippedSkillMod : SkillMod { - private Item m_Item; - private Mobile m_Mobile; + private readonly Item m_Item; + private readonly Mobile m_Mobile; public EquippedSkillMod(SkillName skill, bool relative, double value, Item item, Mobile mobile) : base(skill, relative, value) @@ -87,10 +82,7 @@ namespace Server m_Mobile = mobile; } - public override bool CheckCondition() - { - return !m_Item.Deleted && !m_Mobile.Deleted && m_Item.Parent == m_Mobile; - } + public override bool CheckCondition() => !m_Item.Deleted && !m_Mobile.Deleted && m_Item.Parent == m_Mobile; } public class DefaultSkillMod : SkillMod @@ -100,10 +92,7 @@ namespace Server { } - public override bool CheckCondition() - { - return true; - } + public override bool CheckCondition() => true; } public abstract class SkillMod @@ -265,8 +254,8 @@ namespace Server public class StatMod { - private DateTime m_Added; - private TimeSpan m_Duration; + private readonly DateTime m_Added; + private readonly TimeSpan m_Duration; public StatMod(StatType type, string name, int offset, TimeSpan duration) { @@ -296,10 +285,7 @@ namespace Server public class DamageEntry { - public DamageEntry(Mobile damager) - { - Damager = damager; - } + public DamageEntry(Mobile damager) => Damager = damager; public Mobile Damager{ get; } @@ -425,10 +411,8 @@ namespace Server public class MobileNotConnectedException : Exception { public MobileNotConnectedException(Mobile source, string message) - : base(message) - { + : base(message) => Source = source.ToString(); - } } #region Delegates @@ -460,8 +444,8 @@ namespace Server /// public class Mobile : IHued, IComparable, ISerializable, ISpawnable, IPropertyListObject { - private BufferWriter m_SaveBuffer; - public BufferWriter SaveBuffer { get { return m_SaveBuffer; } } + private readonly BufferWriter m_SaveBuffer; + public BufferWriter SaveBuffer => m_SaveBuffer; private const int WarmodeCatchCount = 4; // Allow four warmode changes in 0.5 seconds, any more will be delay for two seconds @@ -470,23 +454,23 @@ namespace Server private static readonly TimeSpan WarmodeSpamDelay = TimeSpan.FromSeconds(Core.SE ? 4.0 : 2.0); - private static Packet[][] m_MovingPacketCache = new Packet[][] + private static readonly Packet[][] m_MovingPacketCache = new Packet[][] { new Packet[8], new Packet[8] }; - private static List m_MoveList = new List(); - private static List m_MoveClientList = new List(); + private static readonly List m_MoveList = new List(); + private static readonly List m_MoveClientList = new List(); - private static object m_GhostMutateContext = new object(); + private static readonly object m_GhostMutateContext = new object(); - private static List m_Hears = new List(); - private static List m_OnSpeech = new List(); + private static readonly List m_Hears = new List(); + private static readonly List m_OnSpeech = new List(); public static bool m_DefaultShowVisibleDamage, m_DefaultCanSeeVisibleDamage; - private static string[] m_AccessLevelNames = + private static readonly string[] m_AccessLevelNames = { "a player", "a counselor", @@ -497,7 +481,7 @@ namespace Server "an owner" }; - private static int[] m_InvalidBodies = + private static readonly int[] m_InvalidBodies = { 32, 95, @@ -506,12 +490,12 @@ namespace Server 198 }; - private static Queue m_DeltaQueue = new Queue(); - private static Queue m_DeltaQueueR = new Queue(); + private static readonly Queue m_DeltaQueue = new Queue(); + private static readonly Queue m_DeltaQueueR = new Queue(); private static bool _processing; - private static string[] m_GuildTypes = + private static readonly string[] m_GuildTypes = { "", " (Chaos)", @@ -4367,10 +4351,7 @@ namespace Server /// /// /// True to continue with death, false to override it. - public virtual bool OnBeforeDeath() - { - return true; - } + public virtual bool OnBeforeDeath() => true; /// /// Overridable. Event invoked after the Mobile is killed. Primarily, this method is responsible for @@ -5089,10 +5070,7 @@ namespace Server public static Mobile GetDamagerFrom(DamageEntry de) => de?.Damager; - public Mobile FindMostRecentDamager(bool allowSelf) - { - return GetDamagerFrom(FindMostRecentDamageEntry(allowSelf)); - } + public Mobile FindMostRecentDamager(bool allowSelf) => GetDamagerFrom(FindMostRecentDamageEntry(allowSelf)); public DamageEntry FindMostRecentDamageEntry(bool allowSelf) { @@ -5199,10 +5177,7 @@ namespace Server return null; } - public virtual Mobile GetDamageMaster(Mobile damagee) - { - return null; - } + public virtual Mobile GetDamageMaster(Mobile damagee) => null; public virtual DamageEntry RegisterDamage(int amount, Mobile from) { @@ -5251,10 +5226,7 @@ namespace Server Damage(amount, null); } - public virtual bool CanBeDamaged() - { - return !m_Blessed; - } + public virtual bool CanBeDamaged() => !m_Blessed; public virtual void Damage(int amount, Mobile from) { @@ -5906,15 +5878,9 @@ namespace Server } } - public static string GetAccessLevelName(AccessLevel level) - { - return m_AccessLevelNames[(int)level]; - } + public static string GetAccessLevelName(AccessLevel level) => m_AccessLevelNames[(int)level]; - public virtual bool CanPaperdollBeOpenedBy(Mobile from) - { - return Body.IsHuman || Body.IsGhost || IsBodyMod; - } + public virtual bool CanPaperdollBeOpenedBy(Mobile from) => Body.IsHuman || Body.IsGhost || IsBodyMod; public virtual void GetChildContextMenuEntries(Mobile from, List list, Item item) { @@ -6215,10 +6181,7 @@ namespace Server eable.Free(); } - public bool Send(Packet p) - { - return Send(p, false); - } + public bool Send(Packet p) => Send(p, false); public bool Send(Packet p, bool throwOnOffline) { @@ -6254,10 +6217,7 @@ namespace Server RevealingAction(); } - public virtual bool HandlesOnSpeech(Mobile from) - { - return false; - } + public virtual bool HandlesOnSpeech(Mobile from) => false; /// /// Overridable. Virtual event invoked when the Mobile hears speech. This event will only be invoked if @@ -6337,10 +6297,7 @@ namespace Server m_Direction = dir; } - public virtual int GetSeason() - { - return m_Map?.Season ?? 1; - } + public virtual int GetSeason() => m_Map?.Season ?? 1; public virtual int GetPacketFlags() { @@ -6505,10 +6462,7 @@ namespace Server m_AccessLevel > AccessLevel.Player || m.Warmode); } - public virtual bool CanBeRenamedBy(Mobile from) - { - return from.AccessLevel >= AccessLevel.GameMaster && from.m_AccessLevel > m_AccessLevel; - } + public virtual bool CanBeRenamedBy(Mobile from) => from.AccessLevel >= AccessLevel.GameMaster && from.m_AccessLevel > m_AccessLevel; public virtual void OnGuildTitleChange(string oldTitle) { @@ -6738,10 +6692,7 @@ namespace Server public bool HasFreeHand() => FindItemOnLayer(Layer.TwoHanded) == null; - public virtual IWeapon GetDefaultWeapon() - { - return DefaultWeapon; - } + public virtual IWeapon GetDefaultWeapon() => DefaultWeapon; public BankBox FindBankNoCreate() { @@ -6827,21 +6778,13 @@ namespace Server return true; } - public virtual bool CheckLift(Mobile from, Item item, ref LRReason reject) - { - return true; - } + public virtual bool CheckLift(Mobile from, Item item, ref LRReason reject) => true; - public virtual bool CheckNonlocalLift(Mobile from, Item item) - { - return from == this || from.AccessLevel > AccessLevel && from.AccessLevel >= AccessLevel.GameMaster; - } + public virtual bool CheckNonlocalLift(Mobile from, Item item) => from == this || from.AccessLevel > AccessLevel && from.AccessLevel >= AccessLevel.GameMaster; public virtual bool CheckTrade(Mobile to, Item item, SecureTradeContainer cont, bool message, bool checkItems, - int plusItems, int plusWeight) - { - return true; - } + int plusItems, int plusWeight) => + true; public virtual bool OpenTrade(Mobile from, Item offer = null) { @@ -6927,10 +6870,7 @@ namespace Server /// return base.OnDragLift( item ); /// } /// - public virtual bool OnDragLift(Item item) - { - return true; - } + public virtual bool OnDragLift(Item item) => true; /// /// Overridable. Virtual event invoked when the Mobile attempts to drop into a @@ -6940,40 +6880,28 @@ namespace Server /// . /// /// True if the drop is allowed, false if otherwise. - public virtual bool OnDroppedItemInto(Item item, Container container, Point3D loc) - { - return true; - } + public virtual bool OnDroppedItemInto(Item item, Container container, Point3D loc) => true; /// /// Overridable. Virtual event invoked when the Mobile attempts to drop directly onto another /// , . This is the case of stacking items. /// /// True if the drop is allowed, false if otherwise. - public virtual bool OnDroppedItemOnto(Item item, Item target) - { - return true; - } + public virtual bool OnDroppedItemOnto(Item item, Item target) => true; /// /// Overridable. Virtual event invoked when the Mobile attempts to drop into another /// , . The target item is most likely a . /// /// True if the drop is allowed, false if otherwise. - public virtual bool OnDroppedItemToItem(Item item, Item target, Point3D loc) - { - return true; - } + public virtual bool OnDroppedItemToItem(Item item, Item target, Point3D loc) => true; /// /// Overridable. Virtual event invoked when the Mobile attempts to give to a Mobile ( /// ). /// /// True if the drop is allowed, false if otherwise. - public virtual bool OnDroppedItemToMobile(Item item, Mobile target) - { - return true; - } + public virtual bool OnDroppedItemToMobile(Item item, Mobile target) => true; /// /// Overridable. Virtual event invoked when the Mobile attempts to drop to the world at a @@ -6983,10 +6911,7 @@ namespace Server /// . /// /// True if the drop is allowed, false if otherwise. - public virtual bool OnDroppedItemToWorld(Item item, Point3D location) - { - return true; - } + public virtual bool OnDroppedItemToWorld(Item item, Point3D location) => true; /// /// Overridable. Virtual event when successfully uses while it's on this @@ -6997,15 +6922,9 @@ namespace Server { } - public virtual bool CheckNonlocalDrop(Mobile from, Item item, Item target) - { - return from == this || from.AccessLevel > AccessLevel && from.AccessLevel >= AccessLevel.GameMaster; - } + public virtual bool CheckNonlocalDrop(Mobile from, Item item, Item target) => from == this || from.AccessLevel > AccessLevel && from.AccessLevel >= AccessLevel.GameMaster; - public virtual bool CheckItemUse(Mobile from, Item item) - { - return true; - } + public virtual bool CheckItemUse(Mobile from, Item item) => true; /// /// Overridable. Virtual event invoked when successfully lifts from this @@ -7016,15 +6935,9 @@ namespace Server { } - public virtual bool AllowItemUse(Item item) - { - return true; - } + public virtual bool AllowItemUse(Item item) => true; - public virtual bool AllowEquipFrom(Mobile mob) - { - return mob == this || mob.AccessLevel >= AccessLevel.GameMaster && mob.AccessLevel > AccessLevel; - } + public virtual bool AllowEquipFrom(Mobile mob) => mob == this || mob.AccessLevel >= AccessLevel.GameMaster && mob.AccessLevel > AccessLevel; public virtual bool EquipItem(Item item) { @@ -7304,13 +7217,10 @@ namespace Server private class MovementRecord { - private static Queue m_InstancePool = new Queue(); + private static readonly Queue m_InstancePool = new Queue(); public long m_End; - private MovementRecord(long end) - { - m_End = end; - } + private MovementRecord(long end) => m_End = end; public static MovementRecord NewInstance(long end) { @@ -7343,7 +7253,7 @@ namespace Server private class WarmodeTimer : Timer { - private Mobile m_Mobile; + private readonly Mobile m_Mobile; public WarmodeTimer(Mobile m, bool value) : base(WarmodeSpamDelay) @@ -7365,13 +7275,11 @@ namespace Server private class SimpleTarget : Target { - private TargetCallback m_Callback; + private readonly TargetCallback m_Callback; public SimpleTarget(int range, TargetFlags flags, bool allowGround, TargetCallback callback) - : base(range, allowGround, flags) - { + : base(range, allowGround, flags) => m_Callback = callback; - } protected override void OnTarget(Mobile from, object targeted) { @@ -7381,8 +7289,8 @@ namespace Server private class SimpleStateTarget : Target { - private TargetStateCallback m_Callback; - private T m_State; + private readonly TargetStateCallback m_Callback; + private readonly T m_State; public SimpleStateTarget(int range, TargetFlags flags, bool allowGround, TargetStateCallback callback, T state) @@ -7400,13 +7308,11 @@ namespace Server private class AutoManifestTimer : Timer { - private Mobile m_Mobile; + private readonly Mobile m_Mobile; public AutoManifestTimer(Mobile m, TimeSpan delay) - : base(delay) - { + : base(delay) => m_Mobile = m; - } protected override void OnTick() { @@ -7419,17 +7325,11 @@ namespace Server { private static LocationComparer m_Instance; - public LocationComparer(IEntity relativeTo) - { - RelativeTo = relativeTo; - } + public LocationComparer(IEntity relativeTo) => RelativeTo = relativeTo; public IEntity RelativeTo{ get; set; } - public int Compare(IEntity x, IEntity y) - { - return GetDistance(x) - GetDistance(y); - } + public int Compare(IEntity x, IEntity y) => GetDistance(x) - GetDistance(y); public static LocationComparer GetInstance(IEntity relativeTo) { @@ -7454,15 +7354,9 @@ namespace Server } } - int IComparable.CompareTo(IEntity other) - { - return other == null ? -1 : Serial.CompareTo(other.Serial); - } + int IComparable.CompareTo(IEntity other) => other == null ? -1 : Serial.CompareTo(other.Serial); - public int CompareTo(Mobile other) - { - return other == null ? -1 : Serial.CompareTo(other.Serial); - } + public int CompareTo(Mobile other) => other == null ? -1 : Serial.CompareTo(other.Serial); #region Handlers @@ -7581,7 +7475,7 @@ namespace Server private class ManaTimer : Timer { - private Mobile m_Owner; + private readonly Mobile m_Owner; public ManaTimer(Mobile m) : base(GetManaRegenRate(m), GetManaRegenRate(m)) @@ -7601,7 +7495,7 @@ namespace Server private class HitsTimer : Timer { - private Mobile m_Owner; + private readonly Mobile m_Owner; public HitsTimer(Mobile m) : base(GetHitsRegenRate(m), GetHitsRegenRate(m)) @@ -7621,7 +7515,7 @@ namespace Server private class StamTimer : Timer { - private Mobile m_Owner; + private readonly Mobile m_Owner; public StamTimer(Mobile m) : base(GetStamRegenRate(m), GetStamRegenRate(m)) @@ -7641,7 +7535,7 @@ namespace Server private class LogoutTimer : Timer { - private Mobile m_Mobile; + private readonly Mobile m_Mobile; public LogoutTimer(Mobile m) : base(TimeSpan.FromDays(1.0)) @@ -7666,7 +7560,7 @@ namespace Server private class ParalyzedTimer : Timer { - private Mobile m_Mobile; + private readonly Mobile m_Mobile; public ParalyzedTimer(Mobile m, TimeSpan duration) : base(duration) @@ -7683,7 +7577,7 @@ namespace Server private class FrozenTimer : Timer { - private Mobile m_Mobile; + private readonly Mobile m_Mobile; public FrozenTimer(Mobile m, TimeSpan duration) : base(duration) @@ -7700,7 +7594,7 @@ namespace Server private class CombatTimer : Timer { - private Mobile m_Mobile; + private readonly Mobile m_Mobile; public CombatTimer(Mobile m) : base(TimeSpan.FromSeconds(0.0), TimeSpan.FromSeconds(0.01)) { @@ -7744,7 +7638,7 @@ namespace Server private class ExpireCombatantTimer : Timer { - private Mobile m_Mobile; + private readonly Mobile m_Mobile; public ExpireCombatantTimer(Mobile m) : base(TimeSpan.FromMinutes(1.0)) @@ -7763,7 +7657,7 @@ namespace Server private class ExpireCriminalTimer : Timer { - private Mobile m_Mobile; + private readonly Mobile m_Mobile; public ExpireCriminalTimer(Mobile m) : base(ExpireCriminalDelay) @@ -7780,7 +7674,7 @@ namespace Server private class ExpireAggressorsTimer : Timer { - private Mobile m_Mobile; + private readonly Mobile m_Mobile; public ExpireAggressorsTimer(Mobile m) : base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(5.0)) @@ -7804,9 +7698,9 @@ namespace Server private class SimplePrompt : Prompt { - private PromptCallback m_Callback; - private bool m_CallbackHandlesCancel; - private PromptCallback m_CancelCallback; + private readonly PromptCallback m_Callback; + private readonly bool m_CallbackHandlesCancel; + private readonly PromptCallback m_CancelCallback; public SimplePrompt(PromptCallback callback, PromptCallback cancelCallback) { @@ -7830,9 +7724,7 @@ namespace Server if (m_CallbackHandlesCancel && m_Callback != null) m_Callback(from, ""); else - { - m_CancelCallback?.Invoke(from, ""); - } + m_CancelCallback?.Invoke(@from, ""); } } @@ -7848,10 +7740,10 @@ namespace Server private class SimpleStatePrompt : Prompt { - private PromptStateCallback m_Callback; - private PromptStateCallback m_CancelCallback; + private readonly PromptStateCallback m_Callback; + private readonly PromptStateCallback m_CancelCallback; - private T m_State; + private readonly T m_State; public SimpleStatePrompt(PromptStateCallback callback, PromptStateCallback cancelCallback, T state) { @@ -7962,10 +7854,7 @@ namespace Server #region Get*InRange - public IPooledEnumerable GetItemsInRange(int range) - { - return GetItemsInRange(range); - } + public IPooledEnumerable GetItemsInRange(int range) => GetItemsInRange(range); public IPooledEnumerable GetItemsInRange(int range) where T : Item { @@ -7987,10 +7876,7 @@ namespace Server return map.GetObjectsInRange(m_Location, range); } - public IPooledEnumerable GetMobilesInRange(int range) - { - return GetMobilesInRange(range); - } + public IPooledEnumerable GetMobilesInRange(int range) => GetMobilesInRange(range); public IPooledEnumerable GetMobilesInRange(int range) where T : Mobile { @@ -8177,10 +8063,7 @@ namespace Server return true; } - public bool HasGump() where T : Gump - { - return FindGump() != null; - } + public bool HasGump() where T : Gump => FindGump() != null; public bool SendGump(Gump g) { @@ -8204,15 +8087,9 @@ namespace Server #region Beneficial Checks/Actions - public virtual bool CanBeBeneficial(Mobile target) - { - return CanBeBeneficial(target, true, false); - } + public virtual bool CanBeBeneficial(Mobile target) => CanBeBeneficial(target, true, false); - public virtual bool CanBeBeneficial(Mobile target, bool message) - { - return CanBeBeneficial(target, message, false); - } + public virtual bool CanBeBeneficial(Mobile target, bool message) => CanBeBeneficial(target, message, false); public virtual bool CanBeBeneficial(Mobile target, bool message, bool allowDead) { @@ -9001,10 +8878,7 @@ namespace Server /// /// /// - public virtual bool CheckPoisonImmunity(Mobile from, Poison poison) - { - return false; - } + public virtual bool CheckPoisonImmunity(Mobile from, Poison poison) => false; /// /// Overridable. Called from , this method checks if the Mobile is already poisoned by some @@ -9014,10 +8888,7 @@ namespace Server /// /// /// - public virtual bool CheckHigherPoison(Mobile from, Poison poison) - { - return m_Poison != null && m_Poison.Level >= poison.Level; - } + public virtual bool CheckHigherPoison(Mobile from, Poison poison) => m_Poison != null && m_Poison.Level >= poison.Level; /// /// Overridable. Attempts to apply poison to the Mobile. Checks are made such that no @@ -9090,10 +8961,7 @@ namespace Server /// /// /// - public virtual bool CheckCure(Mobile from) - { - return true; - } + public virtual bool CheckCure(Mobile from) => true; /// /// Overridable. Virtual event invoked when a call to succeeded. @@ -9166,10 +9034,7 @@ namespace Server [CommandProperty(AccessLevel.GameMaster)] public int FacialHairItemID { - get - { - return m_FacialHair?.ItemID ?? 0; - } + get => m_FacialHair?.ItemID ?? 0; set { if (m_FacialHair == null && value > 0) @@ -9327,15 +9192,9 @@ namespace Server return ret; } - public Direction GetDirectionTo(Point2D p) - { - return GetDirectionTo(p.m_X, p.m_Y); - } + public Direction GetDirectionTo(Point2D p) => GetDirectionTo(p.m_X, p.m_Y); - public Direction GetDirectionTo(Point3D p) - { - return GetDirectionTo(p.m_X, p.m_Y); - } + public Direction GetDirectionTo(Point3D p) => GetDirectionTo(p.m_X, p.m_Y); public Direction GetDirectionTo(IPoint2D p) { diff --git a/Projects/Server/MultiData.cs b/Projects/Server/MultiData.cs index db4a68048..7dffc4cbd 100644 --- a/Projects/Server/MultiData.cs +++ b/Projects/Server/MultiData.cs @@ -25,10 +25,12 @@ namespace Server { public static class MultiData { - private static MultiComponentList[] m_Components; + private static readonly MultiComponentList[] m_Components; - private static FileStream m_Index, m_Stream; - private static BinaryReader m_IndexReader, m_StreamReader; + private static readonly FileStream m_Index; + private static readonly FileStream m_Stream; + private static readonly BinaryReader m_IndexReader; + private static readonly BinaryReader m_StreamReader; static MultiData() { diff --git a/Projects/Server/Network/Listener.cs b/Projects/Server/Network/Listener.cs deleted file mode 100644 index f0b929748..000000000 --- a/Projects/Server/Network/Listener.cs +++ /dev/null @@ -1,177 +0,0 @@ -/*************************************************************************** - * Listener.cs - * ------------------- - * begin : May 1, 2002 - * copyright : (C) The RunUO Software Team - * email : info@runuo.com - * - * $Id$ - * - ***************************************************************************/ - -/*************************************************************************** - * - * 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 2 of the License, or - * (at your option) any later version. - * - ***************************************************************************/ - -using System; -using System.Net; -using System.Net.NetworkInformation; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; -using Libuv; -using Libuv.Internal; -using Microsoft.AspNetCore.Connections; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Logging; - -namespace Server.Network -{ - public class Listener - { - private static readonly LibuvFunctions functions = new LibuvFunctions(); - - private readonly IPEndPoint m_EndPoint; - private LibuvConnectionListener m_Listener; - - public Listener(IPEndPoint ipep) - { - m_EndPoint = ipep; - LibuvTransportContext transport = new LibuvTransportContext - { - Options = new LibuvTransportOptions(), - AppLifetime = new ApplicationLifetime( - LoggerFactory.Create(builder => { builder.AddConsole(); }).CreateLogger() - ), - Log = new LibuvTrace(LoggerFactory.Create(builder => { builder.AddConsole(); }).CreateLogger("network")) - }; - - m_Listener = new LibuvConnectionListener(functions, transport, ipep); - } - - public virtual async Task Start(MessagePump pump) - { - try - { - await m_Listener.BindAsync(); - } - catch (AddressInUseException) - { - Console.WriteLine("Listener Failed: {0}:{1} (In Use)", m_EndPoint.Address, m_EndPoint.Port); - m_Listener = null; - return; - } - catch (Exception e) - { - Console.WriteLine("Listener Exception:"); - Console.WriteLine(e); - - m_Listener = null; - return; - } - - DisplayListener(); - - while (true) - { - ConnectionContext context; - try - { - context = await m_Listener.AcceptAsync(); - } - catch (SocketException ex) - { - NetState.TraceException(ex); - continue; - } - - if (VerifySocket(context)) - _ = new NetState(context, pump); - else - Release(context); - } - } - - private void DisplayListener() - { - if (!(m_Listener.EndPoint is IPEndPoint ipep)) - return; - - if (ipep.Address.Equals(IPAddress.Any) || ipep.Address.Equals(IPAddress.IPv6Any)) - { - NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces(); - foreach (NetworkInterface adapter in adapters) - { - IPInterfaceProperties properties = adapter.GetIPProperties(); - foreach (UnicastIPAddressInformation unicast in properties.UnicastAddresses) - if (ipep.AddressFamily == unicast.Address.AddressFamily) - Console.WriteLine("Listening: {0}:{1}", unicast.Address, ipep.Port); - } - } - else - Console.WriteLine("Listening: {0}:{1}", ipep.Address, ipep.Port); - } - - private static bool VerifySocket(ConnectionContext context) - { - try - { - SocketConnectEventArgs args = new SocketConnectEventArgs(context); - - EventSink.InvokeSocketConnect(args); - - return args.AllowConnection; - } - catch (Exception ex) - { - NetState.TraceException(ex); - return false; - } - } - - private static void Release(ConnectionContext context) - { - try - { - context.Abort(new ConnectionAbortedException("Failed socket verification.")); - } - catch (Exception ex) - { - NetState.TraceException(ex); - } - - try - { - // TODO: Is this needed? - context.DisposeAsync(); - } - catch (Exception ex) - { - NetState.TraceException(ex); - } - } - - public async Task Dispose() - { - LibuvConnectionListener listener = Interlocked.Exchange(ref m_Listener, null); - if (listener != null) - try - { - await listener.UnbindAsync(); - await listener.DisposeAsync(); - } - catch (Exception ex) - { - Console.WriteLine("Listener: Failed to dispose."); - Console.WriteLine(ex); - } - - GC.SuppressFinalize(this); - } - } -} diff --git a/Projects/Server/Network/MessagePump.cs b/Projects/Server/Network/MessagePumpService.cs similarity index 76% rename from Projects/Server/Network/MessagePump.cs rename to Projects/Server/Network/MessagePumpService.cs index 91b24bc92..aaaac3a0b 100644 --- a/Projects/Server/Network/MessagePump.cs +++ b/Projects/Server/Network/MessagePumpService.cs @@ -19,26 +19,20 @@ * ***************************************************************************/ -using System; using System.Buffers; using System.Collections.Concurrent; -using System.Net; namespace Server.Network { - public class MessagePump + public interface IMessagePumpService { - private ConcurrentQueue m_WorkQueue = new ConcurrentQueue(); - public Listener[] Listeners => new Listener[0]; + void QueueWork(NetState ns, IMemoryOwner memOwner, OnPacketReceive onReceive); + void DoWork(); + } - public void AddListener(IPEndPoint ipep) - { - Listener[] listeners = new Listener[Listeners.Length + 1]; - Array.Copy(Listeners, listeners, Listeners.Length); - Listener listener = new Listener(ipep); - _ = listener.Start(this); - listeners[Listeners.Length] = listener; - } + public class MessagePumpService : IMessagePumpService + { + private readonly ConcurrentQueue m_WorkQueue = new ConcurrentQueue(); public void QueueWork(NetState ns, IMemoryOwner memOwner, OnPacketReceive onReceive) { diff --git a/Projects/Server/Network/NetState.cs b/Projects/Server/Network/NetState.cs index a37902ffa..3f9d9fc10 100644 --- a/Projects/Server/Network/NetState.cs +++ b/Projects/Server/Network/NetState.cs @@ -19,7 +19,6 @@ ***************************************************************************/ using System; -using System.Buffers; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; @@ -91,7 +90,7 @@ namespace Server.Network public class NetState : IComparable { - private string m_ToString; + private readonly string m_ToString; private ClientVersion m_Version; public DateTime ConnectedOn { get; } @@ -105,10 +104,11 @@ namespace Server.Network public IPAddress Address { get; } - private static AsyncState m_PauseState = new AsyncState(true); - private static AsyncState m_ResumeState = new AsyncState(false); + private static readonly AsyncState m_PauseState = new AsyncState(true); + private static readonly AsyncState m_ResumeState = new AsyncState(false); private static AsyncState m_AsyncState = m_ResumeState; + public static AsyncState AsyncState => m_AsyncState; public IPacketEncoder PacketEncoder { get; set; } @@ -279,9 +279,6 @@ namespace Server.Network public List Menus { get; private set; } - public PipeReader RecvPipe => Connection.Transport.Input; - public PipeWriter SendPipe => Connection.Transport.Output; - public static int GumpCap { get; set; } = 512; public static int HuePickerCap { get; set; } = 512; @@ -399,11 +396,7 @@ namespace Server.Network public override string ToString() => m_ToString; - public static List Instances { get; } = new List(); - - public void SetConnectionAlive() => m_NextCheckActivity = Core.TickCount + 60000; - - public NetState(ConnectionContext connection, MessagePump pump) + public NetState(ConnectionContext connection) { Connection = connection; Seeded = false; @@ -412,10 +405,6 @@ namespace Server.Network Menus = new List(); Trades = new List(); - SetConnectionAlive(); - - Instances.Add(this); - try { Address = Utility.Intern(((IPEndPoint)Connection.RemoteEndPoint).Address); @@ -429,11 +418,6 @@ namespace Server.Network } ConnectedOn = DateTime.UtcNow; - Console.WriteLine("Client: {0}: Connected. [{1} Online]", this, Instances.Count); - -#pragma warning disable 4014 - ProcessRecvs(pump); -#pragma warning restore 4014 CreatedCallback?.Invoke(this); } @@ -448,7 +432,7 @@ namespace Server.Network m_AsyncState = Interlocked.Exchange(ref m_AsyncState, m_ResumeState); } - public virtual void Send(Packet p) + public virtual async void Send(Packet p) { if (Connection == null || BlockAllPackets) { @@ -456,19 +440,29 @@ namespace Server.Network return; } + var outPipe = Connection.Transport.Output; + try { - ReadOnlySpan buffer = p.Compile(CompressionEnabled, out int length); + //TODO: Rented memory + ReadOnlyMemory buffer = p.Compile(CompressionEnabled, out int length); - if (buffer.Length <= 0 || length <= 0) - { - p.OnSend(); - return; - } + if (buffer.Length > 0 && length > 0) + try + { + FlushResult result = await outPipe.WriteAsync(buffer.Slice(0, length)); - buffer.Slice(0, length).CopyTo(SendPipe.GetSpan(length)); - SendPipe.Advance(length); - SendPipe.FlushAsync().GetAwaiter().GetResult(); + if (result.IsCanceled || result.IsCompleted) + { + Dispose(); + return; + } + } + catch + { + Dispose(); + // ignored + } p.OnSend(); } @@ -497,48 +491,10 @@ namespace Server.Network return false; } - private async Task ProcessRecvs(MessagePump pump) - { - while (true) - { - ReadResult result = await RecvPipe.ReadAsync(); - ReadOnlySequence seq = result.Buffer; - - if (seq.IsEmpty) - break; - - SetConnectionAlive(); - - int pos = PacketHandlers.ProcessPacket(pump, this, seq); - - if (pos <= 0) - break; - - RecvPipe.AdvanceTo(seq.Slice(0, pos).End); - - if (result.IsCompleted || result.IsCanceled) - break; - } - - RecvPipe.Complete(); - Dispose(); - } - public PacketHandler GetHandler(int packetID) => ContainerGridLines ? PacketHandlers.Get6017Handler(packetID) : PacketHandlers.GetHandler(packetID); - private long m_NextCheckActivity; - - public void CheckAlive(long curTicks) - { - if (Connection == null || m_NextCheckActivity - curTicks >= 0) - return; - - Console.WriteLine("Client: {0}: Disconnecting due to inactivity...", this); - Dispose(); - } - public static void TraceException(Exception ex) { if (!Core.Debug) @@ -586,30 +542,7 @@ namespace Server.Network m_Disposed.Enqueue(this); } - public static void Initialize() - { - Timer.DelayCall(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(1.5), CheckAllAlive); - } - - public static void CheckAllAlive() - { - try - { - long curTicks = Core.TickCount; - - if (Instances.Count >= 1024) - Parallel.ForEach(Instances, ns => ns.CheckAlive(curTicks)); - else - for (int i = 0; i < Instances.Count; ++i) - Instances[i].CheckAlive(curTicks); - } - catch (Exception ex) - { - TraceException(ex); - } - } - - private static ConcurrentQueue m_Disposed = new ConcurrentQueue(); + private static readonly ConcurrentQueue m_Disposed = new ConcurrentQueue(); public static void ProcessDisposedQueue() { @@ -636,12 +569,10 @@ namespace Server.Network ns.ServerInfo = null; ns.CityInfo = null; - Instances.Remove(ns); - if (a != null) - ns.WriteConsole("Disconnected. [{0} Online] [{1}]", Instances.Count, a); + ns.WriteConsole("Disconnected. [{0} Online] [{1}]", TcpServer.Instances.Count, a); else - ns.WriteConsole("Disconnected. [{0} Online]", Instances.Count); + ns.WriteConsole("Disconnected. [{0} Online]", TcpServer.Instances.Count); } } diff --git a/Projects/Server/Network/Packet.cs b/Projects/Server/Network/Packet.cs index bb96362d5..6f6d54f7c 100644 --- a/Projects/Server/Network/Packet.cs +++ b/Projects/Server/Network/Packet.cs @@ -34,7 +34,7 @@ namespace Server.Network private byte[] m_CompiledBuffer; private int m_CompiledLength; - private int m_Length; + private readonly int m_Length; private State m_State; protected PacketWriter m_Stream; diff --git a/Projects/Server/Network/PacketHandlers.cs b/Projects/Server/Network/PacketHandlers.cs index 0f76afa73..a47cf99da 100644 --- a/Projects/Server/Network/PacketHandlers.cs +++ b/Projects/Server/Network/PacketHandlers.cs @@ -62,17 +62,17 @@ namespace Server.Network private const int BadUOTD = unchecked((int)0xFFCEFFCE); private const int m_AuthIDWindowSize = 128; - private static PacketHandler[] m_6017Handlers; + private static readonly PacketHandler[] m_6017Handlers; - private static PacketHandler[] m_ExtendedHandlersLow; - private static Dictionary m_ExtendedHandlersHigh; + private static readonly PacketHandler[] m_ExtendedHandlersLow; + private static readonly Dictionary m_ExtendedHandlersHigh; - private static EncodedPacketHandler[] m_EncodedHandlersLow; - private static Dictionary m_EncodedHandlersHigh; + private static readonly EncodedPacketHandler[] m_EncodedHandlersLow; + private static readonly Dictionary m_EncodedHandlersHigh; - private static int[] m_EmptyInts = new int[0]; + private static readonly int[] m_EmptyInts = new int[0]; - private static KeywordList m_KeywordList = new KeywordList(); + private static readonly KeywordList m_KeywordList = new KeywordList(); public static int[] m_ValidAnimations = { @@ -91,7 +91,7 @@ namespace Server.Network public static PlayCharCallback ThirdPartyAuthCallback = null, ThirdPartyHackedCallback = null; - private static Dictionary m_AuthIDWindow = + private static readonly Dictionary m_AuthIDWindow = new Dictionary(m_AuthIDWindowSize); static PacketHandlers() @@ -277,9 +277,9 @@ namespace Server.Network ph.ThrottleCallback = t; } - private static MemoryPool _memoryPool = SlabMemoryPoolFactory.Create(); + private static readonly MemoryPool _memoryPool = SlabMemoryPoolFactory.Create(); - public static int ProcessPacket(MessagePump pump, NetState ns, in ReadOnlySequence seq) + public static int ProcessPacket(IMessagePumpService pump, NetState ns, in ReadOnlySequence seq) { PacketReader r = new PacketReader(seq); @@ -2495,8 +2495,8 @@ namespace Server.Network private class LoginTimer : Timer { - private Mobile m_Mobile; - private NetState m_State; + private readonly Mobile m_Mobile; + private readonly NetState m_State; public LoginTimer(NetState state, Mobile m) : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0)) { @@ -2507,7 +2507,10 @@ namespace Server.Network protected override void OnTick() { if (m_State == null) + { Stop(); + return; + } if (m_State.Version != null) { diff --git a/Projects/Server/Network/PacketWriter.cs b/Projects/Server/Network/PacketWriter.cs index 6587e3a7a..3419171b9 100644 --- a/Projects/Server/Network/PacketWriter.cs +++ b/Projects/Server/Network/PacketWriter.cs @@ -30,12 +30,12 @@ namespace Server.Network /// public class PacketWriter { - private static ConcurrentQueue m_Pool = new ConcurrentQueue(); + private static readonly ConcurrentQueue m_Pool = new ConcurrentQueue(); /// /// Internal format buffer. /// - private byte[] m_Buffer = new byte[4]; + private readonly byte[] m_Buffer = new byte[4]; private int m_Capacity; diff --git a/Projects/Server/Network/Packets.cs b/Projects/Server/Network/Packets.cs index 920e07326..16e20b13a 100644 --- a/Projects/Server/Network/Packets.cs +++ b/Projects/Server/Network/Packets.cs @@ -540,7 +540,7 @@ namespace Server.Network public sealed class ChangeUpdateRange : Packet { - private static ChangeUpdateRange[] m_Cache = new ChangeUpdateRange[0x100]; + private static readonly ChangeUpdateRange[] m_Cache = new ChangeUpdateRange[0x100]; public ChangeUpdateRange(int range) : base(0xC8, 2) { @@ -811,7 +811,7 @@ namespace Server.Network public sealed class GlobalLightLevel : Packet { - private static GlobalLightLevel[] m_Cache = new GlobalLightLevel[0x100]; + private static readonly GlobalLightLevel[] m_Cache = new GlobalLightLevel[0x100]; public GlobalLightLevel(int level) : base(0x4F, 2) { @@ -2105,9 +2105,9 @@ namespace Server.Network public sealed class MessageLocalized : Packet { - private static MessageLocalized[] m_Cache_IntLoc = new MessageLocalized[15000]; - private static MessageLocalized[] m_Cache_CliLoc = new MessageLocalized[100000]; - private static MessageLocalized[] m_Cache_CliLocCmp = new MessageLocalized[5000]; + private static readonly MessageLocalized[] m_Cache_IntLoc = new MessageLocalized[15000]; + private static readonly MessageLocalized[] m_Cache_CliLoc = new MessageLocalized[100000]; + private static readonly MessageLocalized[] m_Cache_CliLocCmp = new MessageLocalized[5000]; public MessageLocalized(Serial serial, int graphic, MessageType type, int hue, int font, int number, string name, string args) : base(0xC1) @@ -2318,20 +2318,20 @@ namespace Server.Network public sealed class DisplayGumpPacked : Packet, IGumpWriter { - private static byte[] m_True = Gump.StringToBuffer(" 1"); - private static byte[] m_False = Gump.StringToBuffer(" 0"); + private static readonly byte[] m_True = Gump.StringToBuffer(" 1"); + private static readonly byte[] m_False = Gump.StringToBuffer(" 0"); - private static byte[] m_BeginTextSeparator = Gump.StringToBuffer(" @"); - private static byte[] m_EndTextSeparator = Gump.StringToBuffer("@"); + private static readonly byte[] m_BeginTextSeparator = Gump.StringToBuffer(" @"); + private static readonly byte[] m_EndTextSeparator = Gump.StringToBuffer("@"); - private static byte[] m_Buffer = new byte[48]; + private static readonly byte[] m_Buffer = new byte[48]; - private Gump m_Gump; + private readonly Gump m_Gump; - private PacketWriter m_Layout; + private readonly PacketWriter m_Layout; private int m_StringCount; - private PacketWriter m_Strings; + private readonly PacketWriter m_Strings; static DisplayGumpPacked() => m_Buffer[0] = (byte)' '; @@ -2457,13 +2457,13 @@ namespace Server.Network public sealed class DisplayGumpFast : Packet, IGumpWriter { - private static byte[] m_True = Gump.StringToBuffer(" 1"); - private static byte[] m_False = Gump.StringToBuffer(" 0"); + private static readonly byte[] m_True = Gump.StringToBuffer(" 1"); + private static readonly byte[] m_False = Gump.StringToBuffer(" 0"); - private static byte[] m_BeginTextSeparator = Gump.StringToBuffer(" @"); - private static byte[] m_EndTextSeparator = Gump.StringToBuffer("@"); + private static readonly byte[] m_BeginTextSeparator = Gump.StringToBuffer(" @"); + private static readonly byte[] m_EndTextSeparator = Gump.StringToBuffer("@"); - private byte[] m_Buffer = new byte[48]; + private readonly byte[] m_Buffer = new byte[48]; private int m_LayoutLength; public DisplayGumpFast(Gump g) : base(0xB0) @@ -2629,7 +2629,7 @@ namespace Server.Network { public static readonly Packet InvalidInstance = SetStatic(new PlayMusic(MusicName.Invalid)); - private static Packet[] m_Instances = new Packet[60]; + private static readonly Packet[] m_Instances = new Packet[60]; public PlayMusic(MusicName name) : base(0x6D, 3) { @@ -2700,7 +2700,7 @@ namespace Server.Network public sealed class SeasonChange : Packet { - private static SeasonChange[][] m_Cache = new SeasonChange[][] + private static readonly SeasonChange[][] m_Cache = new SeasonChange[][] { new SeasonChange[2], new SeasonChange[2], @@ -3250,8 +3250,8 @@ namespace Server.Network public sealed class MobileIncoming : Packet { - private static ThreadLocal m_DupedLayersTL = new ThreadLocal(() => { return new int[256]; }); - private static ThreadLocal m_VersionTL = new ThreadLocal(); + private static readonly ThreadLocal m_DupedLayersTL = new ThreadLocal(() => { return new int[256]; }); + private static readonly ThreadLocal m_VersionTL = new ThreadLocal(); public Mobile m_Beheld; @@ -3363,8 +3363,8 @@ namespace Server.Network public sealed class MobileIncomingSA : Packet { - private static ThreadLocal m_DupedLayersTL = new ThreadLocal(() => { return new int[256]; }); - private static ThreadLocal m_VersionTL = new ThreadLocal(); + private static readonly ThreadLocal m_DupedLayersTL = new ThreadLocal(() => { return new int[256]; }); + private static readonly ThreadLocal m_VersionTL = new ThreadLocal(); public Mobile m_Beheld; @@ -3485,8 +3485,8 @@ namespace Server.Network // Pre-7.0.0.0 Mobile Incoming public sealed class MobileIncomingOld : Packet { - private static ThreadLocal m_DupedLayersTL = new ThreadLocal(() => { return new int[256]; }); - private static ThreadLocal m_VersionTL = new ThreadLocal(); + private static readonly ThreadLocal m_DupedLayersTL = new ThreadLocal(() => { return new int[256]; }); + private static readonly ThreadLocal m_VersionTL = new ThreadLocal(); public Mobile m_Beheld; @@ -3654,7 +3654,7 @@ namespace Server.Network public sealed class PingAck : Packet { - private static PingAck[] m_Cache = new PingAck[0x100]; + private static readonly PingAck[] m_Cache = new PingAck[0x100]; public PingAck(byte ping) : base(0x73, 2) { @@ -3689,7 +3689,7 @@ namespace Server.Network public sealed class MovementAck : Packet { - private static MovementAck[] m_Cache = new MovementAck[8 * 256]; + private static readonly MovementAck[] m_Cache = new MovementAck[8 * 256]; private MovementAck(int seq, int noto) : base(0x22, 3) { diff --git a/Projects/Server/Network/ServerStartup.cs b/Projects/Server/Network/ServerStartup.cs new file mode 100644 index 000000000..d0f0324c5 --- /dev/null +++ b/Projects/Server/Network/ServerStartup.cs @@ -0,0 +1,23 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Server.Network; + +namespace Server.Network +{ + public class ServerStartup + { + private readonly IMessagePumpService _messagePumpService; + public ServerStartup(IMessagePumpService messagePumpService) => _messagePumpService = messagePumpService; + + public void ConfigureServices(IServiceCollection services) + { + } + + public void Configure(IApplicationBuilder app) + { + // Run async? + Task.Run(() => Core.RunEventLoop(_messagePumpService)); + } + } +} diff --git a/Projects/Server/Network/StaticPacketHandlers.cs b/Projects/Server/Network/StaticPacketHandlers.cs index 6f8e2b2f6..259647f95 100644 --- a/Projects/Server/Network/StaticPacketHandlers.cs +++ b/Projects/Server/Network/StaticPacketHandlers.cs @@ -19,19 +19,18 @@ * along with this program. If not, see . * *************************************************************************/ -using System; using System.Collections.Concurrent; namespace Server.Network { public static class StaticPacketHandlers { - private static ConcurrentDictionary OPLInfoPackets = new ConcurrentDictionary(); - private static ConcurrentDictionary RemoveEntityPackets = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary OPLInfoPackets = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary RemoveEntityPackets = new ConcurrentDictionary(); - private static ConcurrentDictionary WorldItemPackets = new ConcurrentDictionary(); - private static ConcurrentDictionary WorldItemSAPackets = new ConcurrentDictionary(); - private static ConcurrentDictionary WorldItemHSPackets = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary WorldItemPackets = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary WorldItemSAPackets = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary WorldItemHSPackets = new ConcurrentDictionary(); public static OPLInfo GetOPLInfoPacket(IPropertyListObject obj) { diff --git a/Projects/Server/Network/TcpServer.cs b/Projects/Server/Network/TcpServer.cs new file mode 100644 index 000000000..270beec52 --- /dev/null +++ b/Projects/Server/Network/TcpServer.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.NetworkInformation; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; + +namespace Server.Network +{ + public class TcpServer + { + public static List Listeners { get; } = new List(); + // Make this thread safe + public static List Instances { get; } = new List(); + + public static IWebHostBuilder CreateWebHostBuilder(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseSetting(WebHostDefaults.SuppressStatusMessagesKey, "True") + .ConfigureServices(services => + { + services.AddSingleton(new MessagePumpService()); + }) + .UseKestrel(options => + { + foreach (var ipep in Listeners) + { + options.Listen(ipep, builder => { builder.UseConnectionHandler(); }); + DisplayListener(ipep); + } + + options.ListenLocalhost(2593, builder => { builder.UseConnectionHandler(); }); + + // Webservices here + }) + .UseLibuv() + .UseStartup(); + + private static void DisplayListener(IPEndPoint ipep) + { + if (ipep.Address.Equals(IPAddress.Any) || ipep.Address.Equals(IPAddress.IPv6Any)) + { + NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces(); + foreach (NetworkInterface adapter in adapters) + { + IPInterfaceProperties properties = adapter.GetIPProperties(); + foreach (UnicastIPAddressInformation unicast in properties.UnicastAddresses) + if (ipep.AddressFamily == unicast.Address.AddressFamily) + Console.WriteLine("Listening: {0}:{1}", unicast.Address, ipep.Port); + } + } + else + Console.WriteLine("Listening: {0}:{1}", ipep.Address, ipep.Port); + } + } +} diff --git a/Projects/Server/Network/UOConnectionHandler.cs b/Projects/Server/Network/UOConnectionHandler.cs new file mode 100644 index 000000000..75f24c1ef --- /dev/null +++ b/Projects/Server/Network/UOConnectionHandler.cs @@ -0,0 +1,116 @@ +using System; +using System.Buffers; +using System.IO.Pipelines; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Connections; +using Microsoft.Extensions.Logging; + +namespace Server.Network +{ + public class ServerConnectionHandler : ConnectionHandler + { + private readonly IMessagePumpService _messagePumpService; + private readonly ILogger _logger; + + public ServerConnectionHandler( + IMessagePumpService messagePumpService, + ILogger logger + ) + { + _messagePumpService = messagePumpService; + _logger = logger; + } + + public override async Task OnConnectedAsync(ConnectionContext connection) + { + if (!VerifySocket(connection)) + { + Release(connection); + return; + } + + NetState ns = new NetState(connection); + TcpServer.Instances.Add(ns); + _logger.LogInformation($"Client: {ns}: Connected. [{TcpServer.Instances.Count} Online]"); + + connection.ConnectionClosed.Register(() => { TcpServer.Instances.Remove(ns); }); + + await ProcessIncoming(ns); + } + + private async Task ProcessIncoming(NetState ns) + { + var inPipe = ns.Connection.Transport.Input; + + while (true) + { + if (NetState.AsyncState.Paused) + continue; + + try + { + ReadResult result = await inPipe.ReadAsync(); + if (result.IsCanceled || result.IsCompleted) + return; + + ReadOnlySequence seq = result.Buffer; + + if (seq.IsEmpty) + break; + + int pos = PacketHandlers.ProcessPacket(_messagePumpService, ns, seq); + + if (pos <= 0) + break; + + inPipe.AdvanceTo(seq.Slice(0, pos).End); + } + catch + { + // ignored + } + } + + inPipe.Complete(); + } + + private static bool VerifySocket(ConnectionContext connection) + { + try + { + SocketConnectEventArgs args = new SocketConnectEventArgs(connection); + + EventSink.InvokeSocketConnect(args); + + return args.AllowConnection; + } + catch (Exception ex) + { + NetState.TraceException(ex); + return false; + } + } + + private static void Release(ConnectionContext connection) + { + try + { + connection.Abort(new ConnectionAbortedException("Failed socket verification.")); + } + catch (Exception ex) + { + NetState.TraceException(ex); + } + + try + { + // TODO: Is this needed? + connection.DisposeAsync(); + } + catch (Exception ex) + { + NetState.TraceException(ex); + } + } + } +} diff --git a/Projects/Server/ObjectPropertyList.cs b/Projects/Server/ObjectPropertyList.cs index 0f845e62a..b89da34a8 100644 --- a/Projects/Server/ObjectPropertyList.cs +++ b/Projects/Server/ObjectPropertyList.cs @@ -35,10 +35,10 @@ namespace Server public sealed class ObjectPropertyList : Packet { private static byte[] m_Buffer = new byte[1024]; - private static Encoding m_Encoding = Encoding.Unicode; + private static readonly Encoding m_Encoding = Encoding.Unicode; // Each of these are localized to "~1_NOTHING~" which allows the string argument to be used - private static int[] m_StringNumbers = + private static readonly int[] m_StringNumbers = { 1042971, 1070722 diff --git a/Projects/Server/Persistence/BinaryMemoryWriter.cs b/Projects/Server/Persistence/BinaryMemoryWriter.cs index 5cc2f0a51..04697d869 100644 --- a/Projects/Server/Persistence/BinaryMemoryWriter.cs +++ b/Projects/Server/Persistence/BinaryMemoryWriter.cs @@ -25,7 +25,7 @@ namespace Server public sealed class BinaryMemoryWriter : BinaryFileWriter { private static byte[] indexBuffer; - private MemoryStream stream; + private readonly MemoryStream stream; public BinaryMemoryWriter() : base(new MemoryStream(512), true) => diff --git a/Projects/Server/Persistence/DynamicSaveStrategy.cs b/Projects/Server/Persistence/DynamicSaveStrategy.cs index 0132c1f52..175b168f8 100644 --- a/Projects/Server/Persistence/DynamicSaveStrategy.cs +++ b/Projects/Server/Persistence/DynamicSaveStrategy.cs @@ -29,16 +29,16 @@ namespace Server { public sealed class DynamicSaveStrategy : SaveStrategy { - private ConcurrentBag _decayBag; + private readonly ConcurrentBag _decayBag; private SequentialFileWriter _guildData, _guildIndex; - private BlockingCollection _guildThreadWriters; + private readonly BlockingCollection _guildThreadWriters; private SequentialFileWriter _itemData, _itemIndex; - private BlockingCollection _itemThreadWriters; + private readonly BlockingCollection _itemThreadWriters; private SequentialFileWriter _mobileData, _mobileIndex; - private BlockingCollection _mobileThreadWriters; + private readonly BlockingCollection _mobileThreadWriters; public DynamicSaveStrategy() { diff --git a/Projects/Server/Persistence/FileOperations.cs b/Projects/Server/Persistence/FileOperations.cs index 3939c9e48..7e5eb04c8 100644 --- a/Projects/Server/Persistence/FileOperations.cs +++ b/Projects/Server/Persistence/FileOperations.cs @@ -71,7 +71,7 @@ namespace Server #if !MONO private class UnbufferedFileStream : FileStream { - private SafeFileHandle fileHandle; + private readonly SafeFileHandle fileHandle; public UnbufferedFileStream(SafeFileHandle fileHandle, FileAccess access, int bufferSize, bool isAsync) : base(fileHandle, access, bufferSize, isAsync) => diff --git a/Projects/Server/Persistence/FileQueue.cs b/Projects/Server/Persistence/FileQueue.cs index 3ec5af2f5..f3f3d2e8d 100644 --- a/Projects/Server/Persistence/FileQueue.cs +++ b/Projects/Server/Persistence/FileQueue.cs @@ -29,19 +29,19 @@ namespace Server public sealed class FileQueue : IDisposable { - private static int bufferSize; + private static readonly int bufferSize; - private Chunk[] active; + private readonly Chunk[] active; private int activeCount; private Page buffered; - private FileCommitCallback callback; + private readonly FileCommitCallback callback; private ManualResetEvent idle; - private Queue pending; + private readonly Queue pending; - private object syncRoot; + private readonly object syncRoot; static FileQueue() => bufferSize = FileOperations.BufferSize; @@ -193,8 +193,8 @@ namespace Server public sealed class Chunk { private int offset; - private FileQueue owner; - private int slot; + private readonly FileQueue owner; + private readonly int slot; public Chunk(FileQueue owner, int slot, byte[] buffer, int offset, int size) { diff --git a/Projects/Server/Persistence/ParallelSaveStrategy.cs b/Projects/Server/Persistence/ParallelSaveStrategy.cs index 80614bc3c..45f28795e 100644 --- a/Projects/Server/Persistence/ParallelSaveStrategy.cs +++ b/Projects/Server/Persistence/ParallelSaveStrategy.cs @@ -28,7 +28,7 @@ namespace Server { public sealed class ParallelSaveStrategy : SaveStrategy { - private Queue _decayQueue; + private readonly Queue _decayQueue; private Consumer[] consumers; private int cycle; @@ -40,7 +40,7 @@ namespace Server private SequentialFileWriter mobileData, mobileIndex; - private int processorCount; + private readonly int processorCount; public ParallelSaveStrategy(int processorCount) { @@ -226,9 +226,9 @@ namespace Server private sealed class Producer : IEnumerable { - private IEnumerable guilds; - private IEnumerable items; - private IEnumerable mobiles; + private readonly IEnumerable guilds; + private readonly IEnumerable items; + private readonly IEnumerable mobiles; public Producer() { @@ -257,13 +257,13 @@ namespace Server private sealed class Consumer { - public ConsumableEntry[] buffer; + public readonly ConsumableEntry[] buffer; - public ManualResetEvent completionEvent; + public readonly ManualResetEvent completionEvent; public int head, done, tail; - private ParallelSaveStrategy owner; + private readonly ParallelSaveStrategy owner; - private Thread thread; + private readonly Thread thread; public Consumer(ParallelSaveStrategy owner, int bufferSize) { diff --git a/Projects/Server/Persistence/QueuedMemoryWriter.cs b/Projects/Server/Persistence/QueuedMemoryWriter.cs index 1bcd67982..6effa9f97 100644 --- a/Projects/Server/Persistence/QueuedMemoryWriter.cs +++ b/Projects/Server/Persistence/QueuedMemoryWriter.cs @@ -25,8 +25,8 @@ namespace Server { public sealed class QueuedMemoryWriter : BinaryFileWriter { - private MemoryStream _memStream; - private List _orderedIndexInfo = new List(); + private readonly MemoryStream _memStream; + private readonly List _orderedIndexInfo = new List(); public QueuedMemoryWriter() : base(new MemoryStream(1024 * 1024), true) => diff --git a/Projects/Server/Persistence/StandardSaveStrategy.cs b/Projects/Server/Persistence/StandardSaveStrategy.cs index d65de691d..d75403754 100644 --- a/Projects/Server/Persistence/StandardSaveStrategy.cs +++ b/Projects/Server/Persistence/StandardSaveStrategy.cs @@ -35,7 +35,7 @@ namespace Server public static SaveOption SaveType = SaveOption.Normal; - private Queue _decayQueue; + private readonly Queue _decayQueue; public StandardSaveStrategy() => _decayQueue = new Queue(); diff --git a/Projects/Server/Point3DList.cs b/Projects/Server/Point3DList.cs index 635121987..6b34f72da 100644 --- a/Projects/Server/Point3DList.cs +++ b/Projects/Server/Point3DList.cs @@ -22,7 +22,7 @@ namespace Server { public class Point3DList { - private static Point3D[] m_EmptyList = new Point3D[0]; + private static readonly Point3D[] m_EmptyList = new Point3D[0]; private Point3D[] m_List; public Point3DList() diff --git a/Projects/Server/Region.cs b/Projects/Server/Region.cs index c731f7964..dcda3c477 100644 --- a/Projects/Server/Region.cs +++ b/Projects/Server/Region.cs @@ -110,8 +110,8 @@ namespace Server private Point3D m_GoLocation; - private string m_Name; - private int m_Priority; + private readonly string m_Name; + private readonly int m_Priority; public Region(string name, Map map, int priority, params Rectangle2D[] area) : this(name, map, priority, ConvertTo3D(area)) diff --git a/Projects/Server/Sector.cs b/Projects/Server/Sector.cs index ae9ef8b94..5713accbd 100644 --- a/Projects/Server/Sector.cs +++ b/Projects/Server/Sector.cs @@ -48,11 +48,11 @@ namespace Server public class Sector { // TODO: Can we avoid this? - private static List m_DefaultMobileList = new List(); - private static List m_DefaultItemList = new List(); - private static List m_DefaultClientList = new List(); - private static List m_DefaultMultiList = new List(); - private static List m_DefaultRectList = new List(); + private static readonly List m_DefaultMobileList = new List(); + private static readonly List m_DefaultItemList = new List(); + private static readonly List m_DefaultClientList = new List(); + private static readonly List m_DefaultMultiList = new List(); + private static readonly List m_DefaultRectList = new List(); private bool m_Active; private List m_Clients; private List m_Items; diff --git a/Projects/Server/Serialization/AsyncWriter.cs b/Projects/Server/Serialization/AsyncWriter.cs index c8cfd2c55..7112ea59c 100644 --- a/Projects/Server/Serialization/AsyncWriter.cs +++ b/Projects/Server/Serialization/AsyncWriter.cs @@ -29,18 +29,18 @@ namespace Server { public sealed class AsyncWriter : IGenericWriter { - private int BufferSize; + private readonly int BufferSize; private BinaryWriter m_Bin; private bool m_Closed; - private FileStream m_File; + private readonly FileStream m_File; private long m_LastPos, m_CurPos; private MemoryStream m_Mem; private Thread m_WorkerThread; - private Queue m_WriteQueue; - private bool PrefixStrings; + private readonly Queue m_WriteQueue; + private readonly bool PrefixStrings; public AsyncWriter(string filename, bool prefix) : this(filename, 1048576, prefix) //1 mb buffer @@ -565,7 +565,7 @@ namespace Server private class WorkerThread { - private AsyncWriter m_Owner; + private readonly AsyncWriter m_Owner; public WorkerThread(AsyncWriter owner) => m_Owner = owner; diff --git a/Projects/Server/Serialization/BinaryFileReader.cs b/Projects/Server/Serialization/BinaryFileReader.cs index 5d21a0faf..2abbc1d2f 100644 --- a/Projects/Server/Serialization/BinaryFileReader.cs +++ b/Projects/Server/Serialization/BinaryFileReader.cs @@ -29,7 +29,7 @@ namespace Server { public sealed class BinaryFileReader : IGenericReader { - private BinaryReader m_File; + private readonly BinaryReader m_File; public BinaryFileReader(BinaryReader br) => m_File = br; diff --git a/Projects/Server/Serialization/BinaryFileWriter.cs b/Projects/Server/Serialization/BinaryFileWriter.cs index 9cb205354..bd8bc9783 100644 --- a/Projects/Server/Serialization/BinaryFileWriter.cs +++ b/Projects/Server/Serialization/BinaryFileWriter.cs @@ -32,20 +32,20 @@ namespace Server { private const int LargeByteBufferSize = 256; - private byte[] m_Buffer; + private readonly byte[] m_Buffer; private byte[] m_CharacterBuffer; - private Encoding m_Encoding; - private Stream m_File; + private readonly Encoding m_Encoding; + private readonly Stream m_File; private int m_Index; private int m_MaxBufferChars; private long m_Position; - private char[] m_SingleCharBuffer = new char[1]; - private bool PrefixStrings; + private readonly char[] m_SingleCharBuffer = new char[1]; + private readonly bool PrefixStrings; public BinaryFileWriter(Stream strm, bool prefixStr) { diff --git a/Projects/Server/Serialization/BufferWriter.cs b/Projects/Server/Serialization/BufferWriter.cs index 0462a21a9..e2e06323c 100644 --- a/Projects/Server/Serialization/BufferWriter.cs +++ b/Projects/Server/Serialization/BufferWriter.cs @@ -35,13 +35,13 @@ namespace Server private byte[] m_CharacterBuffer; - private Encoding m_Encoding; + private readonly Encoding m_Encoding; private int m_Index; private int m_MaxBufferChars; - private char[] m_SingleCharBuffer = new char[1]; - private bool PrefixStrings; + private readonly char[] m_SingleCharBuffer = new char[1]; + private readonly bool PrefixStrings; public BufferWriter(bool prefixStr) { diff --git a/Projects/Server/Server.csproj b/Projects/Server/Server.csproj index d8fffcd3b..8b9200a2f 100644 --- a/Projects/Server/Server.csproj +++ b/Projects/Server/Server.csproj @@ -6,7 +6,7 @@ Server.Core ModernUO - 0.2.1 + 0.3.0 Kamron Batman ModernUO ModernUO Server @@ -35,21 +35,24 @@ libdrng.dll Always - - libuv.dll - Always - zlib.dll Always - - - - - - + + + + + + + + + + + + + diff --git a/Projects/Server/SignalR/AsyncDisposableExtensions.cs b/Projects/Server/SignalR/AsyncDisposableExtensions.cs deleted file mode 100644 index ac2ab7c2d..000000000 --- a/Projects/Server/SignalR/AsyncDisposableExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Threading.Tasks; - -namespace SignalR -{ - public static class AsyncDisposableExtensions - { - // Does a light up check to see if a type is IAsyncDisposable and calls DisposeAsync if it is - public static ValueTask DisposeAsync(this IDisposable disposable) - { - if (disposable is IAsyncDisposable asyncDisposable) return asyncDisposable.DisposeAsync(); - disposable.Dispose(); - return default; - } - } -} diff --git a/Projects/Server/Skills.cs b/Projects/Server/Skills.cs index 9088bf63f..f9b44c370 100644 --- a/Projects/Server/Skills.cs +++ b/Projects/Server/Skills.cs @@ -487,7 +487,7 @@ namespace Server public class Skills : IEnumerable { private Skill m_Highest; - private Skill[] m_Skills; + private readonly Skill[] m_Skills; public Skills(Mobile owner) { diff --git a/Projects/Server/Targeting/Target.cs b/Projects/Server/Targeting/Target.cs index 72f595a95..155e41107 100644 --- a/Projects/Server/Targeting/Target.cs +++ b/Projects/Server/Targeting/Target.cs @@ -257,11 +257,11 @@ namespace Server.Targeting private class TimeoutTimer : Timer { - private static TimeSpan ThirtySeconds = TimeSpan.FromSeconds(30.0); - private static TimeSpan TenSeconds = TimeSpan.FromSeconds(10.0); - private static TimeSpan OneSecond = TimeSpan.FromSeconds(1.0); - private Mobile m_Mobile; - private Target m_Target; + private static readonly TimeSpan ThirtySeconds = TimeSpan.FromSeconds(30.0); + private static readonly TimeSpan TenSeconds = TimeSpan.FromSeconds(10.0); + private static readonly TimeSpan OneSecond = TimeSpan.FromSeconds(1.0); + private readonly Mobile m_Mobile; + private readonly Target m_Target; public TimeoutTimer(Target target, Mobile m, TimeSpan delay) : base(delay) { diff --git a/Projects/Server/TileData.cs b/Projects/Server/TileData.cs index ff97764af..0865840b8 100644 --- a/Projects/Server/TileData.cs +++ b/Projects/Server/TileData.cs @@ -177,7 +177,7 @@ namespace Server public static class TileData { - private static byte[] m_StringBuffer = new byte[20]; + private static readonly byte[] m_StringBuffer = new byte[20]; static TileData() { diff --git a/Projects/Server/TileList.cs b/Projects/Server/TileList.cs index 1097c3c37..1212a39ae 100644 --- a/Projects/Server/TileList.cs +++ b/Projects/Server/TileList.cs @@ -22,7 +22,7 @@ namespace Server { public class TileList { - private static StaticTile[] m_EmptyTiles = new StaticTile[0]; + private static readonly StaticTile[] m_EmptyTiles = new StaticTile[0]; private StaticTile[] m_Tiles; public TileList() diff --git a/Projects/Server/TileMatrix.cs b/Projects/Server/TileMatrix.cs index 44dc98601..d45da5ac3 100644 --- a/Projects/Server/TileMatrix.cs +++ b/Projects/Server/TileMatrix.cs @@ -29,30 +29,30 @@ namespace Server { public class TileMatrix { - private static List m_Instances = new List(); + private static readonly List m_Instances = new List(); - private int m_FileIndex; - private List m_FileShare = new List(); + private readonly int m_FileIndex; + private readonly List m_FileShare = new List(); - private LandTile[] m_InvalidLandBlock; - private int[][] m_LandPatches; - private LandTile[][][] m_LandTiles; + private readonly LandTile[] m_InvalidLandBlock; + private readonly int[][] m_LandPatches; + private readonly LandTile[][][] m_LandTiles; private TileList[][] m_Lists; - private UOPIndex m_MapIndex; + private readonly UOPIndex m_MapIndex; private DateTime m_NextLandWarning; private DateTime m_NextStaticWarning; - private Map m_Owner; + private readonly Map m_Owner; - private int[][] m_StaticPatches; - private StaticTile[][][][][] m_StaticTiles; + private readonly int[][] m_StaticPatches; + private readonly StaticTile[][][][][] m_StaticTiles; private StaticTile[] m_TileBuffer = new StaticTile[128]; - private TileList m_TilesList = new TileList(); + private readonly TileList m_TilesList = new TileList(); // private int m_Width, m_Height; public TileMatrix(Map owner, int fileIndex, int mapID, int width, int height) @@ -564,10 +564,10 @@ namespace Server public class UOPIndex { - private UOPEntry[] m_Entries; - private int m_Length; + private readonly UOPEntry[] m_Entries; + private readonly int m_Length; - private BinaryReader m_Reader; + private readonly BinaryReader m_Reader; public UOPIndex(FileStream stream) { @@ -652,7 +652,7 @@ namespace Server private class UOPEntry : IComparable { - public int m_Length; + public readonly int m_Length; public int m_Offset; public int m_Order; diff --git a/Projects/Server/TileMatrixPatch.cs b/Projects/Server/TileMatrixPatch.cs index e515fee8a..9c0bb2a0a 100644 --- a/Projects/Server/TileMatrixPatch.cs +++ b/Projects/Server/TileMatrixPatch.cs @@ -25,7 +25,8 @@ namespace Server { public class TileMatrixPatch { - private int m_LandBlocks, m_StaticBlocks; + private readonly int m_LandBlocks; + private readonly int m_StaticBlocks; private StaticTile[] m_TileBuffer = new StaticTile[128]; diff --git a/Projects/Server/Timer.cs b/Projects/Server/Timer.cs index 21b9db12b..5b4d2ef46 100644 --- a/Projects/Server/Timer.cs +++ b/Projects/Server/Timer.cs @@ -45,11 +45,12 @@ namespace Server public class Timer { - private static Queue m_Queue = new Queue(); + private static readonly Queue m_Queue = new Queue(); private static int m_QueueCountAtSlice; private long m_Delay; - private int m_Index, m_Count; + private int m_Index; + private readonly int m_Count; private long m_Interval; private List m_List; private long m_Next; @@ -232,11 +233,11 @@ namespace Server public class TimerThread { - private static Dictionary m_Changed = new Dictionary(); + private static readonly Dictionary m_Changed = new Dictionary(); - private static long[] m_NextPriorities = new long[8]; + private static readonly long[] m_NextPriorities = new long[8]; - private static long[] m_PriorityDelays = { + private static readonly long[] m_PriorityDelays = { 0, 10, 25, @@ -247,7 +248,7 @@ namespace Server 60000 }; - private static List[] m_Timers = { + private static readonly List[] m_Timers = { new List(), new List(), new List(), @@ -258,7 +259,7 @@ namespace Server new List() }; - private static AutoResetEvent m_Signal = new AutoResetEvent(false); + private static readonly AutoResetEvent m_Signal = new AutoResetEvent(false); public static void DumpInfo(TextWriter tw) { @@ -415,7 +416,7 @@ namespace Server private class TimerChangeEntry { - private static Queue m_InstancePool = new Queue(); + private static readonly Queue m_InstancePool = new Queue(); public bool m_IsAdd; public int m_NewIndex; public Timer m_Timer; @@ -528,7 +529,7 @@ namespace Server private class DelayStateCallTimer : Timer { - private T m_State; + private readonly T m_State; public DelayStateCallTimer(TimeSpan delay, TimeSpan interval, int count, TimerStateCallback callback, T state) : base(delay, interval, count) @@ -555,7 +556,7 @@ namespace Server private class DelayTaskTimer : Timer { - private TaskCompletionSource m_TaskCompleter; + private readonly TaskCompletionSource m_TaskCompleter; public Task Task => m_TaskCompleter.Task; diff --git a/Projects/Server/Utilities/ActivatorUtil.cs b/Projects/Server/Utilities/ActivatorUtil.cs index 32a92a71c..945ee63c6 100644 --- a/Projects/Server/Utilities/ActivatorUtil.cs +++ b/Projects/Server/Utilities/ActivatorUtil.cs @@ -11,18 +11,12 @@ namespace Server.Utilities { ConstructorInfo emptyCtor = type.GetConstructor(Type.EmptyTypes); - if (emptyCtor != null && predicate?.Invoke(emptyCtor) != false) - { - return emptyCtor; - } + if (emptyCtor != null && predicate?.Invoke(emptyCtor) != false) return emptyCtor; ConstructorInfo optionalCtor = type.GetConstructors().SingleOrDefault(info => predicate?.Invoke(info) != false && info.GetParameters().All(x => x.IsOptional)); - if (optionalCtor != null) - { - return optionalCtor; - } + if (optionalCtor != null) return optionalCtor; throw new TypeInitializationException(type.ToString(), new Exception($"There is no empty/default constructor for {type} that matches predicate.")); @@ -38,39 +32,26 @@ namespace Server.Utilities { ctor = type.GetConstructor(args); - if (ctor != null && predicate?.Invoke(ctor) != false) - { - return ctor; - } + if (ctor != null && predicate?.Invoke(ctor) != false) return ctor; } else { ctor = type.GetConstructors().SingleOrDefault(info => { - if (predicate?.Invoke(info) == false) - { - return false; - } + if (predicate?.Invoke(info) == false) return false; List paramList = info.GetParameters().ToList(); // If more args are given than parameters, skip. - if (args.Length > paramList.Count) - { - return false; - } + if (args.Length > paramList.Count) return false; // check all given args map to params. for (int i = 0; i < args.Length; i++) - { - // if a null reference is passed, but the type is not nullable + // if a null reference is passed, but the type is not nullable if (args[i] == null && paramList[i].ParameterType.IsValueType // or if an arg is not null and is not assignable to the parameter type, skip. || !(args[i] == null || paramList[i].ParameterType.IsAssignableFrom(args[i]))) - { return false; - } - } // If there are more parameters, check if they any are not optional, if any are not, skip. // Otherwise all checks have passed. We have found a match @@ -78,10 +59,7 @@ namespace Server.Utilities .All(x => x.IsOptional); }); - if (ctor != null) - { - return ctor; - } + if (ctor != null) return ctor; } throw new Exception($"There is no empty/default constructor for {type} that matches predicate."); @@ -97,10 +75,7 @@ namespace Server.Utilities ConstructorInfo cctor = GetConstructor(type, constructorPredicate); ParameterInfo[] args = cctor.GetParameters(); - if (args.Length == 0) - { - return cctor.Invoke(Type.EmptyTypes); - } + if (args.Length == 0) return cctor.Invoke(Type.EmptyTypes); object[] argList = new object[args.Length]; Array.Fill(argList, Type.Missing); @@ -110,10 +85,7 @@ namespace Server.Utilities public static object CreateInstance(Type type, Predicate constructorPredicate = null, params object[] args) { - if (args == null || args.Length == 0) - { - return CreateInstance(type, constructorPredicate); - } + if (args == null || args.Length == 0) return CreateInstance(type, constructorPredicate); ConstructorInfo cctor = GetConstructor(type, constructorPredicate, args.Select(x => x?.GetType()).ToArray()); return cctor.Invoke(args); diff --git a/Projects/Server/Utilities/RefPool.cs b/Projects/Server/Utilities/RefPool.cs index f9f61cb12..76c0f6178 100644 --- a/Projects/Server/Utilities/RefPool.cs +++ b/Projects/Server/Utilities/RefPool.cs @@ -20,11 +20,8 @@ namespace Server.Utilities /// public abstract class BaseRef : IRef where TDerived : IRef { - private RefPool m_Pool; - public BaseRef(RefPool pool) - { - m_Pool = pool; - } + private readonly RefPool m_Pool; + public BaseRef(RefPool pool) => m_Pool = pool; protected abstract void OnDispose(); public void Dispose() { @@ -42,8 +39,8 @@ namespace Server.Utilities public delegate TRef Generator(RefPool targetPool); public const int DEFAULT_RESOURCE_RETENTION = 10; - private Stack m_Resources = new Stack(); - private Generator m_Generator; + private readonly Stack m_Resources = new Stack(); + private readonly Generator m_Generator; private int m_MaxRefrenceRetention; /// @@ -90,8 +87,9 @@ namespace Server.Utilities /// public class QueueRef : Queue, IRef { - private RefPool> m_Pool; - private QueueRef(RefPool> pool) { m_Pool = pool; } + private readonly RefPool> m_Pool; + private QueueRef(RefPool> pool) => m_Pool = pool; + /// Clears the queue and returns this resource to its parent resource pool. public void Dispose() { Clear(); m_Pool.Return(this); } /// @@ -102,8 +100,9 @@ namespace Server.Utilities /// public class StackRef : Stack, IRef { - private RefPool> m_Pool; - private StackRef(RefPool> pool) { m_Pool = pool; } + private readonly RefPool> m_Pool; + private StackRef(RefPool> pool) => m_Pool = pool; + /// Clears the stack and returns this resource to its parent resource pool. public void Dispose() { Clear(); m_Pool.Return(this); } /// diff --git a/Projects/Server/Utilities/Utility.cs b/Projects/Server/Utilities/Utility.cs index 1e68ff305..12c841164 100644 --- a/Projects/Server/Utilities/Utility.cs +++ b/Projects/Server/Utilities/Utility.cs @@ -36,7 +36,7 @@ namespace Server private static Dictionary _ipAddressTable; - private static SkillName[] m_AllSkills = + private static readonly SkillName[] m_AllSkills = { SkillName.Alchemy, SkillName.Anatomy, @@ -95,7 +95,7 @@ namespace Server SkillName.Spellweaving }; - private static SkillName[] m_CombatSkills = + private static readonly SkillName[] m_CombatSkills = { SkillName.Archery, SkillName.Swords, @@ -104,7 +104,7 @@ namespace Server SkillName.Wrestling }; - private static SkillName[] m_CraftSkills = + private static readonly SkillName[] m_CraftSkills = { SkillName.Alchemy, SkillName.Blacksmith, @@ -117,7 +117,7 @@ namespace Server SkillName.Tinkering }; - private static Stack m_ConsoleColors = new Stack(); + private static readonly Stack m_ConsoleColors = new Stack(); public static Encoding UTF8 => m_UTF8 ?? (m_UTF8 = new UTF8Encoding(false, false)); public static Encoding UTF8WithEncoding => m_UTF8WithEncoding ?? (m_UTF8WithEncoding = new UTF8Encoding(true, false)); diff --git a/Projects/Server/World.cs b/Projects/Server/World.cs index 93c2fd1b6..d4c75c5ae 100644 --- a/Projects/Server/World.cs +++ b/Projects/Server/World.cs @@ -31,7 +31,7 @@ namespace Server { public static class World { - private static ManualResetEvent m_DiskWriteHandle = new ManualResetEvent(true); + private static readonly ManualResetEvent m_DiskWriteHandle = new ManualResetEvent(true); private static Queue _addQueue, _deleteQueue; @@ -98,7 +98,7 @@ namespace Server else p = new UnicodeMessage(Serial.MinusOne, -1, MessageType.Regular, hue, 3, "ENU", "System", text); - List list = NetState.Instances; + List list = TcpServer.Instances; p.Acquire(); diff --git a/Publish-Linux.sh b/Publish-Linux.sh old mode 100644 new mode 100755