LibUv Networking (#65)
This commit is contained in:
parent
ec6629fbe9
commit
5e2be2d7b6
69 changed files with 5612 additions and 586 deletions
|
|
@ -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()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue