Space-Smash-Out/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Common/Connection.cs

91 lines
2.5 KiB
C#

using System;
using System.Collections.Concurrent;
using System.IO;
using System.Net.Sockets;
using System.Threading;
namespace JamesFrowen.SimpleWeb
{
internal sealed class Connection : IDisposable
{
public const int IdNotSet = -1;
readonly object disposedLock = new object();
public TcpClient client;
public int connId = IdNotSet;
public Stream stream;
public Thread receiveThread;
public Thread sendThread;
public ManualResetEventSlim sendPending = new ManualResetEventSlim(false);
public ConcurrentQueue<ArrayBuffer> sendQueue = new ConcurrentQueue<ArrayBuffer>();
public Action<Connection> onDispose;
volatile bool hasDisposed;
public Connection(TcpClient client, Action<Connection> onDispose)
{
this.client = client ?? throw new ArgumentNullException(nameof(client));
this.onDispose = onDispose;
}
/// <summary>
/// disposes client and stops threads
/// </summary>
public void Dispose()
{
Log.Verbose($"Dispose {ToString()}");
// check hasDisposed first to stop ThreadInterruptedException on lock
if (hasDisposed) { return; }
Log.Info($"Connection Close: {ToString()}");
lock (disposedLock)
{
// check hasDisposed again inside lock to make sure no other object has called this
if (hasDisposed) { return; }
hasDisposed = true;
// stop threads first so they dont try to use disposed objects
receiveThread.Interrupt();
sendThread?.Interrupt();
try
{
// stream
stream?.Dispose();
stream = null;
client.Dispose();
client = null;
}
catch (Exception e)
{
Log.Exception(e);
}
sendPending.Dispose();
// release all buffers in send queue
while (sendQueue.TryDequeue(out ArrayBuffer buffer))
{
buffer.Release();
}
onDispose.Invoke(this);
}
}
public override string ToString()
{
System.Net.EndPoint endpoint = client?.Client?.RemoteEndPoint;
return $"[Conn:{connId}, endPoint:{endpoint}]";
}
}
}