Switches to Kestrel (#102)

This commit is contained in:
Kamron Batman 2020-04-12 20:57:48 -07:00 committed by GitHub
parent 70fddfebde
commit 2c0d97cd36
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
141 changed files with 1040 additions and 1679 deletions

11
.gitignore vendored
View file

@ -4,6 +4,7 @@
/Distribution/Logs /Distribution/Logs
/Distribution/Backups /Distribution/Backups
/Distribution/Saves /Distribution/Saves
/Distribution/docs
/Distribution/System.IO.Pipelines.dll /Distribution/System.IO.Pipelines.dll
/Distribution/libdrng.dll /Distribution/libdrng.dll
/Distribution/zlib.dll /Distribution/zlib.dll
@ -12,21 +13,17 @@
/Distribution/System.Runtime.CompilerServices.Unsafe.dll /Distribution/System.Runtime.CompilerServices.Unsafe.dll
# LibUv Dependencies # LibUv Dependencies
/Distribution/libuv.dylib
/Distribution/libuv.dll /Distribution/libuv.dll
/Distribution/libuv.so
/Distribution/Microsoft.AspNetCore.Connections.Abstractions.dll /Distribution/Microsoft.AspNetCore.Connections.Abstractions.dll
/Distribution/Microsoft.AspNetCore.Http.Features.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.Abstractions.dll
/Distribution/Microsoft.Extensions.Configuration.Binder.dll
/Distribution/Microsoft.Extensions.Configuration.dll
/Distribution/Microsoft.Extensions.DependencyInjection.Abstractions.dll /Distribution/Microsoft.Extensions.DependencyInjection.Abstractions.dll
/Distribution/Microsoft.Extensions.DependencyInjection.dll
/Distribution/Microsoft.Extensions.FileProviders.Abstractions.dll /Distribution/Microsoft.Extensions.FileProviders.Abstractions.dll
/Distribution/Microsoft.Extensions.Hosting.Abstractions.dll /Distribution/Microsoft.Extensions.Hosting.Abstractions.dll
/Distribution/Microsoft.Extensions.Logging.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.Options.dll
/Distribution/Microsoft.Extensions.Primitives.dll /Distribution/Microsoft.Extensions.Primitives.dll

View file

@ -30,7 +30,7 @@ namespace Server.Misc
if (!Enabled || IsExempt(ourAddress)) if (!Enabled || IsExempt(ourAddress))
return true; return true;
List<NetState> netStates = NetState.Instances; List<NetState> netStates = TcpServer.Instances;
int count = 0; int count = 0;
@ -50,4 +50,4 @@ namespace Server.Misc
return true; return true;
} }
} }
} }

View file

@ -36,7 +36,7 @@ namespace Server.Commands.Generic
List<object> list = new List<object>(); List<object> list = new List<object>();
List<IPAddress> addresses = new List<IPAddress>(); List<IPAddress> addresses = new List<IPAddress>();
List<NetState> states = NetState.Instances; List<NetState> states = TcpServer.Instances;
for (int i = 0; i < states.Count; ++i) for (int i = 0; i < states.Count; ++i)
{ {
@ -60,4 +60,4 @@ namespace Server.Commands.Generic
} }
} }
} }
} }

View file

@ -34,7 +34,7 @@ namespace Server.Commands.Generic
List<object> list = new List<object>(); List<object> list = new List<object>();
List<NetState> states = NetState.Instances; List<NetState> states = TcpServer.Instances;
for (int i = 0; i < states.Count; ++i) for (int i = 0; i < states.Count; ++i)
{ {
@ -61,4 +61,4 @@ namespace Server.Commands.Generic
} }
} }
} }
} }

View file

@ -671,7 +671,7 @@ namespace Server.Commands
public static void BroadcastMessage(AccessLevel ac, int hue, string message) 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; Mobile m = state.Mobile;
@ -743,7 +743,7 @@ namespace Server.Commands
[Description("View some stats about the server.")] [Description("View some stats about the server.")]
public static void Stats_OnCommand(CommandEventArgs e) 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("Mobiles: {0}", World.Mobiles.Count);
e.Mobile.SendMessage("Items: {0}", World.Items.Count); e.Mobile.SendMessage("Items: {0}", World.Items.Count);
} }

View file

