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

View file

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

View file

@ -36,7 +36,7 @@ namespace Server.Commands.Generic
List<object> list = new List<object>();
List<IPAddress> addresses = new List<IPAddress>();
List<NetState> states = NetState.Instances;
List<NetState> states = TcpServer.Instances;
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<NetState> states = NetState.Instances;
List<NetState> states = TcpServer.Instances;
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)
{
foreach (NetState state in NetState.Instances)
foreach (NetState state in TcpServer.Instances)
{
Mobile m = state.Mobile;
@ -743,7 +743,7 @@ namespace Server.Commands
[Description("View some stats about the server.")]
public static void Stats_OnCommand(CommandEventArgs e)
{
e.Mobile.SendMessage("Open Connections: {0}", NetState.Instances.Count);
e.Mobile.SendMessage("Open Connections: {0}", TcpServer.Instances.Count);
e.Mobile.SendMessage("Mobiles: {0}", World.Mobiles.Count);
e.Mobile.SendMessage("Items: {0}", World.Items.Count);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -9,7 +9,7 @@ using Server.Network;
namespace Server.Misc
{
public class ServerList
public static class ServerList
{
/*
* The default setting for Address, a value of 'null', will use your local IP address. If all of your local IP addresses

View file

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

View file

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

View file

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

View file

@ -119,7 +119,7 @@ namespace Server.Misc
int index = 0;
foreach (Mobile m in NetState.Instances.Where(state => state.Mobile != null).Select(state => state.Mobile))
foreach (Mobile m in TcpServer.Instances.Where(state => state.Mobile != null).Select(state => state.Mobile))
{
++index;
@ -181,4 +181,4 @@ namespace Server.Misc
}
}
}
}
}

View file

@ -36,6 +36,8 @@
</ItemGroup>
<ItemGroup>
<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>
</Project>

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -25,7 +25,7 @@ namespace Server.Diagnostics
{
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)
{

View file

@ -53,7 +53,7 @@ namespace Server.Diagnostics
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;
@ -87,7 +87,7 @@ namespace Server.Diagnostics
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)
: base($"0x{packetId:X2}")

View file

@ -25,7 +25,7 @@ namespace Server.Diagnostics
{
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)
: base(type.FullName)

View file

@ -25,7 +25,7 @@ namespace Server.Diagnostics
{
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)
: base(name)

View file

@ -196,7 +196,7 @@ namespace Server
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)
{
@ -512,7 +512,7 @@ namespace Server
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)
{

View file

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

View file

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

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{
public class GumpAlphaRegion : GumpEntry
{
private static byte[] m_LayoutName = Gump.StringToBuffer("checkertrans");
private static readonly byte[] m_LayoutName = Gump.StringToBuffer("checkertrans");
private int m_Width, m_Height;
private int m_X, m_Y;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{
public class GumpBackground : GumpEntry
{
private static byte[] m_LayoutName = Gump.StringToBuffer("resizepic");
private static readonly byte[] m_LayoutName = Gump.StringToBuffer("resizepic");
private int m_GumpID;
private int m_Width, m_Height;
private int m_X, m_Y;

View file

@ -30,7 +30,7 @@ namespace Server.Gumps
public class GumpButton : GumpEntry
{
private static byte[] m_LayoutName = Gump.StringToBuffer("button");
private static readonly byte[] m_LayoutName = Gump.StringToBuffer("button");
private int m_ButtonID;
private int m_ID1, m_ID2;
private int m_Param;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{
public class GumpCheck : GumpEntry
{
private static byte[] m_LayoutName = Gump.StringToBuffer("checkbox");
private static readonly byte[] m_LayoutName = Gump.StringToBuffer("checkbox");
private int m_ID1, m_ID2;
private bool m_InitialState;
private int m_SwitchID;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{
public class GumpGroup : GumpEntry
{
private static byte[] m_LayoutName = Gump.StringToBuffer("group");
private static readonly byte[] m_LayoutName = Gump.StringToBuffer("group");
private int m_Group;
public GumpGroup(int group) => m_Group = group;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{
public class GumpHtml : GumpEntry
{
private static byte[] m_LayoutName = Gump.StringToBuffer("htmlgump");
private static readonly byte[] m_LayoutName = Gump.StringToBuffer("htmlgump");
private bool m_Background, m_Scrollbar;
private string m_Text;
private int m_Width, m_Height;

View file

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

View file

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

View file

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

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{
public class GumpImageTiled : GumpEntry
{
private static byte[] m_LayoutName = Gump.StringToBuffer("gumppictiled");
private static readonly byte[] m_LayoutName = Gump.StringToBuffer("gumppictiled");
private int m_GumpID;
private int m_Width, m_Height;
private int m_X, m_Y;

View file

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

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{
public class GumpItemProperty : GumpEntry
{
private static byte[] m_LayoutName = Gump.StringToBuffer("itemproperty");
private static readonly byte[] m_LayoutName = Gump.StringToBuffer("itemproperty");
private uint m_Serial;
public GumpItemProperty(uint serial) => m_Serial = serial;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{
public class GumpLabel : GumpEntry
{
private static byte[] m_LayoutName = Gump.StringToBuffer("text");
private static readonly byte[] m_LayoutName = Gump.StringToBuffer("text");
private int m_Hue;
private string m_Text;
private int m_X, m_Y;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{
public class GumpLabelCropped : GumpEntry
{
private static byte[] m_LayoutName = Gump.StringToBuffer("croppedtext");
private static readonly byte[] m_LayoutName = Gump.StringToBuffer("croppedtext");
private int m_Hue;
private string m_Text;
private int m_Width, m_Height;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{
public class GumpPage : GumpEntry
{
private static byte[] m_LayoutName = Gump.StringToBuffer("page");
private static readonly byte[] m_LayoutName = Gump.StringToBuffer("page");
private int m_Page;
public GumpPage(int page) => m_Page = page;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{
public class GumpRadio : GumpEntry
{
private static byte[] m_LayoutName = Gump.StringToBuffer("radio");
private static readonly byte[] m_LayoutName = Gump.StringToBuffer("radio");
private int m_ID1, m_ID2;
private bool m_InitialState;
private int m_SwitchID;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{
public class GumpTextEntry : GumpEntry
{
private static byte[] m_LayoutName = Gump.StringToBuffer("textentry");
private static readonly byte[] m_LayoutName = Gump.StringToBuffer("textentry");
private int m_EntryID;
private int m_Hue;
private string m_InitialText;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{
public class GumpTextEntryLimited : GumpEntry
{
private static byte[] m_LayoutName = Gump.StringToBuffer("textentrylimited");
private static readonly byte[] m_LayoutName = Gump.StringToBuffer("textentrylimited");
private int m_EntryID;
private int m_Hue;
private string m_InitialText;

View file

@ -24,7 +24,7 @@ namespace Server.Gumps
{
public class GumpTooltip : GumpEntry
{
private static byte[] m_LayoutName = Gump.StringToBuffer("tooltip");
private static readonly byte[] m_LayoutName = Gump.StringToBuffer("tooltip");
private int m_Number;
public GumpTooltip(int number) => m_Number = number;

View file

@ -201,13 +201,13 @@ namespace Server
public class Item : IHued, IComparable<Item>, ISerializable, ISpawnable, IPropertyListObject
{
private BufferWriter m_SaveBuffer;
public BufferWriter SaveBuffer { get { return m_SaveBuffer; } }
private readonly BufferWriter m_SaveBuffer;
public BufferWriter SaveBuffer => m_SaveBuffer;
public const int QuestItemHue = 0x4EA; // Hmmmm... "for EA"?
public static readonly List<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;

View file

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

View file

@ -4,9 +4,9 @@
using System;
using Microsoft.Extensions.Logging;
namespace Libuv
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
{
public interface ILibuvTrace : ILogger
internal interface ILibuvTrace : ILogger
{
void ConnectionRead(string connectionId, int count);

View file

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

View file

@ -8,19 +8,21 @@ using System.IO.Pipelines;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Libuv.Internal;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
using Microsoft.Extensions.Logging;
namespace Libuv
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
{
public partial class LibuvConnection : TransportConnection
internal partial class LibuvConnection : TransportConnection
{
private static readonly int MinAllocBufferSize = SlabMemoryPool.BlockSize / 2;
private static readonly Action<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 CancellationTokenSource _connectionClosedTokenSource = new CancellationTokenSource();
@ -243,7 +245,7 @@ namespace Libuv
state._waitForConnectionClosedTcs.TrySetResult(null);
},
this,
false);
preferLocal: false);
}
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.
return new ConnectionAbortedException(uvError.Message, uvError);
}
if (LibuvConstants.IsConnectionReset(uvError.StatusCode))
else if (LibuvConstants.IsConnectionReset(uvError.StatusCode))
{
// Log connection resets at a lower (Debug) level.
Log.ConnectionReset(ConnectionId);
return new ConnectionResetException(uvError.Message, uvError);
}
// This is unexpected.
Log.ConnectionError(ConnectionId, uvError);
return new IOException(uvError.Message, uvError);
else
{
// This is unexpected.
Log.ConnectionError(ConnectionId, uvError);
return new IOException(uvError.Message, uvError);
}
}
private void CancelConnectionClosedToken()

View file

@ -7,15 +7,14 @@ using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Libuv.Internal;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Server;
namespace Libuv
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
{
public class LibuvConnectionListener : IConnectionListener
internal class LibuvConnectionListener : IConnectionListener
{
private readonly List<ListenerContext> _listeners = new List<ListenerContext>();
private IAsyncEnumerator<LibuvConnection> _acceptEnumerator;
@ -63,8 +62,7 @@ namespace Libuv
var disposeTasks = _listeners.Select(listener => ((IAsyncDisposable)listener).DisposeAsync()).ToArray();
if (!await WaitAsync(Task.WhenAll(disposeTasks), TimeSpan.FromSeconds(5)).ConfigureAwait(false))
Log.LogError(0, null, "Disposing listeners failed");
if (!await WaitAsync(Task.WhenAll(disposeTasks), TimeSpan.FromSeconds(5)).ConfigureAwait(false)) Log.LogError(0, null, "Disposing listeners failed");
}
@ -101,14 +99,9 @@ namespace Libuv
}
Threads.Clear();
#if DEBUG && !INNER_LOOP
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
#endif
}
public async Task BindAsync()
internal async Task BindAsync()
{
// TODO: Move thread management to LibuvTransportFactory
// TODO: Split endpoint management from thread management
@ -127,7 +120,7 @@ namespace Libuv
}
else
{
var pipeName = (Core.IsWindows ? @"\\.\pipe\kestrel_" : "/tmp/kestrel_") + Guid.NewGuid().ToString("n");
var pipeName = (Libuv.IsWindows ? @"\\.\pipe\kestrel_" : "/tmp/kestrel_") + Guid.NewGuid().ToString("n");
var pipeMessage = Guid.NewGuid().ToByteArray();
var listenerPrimary = new ListenerPrimary(TransportContext);
@ -171,7 +164,7 @@ namespace Libuv
while (remainingSlots > 0)
{
// Calling GetAwaiter().GetResult() is safe because we know the task is completed
var (connection, slot) = (await Task.WhenAny(slots)).GetAwaiter().GetResult();
(var connection, var slot) = (await Task.WhenAny(slots)).GetAwaiter().GetResult();
// If the connection is null then the listener was closed
if (connection == null)

View file

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

View file

@ -4,11 +4,11 @@
using System;
using System.IO.Pipelines;
using System.Threading.Tasks;
using Libuv.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
namespace Libuv
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
{
public class LibuvOutputConsumer
internal class LibuvOutputConsumer
{
private readonly LibuvThread _thread;
private readonly UvStreamHandle _socket;

View file

@ -9,13 +9,13 @@ using System.IO.Pipelines;
using System.Runtime.ExceptionServices;
using System.Threading;
using System.Threading.Tasks;
using Libuv.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Libuv
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
{
public class LibuvThread : PipeScheduler
internal class LibuvThread : PipeScheduler
{
// maximum times the work queues swapped and are processed in a single pass
// as completing a task may immediately have write data to put on the network
@ -35,8 +35,8 @@ namespace Libuv
private readonly object _workSync = new object();
private readonly object _closeHandleSync = new object();
private readonly object _startSync = new object();
private bool _stopImmediate;
private bool _initCompleted;
private bool _stopImmediate = false;
private bool _initCompleted = false;
private Exception _closeError;
private readonly ILibuvTrace _log;
@ -60,9 +60,9 @@ namespace Libuv
#endif
#if !DEBUG
// Mark the thread as being as unimportant to keeping the process alive.
// Don't do this for debug builds, so we know if the thread isn't terminating.
_thread.IsBackground = true;
// Mark the thread as being as unimportant to keeping the process alive.
// Don't do this for debug builds, so we know if the thread isn't terminating.
_thread.IsBackground = true;
#endif
QueueCloseHandle = PostCloseHandle;
QueueCloseAsyncHandle = EnqueueCloseHandle;
@ -76,10 +76,6 @@ namespace Libuv
public WriteReqPool WriteReqPool { get; }
#if DEBUG
public List<WeakReference> Requests { get; } = new List<WeakReference>();
#endif
public Exception FatalError => _closeError;
public Action<Action<IntPtr>, IntPtr> QueueCloseHandle { get; }
@ -129,18 +125,6 @@ namespace Libuv
if (_closeError != null) ExceptionDispatchInfo.Capture(_closeError).Throw();
}
#if DEBUG && !INNER_LOOP
private void CheckUvReqLeaks()
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
// Detect leaks in UvRequest objects
foreach (var request in Requests) Debug.Assert(request.Target == null, $"{request.Target?.GetType()} object is still alive.");
}
#endif
private void AllowStop()
{
_post.Unreference();
@ -320,11 +304,6 @@ namespace Libuv
}
WriteReqPool.Dispose();
_threadTcs.SetResult(null);
#if DEBUG && !INNER_LOOP
// Check for handle leaks after disposing everything
CheckUvReqLeaks();
#endif
}
}
@ -406,8 +385,7 @@ namespace Libuv
return wasWork;
}
private static async Task<bool> WaitAsync(Task task, TimeSpan timeout) =>
await Task.WhenAny(task, Task.Delay(timeout)).ConfigureAwait(false) == task;
private static async Task<bool> WaitAsync(Task task, TimeSpan timeout) => await Task.WhenAny(task, Task.Delay(timeout)).ConfigureAwait(false) == task;
public override void Schedule(Action<object> action, object state)
{

View file

@ -4,9 +4,9 @@
using System;
using Microsoft.Extensions.Logging;
namespace Libuv
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
{
public class LibuvTrace : ILibuvTrace
internal class LibuvTrace : ILibuvTrace
{
// ConnectionRead: Reserved: 3

View file

@ -3,9 +3,9 @@
using Microsoft.Extensions.Hosting;
namespace Libuv
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
{
public class LibuvTransportContext
internal class LibuvTransportContext
{
public LibuvTransportOptions Options { get; set; }

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

View file

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

View file

@ -7,19 +7,16 @@ using System.IO;
using System.Net;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Libuv.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
using Microsoft.Extensions.Logging;
using Server;
#pragma warning disable 169
namespace Libuv
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
{
/// <summary>
/// A primary listener waits for incoming connections on a specified socket. Incoming
/// connections may be passed to a secondary listener to handle.
/// </summary>
public class ListenerPrimary : Listener
internal class ListenerPrimary : Listener
{
// The list of pipes that can be dispatched to (where we've confirmed the _pipeMessage)
private readonly List<UvPipeHandle> _dispatchPipes = new List<UvPipeHandle>();
@ -29,7 +26,7 @@ namespace Libuv
private string _pipeName;
private byte[] _pipeMessage;
private IntPtr _fileCompletionInfoPtr;
private bool _tryDetachFromIOCP = Core.IsWindows;
private bool _tryDetachFromIOCP = PlatformApis.IsWindows;
// this message is passed to write2 because it must be non-zero-length,
// but it has no other functional significance
@ -151,15 +148,17 @@ namespace Libuv
Thread.Loop.Libuv.uv_fileno(handle, ref socket);
if (NtSetInformationFile(socket, out statusBlock, _fileCompletionInfoPtr,
(uint)Marshal.SizeOf<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
_tryDetachFromIOCP = false;
}
private struct IO_STATUS_BLOCK
{
#pragma warning disable 169
uint status;
ulong information;
#pragma warning restore 169
}
private struct FILE_COMPLETION_INFORMATION
@ -219,7 +218,7 @@ namespace Libuv
{
// This is an unexpected immediate termination of the dispatch pipe most likely caused by an
// external process scanning the pipe, so don't we don't log it too severely.
// https://github.com/aspnet/AspNetCore/issues/4741
// https://github.com/dotnet/aspnetcore/issues/4741
dispatchPipe.Dispose();
_bufHandle.Free();

View file

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

View file

@ -4,14 +4,15 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Server;
namespace Libuv.Internal
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking
{
public class LibuvFunctions
internal class LibuvFunctions
{
public LibuvFunctions()
{
IsWindows = PlatformApis.IsWindows;
_uv_loop_init = NativeMethods.uv_loop_init;
_uv_loop_close = NativeMethods.uv_loop_close;
_uv_run = NativeMethods.uv_run;
@ -63,6 +64,8 @@ namespace Libuv.Internal
{
}
public readonly bool IsWindows;
public void ThrowIfErrored(int statusCode)
{
// Note: method is explicitly small so the success case is easily inlined
@ -83,47 +86,51 @@ namespace Libuv.Internal
error = statusCode < 0 ? GetError(statusCode) : null;
}
// Note: method marked as NoInlining so it doesn't bloat either of the two preceding functions
// Check and ThrowError and alter their jit heuristics.
[MethodImpl(MethodImplOptions.NoInlining)]
private UvException GetError(int statusCode) =>
new UvException($"Error {statusCode} {err_name(statusCode)} {strerror(statusCode)}", statusCode);
private UvException GetError(int statusCode)
{
// Note: method marked as NoInlining so it doesn't bloat either of the two preceding functions
// Check and ThrowError and alter their jit heuristics.
var errorName = err_name(statusCode);
var errorDescription = strerror(statusCode);
return new UvException("Error " + statusCode + " " + errorName + " " + errorDescription, statusCode);
}
public Func<UvLoopHandle, int> _uv_loop_init;
protected Func<UvLoopHandle, int> _uv_loop_init;
public void loop_init(UvLoopHandle 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)
{
handle.Validate(true);
handle.Validate(closed: true);
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)
{
handle.Validate();
ThrowIfErrored(_uv_run(handle, mode));
}
public Action<UvLoopHandle> _uv_stop;
protected Action<UvLoopHandle> _uv_stop;
public void stop(UvLoopHandle handle)
{
handle.Validate();
_uv_stop(handle);
}
public Action<UvHandle> _uv_ref;
protected Action<UvHandle> _uv_ref;
public void @ref(UvHandle handle)
{
handle.Validate();
_uv_ref(handle);
}
public Action<UvHandle> _uv_unref;
protected Action<UvHandle> _uv_unref;
public void unref(UvHandle handle)
{
handle.Validate();
@ -131,8 +138,8 @@ namespace Libuv.Internal
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int uv_fileno_func(UvHandle handle, ref IntPtr socket);
public uv_fileno_func _uv_fileno;
protected delegate int uv_fileno_func(UvHandle handle, ref IntPtr socket);
protected uv_fileno_func _uv_fileno;
public void uv_fileno(UvHandle handle, ref IntPtr socket)
{
handle.Validate();
@ -141,10 +148,10 @@ namespace Libuv.Internal
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void uv_close_cb(IntPtr handle);
public Action<IntPtr, uv_close_cb> _uv_close;
protected Action<IntPtr, uv_close_cb> _uv_close;
public void close(UvHandle handle, uv_close_cb close_cb)
{
handle.Validate(true);
handle.Validate(closed: true);
_uv_close(handle.InternalGetHandle(), close_cb);
}
@ -155,7 +162,7 @@ namespace Libuv.Internal
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void uv_async_cb(IntPtr handle);
public Func<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)
{
loop.Validate();
@ -163,19 +170,19 @@ namespace Libuv.Internal
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)
{
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)
{
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)
{
loop.Validate();
@ -183,29 +190,29 @@ namespace Libuv.Internal
ThrowIfErrored(_uv_tcp_init(loop, handle));
}
public delegate int uv_tcp_bind_func(UvTcpHandle handle, ref SockAddr addr, int flags);
public uv_tcp_bind_func _uv_tcp_bind;
protected delegate int uv_tcp_bind_func(UvTcpHandle handle, ref SockAddr addr, int flags);
protected uv_tcp_bind_func _uv_tcp_bind;
public void tcp_bind(UvTcpHandle handle, ref SockAddr addr, int flags)
{
handle.Validate();
ThrowIfErrored(_uv_tcp_bind(handle, ref addr, flags));
}
public Func<UvTcpHandle, IntPtr, int> _uv_tcp_open;
protected Func<UvTcpHandle, IntPtr, int> _uv_tcp_open;
public void tcp_open(UvTcpHandle handle, IntPtr hSocket)
{
handle.Validate();
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)
{
handle.Validate();
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)
{
loop.Validate();
@ -213,14 +220,14 @@ namespace Libuv.Internal
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)
{
handle.Validate();
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)
{
handle.Validate();
@ -229,14 +236,14 @@ namespace Libuv.Internal
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
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)
{
handle.Validate();
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)
{
server.Validate();
@ -246,7 +253,7 @@ namespace Libuv.Internal
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
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)
{
req.Validate();
@ -254,7 +261,7 @@ namespace Libuv.Internal
_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)
{
handle.Validate();
@ -265,21 +272,21 @@ namespace Libuv.Internal
public delegate void uv_alloc_cb(IntPtr server, int suggested_size, out uv_buf_t buf);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void uv_read_cb(IntPtr server, int nread, ref uv_buf_t buf);
public Func<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)
{
handle.Validate();
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)
{
handle.Validate();
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)
{
handle.Validate();
@ -291,8 +298,8 @@ namespace Libuv.Internal
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void uv_write_cb(IntPtr req, int status);
public unsafe delegate int uv_write_func(UvRequest req, UvStreamHandle handle, uv_buf_t* bufs, int nbufs, uv_write_cb cb);
public uv_write_func _uv_write;
protected unsafe delegate int uv_write_func(UvRequest req, UvStreamHandle handle, uv_buf_t* bufs, int nbufs, uv_write_cb cb);
protected uv_write_func _uv_write;
public unsafe void write(UvRequest req, UvStreamHandle handle, uv_buf_t* bufs, int nbufs, uv_write_cb cb)
{
req.Validate();
@ -300,8 +307,8 @@ namespace Libuv.Internal
ThrowIfErrored(_uv_write(req, handle, bufs, nbufs, cb));
}
public unsafe delegate int uv_write2_func(UvRequest req, UvStreamHandle handle, uv_buf_t* bufs, int nbufs, UvStreamHandle sendHandle, uv_write_cb cb);
public uv_write2_func _uv_write2;
protected unsafe delegate int uv_write2_func(UvRequest req, UvStreamHandle handle, uv_buf_t* bufs, int nbufs, UvStreamHandle sendHandle, uv_write_cb cb);
protected uv_write2_func _uv_write2;
public unsafe void write2(UvRequest req, UvStreamHandle handle, uv_buf_t* bufs, int nbufs, UvStreamHandle sendHandle, uv_write_cb cb)
{
req.Validate();
@ -309,38 +316,38 @@ namespace Libuv.Internal
ThrowIfErrored(_uv_write2(req, handle, bufs, nbufs, sendHandle, cb));
}
public Func<int, IntPtr> _uv_err_name;
protected Func<int, IntPtr> _uv_err_name;
public string err_name(int err)
{
IntPtr ptr = _uv_err_name(err);
return ptr == IntPtr.Zero ? null : Marshal.PtrToStringAnsi(ptr);
}
public Func<int, IntPtr> _uv_strerror;
protected Func<int, IntPtr> _uv_strerror;
public string strerror(int err)
{
IntPtr ptr = _uv_strerror(err);
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 Func<HandleType, int> _uv_handle_size;
protected Func<HandleType, int> _uv_handle_size;
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 delegate int uv_ip4_addr_func(string ip, int port, out SockAddr addr);
public uv_ip4_addr_func _uv_ip4_addr;
protected delegate int uv_ip4_addr_func(string ip, int port, out SockAddr addr);
protected uv_ip4_addr_func _uv_ip4_addr;
public void ip4_addr(string ip, int port, out SockAddr addr, out UvException error)
{
Check(_uv_ip4_addr(ip, port, out addr), out error);
}
public delegate int uv_ip6_addr_func(string ip, int port, out SockAddr addr);
public uv_ip6_addr_func _uv_ip6_addr;
protected delegate int uv_ip6_addr_func(string ip, int port, out SockAddr addr);
protected uv_ip6_addr_func _uv_ip6_addr;
public void ip6_addr(string ip, int port, out SockAddr addr, out UvException error)
{
Check(_uv_ip6_addr(ip, port, out addr), out error);
@ -348,15 +355,15 @@ namespace Libuv.Internal
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void uv_walk_cb(IntPtr handle, IntPtr arg);
public Func<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)
{
loop.Validate();
_uv_walk(loop, walk_cb, arg);
}
public Func<UvLoopHandle, UvTimerHandle, int> _uv_timer_init;
public void timer_init(UvLoopHandle loop, UvTimerHandle handle)
protected Func<UvLoopHandle, UvTimerHandle, int> _uv_timer_init;
public unsafe void timer_init(UvLoopHandle loop, UvTimerHandle handle)
{
loop.Validate();
handle.Validate();
@ -365,29 +372,29 @@ namespace Libuv.Internal
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void uv_timer_cb(IntPtr handle);
public Func<UvTimerHandle, uv_timer_cb, long, long, int> _uv_timer_start;
public void timer_start(UvTimerHandle handle, uv_timer_cb cb, long timeout, long repeat)
protected Func<UvTimerHandle, uv_timer_cb, long, long, int> _uv_timer_start;
public unsafe void timer_start(UvTimerHandle handle, uv_timer_cb cb, long timeout, long repeat)
{
handle.Validate();
ThrowIfErrored(_uv_timer_start(handle, cb, timeout, repeat));
}
public Func<UvTimerHandle, int> _uv_timer_stop;
public void timer_stop(UvTimerHandle handle)
protected Func<UvTimerHandle, int> _uv_timer_stop;
public unsafe void timer_stop(UvTimerHandle handle)
{
handle.Validate();
ThrowIfErrored(_uv_timer_stop(handle));
}
public Func<UvLoopHandle, long> _uv_now;
public long now(UvLoopHandle loop)
protected Func<UvLoopHandle, long> _uv_now;
public unsafe long now(UvLoopHandle loop)
{
loop.Validate();
return _uv_now(loop);
}
public delegate int uv_tcp_getsockname_func(UvTcpHandle handle, out SockAddr addr, ref int namelen);
public uv_tcp_getsockname_func _uv_tcp_getsockname;
protected uv_tcp_getsockname_func _uv_tcp_getsockname;
public void tcp_getsockname(UvTcpHandle handle, out SockAddr addr, ref int namelen)
{
handle.Validate();
@ -395,14 +402,14 @@ namespace Libuv.Internal
}
public delegate int uv_tcp_getpeername_func(UvTcpHandle handle, out SockAddr addr, ref int namelen);
public uv_tcp_getpeername_func _uv_tcp_getpeername;
protected uv_tcp_getpeername_func _uv_tcp_getpeername;
public void tcp_getpeername(UvTcpHandle handle, out SockAddr addr, ref int namelen)
{
handle.Validate();
ThrowIfErrored(_uv_tcp_getpeername(handle, out addr, ref namelen));
}
public uv_buf_t buf_init(IntPtr memory, int len) => new uv_buf_t(memory, len, Core.IsWindows);
public uv_buf_t buf_init(IntPtr memory, int len) => new uv_buf_t(memory, len, IsWindows);
public struct uv_buf_t
{
@ -417,9 +424,9 @@ namespace Libuv.Internal
private readonly IntPtr _field0;
private readonly IntPtr _field1;
public uv_buf_t(IntPtr memory, int len, bool windows)
public uv_buf_t(IntPtr memory, int len, bool IsWindows)
{
if (windows)
if (IsWindows)
{
_field0 = (IntPtr)len;
_field1 = memory;
@ -581,16 +588,16 @@ namespace Libuv.Internal
public static extern int uv_walk(UvLoopHandle loop, uv_walk_cb walk_cb, IntPtr arg);
[DllImport("libuv", CallingConvention = CallingConvention.Cdecl)]
public static extern int uv_timer_init(UvLoopHandle loop, UvTimerHandle handle);
public static extern unsafe int uv_timer_init(UvLoopHandle loop, UvTimerHandle handle);
[DllImport("libuv", CallingConvention = CallingConvention.Cdecl)]
public static extern int uv_timer_start(UvTimerHandle handle, uv_timer_cb cb, long timeout, long repeat);
public static extern unsafe int uv_timer_start(UvTimerHandle handle, uv_timer_cb cb, long timeout, long repeat);
[DllImport("libuv", CallingConvention = CallingConvention.Cdecl)]
public static extern int uv_timer_stop(UvTimerHandle handle);
public static extern unsafe int uv_timer_stop(UvTimerHandle handle);
[DllImport("libuv", CallingConvention = CallingConvention.Cdecl)]
public static extern long uv_now(UvLoopHandle loop);
public static extern unsafe long uv_now(UvLoopHandle loop);
[DllImport("WS2_32.dll", CallingConvention = CallingConvention.Winapi)]
public static extern unsafe int WSAIoctl(

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

View file

@ -5,13 +5,13 @@ using System;
using System.Diagnostics;
using System.Threading;
namespace Libuv.Internal
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking
{
public class UvAsyncHandle : UvHandle
internal class UvAsyncHandle : UvHandle
{
private static readonly LibuvFunctions.uv_close_cb _destroyMemory = handle => DestroyMemory(handle);
private static readonly LibuvFunctions.uv_close_cb _destroyMemory = (handle) => DestroyMemory(handle);
private static readonly LibuvFunctions.uv_async_cb _uv_async_cb = handle => AsyncCb(handle);
private static readonly LibuvFunctions.uv_async_cb _uv_async_cb = (handle) => AsyncCb(handle);
private Action _callback;
private Action<Action<IntPtr>, IntPtr> _queueCloseHandle;
@ -56,7 +56,7 @@ namespace Libuv.Internal
{
// This can be called from the finalizer.
// Ensure the closure doesn't reference "this".
LibuvFunctions uv = _uv;
var uv = _uv;
_queueCloseHandle(memory2 => uv.close(memory2, _destroyMemory), memory);
uv.unsafe_async_send(memory);
}

View file

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

View file

@ -3,9 +3,9 @@
using System;
namespace Libuv.Internal
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking
{
public class UvException : Exception
internal class UvException : Exception
{
public UvException(string message, int statusCode) : base(message) => StatusCode = statusCode;

View file

@ -5,11 +5,11 @@ using System;
using System.Diagnostics;
using System.Threading;
namespace Libuv.Internal
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking
{
public abstract class UvHandle : UvMemory
internal abstract class UvHandle : UvMemory
{
private static readonly LibuvFunctions.uv_close_cb _destroyMemory = DestroyMemory;
private static readonly LibuvFunctions.uv_close_cb _destroyMemory = (handle) => DestroyMemory(handle);
private Action<Action<IntPtr>, IntPtr> _queueCloseHandle;
protected UvHandle(ILibuvTrace logger) : base (logger)
@ -28,7 +28,7 @@ namespace Libuv.Internal
protected override bool ReleaseHandle()
{
IntPtr memory = handle;
var memory = handle;
if (memory != IntPtr.Zero)
{
handle = IntPtr.Zero;
@ -41,7 +41,7 @@ namespace Libuv.Internal
{
// This can be called from the finalizer.
// Ensure the closure doesn't reference "this".
LibuvFunctions uv = _uv;
var uv = _uv;
_queueCloseHandle(memory2 => uv.close(memory2, _destroyMemory), memory);
}
else

View file

@ -4,9 +4,9 @@
using System;
using System.Threading;
namespace Libuv.Internal
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking
{
public class UvLoopHandle : UvMemory
internal class UvLoopHandle : UvMemory
{
public UvLoopHandle(ILibuvTrace logger) : base(logger)
{

View file

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

View file

@ -3,9 +3,9 @@
using System;
namespace Libuv.Internal
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking
{
public class UvPipeHandle : UvStreamHandle
internal class UvPipeHandle : UvStreamHandle
{
public UvPipeHandle(ILibuvTrace logger) : base(logger)
{

View file

@ -4,9 +4,9 @@
using System;
using System.Runtime.InteropServices;
namespace Libuv.Internal
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking
{
public class UvRequest : UvMemory
internal class UvRequest : UvMemory
{
protected UvRequest(ILibuvTrace logger) : base(logger, GCHandleType.Normal)
{
@ -14,11 +14,6 @@ namespace Libuv.Internal
public virtual void Init(LibuvThread thread)
{
#if DEBUG
// Store weak handles to all UvRequest objects so we can do leak detection
// while running tests
thread.Requests.Add(new WeakReference(this));
#endif
}
protected override bool ReleaseHandle()
@ -29,3 +24,4 @@ namespace Libuv.Internal
}
}
}

View file

@ -5,16 +5,14 @@ using System;
using System.Runtime.InteropServices;
using Microsoft.Extensions.Logging;
namespace Libuv.Internal
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking
{
public abstract class UvStreamHandle : UvHandle
internal abstract class UvStreamHandle : UvHandle
{
private static readonly LibuvFunctions.uv_connection_cb _uv_connection_cb = UvConnectionCb;
private static readonly LibuvFunctions.uv_connection_cb _uv_connection_cb = (handle, status) => UvConnectionCb(handle, status);
// Ref and out lamda params must be explicitly typed
private static readonly LibuvFunctions.uv_alloc_cb _uv_alloc_cb =
(IntPtr handle, int suggested_size, out LibuvFunctions.uv_buf_t buf) => UvAllocCb(handle, suggested_size, out buf);
private static readonly LibuvFunctions.uv_read_cb _uv_read_cb =
(IntPtr handle, int status, ref LibuvFunctions.uv_buf_t buf) => UvReadCb(handle, status, ref buf);
private static readonly LibuvFunctions.uv_alloc_cb _uv_alloc_cb = (IntPtr handle, int suggested_size, out LibuvFunctions.uv_buf_t buf) => UvAllocCb(handle, suggested_size, out buf);
private static readonly LibuvFunctions.uv_read_cb _uv_read_cb = (IntPtr handle, int status, ref LibuvFunctions.uv_buf_t buf) => UvReadCb(handle, status, ref buf);
private Action<UvStreamHandle, int, UvException, object> _listenCallback;
private object _listenState;

View file

@ -5,9 +5,9 @@ using System;
using System.Net;
using System.Runtime.InteropServices;
namespace Libuv.Internal
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking
{
public class UvTcpHandle : UvStreamHandle
internal class UvTcpHandle : UvStreamHandle
{
public UvTcpHandle(ILibuvTrace logger) : base(logger)
{

View file

@ -4,9 +4,9 @@
using System;
using Microsoft.Extensions.Logging;
namespace Libuv.Internal
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking
{
public class UvTimerHandle : UvHandle
internal class UvTimerHandle : UvHandle
{
private static readonly LibuvFunctions.uv_timer_cb _uv_timer_cb = UvTimerCb;

View file

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

View file

@ -3,11 +3,11 @@
using System;
using System.Collections.Generic;
using Libuv.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
namespace Libuv
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
{
public class WriteReqPool
internal class WriteReqPool
{
private const int _maxPooledWriteReqs = 1024;

View file

@ -4,7 +4,7 @@
using System;
using System.Buffers;
namespace Libuv
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv
{
/// <summary>
/// Provides programmatic configuration of Libuv transport features.
@ -19,6 +19,14 @@ namespace Libuv
/// </remarks>
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>
/// The maximum length of the pending connection queue.
/// </summary>
@ -39,12 +47,19 @@ namespace Libuv
{
// Actual core count would be a better number
// rather than logical cores which includes hyper-threaded cores.
// Divide by 2 for hyper-threading, and good defaults (still need threads for the game thread).
// Divide by 2 for hyper-threading, and good defaults (still need threads to do webserving).
var threadCount = Environment.ProcessorCount >> 1;
// Receive Side Scaling RSS Processor count currently maxes out at 16
// would be better to check the NIC's current hardware queues; but xplat...
return threadCount < 1 ? 1 : threadCount > 16 ? 16 : threadCount;
if (threadCount < 1)
// Ensure shifted value is at least one
return 1;
if (threadCount > 16)
// Receive Side Scaling RSS Processor count currently maxes out at 16
// would be better to check the NIC's current hardware queues; but xplat...
return 16;
return threadCount;
}
}
}

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
{
private static int[] m_EmptyInts = new int[0];
private static readonly int[] m_EmptyInts = new int[0];
private int[] m_Keywords;
public KeywordList()

View file

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

View file

@ -262,16 +262,17 @@ namespace Server
private static readonly List<Item> _EmptyFixItems = new List<Item>();
private Region m_DefaultRegion;
private int m_FileIndex;
private readonly int m_FileIndex;
private string m_Name;
private Sector[][] m_Sectors;
private readonly Sector[][] m_Sectors;
private int m_SectorsWidth, m_SectorsHeight;
private readonly int m_SectorsWidth;
private readonly int m_SectorsHeight;
private TileMatrix m_Tiles;
private object tileLock = new object();
private readonly object tileLock = new object();
public Map(int mapID, int mapIndex, int fileIndex, int width, int height, int season, string name, MapRules rules)
{

View file

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

View file

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

View file

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

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