LibUv Networking (#65)

This commit is contained in:
Kamron Batman 2019-12-26 18:08:50 -08:00 committed by GitHub
parent ec6629fbe9
commit 5e2be2d7b6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
69 changed files with 5612 additions and 586 deletions

View file

@ -28,6 +28,7 @@ using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Connections;
using Server.Accounting;
using Server.Diagnostics;
using Server.Gumps;
@ -93,7 +94,6 @@ namespace Server.Network
{
private string m_ToString;
private ClientVersion m_Version;
private SendQueue<Packet> m_SendQueue = new SendQueue<Packet>();
public DateTime ConnectedOn { get; }
@ -266,11 +266,9 @@ namespace Server.Network
return newTrade.From.Container;
}
public bool Running { get; private set; }
public bool Seeded { get; set; }
public Socket Socket { get; private set; }
public ConnectionContext Connection { get; private set; }
public bool CompressionEnabled { get; set; }
@ -282,12 +280,16 @@ namespace Server.Network
public List<IMenu> Menus { get; private set; }
public PipeReader RecvPipe => Connection.Transport.Input;
public PipeWriter SendPipe => Connection.Transport.Output;
public static int GumpCap { get; set; } = 512;
public static int HuePickerCap { get; set; } = 512;
public static int MenuCap { get; set; } = 512;
public void WriteConsole(string text)
{
Console.WriteLine("Client: {0}: {1}", this, text);
@ -403,23 +405,24 @@ namespace Server.Network
public static List<NetState> Instances { get; } = new List<NetState>();
public NetState(Socket socket, MessagePump pump)
public void SetConnectionAlive() => m_NextCheckActivity = Core.TickCount + 60000;
public NetState(ConnectionContext connection, MessagePump pump)
{
Socket = socket;
Connection = connection;
Seeded = false;
Running = false;
Gumps = new List<Gump>();
HuePickers = new List<HuePicker>();
Menus = new List<IMenu>();
Trades = new List<SecureTrade>();
m_NextCheckActivity = Core.TickCount + 30000;
SetConnectionAlive();
Instances.Add(this);
try
{
Address = Utility.Intern(((IPEndPoint)Socket.RemoteEndPoint).Address);
Address = Utility.Intern(((IPEndPoint)Connection.RemoteEndPoint).Address);
m_ToString = Address.ToString();
}
catch (Exception ex)
@ -430,10 +433,11 @@ namespace Server.Network
}
ConnectedOn = DateTime.UtcNow;
_ = Start(pump);
Console.WriteLine("Client: {0}: Connected. [{1} Online]", this, Instances.Count);
_ = ProcessRecvs(pump);
CreatedCallback?.Invoke(this);
Console.WriteLine("Client: {0}: Connected. [{1} Online]", this, NetState.Instances.Count);
}
public static void Pause()
@ -448,13 +452,38 @@ namespace Server.Network
public virtual void Send(Packet p)
{
if (Socket == null || BlockAllPackets)
if (Connection == null || BlockAllPackets)
{
p.OnSend();
return;
}
m_SendQueue.Enqueue(p);
try
{
ReadOnlySpan<byte> buffer = p.Compile(CompressionEnabled, out int length);
if (buffer.Length <= 0 || length <= 0)
{
p.OnSend();
return;
}
buffer.Slice(0, length).CopyTo(SendPipe.GetSpan(length));
SendPipe.Advance(length);
SendPipe.FlushAsync().GetAwaiter().GetResult();
p.OnSend();
}
catch (SocketException ex)
{
Console.WriteLine(ex);
TraceException(ex);
Dispose();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
public bool CheckEncrypted(int packetID)
@ -470,121 +499,31 @@ namespace Server.Network
return false;
}
private Pipe m_RecvdPipe;
private async Task Start(MessagePump pump)
private async Task ProcessRecvs(MessagePump pump)
{
m_RecvdPipe = new Pipe();
Running = true;
await Task.WhenAll(ProcessSends(), ProcessRecvs(), HandlePackets(pump)).ConfigureAwait(false);
}
private async Task ProcessRecvs()
{
PipeWriter w = m_RecvdPipe.Writer;
while (true)
{
if (m_AsyncState.Paused)
{
await Timer.Pause(50).ConfigureAwait(false);
continue;
}
try
{
Memory<byte> memory = w.GetMemory();
int bytesRead = await Socket.ReceiveAsync(memory, SocketFlags.None).ConfigureAwait(false);
if (bytesRead == 0)
break;
Interlocked.Exchange(ref m_NextCheckActivity, Core.TickCount + 90000);
w.Advance(bytesRead);
FlushResult result = await w.FlushAsync().ConfigureAwait(false);
if (result.IsCompleted || result.IsCanceled)
break;
}
catch
{
break;
}
}
w.Complete();
Dispose();
}
private async Task ProcessSends()
{
while (true)
try
{
Packet p = await m_SendQueue?.DequeueAsync();
if (p == null)
break;
ReadOnlyMemory<byte> buffer = p.Compile(CompressionEnabled, out int length);
if (buffer.Length <= 0 || length <= 0)
{
p.OnSend();
return;
}
buffer = buffer.Slice(0, length);
PacketSendProfile prof = null;
if (Core.Profiling)
prof = PacketSendProfile.Acquire(p.GetType());
prof?.Start();
await Socket.SendAsync(buffer, SocketFlags.None).ConfigureAwait(false);
p.OnSend();
prof?.Finish(length);
}
catch (SocketException ex)
{
Console.WriteLine(ex);
TraceException(ex);
Dispose();
break;
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
private async Task HandlePackets(MessagePump pump)
{
PipeReader pr = m_RecvdPipe.Reader;
while (true)
{
ReadResult result = await pr.ReadAsync();
ReadResult result = await RecvPipe.ReadAsync();
ReadOnlySequence<byte> seq = result.Buffer;
if (seq.Length == 0)
if (seq.IsEmpty)
break;
long pos = PacketHandlers.ProcessPacket(pump, this, seq);
SetConnectionAlive();
int pos = PacketHandlers.ProcessPacket(pump, this, seq);
if (pos <= 0)
break;
pr.AdvanceTo(seq.GetPosition(pos, seq.Start));
RecvPipe.AdvanceTo(seq.Slice(0, pos).End);
if (result.IsCompleted || result.IsCanceled)
break;
}
pr.Complete();
RecvPipe.Complete();
Dispose();
}
public PacketHandler GetHandler(int packetID) =>
@ -595,7 +534,7 @@ namespace Server.Network
public void CheckAlive(long curTicks)
{
if (Socket == null || m_NextCheckActivity - curTicks >= 0)
if (Connection == null || m_NextCheckActivity - curTicks >= 0)
return;
Console.WriteLine("Client: {0}: Disconnecting due to inactivity...", this);
@ -637,21 +576,18 @@ namespace Server.Network
if (disposing == 1)
return;
Task.Run(async () =>
try
{
m_RecvdPipe.Reader.CancelPendingRead();
m_RecvdPipe.Reader.Complete();
await m_RecvdPipe.Writer.FlushAsync().ConfigureAwait(false);
m_RecvdPipe.Writer.Complete();
Connection.Abort();
Task.Run(Connection.DisposeAsync).Wait();
}
catch (Exception ex)
{
TraceException(ex);
}
try { Socket.Shutdown(SocketShutdown.Both); } catch (Exception ex) { TraceException(ex); }
try { Socket.Close(); } catch (Exception ex) { TraceException(ex); }
Socket = null;
m_RecvdPipe = null;
m_SendQueue = null;
m_Disposed.Enqueue(this);
});
Connection = null;
m_Disposed.Enqueue(this);
}
public static void Initialize()