@ -212,7 +212,7 @@ namespace Server.Engines.Help
bool isStaffOnline = false; bool isStaffOnline = false;
foreach (NetState ns in NetState.Instances) foreach (NetState ns in TcpServer.Instances)
{ {
Mobile m = ns.Mobile; Mobile m = ns.Mobile;

View file

@ -133,7 +133,7 @@ namespace Server.Gumps
AddLabel(150, 170, LabelHue, Firewall.List.Count.ToString()); AddLabel(150, 170, LabelHue, Firewall.List.Count.ToString());
AddLabel(20, 190, LabelHue, "Clients:"); 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(20, 210, LabelHue, "Mobiles:");
AddLabel(150, 210, LabelHue, World.Mobiles.Count.ToString()); AddLabel(150, 210, LabelHue, World.Mobiles.Count.ToString());
@ -380,7 +380,7 @@ namespace Server.Gumps
{ {
if (m_List == null) if (m_List == null)
{ {
List<NetState> states = NetState.Instances.ToList(); List<NetState> states = TcpServer.Instances;
states.Sort(NetStateComparer.Instance); states.Sort(NetStateComparer.Instance);
m_List = states.ToList<object>(); m_List = states.ToList<object>();
@ -1932,7 +1932,7 @@ namespace Server.Gumps
if (level > AccessLevel.Player) if (level > AccessLevel.Player)
{ {
List<NetState> clients = NetState.Instances; List<NetState> clients = TcpServer.Instances;
int count = 0; int count = 0;
for (int i = 0; i < clients.Count; ++i) for (int i = 0; i < clients.Count; ++i)
@ -2020,7 +2020,7 @@ namespace Server.Gumps
} }
else else
{ {
List<NetState> instances = NetState.Instances; List<NetState> instances = TcpServer.Instances;
for (int i = 0; i < instances.Count; ++i) for (int i = 0; i < instances.Count; ++i)
{ {

View file

@ -112,7 +112,7 @@ namespace Server.Gumps
string filter = string.IsNullOrWhiteSpace(rawFilter) ? null : rawFilter.Trim().ToLower(); string filter = string.IsNullOrWhiteSpace(rawFilter) ? null : rawFilter.Trim().ToLower();
List<Mobile> list = new List<Mobile>(); List<Mobile> list = new List<Mobile>();
List<NetState> states = NetState.Instances; List<NetState> states = TcpServer.Instances;
for ( int i = 0; i < states.Count; ++i ) for ( int i = 0; i < states.Count; ++i )
{ {

View file

@ -202,7 +202,7 @@ namespace Server.Misc
try try
{ {
List<NetState> states = NetState.Instances; List<NetState> states = TcpServer.Instances;
op.WriteLine("- Count: {0}", states.Count); op.WriteLine("- Count: {0}", states.Count);

View file

@ -19,7 +19,7 @@ namespace Server.Misc
public static void FoodDecay() public static void FoodDecay()
{ {
foreach (NetState state in NetState.Instances) foreach (NetState state in TcpServer.Instances)
{ {
HungerDecay(state.Mobile); HungerDecay(state.Mobile);
ThirstDecay(state.Mobile); ThirstDecay(state.Mobile);

View file

@ -20,9 +20,9 @@ namespace Server
{ {
m_LevelOverride = value; 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; Mobile m = ns.Mobile;
m?.CheckLightLevels(false); m?.CheckLightLevels(false);
@ -69,12 +69,12 @@ namespace Server
Clock.GetTime(from.Map, from.X, from.Y, out int hours, out int minutes); Clock.GetTime(from.Map, from.X, from.Y, out int hours, out int minutes);
/* OSI times: /* OSI times:
* *
* Midnight -> 3:59 AM : Night * Midnight -> 3:59 AM : Night
* 4:00 AM -> 11:59 PM : Day * 4:00 AM -> 11:59 PM : Day
* *
* RunUO times: * RunUO times:
* *
* 10:00 PM -> 11:59 PM : Scale to night * 10:00 PM -> 11:59 PM : Scale to night
* Midnight -> 3:59 AM : Night * Midnight -> 3:59 AM : Night
* 4:00 AM -> 5:59 AM : Scale to day * 4:00 AM -> 5:59 AM : Scale to day
@ -102,9 +102,9 @@ namespace Server
protected override void OnTick() 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; Mobile m = ns.Mobile;
m?.CheckLightLevels(false); m?.CheckLightLevels(false);
@ -130,4 +130,4 @@ namespace Server
} }
} }
} }
} }

View file

@ -12,7 +12,7 @@ namespace Server.Misc
private static void EventSink_Login(LoginEventArgs args) private static void EventSink_Login(LoginEventArgs args)
{ {
int userCount = NetState.Instances.Count; int userCount = TcpServer.Instances.Count;
int itemCount = World.Items.Count; int itemCount = World.Items.Count;
int mobileCount = World.Mobiles.Count; int mobileCount = World.Mobiles.Count;
@ -27,4 +27,4 @@ namespace Server.Misc
mobileCount, mobileCount == 1 ? "" : "s"); mobileCount, mobileCount == 1 ? "" : "s");
} }
} }
} }

View file

@ -9,7 +9,7 @@ using Server.Network;
namespace Server.Misc 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 * The default setting for Address, a value of 'null', will use your local IP address. If all of your local IP addresses

View file

@ -1,4 +1,5 @@
using System.Net; using System.Net;
using Server.Network;
namespace Server namespace Server
{ {
@ -15,8 +16,7 @@ namespace Server
public static void RegisterListeners() public static void RegisterListeners()
{ {
for (int i = 0; i < m_ListenerEndPoints.Length; i++) TcpServer.Listeners.AddRange(m_ListenerEndPoints);
Core.MessagePump.AddListener(m_ListenerEndPoints[i]);
} }
} }
} }

View file

@ -316,10 +316,7 @@ namespace Server
private static void ProcessDisplayCase(Map map, StaticTile[] tiles, int x, int y) private static void ProcessDisplayCase(Map map, StaticTile[] tiles, int x, int y)
{ {
ShopFlags flags = ShopFlags.None; ShopFlags flags = tiles.Aggregate(ShopFlags.None, (current, t) => current | ProcessDisplayedItem(t.ID));
for (int i = 0; i < tiles.Length; ++i)
flags |= ProcessDisplayedItem(tiles[i].ID);
if (flags != ShopFlags.None) if (flags != ShopFlags.None)
{ {

View file

@ -263,7 +263,7 @@ namespace Server.Misc
else else
type = 2; type = 2;
List<NetState> states = NetState.Instances; List<NetState> states = TcpServer.Instances;
Packet weatherPacket = null; Packet weatherPacket = null;

View file

@ -119,7 +119,7 @@ namespace Server.Misc
int index = 0; 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; ++index;
@ -181,4 +181,4 @@ namespace Server.Misc
} }
} }
} }
} }

View file

@ -36,6 +36,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MailKit" Version="2.4.1" /> <PackageReference Include="MailKit" Version="2.4.1" />
<PackageReference Include="Microsoft.AspNetCore.Connections.Abstractions" Version="3.1.1" /> <PackageReference Include="Microsoft.AspNetCore.Connections.Abstractions" Version="3.1.3" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.3" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.3" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -41,7 +41,7 @@ namespace Server.Misc
{ {
Mobile from = e.Mobile; Mobile from = e.Mobile;
if (from?.AccessLevel < AccessLevel.Counselor) if (from == null || from.AccessLevel < AccessLevel.Counselor)
return; return;
if (HasDisconnected(from)) if (HasDisconnected(from))

View file

@ -27,7 +27,7 @@ namespace Server
{ {
public class AggressorInfo public class AggressorInfo
{ {
private static Queue<AggressorInfo> m_Pool = new Queue<AggressorInfo>(); private static readonly Queue<AggressorInfo> m_Pool = new Queue<AggressorInfo>();
private Mobile m_Attacker, m_Defender; private Mobile m_Attacker, m_Defender;
private bool m_CanReportMurder; private bool m_CanReportMurder;
private bool m_CriminalAggression; private bool m_CriminalAggression;

View file

@ -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
{
/// <summary>
/// Allows consumers to perform cleanup during a graceful shutdown.
/// </summary>
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<ApplicationLifetime> _logger;
public ApplicationLifetime(ILogger<ApplicationLifetime> logger) => _logger = logger;
/// <summary>
/// Triggered when the application host has fully started and is about to wait
/// for a graceful shutdown.
/// </summary>
public CancellationToken ApplicationStarted => _startedSource.Token;
/// <summary>
/// Triggered when the application host is performing a graceful shutdown.
/// Request may still be in flight. Shutdown will block until this event completes.
/// </summary>
public CancellationToken ApplicationStopping => _stoppingSource.Token;
/// <summary>
/// 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.
/// </summary>
public CancellationToken ApplicationStopped => _stoppedSource.Token;
/// <summary>
/// Signals the ApplicationStopping event and blocks until it completes.
/// </summary>
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);*/
}
}
}
/// <summary>
/// Signals the ApplicationStarted event and blocks until it completes.
/// </summary>
public void NotifyStarted()
{
try
{
ExecuteHandlers(_startedSource);
}
catch (Exception)
{
/* _logger.ApplicationError(LoggerEventIds.ApplicationStartupException,
"An error occurred starting the application",
ex);*/
}
}
/// <summary>
/// Signals the ApplicationStopped event and blocks until it completes.
/// </summary>
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);
}
}
}

Binary file not shown.

View file

@ -29,7 +29,7 @@ namespace Server
{ {
public static class AssemblyHandler public static class AssemblyHandler
{ {
private static Dictionary<Assembly, TypeCache> m_TypeCaches = new Dictionary<Assembly, TypeCache>(); private static readonly Dictionary<Assembly, TypeCache> m_TypeCaches = new Dictionary<Assembly, TypeCache>();
private static TypeCache m_NullCache; private static TypeCache m_NullCache;
public static Assembly[] Assemblies { get; set; } public static Assembly[] Assemblies { get; set; }
@ -85,10 +85,7 @@ namespace Server
List<Type> types = new List<Type>(); List<Type> types = new List<Type>();
if(ignoreCase) if(ignoreCase)
name = name.ToLower(); name = name.ToLower();
for (int i = 0; i < Assemblies.Length; i++) for (int i = 0; i < Assemblies.Length; i++) types.AddRange(GetTypeCache(Assemblies[i])[name]);
{
types.AddRange(GetTypeCache(Assemblies[i])[name]);
}
if (types.Count == 0) if (types.Count == 0)
types.AddRange(GetTypeCache(Core.Assembly)[name]); types.AddRange(GetTypeCache(Core.Assembly)[name]);
return types; return types;
@ -107,15 +104,12 @@ namespace Server
public class TypeCache public class TypeCache
{ {
private Dictionary<string, int[]> m_NameMap = new Dictionary<string, int[]>(); private readonly Dictionary<string, int[]> m_NameMap = new Dictionary<string, int[]>();
private Type[] m_Types; private readonly Type[] m_Types;
public IEnumerable<Type> Types { get => m_Types; } public IEnumerable<Type> Types => m_Types;
public IEnumerable<string> Names { get => m_NameMap.Keys; } public IEnumerable<string> Names => m_NameMap.Keys;
public IEnumerable<Type> this[string name] public IEnumerable<Type> this[string name] => m_NameMap.TryGetValue(name, out int[] value) ? value.Select(x => m_Types[x]) : new Type[0];
{
get => m_NameMap.TryGetValue(name, out int[] value) ? value.Select(x => m_Types[x]) : new Type[0];
}
public TypeCache(Assembly asm) public TypeCache(Assembly asm)
{ {

View file

@ -35,7 +35,7 @@ namespace Server
public struct Body public struct Body
{ {
private static BodyType[] m_Types; private static readonly BodyType[] m_Types;
static Body() static Body()
{ {

View file

@ -20,7 +20,7 @@ namespace System.Buffers
private readonly IMemoryOwner<byte> _memoryOwner; private readonly IMemoryOwner<byte> _memoryOwner;
private MemoryHandle? _memoryHandle; private MemoryHandle? _memoryHandle;
private Memory<byte> _memory; private readonly Memory<byte> _memory;
private readonly object _syncObj = new object(); private readonly object _syncObj = new object();
private bool _isDisposed; private bool _isDisposed;

View file

@ -5,15 +5,7 @@ namespace System.Buffers
{ {
public static class SlabMemoryPoolFactory public static class SlabMemoryPoolFactory
{ {
public static MemoryPool<byte> Create() public static MemoryPool<byte> Create() => CreateSlabMemoryPool();
{
#if DEBUG
return new DiagnosticMemoryPool(CreateSlabMemoryPool());
#else
return CreateSlabMemoryPool();
#endif
}
public static MemoryPool<byte> CreateSlabMemoryPool() => new SlabMemoryPool(); public static MemoryPool<byte> CreateSlabMemoryPool() => new SlabMemoryPool();
} }
} }

View file

@ -22,7 +22,7 @@ namespace Server.ContextMenus
{ {
public class OpenBackpackEntry : ContextMenuEntry public class OpenBackpackEntry : ContextMenuEntry
{ {
private Mobile m_Mobile; private readonly Mobile m_Mobile;
public OpenBackpackEntry(Mobile m) : base(6145) => m_Mobile = m; public OpenBackpackEntry(Mobile m) : base(6145) => m_Mobile = m;

View file

@ -22,7 +22,7 @@ namespace Server.ContextMenus
{ {
public class PaperdollEntry : ContextMenuEntry public class PaperdollEntry : ContextMenuEntry
{ {
private Mobile m_Mobile; private readonly Mobile m_Mobile;
public PaperdollEntry(Mobile m) : base(6123, 18) => m_Mobile = m; public PaperdollEntry(Mobile m) : base(6123, 18) => m_Mobile = m;

View file

@ -27,7 +27,7 @@ namespace Server.Diagnostics
{ {
public abstract class BaseProfile public abstract class BaseProfile
{ {
private Stopwatch _stopwatch; private readonly Stopwatch _stopwatch;
protected BaseProfile(string name) protected BaseProfile(string name)
{ {

View file

@ -25,7 +25,7 @@ namespace Server.Diagnostics
{ {
public class GumpProfile : BaseProfile public class GumpProfile : BaseProfile
{ {
private static Dictionary<Type, GumpProfile> _profiles = new Dictionary<Type, GumpProfile>(); private static readonly Dictionary<Type, GumpProfile> _profiles = new Dictionary<Type, GumpProfile>();
public GumpProfile(Type type) : base(type.FullName) public GumpProfile(Type type) : base(type.FullName)
{ {

View file

@ -53,7 +53,7 @@ namespace Server.Diagnostics
public class PacketSendProfile : BasePacketProfile public class PacketSendProfile : BasePacketProfile
{ {
private static Dictionary<Type, PacketSendProfile> _profiles = new Dictionary<Type, PacketSendProfile>(); private static readonly Dictionary<Type, PacketSendProfile> _profiles = new Dictionary<Type, PacketSendProfile>();
private long _created; private long _created;
@ -87,7 +87,7 @@ namespace Server.Diagnostics
public class PacketReceiveProfile : BasePacketProfile public class PacketReceiveProfile : BasePacketProfile
{ {
private static Dictionary<int, PacketReceiveProfile> _profiles = new Dictionary<int, PacketReceiveProfile>(); private static readonly Dictionary<int, PacketReceiveProfile> _profiles = new Dictionary<int, PacketReceiveProfile>();
public PacketReceiveProfile(int packetId) public PacketReceiveProfile(int packetId)
: base($"0x{packetId:X2}") : base($"0x{packetId:X2}")

View file

@ -25,7 +25,7 @@ namespace Server.Diagnostics
{ {
public class TargetProfile : BaseProfile public class TargetProfile : BaseProfile
{ {
private static Dictionary<Type, TargetProfile> _profiles = new Dictionary<Type, TargetProfile>(); private static readonly Dictionary<Type, TargetProfile> _profiles = new Dictionary<Type, TargetProfile>();
public TargetProfile(Type type) public TargetProfile(Type type)
: base(type.FullName) : base(type.FullName)

View file

@ -25,7 +25,7 @@ namespace Server.Diagnostics
{ {
public class TimerProfile : BaseProfile public class TimerProfile : BaseProfile
{ {
private static Dictionary<string, TimerProfile> _profiles = new Dictionary<string, TimerProfile>(); private static readonly Dictionary<string, TimerProfile> _profiles = new Dictionary<string, TimerProfile>();
public TimerProfile(string name) public TimerProfile(string name)
: base(name) : base(name)

View file

@ -196,7 +196,7 @@ namespace Server
public class AggressiveActionEventArgs : EventArgs public class AggressiveActionEventArgs : EventArgs
{ {
private static Queue<AggressiveActionEventArgs> m_Pool = new Queue<AggressiveActionEventArgs>(); private static readonly Queue<AggressiveActionEventArgs> m_Pool = new Queue<AggressiveActionEventArgs>();
private AggressiveActionEventArgs(Mobile aggressed, Mobile aggressor, bool criminal) private AggressiveActionEventArgs(Mobile aggressed, Mobile aggressor, bool criminal)
{ {
@ -512,7 +512,7 @@ namespace Server
public class MovementEventArgs : EventArgs public class MovementEventArgs : EventArgs
{ {
private static Queue<MovementEventArgs> m_Pool = new Queue<MovementEventArgs>(); private static readonly Queue<MovementEventArgs> m_Pool = new Queue<MovementEventArgs>();
public MovementEventArgs(Mobile mobile, Direction dir) public MovementEventArgs(Mobile mobile, Direction dir)
{ {

View file

@ -32,7 +32,7 @@ namespace Server.Guilds
public abstract class BaseGuild : ISerializable public abstract class BaseGuild : ISerializable
{ {
private BufferWriter m_SaveBuffer; private readonly BufferWriter m_SaveBuffer;
public BufferWriter SaveBuffer => m_SaveBuffer; public BufferWriter SaveBuffer => m_SaveBuffer;
private static uint m_NextID = 1; private static uint m_NextID = 1;

View file

@ -29,13 +29,13 @@ namespace Server.Gumps
{ {
private static uint m_NextSerial = 1; private static uint m_NextSerial = 1;
private static byte[] m_BeginLayout = StringToBuffer("{ "); private static readonly byte[] m_BeginLayout = StringToBuffer("{ ");
private static byte[] m_EndLayout = StringToBuffer(" }"); private static readonly byte[] m_EndLayout = StringToBuffer(" }");
private static byte[] m_NoMove = StringToBuffer("{ nomove }"); private static readonly byte[] m_NoMove = StringToBuffer("{ nomove }");
private static byte[] m_NoClose = StringToBuffer("{ noclose }"); private static readonly byte[] m_NoClose = StringToBuffer("{ noclose }");
private static byte[] m_NoDispose = StringToBuffer("{ nodispose }"); private static readonly byte[] m_NoDispose = StringToBuffer("{ nodispose }");
private static byte[] m_NoResize = StringToBuffer("{ noresize }"); private static readonly byte[] m_NoResize = StringToBuffer("{ noresize }");
private bool m_Closable = true; private bool m_Closable = true;
private bool m_Disposable = true; private bool m_Disposable = true;
@ -43,7 +43,7 @@ namespace Server.Gumps
private bool m_Resizable = true; private bool m_Resizable = true;
private uint m_Serial; private uint m_Serial;
private List<string> m_Strings; private readonly List<string> m_Strings;
internal int m_TextEntries, m_Switches; internal int m_TextEntries, m_Switches;
private int m_X, m_Y; private int m_X, m_Y;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{ {
public class GumpAlphaRegion : GumpEntry 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_Width, m_Height;
private int m_X, m_Y; private int m_X, m_Y;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{ {
public class GumpBackground : GumpEntry 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_GumpID;
private int m_Width, m_Height; private int m_Width, m_Height;
private int m_X, m_Y; private int m_X, m_Y;

View file

@ -30,7 +30,7 @@ namespace Server.Gumps
public class GumpButton : GumpEntry 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_ButtonID;
private int m_ID1, m_ID2; private int m_ID1, m_ID2;
private int m_Param; private int m_Param;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{ {
public class GumpCheck : GumpEntry 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 int m_ID1, m_ID2;
private bool m_InitialState; private bool m_InitialState;
private int m_SwitchID; private int m_SwitchID;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{ {
public class GumpGroup : GumpEntry 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; private int m_Group;
public GumpGroup(int group) => m_Group = group; public GumpGroup(int group) => m_Group = group;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{ {
public class GumpHtml : GumpEntry 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 bool m_Background, m_Scrollbar;
private string m_Text; private string m_Text;
private int m_Width, m_Height; private int m_Width, m_Height;

View file

@ -31,9 +31,9 @@ namespace Server.Gumps
public class GumpHtmlLocalized : GumpEntry public class GumpHtmlLocalized : GumpEntry
{ {
private static byte[] m_LayoutNamePlain = Gump.StringToBuffer("xmfhtmlgump"); private static readonly byte[] m_LayoutNamePlain = Gump.StringToBuffer("xmfhtmlgump");
private static byte[] m_LayoutNameColor = Gump.StringToBuffer("xmfhtmlgumpcolor"); private static readonly byte[] m_LayoutNameColor = Gump.StringToBuffer("xmfhtmlgumpcolor");
private static byte[] m_LayoutNameArgs = Gump.StringToBuffer("xmfhtmltok"); private static readonly byte[] m_LayoutNameArgs = Gump.StringToBuffer("xmfhtmltok");
private string m_Args; private string m_Args;
private bool m_Background, m_Scrollbar; private bool m_Background, m_Scrollbar;
private int m_Color; private int m_Color;

View file

@ -24,8 +24,8 @@ namespace Server.Gumps
{ {
public class GumpImage : GumpEntry public class GumpImage : GumpEntry
{ {
private static byte[] m_LayoutName = Gump.StringToBuffer("gumppic"); private static readonly byte[] m_LayoutName = Gump.StringToBuffer("gumppic");
private static byte[] m_HueEquals = Gump.StringToBuffer(" hue="); private static readonly byte[] m_HueEquals = Gump.StringToBuffer(" hue=");
private int m_GumpID; private int m_GumpID;
private int m_Hue; private int m_Hue;
private int m_X, m_Y; private int m_X, m_Y;

View file

@ -24,8 +24,8 @@ namespace Server.Gumps
{ {
public class GumpImageTileButton : GumpEntry public class GumpImageTileButton : GumpEntry
{ {
private static byte[] m_LayoutName = Gump.StringToBuffer("buttontileart"); private static readonly byte[] m_LayoutName = Gump.StringToBuffer("buttontileart");
private static byte[] m_LayoutTooltip = Gump.StringToBuffer(" }{ tooltip"); private static readonly byte[] m_LayoutTooltip = Gump.StringToBuffer(" }{ tooltip");
private int m_ButtonID; private int m_ButtonID;
private int m_Height; private int m_Height;
private int m_Hue; private int m_Hue;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{ {
public class GumpImageTiled : GumpEntry 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_GumpID;
private int m_Width, m_Height; private int m_Width, m_Height;
private int m_X, m_Y; private int m_X, m_Y;

View file

@ -24,8 +24,8 @@ namespace Server.Gumps
{ {
public class GumpItem : GumpEntry public class GumpItem : GumpEntry
{ {
private static byte[] m_LayoutName = Gump.StringToBuffer("tilepic"); private static readonly byte[] m_LayoutName = Gump.StringToBuffer("tilepic");
private static byte[] m_LayoutNameHue = Gump.StringToBuffer("tilepichue"); private static readonly byte[] m_LayoutNameHue = Gump.StringToBuffer("tilepichue");
private int m_Hue; private int m_Hue;
private int m_ItemID; private int m_ItemID;
private int m_X, m_Y; private int m_X, m_Y;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{ {
public class GumpItemProperty : GumpEntry 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; private uint m_Serial;
public GumpItemProperty(uint serial) => m_Serial = serial; public GumpItemProperty(uint serial) => m_Serial = serial;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{ {
public class GumpLabel : GumpEntry 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 int m_Hue;
private string m_Text; private string m_Text;
private int m_X, m_Y; private int m_X, m_Y;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{ {
public class GumpLabelCropped : GumpEntry 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 int m_Hue;
private string m_Text; private string m_Text;
private int m_Width, m_Height; private int m_Width, m_Height;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{ {
public class GumpPage : GumpEntry 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; private int m_Page;
public GumpPage(int page) => m_Page = page; public GumpPage(int page) => m_Page = page;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{ {
public class GumpRadio : GumpEntry 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 int m_ID1, m_ID2;
private bool m_InitialState; private bool m_InitialState;
private int m_SwitchID; private int m_SwitchID;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{ {
public class GumpTextEntry : GumpEntry 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_EntryID;
private int m_Hue; private int m_Hue;
private string m_InitialText; private string m_InitialText;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{ {
public class GumpTextEntryLimited : GumpEntry 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_EntryID;
private int m_Hue; private int m_Hue;
private string m_InitialText; private string m_InitialText;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{ {
public class GumpTooltip : GumpEntry 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; private int m_Number;
public GumpTooltip(int number) => m_Number = number; public GumpTooltip(int number) => m_Number = number;

View file

@ -201,13 +201,13 @@ namespace Server
public class Item : IHued, IComparable<Item>, ISerializable, ISpawnable, IPropertyListObject public class Item : IHued, IComparable<Item>, ISerializable, ISpawnable, IPropertyListObject
{ {
private BufferWriter m_SaveBuffer; private readonly BufferWriter m_SaveBuffer;
public BufferWriter SaveBuffer { get { return m_SaveBuffer; } } public BufferWriter SaveBuffer => m_SaveBuffer;
public const int QuestItemHue = 0x4EA; // Hmmmm... "for EA"? public const int QuestItemHue = 0x4EA; // Hmmmm... "for EA"?
public static readonly List<Item> EmptyItems = new List<Item>(); public static readonly List<Item> EmptyItems = new List<Item>();
private static List<Item> m_DeltaQueue = new List<Item>(); private static readonly List<Item> m_DeltaQueue = new List<Item>();
private static bool _processing; private static bool _processing;

View file

@ -36,8 +36,8 @@ namespace Server.Items
public class Container : Item public class Container : Item
{ {
private static QueuePool m_QueuePool = new QueuePool(QueueRef<Container>.Generate, preGenerateCount: 2, maxRefrenceRetention: 5); private static readonly QueuePool m_QueuePool = new QueuePool(QueueRef<Container>.Generate, preGenerateCount: 2, maxRefrenceRetention: 5);
private static List<Item> m_FindItemsList = new List<Item>(); private static readonly List<Item> m_FindItemsList = new List<Item>();
private ContainerData m_ContainerData; 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) 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) if (IsDecoContainer)
{ {
@ -735,7 +735,7 @@ namespace Server.Items
private class GroupComparer : IComparer<Item> private class GroupComparer : IComparer<Item>
{ {
private CheckItemGroup m_Grouper; private readonly CheckItemGroup m_Grouper;
public GroupComparer(CheckItemGroup grouper) => m_Grouper = grouper; public GroupComparer(CheckItemGroup grouper) => m_Grouper = grouper;
@ -754,8 +754,8 @@ namespace Server.Items
private struct ItemStackEntry private struct ItemStackEntry
{ {
public Item m_StackItem; public readonly Item m_StackItem;
public Item m_DropItem; public readonly Item m_DropItem;
public ItemStackEntry(Item stack, Item drop) public ItemStackEntry(Item stack, Item drop)
{ {
@ -1536,12 +1536,10 @@ namespace Server.Items
{ {
var container = queue.Dequeue(); var container = queue.Dequeue();
foreach (var item in container.Items) foreach (var item in container.Items)
{
if (item is T typedItem && predicate?.Invoke(typedItem) != false) if (item is T typedItem && predicate?.Invoke(typedItem) != false)
items.Add(typedItem); items.Add(typedItem);
else if (recurse && item is Container itemContainer) else if (recurse && item is Container itemContainer)
queue.Enqueue(itemContainer); queue.Enqueue(itemContainer);
}
} }
return items; return items;
} }
@ -1583,7 +1581,7 @@ namespace Server.Items
public class ContainerData public class ContainerData
{ {
private static Dictionary<int, ContainerData> m_Table; private static readonly Dictionary<int, ContainerData> m_Table;
static ContainerData() static ContainerData()
{ {

View file

@ -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];
});
}
}
}

View file

@ -3,7 +3,7 @@
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Libuv namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
{ {
interface IAsyncDisposable interface IAsyncDisposable
{ {

View file

@ -4,9 +4,9 @@
using System; using System;
using Microsoft.Extensions.Logging; 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); void ConnectionRead(string connectionId, int count);

View file

@ -5,11 +5,11 @@ using System;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading; 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<TRequest> : ICriticalNotifyCompletion where TRequest : UvRequest internal class LibuvAwaitable<TRequest> : ICriticalNotifyCompletion where TRequest : UvRequest
{ {
private static readonly Action _callbackCompleted = () => { }; private static readonly Action _callbackCompleted = () => { };
@ -53,8 +53,7 @@ namespace Libuv
{ {
// There should never be a race between IsCompleted and OnCompleted since both operations // There should never be a race between IsCompleted and OnCompleted since both operations
// should always be on the libuv thread // should always be on the libuv thread
if (ReferenceEquals(_callback, _callbackCompleted)) if (ReferenceEquals(_callback, _callbackCompleted)) Debug.Fail($"{typeof(LibuvAwaitable<TRequest>)}.{nameof(OnCompleted)} raced with {nameof(IsCompleted)}, scheduling callback.");
Debug.Fail($"{typeof(LibuvAwaitable<TRequest>)}.{nameof(OnCompleted)} raced with {nameof(IsCompleted)}, scheduling callback.");
_callback = continuation; _callback = continuation;
} }
@ -65,7 +64,7 @@ namespace Libuv
} }
} }
public struct UvWriteResult internal struct UvWriteResult
{ {
public int Status { get; } public int Status { get; }
public UvException Error { get; } public UvException Error { get; }

View file

@ -8,19 +8,21 @@ using System.IO.Pipelines;
using System.Net; using System.Net;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Libuv.Internal;
using Microsoft.AspNetCore.Connections; using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
using Microsoft.Extensions.Logging; 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 int MinAllocBufferSize = SlabMemoryPool.BlockSize / 2;
private static readonly Action<UvStreamHandle, int, object> _readCallback = ReadCallback; private static readonly Action<UvStreamHandle, int, object> _readCallback =
(handle, status, state) => ReadCallback(handle, status, state);
private static readonly Func<UvStreamHandle, int, object, LibuvFunctions.uv_buf_t> _allocCallback = AllocCallback; private static readonly Func<UvStreamHandle, int, object, LibuvFunctions.uv_buf_t> _allocCallback =
(handle, suggestedSize, state) => AllocCallback(handle, suggestedSize, state);
private readonly UvStreamHandle _socket; private readonly UvStreamHandle _socket;
private readonly CancellationTokenSource _connectionClosedTokenSource = new CancellationTokenSource(); private readonly CancellationTokenSource _connectionClosedTokenSource = new CancellationTokenSource();
@ -243,7 +245,7 @@ namespace Libuv
state._waitForConnectionClosedTcs.TrySetResult(null); state._waitForConnectionClosedTcs.TrySetResult(null);
}, },
this, this,
false); preferLocal: false);
} }
private async Task ApplyBackpressureAsync(ValueTask<FlushResult> flushTask) private async Task ApplyBackpressureAsync(ValueTask<FlushResult> flushTask)
@ -282,16 +284,18 @@ namespace Libuv
// The operation was canceled by the server not the client. No need for additional logs. // The operation was canceled by the server not the client. No need for additional logs.
return new ConnectionAbortedException(uvError.Message, uvError); return new ConnectionAbortedException(uvError.Message, uvError);
} }
else if (LibuvConstants.IsConnectionReset(uvError.StatusCode))
if (LibuvConstants.IsConnectionReset(uvError.StatusCode))
{ {
// Log connection resets at a lower (Debug) level. // Log connection resets at a lower (Debug) level.
Log.ConnectionReset(ConnectionId); Log.ConnectionReset(ConnectionId);
return new ConnectionResetException(uvError.Message, uvError); return new ConnectionResetException(uvError.Message, uvError);
} }
// This is unexpected. else
Log.ConnectionError(ConnectionId, uvError); {
return new IOException(uvError.Message, uvError); // This is unexpected.
Log.ConnectionError(ConnectionId, uvError);
return new IOException(uvError.Message, uvError);
}
} }
private void CancelConnectionClosedToken() private void CancelConnectionClosedToken()

View file

@ -7,15 +7,14 @@ using System.Linq;
using System.Net; using System.Net;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Libuv.Internal;
using Microsoft.AspNetCore.Connections; using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; 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<ListenerContext> _listeners = new List<ListenerContext>(); private readonly List<ListenerContext> _listeners = new List<ListenerContext>();
private IAsyncEnumerator<LibuvConnection> _acceptEnumerator; private IAsyncEnumerator<LibuvConnection> _acceptEnumerator;
@ -63,8 +62,7 @@ namespace Libuv
var disposeTasks = _listeners.Select(listener => ((IAsyncDisposable)listener).DisposeAsync()).ToArray(); var disposeTasks = _listeners.Select(listener => ((IAsyncDisposable)listener).DisposeAsync()).ToArray();
if (!await WaitAsync(Task.WhenAll(disposeTasks), TimeSpan.FromSeconds(5)).ConfigureAwait(false)) if (!await WaitAsync(Task.WhenAll(disposeTasks), TimeSpan.FromSeconds(5)).ConfigureAwait(false)) Log.LogError(0, null, "Disposing listeners failed");
Log.LogError(0, null, "Disposing listeners failed");
} }
@ -101,14 +99,9 @@ namespace Libuv
} }
Threads.Clear(); 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: Move thread management to LibuvTransportFactory
// TODO: Split endpoint management from thread management // TODO: Split endpoint management from thread management
@ -127,7 +120,7 @@ namespace Libuv
} }
else 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 pipeMessage = Guid.NewGuid().ToByteArray();
var listenerPrimary = new ListenerPrimary(TransportContext); var listenerPrimary = new ListenerPrimary(TransportContext);
@ -171,7 +164,7 @@ namespace Libuv
while (remainingSlots > 0) while (remainingSlots > 0)
{ {
// Calling GetAwaiter().GetResult() is safe because we know the task is completed // 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 the connection is null then the listener was closed
if (connection == null) if (connection == null)

View file

@ -2,11 +2,11 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Runtime.CompilerServices; 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 const int EOF = -4095;
public static readonly int? ECONNRESET = GetECONNRESET(); public static readonly int? ECONNRESET = GetECONNRESET();
@ -22,76 +22,69 @@ namespace Libuv
private static int? GetECONNRESET() private static int? GetECONNRESET()
{ {
if (Core.IsWindows) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return -4077; return -4077;
if (Core.IsLinux) else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return -104; return -104;
if (Core.IsDarwin) else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return -54;
return -5;
return null; return null;
} }
private static int? GetEPIPE() private static int? GetEPIPE()
{ {
if (Core.IsWindows) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return -4047; return -4047;
if (Core.IsLinux) else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return -32;
if (Core.IsDarwin)
return -32; return -32;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return -32;
return null; return null;
} }
private static int? GetENOTCONN() private static int? GetENOTCONN()
{ {
if (Core.IsWindows) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return -4053; return -4053;
if (Core.IsLinux) else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return -107; return -107;
if (Core.IsDarwin) else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return -57;
return -57;
return null; return null;
} }
private static int? GetEINVAL() private static int? GetEINVAL()
{ {
if (Core.IsWindows) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return -4071; return -4071;
if (Core.IsLinux) else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return -22;
if (Core.IsDarwin)
return -22; return -22;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return -22;
return null; return null;
} }
private static int? GetEADDRINUSE() private static int? GetEADDRINUSE()
{ {
if (Core.IsWindows) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return -4091; return -4091;
if (Core.IsLinux) else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return -98; return -98;
if (Core.IsDarwin) else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return -48;
return -48;
return null; return null;
} }
private static int? GetENOTSUP() private static int? GetENOTSUP()
{ {
if (Core.IsLinux) if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return -95; return -95;
if (Core.IsDarwin) else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return -45;
return -45;
return null; return null;
} }
private static int? GetECANCELED() private static int? GetECANCELED()
{ {
if (Core.IsWindows) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return -4081; return -4081;
if (Core.IsLinux) else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return -125; return -125;
if (Core.IsDarwin) else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return -89;
return -89;
return null; return null;
} }
} }

View file

@ -4,11 +4,11 @@
using System; using System;
using System.IO.Pipelines; using System.IO.Pipelines;
using System.Threading.Tasks; 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 LibuvThread _thread;
private readonly UvStreamHandle _socket; private readonly UvStreamHandle _socket;

View file

@ -9,13 +9,13 @@ using System.IO.Pipelines;
using System.Runtime.ExceptionServices; using System.Runtime.ExceptionServices;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Libuv.Internal; using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; 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 // 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 // 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 _workSync = new object();
private readonly object _closeHandleSync = new object(); private readonly object _closeHandleSync = new object();
private readonly object _startSync = new object(); private readonly object _startSync = new object();
private bool _stopImmediate; private bool _stopImmediate = false;
private bool _initCompleted; private bool _initCompleted = false;
private Exception _closeError; private Exception _closeError;
private readonly ILibuvTrace _log; private readonly ILibuvTrace _log;
@ -60,9 +60,9 @@ namespace Libuv
#endif #endif
#if !DEBUG #if !DEBUG
// Mark the thread as being as unimportant to keeping the process alive. // 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. // Don't do this for debug builds, so we know if the thread isn't terminating.
_thread.IsBackground = true; _thread.IsBackground = true;
#endif #endif
QueueCloseHandle = PostCloseHandle; QueueCloseHandle = PostCloseHandle;
QueueCloseAsyncHandle = EnqueueCloseHandle; QueueCloseAsyncHandle = EnqueueCloseHandle;
@ -76,10 +76,6 @@ namespace Libuv
public WriteReqPool WriteReqPool { get; } public WriteReqPool WriteReqPool { get; }
#if DEBUG
public List<WeakReference> Requests { get; } = new List<WeakReference>();
#endif
public Exception FatalError => _closeError; public Exception FatalError => _closeError;
public Action<Action<IntPtr>, IntPtr> QueueCloseHandle { get; } public Action<Action<IntPtr>, IntPtr> QueueCloseHandle { get; }
@ -129,18 +125,6 @@ namespace Libuv
if (_closeError != null) ExceptionDispatchInfo.Capture(_closeError).Throw(); 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() private void AllowStop()
{ {
_post.Unreference(); _post.Unreference();
@ -320,11 +304,6 @@ namespace Libuv
} }
WriteReqPool.Dispose(); WriteReqPool.Dispose();
_threadTcs.SetResult(null); _threadTcs.SetResult(null);
#if DEBUG && !INNER_LOOP
// Check for handle leaks after disposing everything
CheckUvReqLeaks();
#endif
} }
} }
@ -406,8 +385,7 @@ namespace Libuv
return wasWork; return wasWork;
} }
private static async Task<bool> WaitAsync(Task task, TimeSpan timeout) => private static async Task<bool> WaitAsync(Task task, TimeSpan timeout) => await Task.WhenAny(task, Task.Delay(timeout)).ConfigureAwait(false) == task;
await Task.WhenAny(task, Task.Delay(timeout)).ConfigureAwait(false) == task;
public override void Schedule(Action<object> action, object state) public override void Schedule(Action<object> action, object state)
{ {

View file

@ -4,9 +4,9 @@
using System; using System;
using Microsoft.Extensions.Logging; 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 // ConnectionRead: Reserved: 3

View file

@ -3,9 +3,9 @@
using Microsoft.Extensions.Hosting; 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; } public LibuvTransportOptions Options { get; set; }

View file

@ -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<LibuvTransportOptions> 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<IConnectionListener> 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;
}
}
}

View file

@ -5,16 +5,16 @@ using System;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading.Tasks; using System.Threading.Tasks;
using Libuv.Internal;
using Microsoft.AspNetCore.Connections; using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace Libuv namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
{ {
/// <summary> /// <summary>
/// Base class for listeners in Kestrel. Listens for incoming connections /// Base class for listeners in Kestrel. Listens for incoming connections
/// </summary> /// </summary>
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 // REVIEW: This needs to be bounded and we need a strategy for what to do when the queue is full
private bool _closed; private bool _closed;
@ -46,13 +46,17 @@ namespace Libuv
/// </summary> /// </summary>
private UvStreamHandle CreateListenSocket() private UvStreamHandle CreateListenSocket()
{ {
return EndPoint switch switch (EndPoint)
{ {
IPEndPoint _ => ListenTcp(false), case IPEndPoint _:
UnixDomainSocketEndPoint _ => ListenPipe(false), return ListenTcp(useFileHandle: false);
FileHandleEndPoint _ => ListenHandle(), case UnixDomainSocketEndPoint _:
_ => throw new NotSupportedException() return ListenPipe(useFileHandle: false);
}; case FileHandleEndPoint _:
return ListenHandle();
default:
throw new NotSupportedException();
}
} }
private UvTcpHandle ListenTcp(bool useFileHandle) private UvTcpHandle ListenTcp(bool useFileHandle)
@ -62,7 +66,7 @@ namespace Libuv
try try
{ {
socket.Init(Thread.Loop, Thread.QueueCloseHandle); socket.Init(Thread.Loop, Thread.QueueCloseHandle);
socket.NoDelay(true); socket.NoDelay(TransportContext.Options.NoDelay);
if (!useFileHandle) if (!useFileHandle)
{ {
@ -117,9 +121,9 @@ namespace Libuv
case FileHandleType.Auto: case FileHandleType.Auto:
break; break;
case FileHandleType.Tcp: case FileHandleType.Tcp:
return ListenTcp(true); return ListenTcp(useFileHandle: true);
case FileHandleType.Pipe: case FileHandleType.Pipe:
return ListenPipe(true); return ListenPipe(useFileHandle: true);
default: default:
throw new NotSupportedException(); throw new NotSupportedException();
} }
@ -127,7 +131,7 @@ namespace Libuv
UvStreamHandle handle; UvStreamHandle handle;
try try
{ {
handle = ListenTcp(true); handle = ListenTcp(useFileHandle: true);
EndPoint = new FileHandleEndPoint(handleEndPoint.FileHandle, FileHandleType.Tcp); EndPoint = new FileHandleEndPoint(handleEndPoint.FileHandle, FileHandleType.Tcp);
return handle; return handle;
} }
@ -136,7 +140,7 @@ namespace Libuv
Log.LogDebug(0, exception, "Listener.ListenHandle"); Log.LogDebug(0, exception, "Listener.ListenHandle");
} }
handle = ListenPipe(true); handle = ListenPipe(useFileHandle: true);
EndPoint = new FileHandleEndPoint(handleEndPoint.FileHandle, FileHandleType.Pipe); EndPoint = new FileHandleEndPoint(handleEndPoint.FileHandle, FileHandleType.Pipe);
return handle; return handle;
} }

View file

@ -9,13 +9,13 @@ using System.Net.Sockets;
using System.Threading; using System.Threading;
using System.Threading.Channels; using System.Threading.Channels;
using System.Threading.Tasks; using System.Threading.Tasks;
using Libuv.Internal;
using Microsoft.AspNetCore.Connections; using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
using Microsoft.Extensions.Logging; 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 // Single reader, single writer queue since all writes happen from the uv thread and reads happen sequentially
private readonly Channel<LibuvConnection> _acceptQueue = Channel.CreateUnbounded<LibuvConnection>(new UnboundedChannelOptions private readonly Channel<LibuvConnection> _acceptQueue = Channel.CreateUnbounded<LibuvConnection>(new UnboundedChannelOptions
@ -115,7 +115,7 @@ namespace Libuv
try try
{ {
socket.Init(Thread.Loop, Thread.QueueCloseHandle); socket.Init(Thread.Loop, Thread.QueueCloseHandle);
socket.NoDelay(true); socket.NoDelay(TransportContext.Options.NoDelay);
} }
catch catch
{ {
@ -152,17 +152,14 @@ namespace Libuv
{ {
var fileHandleEndPoint = (FileHandleEndPoint)EndPoint; var fileHandleEndPoint = (FileHandleEndPoint)EndPoint;
switch (fileHandleEndPoint.FileHandleType) return fileHandleEndPoint.FileHandleType switch
{ {
case FileHandleType.Auto: FileHandleType.Auto => throw new InvalidOperationException(
throw new InvalidOperationException("Cannot accept on a non-specific file handle, listen should be performed first."); "Cannot accept on a non-specific file handle, listen should be performed first."),
case FileHandleType.Tcp: FileHandleType.Tcp => (UvStreamHandle)AcceptTcp(),
return AcceptTcp(); FileHandleType.Pipe => AcceptPipe(),
case FileHandleType.Pipe: _ => throw new NotSupportedException()
return AcceptPipe(); };
default:
throw new NotSupportedException();
}
} }
} }
} }

View file

@ -7,19 +7,16 @@ using System.IO;
using System.Net; using System.Net;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using Libuv.Internal; using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Server;
#pragma warning disable 169 namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
namespace Libuv
{ {
/// <summary> /// <summary>
/// A primary listener waits for incoming connections on a specified socket. Incoming /// A primary listener waits for incoming connections on a specified socket. Incoming
/// connections may be passed to a secondary listener to handle. /// connections may be passed to a secondary listener to handle.
/// </summary> /// </summary>
public class ListenerPrimary : Listener internal class ListenerPrimary : Listener
{ {
// The list of pipes that can be dispatched to (where we've confirmed the _pipeMessage) // The list of pipes that can be dispatched to (where we've confirmed the _pipeMessage)
private readonly List<UvPipeHandle> _dispatchPipes = new List<UvPipeHandle>(); private readonly List<UvPipeHandle> _dispatchPipes = new List<UvPipeHandle>();
@ -29,7 +26,7 @@ namespace Libuv
private string _pipeName; private string _pipeName;
private byte[] _pipeMessage; private byte[] _pipeMessage;
private IntPtr _fileCompletionInfoPtr; 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, // this message is passed to write2 because it must be non-zero-length,
// but it has no other functional significance // but it has no other functional significance
@ -151,15 +148,17 @@ namespace Libuv
Thread.Loop.Libuv.uv_fileno(handle, ref socket); Thread.Loop.Libuv.uv_fileno(handle, ref socket);
if (NtSetInformationFile(socket, out statusBlock, _fileCompletionInfoPtr, if (NtSetInformationFile(socket, out statusBlock, _fileCompletionInfoPtr,
(uint)Marshal.SizeOf<FILE_COMPLETION_INFORMATION>(), FileReplaceCompletionInformation) == STATUS_INVALID_INFO_CLASS) (uint)Marshal.SizeOf<FILE_COMPLETION_INFORMATION>(), FileReplaceCompletionInformation) == STATUS_INVALID_INFO_CLASS)
// Replacing IOCP information is only supported on Windows 8.1 or newer // Replacing IOCP information is only supported on Windows 8.1 or newer
_tryDetachFromIOCP = false; _tryDetachFromIOCP = false;
} }
private struct IO_STATUS_BLOCK private struct IO_STATUS_BLOCK
{ {
#pragma warning disable 169
uint status; uint status;
ulong information; ulong information;
#pragma warning restore 169
} }
private struct FILE_COMPLETION_INFORMATION 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 // 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. // 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(); dispatchPipe.Dispose();
_bufHandle.Free(); _bufHandle.Free();

View file

@ -6,16 +6,16 @@ using System.Net;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Libuv.Internal; using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace Libuv namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
{ {
/// <summary> /// <summary>
/// A secondary listener is delegated requests from a primary listener via a named pipe or /// A secondary listener is delegated requests from a primary listener via a named pipe or
/// UNIX domain socket. /// UNIX domain socket.
/// </summary> /// </summary>
public class ListenerSecondary : ListenerContext, IAsyncDisposable internal class ListenerSecondary : ListenerContext, IAsyncDisposable
{ {
private string _pipeName; private string _pipeName;
private byte[] _pipeMessage; private byte[] _pipeMessage;

View file

@ -4,14 +4,15 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; 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() public LibuvFunctions()
{ {
IsWindows = PlatformApis.IsWindows;
_uv_loop_init = NativeMethods.uv_loop_init; _uv_loop_init = NativeMethods.uv_loop_init;
_uv_loop_close = NativeMethods.uv_loop_close; _uv_loop_close = NativeMethods.uv_loop_close;
_uv_run = NativeMethods.uv_run; _uv_run = NativeMethods.uv_run;
@ -63,6 +64,8 @@ namespace Libuv.Internal
{ {
} }
public readonly bool IsWindows;
public void ThrowIfErrored(int statusCode) public void ThrowIfErrored(int statusCode)
{ {
// Note: method is explicitly small so the success case is easily inlined // 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; 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)] [MethodImpl(MethodImplOptions.NoInlining)]
private UvException GetError(int statusCode) => private UvException GetError(int statusCode)
new UvException($"Error {statusCode} {err_name(statusCode)} {strerror(statusCode)}", 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<UvLoopHandle, int> _uv_loop_init; protected Func<UvLoopHandle, int> _uv_loop_init;
public void loop_init(UvLoopHandle handle) public void loop_init(UvLoopHandle handle)
{ {
ThrowIfErrored(_uv_loop_init(handle)); ThrowIfErrored(_uv_loop_init(handle));
} }
public Func<IntPtr, int> _uv_loop_close; protected Func<IntPtr, int> _uv_loop_close;
public void loop_close(UvLoopHandle handle) public void loop_close(UvLoopHandle handle)
{ {
handle.Validate(true); handle.Validate(closed: true);
ThrowIfErrored(_uv_loop_close(handle.InternalGetHandle())); ThrowIfErrored(_uv_loop_close(handle.InternalGetHandle()));
} }
public Func<UvLoopHandle, int, int> _uv_run; protected Func<UvLoopHandle, int, int> _uv_run;
public void run(UvLoopHandle handle, int mode) public void run(UvLoopHandle handle, int mode)
{ {
handle.Validate(); handle.Validate();
ThrowIfErrored(_uv_run(handle, mode)); ThrowIfErrored(_uv_run(handle, mode));
} }
public Action<UvLoopHandle> _uv_stop; protected Action<UvLoopHandle> _uv_stop;
public void stop(UvLoopHandle handle) public void stop(UvLoopHandle handle)
{ {
handle.Validate(); handle.Validate();
_uv_stop(handle); _uv_stop(handle);
} }
public Action<UvHandle> _uv_ref; protected Action<UvHandle> _uv_ref;
public void @ref(UvHandle handle) public void @ref(UvHandle handle)
{ {
handle.Validate(); handle.Validate();
_uv_ref(handle); _uv_ref(handle);
} }
public Action<UvHandle> _uv_unref; protected Action<UvHandle> _uv_unref;
public void unref(UvHandle handle) public void unref(UvHandle handle)
{ {
handle.Validate(); handle.Validate();
@ -131,8 +138,8 @@ namespace Libuv.Internal
} }
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int uv_fileno_func(UvHandle handle, ref IntPtr socket); protected delegate int uv_fileno_func(UvHandle handle, ref IntPtr socket);
public uv_fileno_func _uv_fileno; protected uv_fileno_func _uv_fileno;
public void uv_fileno(UvHandle handle, ref IntPtr socket) public void uv_fileno(UvHandle handle, ref IntPtr socket)
{ {
handle.Validate(); handle.Validate();
@ -141,10 +148,10 @@ namespace Libuv.Internal
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void uv_close_cb(IntPtr handle); public delegate void uv_close_cb(IntPtr handle);
public Action<IntPtr, uv_close_cb> _uv_close; protected Action<IntPtr, uv_close_cb> _uv_close;
public void close(UvHandle handle, uv_close_cb close_cb) public void close(UvHandle handle, uv_close_cb close_cb)
{ {
handle.Validate(true); handle.Validate(closed: true);
_uv_close(handle.InternalGetHandle(), close_cb); _uv_close(handle.InternalGetHandle(), close_cb);
} }
@ -155,7 +162,7 @@ namespace Libuv.Internal
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void uv_async_cb(IntPtr handle); public delegate void uv_async_cb(IntPtr handle);
public Func<UvLoopHandle, UvAsyncHandle, uv_async_cb, int> _uv_async_init; protected Func<UvLoopHandle, UvAsyncHandle, uv_async_cb, int> _uv_async_init;
public void async_init(UvLoopHandle loop, UvAsyncHandle handle, uv_async_cb cb) public void async_init(UvLoopHandle loop, UvAsyncHandle handle, uv_async_cb cb)
{ {
loop.Validate(); loop.Validate();
@ -163,19 +170,19 @@ namespace Libuv.Internal
ThrowIfErrored(_uv_async_init(loop, handle, cb)); ThrowIfErrored(_uv_async_init(loop, handle, cb));
} }
public Func<UvAsyncHandle, int> _uv_async_send; protected Func<UvAsyncHandle, int> _uv_async_send;
public void async_send(UvAsyncHandle handle) public void async_send(UvAsyncHandle handle)
{ {
ThrowIfErrored(_uv_async_send(handle)); ThrowIfErrored(_uv_async_send(handle));
} }
public Func<IntPtr, int> _uv_unsafe_async_send; protected Func<IntPtr, int> _uv_unsafe_async_send;
public void unsafe_async_send(IntPtr handle) public void unsafe_async_send(IntPtr handle)
{ {
ThrowIfErrored(_uv_unsafe_async_send(handle)); ThrowIfErrored(_uv_unsafe_async_send(handle));
} }
public Func<UvLoopHandle, UvTcpHandle, int> _uv_tcp_init; protected Func<UvLoopHandle, UvTcpHandle, int> _uv_tcp_init;
public void tcp_init(UvLoopHandle loop, UvTcpHandle handle) public void tcp_init(UvLoopHandle loop, UvTcpHandle handle)
{ {
loop.Validate(); loop.Validate();
@ -183,29 +190,29 @@ namespace Libuv.Internal
ThrowIfErrored(_uv_tcp_init(loop, handle)); ThrowIfErrored(_uv_tcp_init(loop, handle));
} }
public delegate int uv_tcp_bind_func(UvTcpHandle handle, ref SockAddr addr, int flags); protected delegate int uv_tcp_bind_func(UvTcpHandle handle, ref SockAddr addr, int flags);
public uv_tcp_bind_func _uv_tcp_bind; protected uv_tcp_bind_func _uv_tcp_bind;
public void tcp_bind(UvTcpHandle handle, ref SockAddr addr, int flags) public void tcp_bind(UvTcpHandle handle, ref SockAddr addr, int flags)
{ {
handle.Validate(); handle.Validate();
ThrowIfErrored(_uv_tcp_bind(handle, ref addr, flags)); ThrowIfErrored(_uv_tcp_bind(handle, ref addr, flags));
} }
public Func<UvTcpHandle, IntPtr, int> _uv_tcp_open; protected Func<UvTcpHandle, IntPtr, int> _uv_tcp_open;
public void tcp_open(UvTcpHandle handle, IntPtr hSocket) public void tcp_open(UvTcpHandle handle, IntPtr hSocket)
{ {
handle.Validate(); handle.Validate();
ThrowIfErrored(_uv_tcp_open(handle, hSocket)); ThrowIfErrored(_uv_tcp_open(handle, hSocket));
} }
public Func<UvTcpHandle, int, int> _uv_tcp_nodelay; protected Func<UvTcpHandle, int, int> _uv_tcp_nodelay;
public void tcp_nodelay(UvTcpHandle handle, bool enable) public void tcp_nodelay(UvTcpHandle handle, bool enable)
{ {
handle.Validate(); handle.Validate();
ThrowIfErrored(_uv_tcp_nodelay(handle, enable ? 1 : 0)); ThrowIfErrored(_uv_tcp_nodelay(handle, enable ? 1 : 0));
} }
public Func<UvLoopHandle, UvPipeHandle, int, int> _uv_pipe_init; protected Func<UvLoopHandle, UvPipeHandle, int, int> _uv_pipe_init;
public void pipe_init(UvLoopHandle loop, UvPipeHandle handle, bool ipc) public void pipe_init(UvLoopHandle loop, UvPipeHandle handle, bool ipc)
{ {
loop.Validate(); loop.Validate();
@ -213,14 +220,14 @@ namespace Libuv.Internal
ThrowIfErrored(_uv_pipe_init(loop, handle, ipc ? -1 : 0)); ThrowIfErrored(_uv_pipe_init(loop, handle, ipc ? -1 : 0));
} }
public Func<UvPipeHandle, string, int> _uv_pipe_bind; protected Func<UvPipeHandle, string, int> _uv_pipe_bind;
public void pipe_bind(UvPipeHandle handle, string name) public void pipe_bind(UvPipeHandle handle, string name)
{ {
handle.Validate(); handle.Validate();
ThrowIfErrored(_uv_pipe_bind(handle, name)); ThrowIfErrored(_uv_pipe_bind(handle, name));
} }
public Func<UvPipeHandle, IntPtr, int> _uv_pipe_open; protected Func<UvPipeHandle, IntPtr, int> _uv_pipe_open;
public void pipe_open(UvPipeHandle handle, IntPtr hSocket) public void pipe_open(UvPipeHandle handle, IntPtr hSocket)
{ {
handle.Validate(); handle.Validate();
@ -229,14 +236,14 @@ namespace Libuv.Internal
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void uv_connection_cb(IntPtr server, int status); public delegate void uv_connection_cb(IntPtr server, int status);
public Func<UvStreamHandle, int, uv_connection_cb, int> _uv_listen; protected Func<UvStreamHandle, int, uv_connection_cb, int> _uv_listen;
public void listen(UvStreamHandle handle, int backlog, uv_connection_cb cb) public void listen(UvStreamHandle handle, int backlog, uv_connection_cb cb)
{ {
handle.Validate(); handle.Validate();
ThrowIfErrored(_uv_listen(handle, backlog, cb)); ThrowIfErrored(_uv_listen(handle, backlog, cb));
} }
public Func<UvStreamHandle, UvStreamHandle, int> _uv_accept; protected Func<UvStreamHandle, UvStreamHandle, int> _uv_accept;
public void accept(UvStreamHandle server, UvStreamHandle client) public void accept(UvStreamHandle server, UvStreamHandle client)
{ {
server.Validate(); server.Validate();
@ -246,7 +253,7 @@ namespace Libuv.Internal
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void uv_connect_cb(IntPtr req, int status); public delegate void uv_connect_cb(IntPtr req, int status);
public Action<UvConnectRequest, UvPipeHandle, string, uv_connect_cb> _uv_pipe_connect; protected Action<UvConnectRequest, UvPipeHandle, string, uv_connect_cb> _uv_pipe_connect;
public void pipe_connect(UvConnectRequest req, UvPipeHandle handle, string name, uv_connect_cb cb) public void pipe_connect(UvConnectRequest req, UvPipeHandle handle, string name, uv_connect_cb cb)
{ {
req.Validate(); req.Validate();
@ -254,7 +261,7 @@ namespace Libuv.Internal
_uv_pipe_connect(req, handle, name, cb); _uv_pipe_connect(req, handle, name, cb);
} }
public Func<UvPipeHandle, int> _uv_pipe_pending_count; protected Func<UvPipeHandle, int> _uv_pipe_pending_count;
public int pipe_pending_count(UvPipeHandle handle) public int pipe_pending_count(UvPipeHandle handle)
{ {
handle.Validate(); 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); public delegate void uv_alloc_cb(IntPtr server, int suggested_size, out uv_buf_t buf);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void uv_read_cb(IntPtr server, int nread, ref uv_buf_t buf); public delegate void uv_read_cb(IntPtr server, int nread, ref uv_buf_t buf);
public Func<UvStreamHandle, uv_alloc_cb, uv_read_cb, int> _uv_read_start; protected Func<UvStreamHandle, uv_alloc_cb, uv_read_cb, int> _uv_read_start;
public void read_start(UvStreamHandle handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb) public void read_start(UvStreamHandle handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb)
{ {
handle.Validate(); handle.Validate();
ThrowIfErrored(_uv_read_start(handle, alloc_cb, read_cb)); ThrowIfErrored(_uv_read_start(handle, alloc_cb, read_cb));
} }
public Func<UvStreamHandle, int> _uv_read_stop; protected Func<UvStreamHandle, int> _uv_read_stop;
public void read_stop(UvStreamHandle handle) public void read_stop(UvStreamHandle handle)
{ {
handle.Validate(); handle.Validate();
ThrowIfErrored(_uv_read_stop(handle)); ThrowIfErrored(_uv_read_stop(handle));
} }
public Func<UvStreamHandle, uv_buf_t[], int, int> _uv_try_write; protected Func<UvStreamHandle, uv_buf_t[], int, int> _uv_try_write;
public int try_write(UvStreamHandle handle, uv_buf_t[] bufs, int nbufs) public int try_write(UvStreamHandle handle, uv_buf_t[] bufs, int nbufs)
{ {
handle.Validate(); handle.Validate();
@ -291,8 +298,8 @@ namespace Libuv.Internal
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void uv_write_cb(IntPtr req, int status); 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); protected 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 uv_write_func _uv_write;
public unsafe void write(UvRequest req, UvStreamHandle handle, uv_buf_t* bufs, int nbufs, uv_write_cb cb) public unsafe void write(UvRequest req, UvStreamHandle handle, uv_buf_t* bufs, int nbufs, uv_write_cb cb)
{ {
req.Validate(); req.Validate();
@ -300,8 +307,8 @@ namespace Libuv.Internal
ThrowIfErrored(_uv_write(req, handle, bufs, nbufs, cb)); 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); protected 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 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) public unsafe void write2(UvRequest req, UvStreamHandle handle, uv_buf_t* bufs, int nbufs, UvStreamHandle sendHandle, uv_write_cb cb)
{ {
req.Validate(); req.Validate();
@ -309,38 +316,38 @@ namespace Libuv.Internal
ThrowIfErrored(_uv_write2(req, handle, bufs, nbufs, sendHandle, cb)); ThrowIfErrored(_uv_write2(req, handle, bufs, nbufs, sendHandle, cb));
} }
public Func<int, IntPtr> _uv_err_name; protected Func<int, IntPtr> _uv_err_name;
public string err_name(int err) public string err_name(int err)
{ {
IntPtr ptr = _uv_err_name(err); IntPtr ptr = _uv_err_name(err);
return ptr == IntPtr.Zero ? null : Marshal.PtrToStringAnsi(ptr); return ptr == IntPtr.Zero ? null : Marshal.PtrToStringAnsi(ptr);
} }
public Func<int, IntPtr> _uv_strerror; protected Func<int, IntPtr> _uv_strerror;
public string strerror(int err) public string strerror(int err)
{ {
IntPtr ptr = _uv_strerror(err); IntPtr ptr = _uv_strerror(err);
return ptr == IntPtr.Zero ? null : Marshal.PtrToStringAnsi(ptr); return ptr == IntPtr.Zero ? null : Marshal.PtrToStringAnsi(ptr);
} }
public Func<int> _uv_loop_size; protected Func<int> _uv_loop_size;
public int loop_size() => _uv_loop_size(); public int loop_size() => _uv_loop_size();
public Func<HandleType, int> _uv_handle_size; protected Func<HandleType, int> _uv_handle_size;
public int handle_size(HandleType handleType) => _uv_handle_size(handleType); public int handle_size(HandleType handleType) => _uv_handle_size(handleType);
public Func<RequestType, int> _uv_req_size; protected Func<RequestType, int> _uv_req_size;
public int req_size(RequestType reqType) => _uv_req_size(reqType); public int req_size(RequestType reqType) => _uv_req_size(reqType);
public delegate int uv_ip4_addr_func(string ip, int port, out SockAddr addr); protected delegate int uv_ip4_addr_func(string ip, int port, out SockAddr addr);
public uv_ip4_addr_func _uv_ip4_addr; protected uv_ip4_addr_func _uv_ip4_addr;
public void ip4_addr(string ip, int port, out SockAddr addr, out UvException error) public void ip4_addr(string ip, int port, out SockAddr addr, out UvException error)
{ {
Check(_uv_ip4_addr(ip, port, out addr), out 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); protected delegate int uv_ip6_addr_func(string ip, int port, out SockAddr addr);
public uv_ip6_addr_func _uv_ip6_addr; protected uv_ip6_addr_func _uv_ip6_addr;
public void ip6_addr(string ip, int port, out SockAddr addr, out UvException error) public void ip6_addr(string ip, int port, out SockAddr addr, out UvException error)
{ {
Check(_uv_ip6_addr(ip, port, out addr), out error); Check(_uv_ip6_addr(ip, port, out addr), out error);
@ -348,15 +355,15 @@ namespace Libuv.Internal
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void uv_walk_cb(IntPtr handle, IntPtr arg); public delegate void uv_walk_cb(IntPtr handle, IntPtr arg);
public Func<UvLoopHandle, uv_walk_cb, IntPtr, int> _uv_walk; protected Func<UvLoopHandle, uv_walk_cb, IntPtr, int> _uv_walk;
public void walk(UvLoopHandle loop, uv_walk_cb walk_cb, IntPtr arg) public void walk(UvLoopHandle loop, uv_walk_cb walk_cb, IntPtr arg)
{ {
loop.Validate(); loop.Validate();
_uv_walk(loop, walk_cb, arg); _uv_walk(loop, walk_cb, arg);
} }
public Func<UvLoopHandle, UvTimerHandle, int> _uv_timer_init; protected Func<UvLoopHandle, UvTimerHandle, int> _uv_timer_init;
public void timer_init(UvLoopHandle loop, UvTimerHandle handle) public unsafe void timer_init(UvLoopHandle loop, UvTimerHandle handle)
{ {
loop.Validate(); loop.Validate();
handle.Validate(); handle.Validate();
@ -365,29 +372,29 @@ namespace Libuv.Internal
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void uv_timer_cb(IntPtr handle); public delegate void uv_timer_cb(IntPtr handle);
public Func<UvTimerHandle, uv_timer_cb, long, long, int> _uv_timer_start; protected Func<UvTimerHandle, uv_timer_cb, long, long, int> _uv_timer_start;
public void timer_start(UvTimerHandle handle, uv_timer_cb cb, long timeout, long repeat) public unsafe void timer_start(UvTimerHandle handle, uv_timer_cb cb, long timeout, long repeat)
{ {
handle.Validate(); handle.Validate();
ThrowIfErrored(_uv_timer_start(handle, cb, timeout, repeat)); ThrowIfErrored(_uv_timer_start(handle, cb, timeout, repeat));
} }
public Func<UvTimerHandle, int> _uv_timer_stop; protected Func<UvTimerHandle, int> _uv_timer_stop;
public void timer_stop(UvTimerHandle handle) public unsafe void timer_stop(UvTimerHandle handle)
{ {
handle.Validate(); handle.Validate();
ThrowIfErrored(_uv_timer_stop(handle)); ThrowIfErrored(_uv_timer_stop(handle));
} }
public Func<UvLoopHandle, long> _uv_now; protected Func<UvLoopHandle, long> _uv_now;
public long now(UvLoopHandle loop) public unsafe long now(UvLoopHandle loop)
{ {
loop.Validate(); loop.Validate();
return _uv_now(loop); return _uv_now(loop);
} }
public delegate int uv_tcp_getsockname_func(UvTcpHandle handle, out SockAddr addr, ref int namelen); 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) public void tcp_getsockname(UvTcpHandle handle, out SockAddr addr, ref int namelen)
{ {
handle.Validate(); 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 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) public void tcp_getpeername(UvTcpHandle handle, out SockAddr addr, ref int namelen)
{ {
handle.Validate(); handle.Validate();
ThrowIfErrored(_uv_tcp_getpeername(handle, out addr, ref namelen)); 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 public struct uv_buf_t
{ {
@ -417,9 +424,9 @@ namespace Libuv.Internal
private readonly IntPtr _field0; private readonly IntPtr _field0;
private readonly IntPtr _field1; 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; _field0 = (IntPtr)len;
_field1 = memory; _field1 = memory;
@ -581,16 +588,16 @@ namespace Libuv.Internal
public static extern int uv_walk(UvLoopHandle loop, uv_walk_cb walk_cb, IntPtr arg); public static extern int uv_walk(UvLoopHandle loop, uv_walk_cb walk_cb, IntPtr arg);
[DllImport("libuv", CallingConvention = CallingConvention.Cdecl)] [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)] [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)] [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)] [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)] [DllImport("WS2_32.dll", CallingConvention = CallingConvention.Winapi)]
public static extern unsafe int WSAIoctl( public static extern unsafe int WSAIoctl(

View file

@ -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);
}
}

View file

@ -3,20 +3,19 @@
using System.Net; using System.Net;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Server;
namespace Libuv.Internal namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking
{ {
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct SockAddr internal struct SockAddr
{ {
// this type represents native memory occupied by sockaddr struct // this type represents native memory occupied by sockaddr struct
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms740496(v=vs.85).aspx // 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, // 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 // the simplest way to reserve the same size in c# is with four nameless long values
private long _field0; private readonly long _field0;
private long _field1; private readonly long _field1;
private long _field2; private readonly long _field2;
private long _field3; private long _field3;
public SockAddr(long ignored) => _field0 = _field1 = _field2 = _field3 = 0; 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); var port = ((int)(_field0 & 0x00FF0000) >> 8) | (int)((_field0 & 0xFF000000) >> 24);
int family = (int)_field0; int family = (int)_field0;
if (Core.IsDarwin) if (PlatformApis.IsDarwin)
// see explanation in example 4 // see explanation in example 4
family >>= 8; family >>= 8;
family &= 0xFF; family &= 0xFF;
if (family == 2) if (family == 2)
{
// AF_INET => IPv4 // AF_INET => IPv4
return new IPEndPoint(new IPAddress((_field0 >> 32) & 0xFFFFFFFF), port); return new IPEndPoint(new IPAddress((_field0 >> 32) & 0xFFFFFFFF), port);
}
if (IsIPv4MappedToIPv6()) else if (IsIPv4MappedToIPv6())
{ {
var ipv4bits = (_field2 >> 32) & 0x00000000FFFFFFFF; var ipv4bits = (_field2 >> 32) & 0x00000000FFFFFFFF;
return new IPEndPoint(new IPAddress(ipv4bits), port); return new IPEndPoint(new IPAddress(ipv4bits), port);
} }
else
// otherwise IPv6
var bytes = new byte[16];
fixed (byte* b = bytes)
{ {
*(long*)b = _field1; // otherwise IPv6
*(long*)(b + 8) = _field2; 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 public uint ScopeId
@ -100,8 +102,13 @@ namespace Libuv.Internal
} }
} }
// If the IPAddress is an IPv4 mapped to IPv6, return the IPv4 representation instead. private bool IsIPv4MappedToIPv6()
// 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; // 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;
}
} }
} }

View file

@ -5,13 +5,13 @@ using System;
using System.Diagnostics; using System.Diagnostics;
using System.Threading; 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 _callback;
private Action<Action<IntPtr>, IntPtr> _queueCloseHandle; private Action<Action<IntPtr>, IntPtr> _queueCloseHandle;
@ -56,7 +56,7 @@ namespace Libuv.Internal
{ {
// This can be called from the finalizer. // This can be called from the finalizer.
// Ensure the closure doesn't reference "this". // Ensure the closure doesn't reference "this".
LibuvFunctions uv = _uv; var uv = _uv;
_queueCloseHandle(memory2 => uv.close(memory2, _destroyMemory), memory); _queueCloseHandle(memory2 => uv.close(memory2, _destroyMemory), memory);
uv.unsafe_async_send(memory); uv.unsafe_async_send(memory);
} }

View file

@ -4,14 +4,14 @@
using System; using System;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace Libuv.Internal namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking
{ {
/// <summary> /// <summary>
/// Summary description for UvWriteRequest /// Summary description for UvWriteRequest
/// </summary> /// </summary>
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<UvConnectRequest, int, UvException, object> _callback; private Action<UvConnectRequest, int, UvException, object> _callback;
private object _state; private object _state;

View file

@ -3,9 +3,9 @@
using System; 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; public UvException(string message, int statusCode) : base(message) => StatusCode = statusCode;

View file

@ -5,11 +5,11 @@ using System;
using System.Diagnostics; using System.Diagnostics;
using System.Threading; 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<Action<IntPtr>, IntPtr> _queueCloseHandle; private Action<Action<IntPtr>, IntPtr> _queueCloseHandle;
protected UvHandle(ILibuvTrace logger) : base (logger) protected UvHandle(ILibuvTrace logger) : base (logger)
@ -28,7 +28,7 @@ namespace Libuv.Internal
protected override bool ReleaseHandle() protected override bool ReleaseHandle()
{ {
IntPtr memory = handle; var memory = handle;
if (memory != IntPtr.Zero) if (memory != IntPtr.Zero)
{ {
handle = IntPtr.Zero; handle = IntPtr.Zero;
@ -41,7 +41,7 @@ namespace Libuv.Internal
{ {
// This can be called from the finalizer. // This can be called from the finalizer.
// Ensure the closure doesn't reference "this". // Ensure the closure doesn't reference "this".
LibuvFunctions uv = _uv; var uv = _uv;
_queueCloseHandle(memory2 => uv.close(memory2, _destroyMemory), memory); _queueCloseHandle(memory2 => uv.close(memory2, _destroyMemory), memory);
} }
else else

View file

@ -4,9 +4,9 @@
using System; using System;
using System.Threading; 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) public UvLoopHandle(ILibuvTrace logger) : base(logger)
{ {

View file

@ -7,12 +7,12 @@ using System.Diagnostics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
namespace Libuv.Internal namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking
{ {
/// <summary> /// <summary>
/// Summary description for UvMemory /// Summary description for UvMemory
/// </summary> /// </summary>
public abstract class UvMemory : SafeHandle internal abstract class UvMemory : SafeHandle
{ {
protected LibuvFunctions _uv; protected LibuvFunctions _uv;
protected int _threadId; protected int _threadId;
@ -66,7 +66,6 @@ namespace Libuv.Internal
{ {
Debug.Assert(closed || !IsClosed, "Handle is closed"); Debug.Assert(closed || !IsClosed, "Handle is closed");
Debug.Assert(!IsInvalid, "Handle is invalid"); Debug.Assert(!IsInvalid, "Handle is invalid");
Debug.Assert(_threadId == Thread.CurrentThread.ManagedThreadId, "ThreadId is incorrect"); Debug.Assert(_threadId == Thread.CurrentThread.ManagedThreadId, "ThreadId is incorrect");
} }

View file

@ -3,9 +3,9 @@
using System; 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) public UvPipeHandle(ILibuvTrace logger) : base(logger)
{ {

View file

@ -4,9 +4,9 @@
using System; using System;
using System.Runtime.InteropServices; 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) protected UvRequest(ILibuvTrace logger) : base(logger, GCHandleType.Normal)
{ {
@ -14,11 +14,6 @@ namespace Libuv.Internal
public virtual void Init(LibuvThread thread) 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() protected override bool ReleaseHandle()
@ -29,3 +24,4 @@ namespace Libuv.Internal
} }
} }
} }

View file

@ -5,16 +5,14 @@ using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Microsoft.Extensions.Logging; 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 // Ref and out lamda params must be explicitly typed
private static readonly LibuvFunctions.uv_alloc_cb _uv_alloc_cb = 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);
(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_read_cb _uv_read_cb =
(IntPtr handle, int status, ref LibuvFunctions.uv_buf_t buf) => UvReadCb(handle, status, ref buf);
private Action<UvStreamHandle, int, UvException, object> _listenCallback; private Action<UvStreamHandle, int, UvException, object> _listenCallback;
private object _listenState; private object _listenState;

View file

@ -5,9 +5,9 @@ using System;
using System.Net; using System.Net;
using System.Runtime.InteropServices; 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) public UvTcpHandle(ILibuvTrace logger) : base(logger)
{ {

View file

@ -4,9 +4,9 @@
using System; using System;
using Microsoft.Extensions.Logging; 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; private static readonly LibuvFunctions.uv_timer_cb _uv_timer_cb = UvTimerCb;

View file

@ -7,14 +7,14 @@ using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace Libuv.Internal namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking
{ {
/// <summary> /// <summary>
/// Summary description for UvWriteRequest /// Summary description for UvWriteRequest
/// </summary> /// </summary>
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; private IntPtr _bufs;
@ -22,9 +22,9 @@ namespace Libuv.Internal
private object _state; private object _state;
private const int BUFFER_COUNT = 4; private const int BUFFER_COUNT = 4;
private LibuvAwaitable<UvWriteReq> _awaitable = new LibuvAwaitable<UvWriteReq>(); private readonly LibuvAwaitable<UvWriteReq> _awaitable = new LibuvAwaitable<UvWriteReq>();
private List<GCHandle> _pins = new List<GCHandle>(BUFFER_COUNT + 1); private readonly List<GCHandle> _pins = new List<GCHandle>(BUFFER_COUNT + 1);
private List<MemoryHandle> _handles = new List<MemoryHandle>(BUFFER_COUNT + 1); private readonly List<MemoryHandle> _handles = new List<MemoryHandle>(BUFFER_COUNT + 1);
public UvWriteReq(ILibuvTrace logger) : base(logger) public UvWriteReq(ILibuvTrace logger) : base(logger)
{ {
@ -76,9 +76,6 @@ namespace Libuv.Internal
nBuffers++; nBuffers++;
var pBuffers = (LibuvFunctions.uv_buf_t*)_bufs; var pBuffers = (LibuvFunctions.uv_buf_t*)_bufs;
if (pBuffers == null)
throw new NullReferenceException();
if (nBuffers > BUFFER_COUNT) if (nBuffers > BUFFER_COUNT)
{ {
// create and pin buffer array when it's larger than the pre-allocated one // 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); var gcHandle = GCHandle.Alloc(bufArray, GCHandleType.Pinned);
_pins.Add(gcHandle); _pins.Add(gcHandle);
pBuffers = (LibuvFunctions.uv_buf_t*)gcHandle.AddrOfPinnedObject(); pBuffers = (LibuvFunctions.uv_buf_t*)gcHandle.AddrOfPinnedObject();
if (pBuffers == null)
throw new NullReferenceException();
} }
if (nBuffers == 1) if (nBuffers == 1)
@ -137,7 +132,7 @@ namespace Libuv.Internal
Action<UvWriteReq, int, UvException, object> callback, Action<UvWriteReq, int, UvException, object> callback,
object state) object state)
{ {
WriteArraySegmentInternal(handle, bufs, null, callback, state); WriteArraySegmentInternal(handle, bufs, sendHandle: null, callback: callback, state: state);
} }
public void Write2( public void Write2(
@ -154,15 +149,12 @@ namespace Libuv.Internal
UvStreamHandle handle, UvStreamHandle handle,
ArraySegment<ArraySegment<byte>> bufs, ArraySegment<ArraySegment<byte>> bufs,
UvStreamHandle sendHandle, UvStreamHandle sendHandle,
Action<UvWriteReq, int, UvException, object> callback, object state Action<UvWriteReq, int, UvException, object> callback,
) object state)
{ {
try try
{ {
var pBuffers = (LibuvFunctions.uv_buf_t*)_bufs; var pBuffers = (LibuvFunctions.uv_buf_t*)_bufs;
if (pBuffers == null)
throw new NullReferenceException();
var nBuffers = bufs.Count; var nBuffers = bufs.Count;
if (nBuffers > BUFFER_COUNT) if (nBuffers > BUFFER_COUNT)
{ {
@ -171,14 +163,12 @@ namespace Libuv.Internal
var gcHandle = GCHandle.Alloc(bufArray, GCHandleType.Pinned); var gcHandle = GCHandle.Alloc(bufArray, GCHandleType.Pinned);
_pins.Add(gcHandle); _pins.Add(gcHandle);
pBuffers = (LibuvFunctions.uv_buf_t*)gcHandle.AddrOfPinnedObject(); pBuffers = (LibuvFunctions.uv_buf_t*)gcHandle.AddrOfPinnedObject();
if (pBuffers == null)
throw new NullReferenceException();
} }
for (var index = 0; index < nBuffers; index++) for (var index = 0; index < nBuffers; index++)
{ {
// create and pin each segment being written // 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); var gcHandle = GCHandle.Alloc(buf.Array, GCHandleType.Pinned);
_pins.Add(gcHandle); _pins.Add(gcHandle);

View file

@ -3,11 +3,11 @@
using System; using System;
using System.Collections.Generic; 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; private const int _maxPooledWriteReqs = 1024;

View file

@ -4,7 +4,7 @@
using System; using System;
using System.Buffers; using System.Buffers;
namespace Libuv namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv
{ {
/// <summary> /// <summary>
/// Provides programmatic configuration of Libuv transport features. /// Provides programmatic configuration of Libuv transport features.
@ -19,6 +19,14 @@ namespace Libuv
/// </remarks> /// </remarks>
public int ThreadCount { get; set; } = ProcessorThreadCount; public int ThreadCount { get; set; } = ProcessorThreadCount;
/// <summary>
/// Set to false to enable Nagle's algorithm for all connections.
/// </summary>
/// <remarks>
/// Defaults to true.
/// </remarks>
public bool NoDelay { get; set; } = true;
/// <summary> /// <summary>
/// The maximum length of the pending connection queue. /// The maximum length of the pending connection queue.
/// </summary> /// </summary>
@ -39,12 +47,19 @@ namespace Libuv
{ {
// Actual core count would be a better number // Actual core count would be a better number
// rather than logical cores which includes hyper-threaded cores. // 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; var threadCount = Environment.ProcessorCount >> 1;
// Receive Side Scaling RSS Processor count currently maxes out at 16 if (threadCount < 1)
// would be better to check the NIC's current hardware queues; but xplat... // Ensure shifted value is at least one
return threadCount < 1 ? 1 : threadCount > 16 ? 16 : threadCount; 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;
} }
} }
} }

View file

@ -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
{
/// <summary>
/// Specify Libuv as the transport to be used by Kestrel.
/// </summary>
/// <param name="hostBuilder">
/// The Microsoft.AspNetCore.Hosting.IWebHostBuilder to configure.
/// </param>
/// <returns>
/// The Microsoft.AspNetCore.Hosting.IWebHostBuilder.
/// </returns>
public static IWebHostBuilder UseLibuv(this IWebHostBuilder hostBuilder)
{
return hostBuilder.ConfigureServices(services =>
{
services.AddSingleton<IConnectionListenerFactory, LibuvTransportFactory>();
});
}
/// <summary>
/// Specify Libuv as the transport to be used by Kestrel.
/// </summary>
/// <param name="hostBuilder">
/// The Microsoft.AspNetCore.Hosting.IWebHostBuilder to configure.
/// </param>
/// <param name="configureOptions">
/// A callback to configure Libuv options.
/// </param>
/// <returns>
/// The Microsoft.AspNetCore.Hosting.IWebHostBuilder.
/// </returns>
public static IWebHostBuilder UseLibuv(this IWebHostBuilder hostBuilder, Action<LibuvTransportOptions> configureOptions)
{
return hostBuilder.UseLibuv().ConfigureServices(services =>
{
services.Configure(configureOptions);
});
}
}
}

View file

@ -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<byte> IMemoryPoolFeature.MemoryPool => MemoryPool;
IDuplexPipe IConnectionTransportFeature.Transport
{
get => Transport;
set => Transport = value;
}
IDictionary<object, object> 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()."));
}
}

View file

@ -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<KeyValuePair<Type, object>> 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<KeyValuePair<Type, object>>(2);
}
for (var i = 0; i < MaybeExtra.Count; i++)
{
if (MaybeExtra[i].Key == key)
{
MaybeExtra[i] = new KeyValuePair<Type, object>(key, value);
return;
}
}
MaybeExtra.Add(new KeyValuePair<Type, object>(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>()
{
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>(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<KeyValuePair<Type, object>> FastEnumerable()
{
if (_currentIConnectionIdFeature != null)
{
yield return new KeyValuePair<Type, object>(IConnectionIdFeatureType, _currentIConnectionIdFeature);
}
if (_currentIConnectionTransportFeature != null)
{
yield return new KeyValuePair<Type, object>(IConnectionTransportFeatureType, _currentIConnectionTransportFeature);
}
if (_currentIConnectionItemsFeature != null)
{
yield return new KeyValuePair<Type, object>(IConnectionItemsFeatureType, _currentIConnectionItemsFeature);
}
if (_currentIMemoryPoolFeature != null)
{
yield return new KeyValuePair<Type, object>(IMemoryPoolFeatureType, _currentIMemoryPoolFeature);
}
if (_currentIConnectionLifetimeFeature != null)
{
yield return new KeyValuePair<Type, object>(IConnectionLifetimeFeatureType, _currentIConnectionLifetimeFeature);
}
if (MaybeExtra != null)
{
foreach (var item in MaybeExtra)
{
yield return item;
}
}
}
IEnumerator<KeyValuePair<Type, object>> IEnumerable<KeyValuePair<Type, object>>.GetEnumerator() => FastEnumerable().GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => FastEnumerable().GetEnumerator();
}
}

View file

@ -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<object, object> _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<byte> MemoryPool { get; }
public override IDuplexPipe Transport { get; set; }
public IDuplexPipe Application { get; set; }
public override IDictionary<object, object> 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();
}
}
}

View file

@ -22,7 +22,7 @@ namespace Server
{ {
public class KeywordList public class KeywordList
{ {
private static int[] m_EmptyInts = new int[0]; private static readonly int[] m_EmptyInts = new int[0];
private int[] m_Keywords; private int[] m_Keywords;
public KeywordList() public KeywordList()

View file

@ -29,6 +29,9 @@ using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Server.Network; using Server.Network;
namespace Server namespace Server
@ -56,7 +59,7 @@ namespace Server
* GetTickCount and GetTickCount64 have poor resolution. * GetTickCount and GetTickCount64 have poor resolution.
* GetTickCount64 is unavailable on Windows XP and Windows Server 2003. * GetTickCount64 is unavailable on Windows XP and Windows Server 2003.
* Stopwatch.GetTimestamp() (QueryPerformanceCounter) is high resolution, but * 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(), * which is why Stopwatch has been used to verify HRT before calling GetTimestamp(),
* enabling the usage of DateTime.UtcNow instead. * enabling the usage of DateTime.UtcNow instead.
*/ */
@ -80,8 +83,6 @@ namespace Server
private static readonly Type[] m_SerialTypeArray = { typeof(Serial) }; private static readonly Type[] m_SerialTypeArray = { typeof(Serial) };
public static MessagePump MessagePump{ get; set; }
public static bool Profiling public static bool Profiling
{ {
get => m_Profiling; get => m_Profiling;
@ -265,9 +266,7 @@ namespace Server
{ {
try try
{ {
Task.WhenAll( // Close all listeners
MessagePump.Listeners.Select(listener => listener.Dispose())
).Wait();
} }
catch catch
{ {
@ -444,9 +443,6 @@ namespace Server
AssemblyHandler.Invoke("Initialize"); AssemblyHandler.Invoke("Initialize");
// Start accepting new connections
MessagePump = new MessagePump();
AssemblyHandler.Invoke("RegisterListeners"); AssemblyHandler.Invoke("RegisterListeners");
timerThread.Start(); timerThread.Start();
@ -454,10 +450,18 @@ namespace Server
foreach (Map m in Map.AllMaps) foreach (Map m in Map.AllMaps)
m.Tiles.Force(); m.Tiles.Force();
NetState.Initialize();
EventSink.InvokeServerStarted(); EventSink.InvokeServerStarted();
// Start net socket server
var host = TcpServer.CreateWebHostBuilder(new string[0]).Build();
var life = host.Services.GetRequiredService<IHostApplicationLifetime>();
life.ApplicationStopping.Register(() => { Kill(); });
host.Run();
}
public static void RunEventLoop(IMessagePumpService messagePumpService)
{
try try
{ {
long last = TickCount; long last = TickCount;
@ -477,7 +481,7 @@ namespace Server
); );
Timer.Slice(); Timer.Slice();
MessagePump.DoWork(); messagePumpService.DoWork();
NetState.ProcessDisposedQueue(); NetState.ProcessDisposedQueue();

View file

@ -262,16 +262,17 @@ namespace Server
private static readonly List<Item> _EmptyFixItems = new List<Item>(); private static readonly List<Item> _EmptyFixItems = new List<Item>();
private Region m_DefaultRegion; private Region m_DefaultRegion;
private int m_FileIndex; private readonly int m_FileIndex;
private string m_Name; 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 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) public Map(int mapID, int mapIndex, int fileIndex, int width, int height, int season, string name, MapRules rules)
{ {

View file

@ -41,7 +41,7 @@ namespace Server.Menus.ItemLists
public class ItemListMenu : IMenu public class ItemListMenu : IMenu
{ {
private static int m_NextSerial; private static int m_NextSerial;
private int m_Serial; private readonly int m_Serial;
public ItemListMenu(string question, ItemListEntry[] entries) public ItemListMenu(string question, ItemListEntry[] entries)
{ {

View file

@ -25,7 +25,7 @@ namespace Server.Menus.Questions
public class QuestionMenu : IMenu public class QuestionMenu : IMenu
{ {
private static int m_NextSerial; private static int m_NextSerial;
private int m_Serial; private readonly int m_Serial;
public QuestionMenu(string question, string[] answers) public QuestionMenu(string question, string[] answers)
{ {

View file

@ -56,7 +56,7 @@ namespace Server
public class TimedSkillMod : SkillMod public class TimedSkillMod : SkillMod
{ {
private DateTime m_Expire; private readonly DateTime m_Expire;
public TimedSkillMod(SkillName skill, bool relative, double value, TimeSpan delay) public TimedSkillMod(SkillName skill, bool relative, double value, TimeSpan delay)
: this(skill, relative, value, DateTime.UtcNow + delay) : this(skill, relative, value, DateTime.UtcNow + delay)
@ -64,21 +64,16 @@ namespace Server
} }
public TimedSkillMod(SkillName skill, bool relative, double value, DateTime expire) public TimedSkillMod(SkillName skill, bool relative, double value, DateTime expire)
: base(skill, relative, value) : base(skill, relative, value) =>
{
m_Expire = expire; m_Expire = expire;
}
public override bool CheckCondition() public override bool CheckCondition() => DateTime.UtcNow < m_Expire;
{
return DateTime.UtcNow < m_Expire;
}
} }
public class EquippedSkillMod : SkillMod public class EquippedSkillMod : SkillMod
{ {
private Item m_Item; private readonly Item m_Item;
private Mobile m_Mobile; private readonly Mobile m_Mobile;
public EquippedSkillMod(SkillName skill, bool relative, double value, Item item, Mobile mobile) public EquippedSkillMod(SkillName skill, bool relative, double value, Item item, Mobile mobile)
: base(skill, relative, value) : base(skill, relative, value)
@ -87,10 +82,7 @@ namespace Server
m_Mobile = mobile; m_Mobile = mobile;
} }
public override bool CheckCondition() public override bool CheckCondition() => !m_Item.Deleted && !m_Mobile.Deleted && m_Item.Parent == m_Mobile;
{
return !m_Item.Deleted && !m_Mobile.Deleted && m_Item.Parent == m_Mobile;
}
} }
public class DefaultSkillMod : SkillMod public class DefaultSkillMod : SkillMod
@ -100,10 +92,7 @@ namespace Server
{ {
} }
public override bool CheckCondition() public override bool CheckCondition() => true;
{
return true;
}
} }
public abstract class SkillMod public abstract class SkillMod
@ -265,8 +254,8 @@ namespace Server
public class StatMod public class StatMod
{ {
private DateTime m_Added; private readonly DateTime m_Added;
private TimeSpan m_Duration; private readonly TimeSpan m_Duration;
public StatMod(StatType type, string name, int offset, TimeSpan duration) public StatMod(StatType type, string name, int offset, TimeSpan duration)
{ {
@ -296,10 +285,7 @@ namespace Server
public class DamageEntry public class DamageEntry
{ {
public DamageEntry(Mobile damager) public DamageEntry(Mobile damager) => Damager = damager;
{
Damager = damager;
}
public Mobile Damager{ get; } public Mobile Damager{ get; }
@ -425,10 +411,8 @@ namespace Server
public class MobileNotConnectedException : Exception public class MobileNotConnectedException : Exception
{ {
public MobileNotConnectedException(Mobile source, string message) public MobileNotConnectedException(Mobile source, string message)
: base(message) : base(message) =>
{
Source = source.ToString(); Source = source.ToString();
}
} }
#region Delegates #region Delegates
@ -460,8 +444,8 @@ namespace Server
/// </summary> /// </summary>
public class Mobile : IHued, IComparable<Mobile>, ISerializable, ISpawnable, IPropertyListObject public class Mobile : IHued, IComparable<Mobile>, ISerializable, ISpawnable, IPropertyListObject
{ {
private BufferWriter m_SaveBuffer; private readonly BufferWriter m_SaveBuffer;
public BufferWriter SaveBuffer { get { return m_SaveBuffer; } } public BufferWriter SaveBuffer => m_SaveBuffer;
private const int private const int
WarmodeCatchCount = 4; // Allow four warmode changes in 0.5 seconds, any more will be delay for two seconds 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 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],
new Packet[8] new Packet[8]
}; };
private static List<IEntity> m_MoveList = new List<IEntity>(); private static readonly List<IEntity> m_MoveList = new List<IEntity>();
private static List<Mobile> m_MoveClientList = new List<Mobile>(); private static readonly List<Mobile> m_MoveClientList = new List<Mobile>();
private static object m_GhostMutateContext = new object(); private static readonly object m_GhostMutateContext = new object();
private static List<Mobile> m_Hears = new List<Mobile>(); private static readonly List<Mobile> m_Hears = new List<Mobile>();
private static List<IEntity> m_OnSpeech = new List<IEntity>(); private static readonly List<IEntity> m_OnSpeech = new List<IEntity>();
public static bool m_DefaultShowVisibleDamage, m_DefaultCanSeeVisibleDamage; public static bool m_DefaultShowVisibleDamage, m_DefaultCanSeeVisibleDamage;
private static string[] m_AccessLevelNames = private static readonly string[] m_AccessLevelNames =
{ {
"a player", "a player",
"a counselor", "a counselor",
@ -497,7 +481,7 @@ namespace Server
"an owner" "an owner"
}; };
private static int[] m_InvalidBodies = private static readonly int[] m_InvalidBodies =
{ {
32, 32,
95, 95,
@ -506,12 +490,12 @@ namespace Server
198 198
}; };
private static Queue<Mobile> m_DeltaQueue = new Queue<Mobile>(); private static readonly Queue<Mobile> m_DeltaQueue = new Queue<Mobile>();
private static Queue<Mobile> m_DeltaQueueR = new Queue<Mobile>(); private static readonly Queue<Mobile> m_DeltaQueueR = new Queue<Mobile>();
private static bool _processing; private static bool _processing;
private static string[] m_GuildTypes = private static readonly string[] m_GuildTypes =
{ {
"", "",
" (Chaos)", " (Chaos)",
@ -4367,10 +4351,7 @@ namespace Server
/// <seealso cref="OnDeath" /> /// <seealso cref="OnDeath" />
/// </summary> /// </summary>
/// <returns>True to continue with death, false to override it.</returns> /// <returns>True to continue with death, false to override it.</returns>
public virtual bool OnBeforeDeath() public virtual bool OnBeforeDeath() => true;
{
return true;
}
/// <summary> /// <summary>
/// Overridable. Event invoked after the Mobile is <see cref="Kill">killed</see>. Primarily, this method is responsible for /// Overridable. Event invoked after the Mobile is <see cref="Kill">killed</see>. Primarily, this method is responsible for
@ -5089,10 +5070,7 @@ namespace Server
public static Mobile GetDamagerFrom(DamageEntry de) => de?.Damager; public static Mobile GetDamagerFrom(DamageEntry de) => de?.Damager;
public Mobile FindMostRecentDamager(bool allowSelf) public Mobile FindMostRecentDamager(bool allowSelf) => GetDamagerFrom(FindMostRecentDamageEntry(allowSelf));
{
return GetDamagerFrom(FindMostRecentDamageEntry(allowSelf));
}
public DamageEntry FindMostRecentDamageEntry(bool allowSelf) public DamageEntry FindMostRecentDamageEntry(bool allowSelf)
{ {
@ -5199,10 +5177,7 @@ namespace Server
return null; return null;
} }
public virtual Mobile GetDamageMaster(Mobile damagee) public virtual Mobile GetDamageMaster(Mobile damagee) => null;
{
return null;
}
public virtual DamageEntry RegisterDamage(int amount, Mobile from) public virtual DamageEntry RegisterDamage(int amount, Mobile from)
{ {
@ -5251,10 +5226,7 @@ namespace Server
Damage(amount, null); Damage(amount, null);
} }
public virtual bool CanBeDamaged() public virtual bool CanBeDamaged() => !m_Blessed;
{
return !m_Blessed;
}
public virtual void Damage(int amount, Mobile from) public virtual void Damage(int amount, Mobile from)
{ {
@ -5906,15 +5878,9 @@ namespace Server
} }
} }
public static string GetAccessLevelName(AccessLevel level) public static string GetAccessLevelName(AccessLevel level) => m_AccessLevelNames[(int)level];
{
return m_AccessLevelNames[(int)level];
}
public virtual bool CanPaperdollBeOpenedBy(Mobile from) public virtual bool CanPaperdollBeOpenedBy(Mobile from) => Body.IsHuman || Body.IsGhost || IsBodyMod;
{
return Body.IsHuman || Body.IsGhost || IsBodyMod;
}
public virtual void GetChildContextMenuEntries(Mobile from, List<ContextMenuEntry> list, Item item) public virtual void GetChildContextMenuEntries(Mobile from, List<ContextMenuEntry> list, Item item)
{ {
@ -6215,10 +6181,7 @@ namespace Server
eable.Free(); eable.Free();
} }
public bool Send(Packet p) public bool Send(Packet p) => Send(p, false);
{
return Send(p, false);
}
public bool Send(Packet p, bool throwOnOffline) public bool Send(Packet p, bool throwOnOffline)
{ {
@ -6254,10 +6217,7 @@ namespace Server
RevealingAction(); RevealingAction();
} }
public virtual bool HandlesOnSpeech(Mobile from) public virtual bool HandlesOnSpeech(Mobile from) => false;
{
return false;
}
/// <summary> /// <summary>
/// Overridable. Virtual event invoked when the Mobile hears speech. This event will only be invoked if /// 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; m_Direction = dir;
} }
public virtual int GetSeason() public virtual int GetSeason() => m_Map?.Season ?? 1;
{
return m_Map?.Season ?? 1;
}
public virtual int GetPacketFlags() public virtual int GetPacketFlags()
{ {
@ -6505,10 +6462,7 @@ namespace Server
m_AccessLevel > AccessLevel.Player || m.Warmode); m_AccessLevel > AccessLevel.Player || m.Warmode);
} }
public virtual bool CanBeRenamedBy(Mobile from) public virtual bool CanBeRenamedBy(Mobile from) => from.AccessLevel >= AccessLevel.GameMaster && from.m_AccessLevel > m_AccessLevel;
{
return from.AccessLevel >= AccessLevel.GameMaster && from.m_AccessLevel > m_AccessLevel;
}
public virtual void OnGuildTitleChange(string oldTitle) public virtual void OnGuildTitleChange(string oldTitle)
{ {
@ -6738,10 +6692,7 @@ namespace Server
public bool HasFreeHand() => FindItemOnLayer(Layer.TwoHanded) == null; public bool HasFreeHand() => FindItemOnLayer(Layer.TwoHanded) == null;
public virtual IWeapon GetDefaultWeapon() public virtual IWeapon GetDefaultWeapon() => DefaultWeapon;
{
return DefaultWeapon;
}
public BankBox FindBankNoCreate() public BankBox FindBankNoCreate()
{ {
@ -6827,21 +6778,13 @@ namespace Server
return true; return true;
} }
public virtual bool CheckLift(Mobile from, Item item, ref LRReason reject) public virtual bool CheckLift(Mobile from, Item item, ref LRReason reject) => true;
{
return true;
}
public virtual bool CheckNonlocalLift(Mobile from, Item item) public virtual bool CheckNonlocalLift(Mobile from, Item item) => from == this || from.AccessLevel > AccessLevel && from.AccessLevel >= AccessLevel.GameMaster;
{
return from == this || from.AccessLevel > AccessLevel && from.AccessLevel >= AccessLevel.GameMaster;
}
public virtual bool CheckTrade(Mobile to, Item item, SecureTradeContainer cont, bool message, bool checkItems, public virtual bool CheckTrade(Mobile to, Item item, SecureTradeContainer cont, bool message, bool checkItems,
int plusItems, int plusWeight) int plusItems, int plusWeight) =>
{ true;
return true;
}
public virtual bool OpenTrade(Mobile from, Item offer = null) public virtual bool OpenTrade(Mobile from, Item offer = null)
{ {
@ -6927,10 +6870,7 @@ namespace Server
/// return base.OnDragLift( item ); /// return base.OnDragLift( item );
/// }</code> /// }</code>
/// </example> /// </example>
public virtual bool OnDragLift(Item item) public virtual bool OnDragLift(Item item) => true;
{
return true;
}
/// <summary> /// <summary>
/// Overridable. Virtual event invoked when the Mobile attempts to drop <paramref name="item" /> into a /// Overridable. Virtual event invoked when the Mobile attempts to drop <paramref name="item" /> into a
@ -6940,40 +6880,28 @@ namespace Server
/// . /// .
/// </summary> /// </summary>
/// <returns>True if the drop is allowed, false if otherwise.</returns> /// <returns>True if the drop is allowed, false if otherwise.</returns>
public virtual bool OnDroppedItemInto(Item item, Container container, Point3D loc) public virtual bool OnDroppedItemInto(Item item, Container container, Point3D loc) => true;
{
return true;
}
/// <summary> /// <summary>
/// Overridable. Virtual event invoked when the Mobile attempts to drop <paramref name="item" /> directly onto another /// Overridable. Virtual event invoked when the Mobile attempts to drop <paramref name="item" /> directly onto another
/// <see cref="Item" />, <paramref name="target" />. This is the case of stacking items. /// <see cref="Item" />, <paramref name="target" />. This is the case of stacking items.
/// </summary> /// </summary>
/// <returns>True if the drop is allowed, false if otherwise.</returns> /// <returns>True if the drop is allowed, false if otherwise.</returns>
public virtual bool OnDroppedItemOnto(Item item, Item target) public virtual bool OnDroppedItemOnto(Item item, Item target) => true;
{
return true;
}
/// <summary> /// <summary>
/// Overridable. Virtual event invoked when the Mobile attempts to drop <paramref name="item" /> into another /// Overridable. Virtual event invoked when the Mobile attempts to drop <paramref name="item" /> into another
/// <see cref="Item" />, <paramref name="target" />. The target item is most likely a <see cref="Container" />. /// <see cref="Item" />, <paramref name="target" />. The target item is most likely a <see cref="Container" />.
/// </summary> /// </summary>
/// <returns>True if the drop is allowed, false if otherwise.</returns> /// <returns>True if the drop is allowed, false if otherwise.</returns>
public virtual bool OnDroppedItemToItem(Item item, Item target, Point3D loc) public virtual bool OnDroppedItemToItem(Item item, Item target, Point3D loc) => true;
{
return true;
}
/// <summary> /// <summary>
/// Overridable. Virtual event invoked when the Mobile attempts to give <paramref name="item" /> to a Mobile ( /// Overridable. Virtual event invoked when the Mobile attempts to give <paramref name="item" /> to a Mobile (
/// <paramref name="target" />). /// <paramref name="target" />).
/// </summary> /// </summary>
/// <returns>True if the drop is allowed, false if otherwise.</returns> /// <returns>True if the drop is allowed, false if otherwise.</returns>
public virtual bool OnDroppedItemToMobile(Item item, Mobile target) public virtual bool OnDroppedItemToMobile(Item item, Mobile target) => true;
{
return true;
}
/// <summary> /// <summary>
/// Overridable. Virtual event invoked when the Mobile attempts to drop <paramref name="item" /> to the world at a /// Overridable. Virtual event invoked when the Mobile attempts to drop <paramref name="item" /> to the world at a
@ -6983,10 +6911,7 @@ namespace Server
/// . /// .
/// </summary> /// </summary>
/// <returns>True if the drop is allowed, false if otherwise.</returns> /// <returns>True if the drop is allowed, false if otherwise.</returns>
public virtual bool OnDroppedItemToWorld(Item item, Point3D location) public virtual bool OnDroppedItemToWorld(Item item, Point3D location) => true;
{
return true;
}
/// <summary> /// <summary>
/// Overridable. Virtual event when <paramref name="from" /> successfully uses <paramref name="item" /> while it's on this /// Overridable. Virtual event when <paramref name="from" /> successfully uses <paramref name="item" /> while it's on this
@ -6997,15 +6922,9 @@ namespace Server
{ {
} }
public virtual bool CheckNonlocalDrop(Mobile from, Item item, Item target) public virtual bool CheckNonlocalDrop(Mobile from, Item item, Item target) => from == this || from.AccessLevel > AccessLevel && from.AccessLevel >= AccessLevel.GameMaster;
{
return from == this || from.AccessLevel > AccessLevel && from.AccessLevel >= AccessLevel.GameMaster;
}
public virtual bool CheckItemUse(Mobile from, Item item) public virtual bool CheckItemUse(Mobile from, Item item) => true;
{
return true;
}
/// <summary> /// <summary>
/// Overridable. Virtual event invoked when <paramref name="from" /> successfully lifts <paramref name="item" /> from this /// Overridable. Virtual event invoked when <paramref name="from" /> successfully lifts <paramref name="item" /> from this
@ -7016,15 +6935,9 @@ namespace Server
{ {
} }
public virtual bool AllowItemUse(Item item) public virtual bool AllowItemUse(Item item) => true;
{
return true;
}
public virtual bool AllowEquipFrom(Mobile mob) public virtual bool AllowEquipFrom(Mobile mob) => mob == this || mob.AccessLevel >= AccessLevel.GameMaster && mob.AccessLevel > AccessLevel;
{
return mob == this || mob.AccessLevel >= AccessLevel.GameMaster && mob.AccessLevel > AccessLevel;
}
public virtual bool EquipItem(Item item) public virtual bool EquipItem(Item item)
{ {
@ -7304,13 +7217,10 @@ namespace Server
private class MovementRecord private class MovementRecord
{ {
private static Queue<MovementRecord> m_InstancePool = new Queue<MovementRecord>(); private static readonly Queue<MovementRecord> m_InstancePool = new Queue<MovementRecord>();
public long m_End; public long m_End;
private MovementRecord(long end) private MovementRecord(long end) => m_End = end;
{
m_End = end;
}
public static MovementRecord NewInstance(long end) public static MovementRecord NewInstance(long end)
{ {
@ -7343,7 +7253,7 @@ namespace Server
private class WarmodeTimer : Timer private class WarmodeTimer : Timer
{ {
private Mobile m_Mobile; private readonly Mobile m_Mobile;
public WarmodeTimer(Mobile m, bool value) public WarmodeTimer(Mobile m, bool value)
: base(WarmodeSpamDelay) : base(WarmodeSpamDelay)
@ -7365,13 +7275,11 @@ namespace Server
private class SimpleTarget : Target private class SimpleTarget : Target
{ {
private TargetCallback m_Callback; private readonly TargetCallback m_Callback;
public SimpleTarget(int range, TargetFlags flags, bool allowGround, TargetCallback callback) public SimpleTarget(int range, TargetFlags flags, bool allowGround, TargetCallback callback)
: base(range, allowGround, flags) : base(range, allowGround, flags) =>
{
m_Callback = callback; m_Callback = callback;
}
protected override void OnTarget(Mobile from, object targeted) protected override void OnTarget(Mobile from, object targeted)
{ {
@ -7381,8 +7289,8 @@ namespace Server
private class SimpleStateTarget<T> : Target private class SimpleStateTarget<T> : Target
{ {
private TargetStateCallback<T> m_Callback; private readonly TargetStateCallback<T> m_Callback;
private T m_State; private readonly T m_State;
public SimpleStateTarget(int range, TargetFlags flags, bool allowGround, TargetStateCallback<T> callback, public SimpleStateTarget(int range, TargetFlags flags, bool allowGround, TargetStateCallback<T> callback,
T state) T state)
@ -7400,13 +7308,11 @@ namespace Server
private class AutoManifestTimer : Timer private class AutoManifestTimer : Timer
{ {
private Mobile m_Mobile; private readonly Mobile m_Mobile;
public AutoManifestTimer(Mobile m, TimeSpan delay) public AutoManifestTimer(Mobile m, TimeSpan delay)
: base(delay) : base(delay) =>
{
m_Mobile = m; m_Mobile = m;
}
protected override void OnTick() protected override void OnTick()
{ {
@ -7419,17 +7325,11 @@ namespace Server
{ {
private static LocationComparer m_Instance; private static LocationComparer m_Instance;
public LocationComparer(IEntity relativeTo) public LocationComparer(IEntity relativeTo) => RelativeTo = relativeTo;
{
RelativeTo = relativeTo;
}
public IEntity RelativeTo{ get; set; } public IEntity RelativeTo{ get; set; }
public int Compare(IEntity x, IEntity y) public int Compare(IEntity x, IEntity y) => GetDistance(x) - GetDistance(y);
{
return GetDistance(x) - GetDistance(y);
}
public static LocationComparer GetInstance(IEntity relativeTo) public static LocationComparer GetInstance(IEntity relativeTo)
{ {
@ -7454,15 +7354,9 @@ namespace Server
} }
} }
int IComparable<IEntity>.CompareTo(IEntity other) int IComparable<IEntity>.CompareTo(IEntity other) => other == null ? -1 : Serial.CompareTo(other.Serial);
{
return other == null ? -1 : Serial.CompareTo(other.Serial);
}
public int CompareTo(Mobile other) public int CompareTo(Mobile other) => other == null ? -1 : Serial.CompareTo(other.Serial);
{
return other == null ? -1 : Serial.CompareTo(other.Serial);
}
#region Handlers #region Handlers
@ -7581,7 +7475,7 @@ namespace Server
private class ManaTimer : Timer private class ManaTimer : Timer
{ {
private Mobile m_Owner; private readonly Mobile m_Owner;
public ManaTimer(Mobile m) public ManaTimer(Mobile m)
: base(GetManaRegenRate(m), GetManaRegenRate(m)) : base(GetManaRegenRate(m), GetManaRegenRate(m))
@ -7601,7 +7495,7 @@ namespace Server
private class HitsTimer : Timer private class HitsTimer : Timer
{ {
private Mobile m_Owner; private readonly Mobile m_Owner;
public HitsTimer(Mobile m) public HitsTimer(Mobile m)
: base(GetHitsRegenRate(m), GetHitsRegenRate(m)) : base(GetHitsRegenRate(m), GetHitsRegenRate(m))
@ -7621,7 +7515,7 @@ namespace Server
private class StamTimer : Timer private class StamTimer : Timer
{ {
private Mobile m_Owner; private readonly Mobile m_Owner;
public StamTimer(Mobile m) public StamTimer(Mobile m)
: base(GetStamRegenRate(m), GetStamRegenRate(m)) : base(GetStamRegenRate(m), GetStamRegenRate(m))
@ -7641,7 +7535,7 @@ namespace Server
private class LogoutTimer : Timer private class LogoutTimer : Timer
{ {
private Mobile m_Mobile; private readonly Mobile m_Mobile;
public LogoutTimer(Mobile m) public LogoutTimer(Mobile m)
: base(TimeSpan.FromDays(1.0)) : base(TimeSpan.FromDays(1.0))
@ -7666,7 +7560,7 @@ namespace Server
private class ParalyzedTimer : Timer private class ParalyzedTimer : Timer
{ {
private Mobile m_Mobile; private readonly Mobile m_Mobile;
public ParalyzedTimer(Mobile m, TimeSpan duration) public ParalyzedTimer(Mobile m, TimeSpan duration)
: base(duration) : base(duration)
@ -7683,7 +7577,7 @@ namespace Server
private class FrozenTimer : Timer private class FrozenTimer : Timer
{ {
private Mobile m_Mobile; private readonly Mobile m_Mobile;
public FrozenTimer(Mobile m, TimeSpan duration) public FrozenTimer(Mobile m, TimeSpan duration)
: base(duration) : base(duration)
@ -7700,7 +7594,7 @@ namespace Server
private class CombatTimer : Timer 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)) public CombatTimer(Mobile m) : base(TimeSpan.FromSeconds(0.0), TimeSpan.FromSeconds(0.01))
{ {
@ -7744,7 +7638,7 @@ namespace Server
private class ExpireCombatantTimer : Timer private class ExpireCombatantTimer : Timer
{ {
private Mobile m_Mobile; private readonly Mobile m_Mobile;
public ExpireCombatantTimer(Mobile m) public ExpireCombatantTimer(Mobile m)
: base(TimeSpan.FromMinutes(1.0)) : base(TimeSpan.FromMinutes(1.0))
@ -7763,7 +7657,7 @@ namespace Server
private class ExpireCriminalTimer : Timer private class ExpireCriminalTimer : Timer
{ {
private Mobile m_Mobile; private readonly Mobile m_Mobile;
public ExpireCriminalTimer(Mobile m) public ExpireCriminalTimer(Mobile m)
: base(ExpireCriminalDelay) : base(ExpireCriminalDelay)
@ -7780,7 +7674,7 @@ namespace Server
private class ExpireAggressorsTimer : Timer private class ExpireAggressorsTimer : Timer
{ {
private Mobile m_Mobile; private readonly Mobile m_Mobile;
public ExpireAggressorsTimer(Mobile m) public ExpireAggressorsTimer(Mobile m)
: base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(5.0)) : base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(5.0))
@ -7804,9 +7698,9 @@ namespace Server
private class SimplePrompt : Prompt private class SimplePrompt : Prompt
{ {
private PromptCallback m_Callback; private readonly PromptCallback m_Callback;
private bool m_CallbackHandlesCancel; private readonly bool m_CallbackHandlesCancel;
private PromptCallback m_CancelCallback; private readonly PromptCallback m_CancelCallback;
public SimplePrompt(PromptCallback callback, PromptCallback cancelCallback) public SimplePrompt(PromptCallback callback, PromptCallback cancelCallback)
{ {
@ -7830,9 +7724,7 @@ namespace Server
if (m_CallbackHandlesCancel && m_Callback != null) if (m_CallbackHandlesCancel && m_Callback != null)
m_Callback(from, ""); m_Callback(from, "");
else else
{ m_CancelCallback?.Invoke(@from, "");
m_CancelCallback?.Invoke(from, "");
}
} }
} }
@ -7848,10 +7740,10 @@ namespace Server
private class SimpleStatePrompt<T> : Prompt private class SimpleStatePrompt<T> : Prompt
{ {
private PromptStateCallback<T> m_Callback; private readonly PromptStateCallback<T> m_Callback;
private PromptStateCallback<T> m_CancelCallback; private readonly PromptStateCallback<T> m_CancelCallback;
private T m_State; private readonly T m_State;
public SimpleStatePrompt(PromptStateCallback<T> callback, PromptStateCallback<T> cancelCallback, T state) public SimpleStatePrompt(PromptStateCallback<T> callback, PromptStateCallback<T> cancelCallback, T state)
{ {
@ -7962,10 +7854,7 @@ namespace Server
#region Get*InRange #region Get*InRange
public IPooledEnumerable<Item> GetItemsInRange(int range) public IPooledEnumerable<Item> GetItemsInRange(int range) => GetItemsInRange<Item>(range);
{
return GetItemsInRange<Item>(range);
}
public IPooledEnumerable<T> GetItemsInRange<T>(int range) where T : Item public IPooledEnumerable<T> GetItemsInRange<T>(int range) where T : Item
{ {
@ -7987,10 +7876,7 @@ namespace Server
return map.GetObjectsInRange(m_Location, range); return map.GetObjectsInRange(m_Location, range);
} }
public IPooledEnumerable<Mobile> GetMobilesInRange(int range) public IPooledEnumerable<Mobile> GetMobilesInRange(int range) => GetMobilesInRange<Mobile>(range);
{
return GetMobilesInRange<Mobile>(range);
}
public IPooledEnumerable<T> GetMobilesInRange<T>(int range) where T : Mobile public IPooledEnumerable<T> GetMobilesInRange<T>(int range) where T : Mobile
{ {
@ -8177,10 +8063,7 @@ namespace Server
return true; return true;
} }
public bool HasGump<T>() where T : Gump public bool HasGump<T>() where T : Gump => FindGump<T>() != null;
{
return FindGump<T>() != null;
}
public bool SendGump(Gump g) public bool SendGump(Gump g)
{ {
@ -8204,15 +8087,9 @@ namespace Server
#region Beneficial Checks/Actions #region Beneficial Checks/Actions
public virtual bool CanBeBeneficial(Mobile target) public virtual bool CanBeBeneficial(Mobile target) => CanBeBeneficial(target, true, false);
{
return CanBeBeneficial(target, true, false);
}
public virtual bool CanBeBeneficial(Mobile target, bool message) public virtual bool CanBeBeneficial(Mobile target, bool message) => CanBeBeneficial(target, message, false);
{
return CanBeBeneficial(target, message, false);
}
public virtual bool CanBeBeneficial(Mobile target, bool message, bool allowDead) public virtual bool CanBeBeneficial(Mobile target, bool message, bool allowDead)
{ {
@ -9001,10 +8878,7 @@ namespace Server
/// <seealso cref="ApplyPoison" /> /// <seealso cref="ApplyPoison" />
/// <seealso cref="Poison" /> /// <seealso cref="Poison" />
/// </summary> /// </summary>
public virtual bool CheckPoisonImmunity(Mobile from, Poison poison) public virtual bool CheckPoisonImmunity(Mobile from, Poison poison) => false;
{
return false;
}
/// <summary> /// <summary>
/// Overridable. Called from <see cref="ApplyPoison" />, this method checks if the Mobile is already poisoned by some /// Overridable. Called from <see cref="ApplyPoison" />, this method checks if the Mobile is already poisoned by some
@ -9014,10 +8888,7 @@ namespace Server
/// <seealso cref="ApplyPoison" /> /// <seealso cref="ApplyPoison" />
/// <seealso cref="Poison" /> /// <seealso cref="Poison" />
/// </summary> /// </summary>
public virtual bool CheckHigherPoison(Mobile from, Poison poison) public virtual bool CheckHigherPoison(Mobile from, Poison poison) => m_Poison != null && m_Poison.Level >= poison.Level;
{
return m_Poison != null && m_Poison.Level >= poison.Level;
}
/// <summary> /// <summary>
/// Overridable. Attempts to apply poison to the Mobile. Checks are made such that no /// Overridable. Attempts to apply poison to the Mobile. Checks are made such that no
@ -9090,10 +8961,7 @@ namespace Server
/// <seealso cref="CurePoison" /> /// <seealso cref="CurePoison" />
/// <seealso cref="Poison" /> /// <seealso cref="Poison" />
/// </summary> /// </summary>
public virtual bool CheckCure(Mobile from) public virtual bool CheckCure(Mobile from) => true;
{
return true;
}
/// <summary> /// <summary>
/// Overridable. Virtual event invoked when a call to <see cref="CurePoison" /> succeeded. /// Overridable. Virtual event invoked when a call to <see cref="CurePoison" /> succeeded.
@ -9166,10 +9034,7 @@ namespace Server
[CommandProperty(AccessLevel.GameMaster)] [CommandProperty(AccessLevel.GameMaster)]
public int FacialHairItemID public int FacialHairItemID
{ {
get get => m_FacialHair?.ItemID ?? 0;
{
return m_FacialHair?.ItemID ?? 0;
}
set set
{ {
if (m_FacialHair == null && value > 0) if (m_FacialHair == null && value > 0)
@ -9327,15 +9192,9 @@ namespace Server
return ret; return ret;
} }
public Direction GetDirectionTo(Point2D p) public Direction GetDirectionTo(Point2D p) => GetDirectionTo(p.m_X, p.m_Y);
{
return GetDirectionTo(p.m_X, p.m_Y);
}
public Direction GetDirectionTo(Point3D p) public Direction GetDirectionTo(Point3D p) => GetDirectionTo(p.m_X, p.m_Y);
{
return GetDirectionTo(p.m_X, p.m_Y);
}
public Direction GetDirectionTo(IPoint2D p) public Direction GetDirectionTo(IPoint2D p)
{ {

Some files were not shown because too many files have changed in this diff Show more