commit b4cd587115d9e71dabbaf571e1e393557ec0d97f
parent da9d92cdd92bfe14ac802c9eda7fc32ddca5c364
Author: Mikolaj Lenczewski <mikolaj.lenczewski308@gmail.com>
Date: Tue, 7 Apr 2020 14:40:12 +0100
Started architecture rework, with basic TCP and UDP echo servers implemented.
Diffstat:
81 files changed, 6139 insertions(+), 4946 deletions(-)
diff --git a/NetSharp/NetSharp/Connection.cs b/NetSharp/NetSharp/Connection.cs
@@ -1,355 +0,0 @@
-using System;
-using System.Buffers;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.IO;
-using System.Net;
-using System.Net.Sockets;
-using System.Threading;
-using System.Threading.Channels;
-using System.Threading.Tasks;
-using Microsoft.Extensions.ObjectPool;
-using NetSharp.Deprecated;
-using NetSharp.Logging;
-using NetSharp.Packets;
-using NetSharp.Pipelines;
-using NetSharp.Utils;
-
-namespace NetSharp
-{
- /// <summary>
- /// Encapsulates a connection capable of receiving packets and responding to them with registered packet handlers.
- /// </summary>
- public sealed partial class Connection : IDisposable
- {
- private readonly HashSet<EndPoint> datagramConnections;
- private readonly Channel<(EndPoint origin, Memory<byte> packet)> incomingPacketChannel;
-
- /// <summary>
- /// Pipeline to convert incoming byte buffers to <see cref="NetworkPacket"/> instances.
- /// </summary>
- private readonly PacketPipeline<Memory<byte>, Memory<byte>, NetworkPacket> incomingPacketPipeline;
-
- /// <summary>
- /// Lock synchronisation object for the <see cref="logger"/> variable.
- /// </summary>
- private readonly object loggerLockObject = new object();
-
- private readonly Channel<(EndPoint destination, NetworkPacket packet)> outgoingPacketChannel;
-
- /// <summary>
- /// Pipeline to convert outgoing <see cref="NetworkPacket"/> instances to a byte buffer for sending.
- /// </summary>
- private readonly PacketPipeline<NetworkPacket, Memory<byte>, Memory<byte>> outgoingPacketPipeline;
-
- private readonly Channel<(EndPoint origin, IRequestPacket request)> requestChannel;
-
- /// <summary>
- /// Cancellation token which allows observing the shutdown of the server. It is set when <see cref="ShutdownServer"/> is called.
- /// </summary>
- private readonly CancellationToken ServerShutdownToken;
-
- private readonly ConcurrentDictionary<EndPoint, Socket> streamConnections;
-
- /// <summary>
- /// A logger object allowing for writing debug messages to an output stream.
- /// </summary>
- private Logger logger;
-
- /// <summary>
- /// Destroys a <see cref="Connection"/> class instance, freeing all managed resources.
- /// </summary>
- ~Connection()
- {
- Dispose(false);
- }
-
- private async Task AcceptorWork(object shutdownToken)
- {
- CancellationToken cancellationToken = (CancellationToken)shutdownToken;
-
- logger.LogMessage("Started stream acceptor task.");
-
- async Task StreamListenerWork(object clientArgsObj)
- {
- Socket clientSocket = (Socket)clientArgsObj;
- EndPoint clientEndPoint = clientSocket.RemoteEndPoint;
-
- logger.LogMessage($"Client handler started for {clientEndPoint}");
-
- while (!cancellationToken.IsCancellationRequested)
- {
- // TODO: implement receive buffer pooling
- byte[] receiveBuffer = new byte[NetworkPacket.PacketSize];
- Memory<byte> receiveBufferMemory = new Memory<byte>(receiveBuffer);
-
- TransmissionResult result =
- await DoReceiveFromAsync(clientSocket, clientEndPoint, SocketFlags.None, receiveBufferMemory, cancellationToken);
-
- if (result.Count == 0)
- {
- break;
- }
-
- await incomingPacketChannel.Writer.WriteAsync((result.RemoteEndPoint, receiveBufferMemory),
- cancellationToken);
- }
-
- logger.LogMessage($"Client handler stopped for {clientEndPoint}");
-
- await DoDisconnectAsync(clientSocket, cancellationToken);
-
- clientSocket.Shutdown(SocketShutdown.Both);
- clientSocket.Close(1);
- }
-
- streamSocket.Listen(MaximumConnectionBacklog);
-
- while (!cancellationToken.IsCancellationRequested)
- {
- Socket clientSocket = await DoAcceptAsync(streamSocket, cancellationToken);
-
- if (!streamConnections.ContainsKey(clientSocket.RemoteEndPoint))
- {
- streamConnections[clientSocket.RemoteEndPoint] = clientSocket;
-
- await Task.Factory.StartNew(StreamListenerWork, streamConnections[clientSocket.RemoteEndPoint], ServerShutdownToken);
- }
- else
- {
- logger.LogWarning($"Accepted duplicate connection from {clientSocket.RemoteEndPoint}");
- }
- }
-
- logger.LogMessage("Stopped stream acceptor task.");
- }
-
- private async Task DatagramListenerWork(object shutdownToken)
- {
- CancellationToken cancellationToken = (CancellationToken)shutdownToken;
-
- logger.LogMessage("Started datagram listener task.");
-
- while (!cancellationToken.IsCancellationRequested)
- {
- // TODO: implement receive buffer pooling
- byte[] receiveBuffer = new byte[NetworkPacket.PacketSize];
- Memory<byte> receiveBufferMemory = new Memory<byte>(receiveBuffer);
-
- TransmissionResult result =
- await DoReceiveFromAsync(datagramSocket, AnyRemoteEndPoint, SocketFlags.None,
- receiveBufferMemory, cancellationToken);
-
- if (!datagramConnections.Contains(result.RemoteEndPoint))
- {
- datagramConnections.Add(result.RemoteEndPoint);
- }
-
- await incomingPacketChannel.Writer.WriteAsync((result.RemoteEndPoint, receiveBufferMemory), cancellationToken);
- }
-
- logger.LogMessage("Stopped datagram listener task.");
- }
-
- private async Task IncomingPacketHandlerWork(object shutdownToken)
- {
- CancellationToken cancellationToken = (CancellationToken)shutdownToken;
-
- logger.LogMessage("Started incoming packet handler task.");
-
- while (!cancellationToken.IsCancellationRequested)
- {
- (EndPoint origin, Memory<byte> packet) =
- await incomingPacketChannel.Reader.ReadAsync(cancellationToken);
-
- NetworkPacket deserialisedRequest = incomingPacketPipeline.ProcessPacket(packet);
-
- // TODO implement deserialisation according to registered packet deserialisers
-
- // TODO: write to requestChannel, not to outgoingPacketChannel
- await outgoingPacketChannel.Writer.WriteAsync((origin, deserialisedRequest), cancellationToken);
- }
-
- logger.LogMessage("Stopped incoming packet handler task.");
- }
-
- private async Task OutgoingPacketHandlerWork(object shutdownToken)
- {
- CancellationToken cancellationToken = (CancellationToken)shutdownToken;
-
- logger.LogMessage("Started outgoing packet handler task.");
-
- while (!cancellationToken.IsCancellationRequested)
- {
- (EndPoint destination, NetworkPacket packet) =
- await outgoingPacketChannel.Reader.ReadAsync(cancellationToken);
-
- Memory<byte> serialisedResponse = outgoingPacketPipeline.ProcessPacket(packet);
-
- if (streamConnections.ContainsKey(destination))
- {
- Socket streamConnection = streamConnections[destination];
-
- await DoSendToAsync(streamConnection, destination, SocketFlags.None,
- serialisedResponse, cancellationToken);
- }
- else if (datagramConnections.Contains(destination))
- {
- await DoSendToAsync(datagramSocket, destination, SocketFlags.None,
- serialisedResponse, cancellationToken);
- }
- else
- {
- logger.LogWarning($"Packet destined for unknown destination: {destination}");
- }
- }
-
- logger.LogMessage("Stopped outgoing packet handler task.");
- }
-
- private async Task RequestHandlerInvocationWork(object shutdownToken)
- {
- CancellationToken cancellationToken = (CancellationToken)shutdownToken;
-
- logger.LogMessage("Started request handler invocation task.");
-
- while (!cancellationToken.IsCancellationRequested)
- {
- (EndPoint origin, IRequestPacket request) = await requestChannel.Reader.ReadAsync(cancellationToken);
-
- // TODO: implement proper request handling, and conversion to IResponsePacket<IRequestPacke>
-
- NetworkPacket serialisedResponsePacket = new NetworkPacket();
-
- await outgoingPacketChannel.Writer.WriteAsync((origin, serialisedResponsePacket), cancellationToken);
- }
-
- logger.LogMessage("Stopped request handler invocation task.");
- }
-
- internal Connection(
- PacketPipeline<Memory<byte>, Memory<byte>, NetworkPacket> incomingPacketPipeline,
- PacketPipeline<NetworkPacket, Memory<byte>, Memory<byte>> outgoingPacketPipeline,
- int objectPoolSize = 10, bool preallocateBuffers = false, Stream? loggingStream = default,
- LogLevel minimumLoggedSeverity = LogLevel.Info)
- {
- serverShutdownTokenSource = new CancellationTokenSource();
- ServerShutdownToken = serverShutdownTokenSource.Token;
-
- streamSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- datagramSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
-
- sendToBufferPool = ArrayPool<byte>.Create(NetworkPacket.PacketSize, objectPoolSize);
- receiveFromBufferPool = ArrayPool<byte>.Create(NetworkPacket.PacketSize, objectPoolSize);
-
- clientSocketArgsPool =
- new LeakTrackingObjectPool<SocketAsyncEventArgs>(
- new DefaultObjectPool<SocketAsyncEventArgs>(new DefaultPooledObjectPolicy<SocketAsyncEventArgs>(),
- objectPoolSize));
- receiveArgsPool =
- new LeakTrackingObjectPool<SocketAsyncEventArgs>(
- new DefaultObjectPool<SocketAsyncEventArgs>(new DefaultPooledObjectPolicy<SocketAsyncEventArgs>(),
- objectPoolSize));
- sendArgsPool =
- new LeakTrackingObjectPool<SocketAsyncEventArgs>(
- new DefaultObjectPool<SocketAsyncEventArgs>(new DefaultPooledObjectPolicy<SocketAsyncEventArgs>(),
- objectPoolSize));
-
- for (int i = 0; i < objectPoolSize; i++)
- {
- SocketAsyncEventArgs clientArgs = new SocketAsyncEventArgs();
- clientArgs.Completed += HandleIOCompleted;
- clientSocketArgsPool.Return(clientArgs);
-
- SocketAsyncEventArgs receiveArgs = new SocketAsyncEventArgs();
- receiveArgs.Completed += HandleIOCompleted;
- receiveArgsPool.Return(receiveArgs);
-
- SocketAsyncEventArgs sendArgs = new SocketAsyncEventArgs();
- sendArgs.Completed += HandleIOCompleted;
- sendArgsPool.Return(sendArgs);
- }
-
- if (preallocateBuffers)
- {
- //TODO: Preallocate buffers someday
- }
-
- streamConnections = new ConcurrentDictionary<EndPoint, Socket>();
- datagramConnections = new HashSet<EndPoint>();
-
- this.incomingPacketPipeline = incomingPacketPipeline;
- BoundedChannelOptions incomingChannelOptions = new BoundedChannelOptions(MaximumPacketBacklog)
- {
- FullMode = BoundedChannelFullMode.DropOldest,
- SingleReader = true,
- SingleWriter = false,
- };
- incomingPacketChannel = Channel.CreateBounded<(EndPoint origin, Memory<byte> packet)>(incomingChannelOptions);
-
- BoundedChannelOptions requestChannelOptions = new BoundedChannelOptions(MaximumPacketBacklog)
- {
- FullMode = BoundedChannelFullMode.DropOldest,
- SingleReader = true,
- SingleWriter = true,
- };
- requestChannel = Channel.CreateBounded<(EndPoint origin, IRequestPacket request)>(requestChannelOptions);
-
- this.outgoingPacketPipeline = outgoingPacketPipeline;
- BoundedChannelOptions outgoingChannelOptions = new BoundedChannelOptions(MaximumPacketBacklog)
- {
- FullMode = BoundedChannelFullMode.DropOldest,
- SingleReader = true,
- SingleWriter = true,
- };
- outgoingPacketChannel = Channel.CreateBounded<(EndPoint destination, NetworkPacket packet)>(outgoingChannelOptions);
-
- logger = new Logger(loggingStream ?? Stream.Null, minimumLoggedSeverity);
- }
-
- /// <summary>
- /// Makes the connection listen for incoming request packets, and handle them according to registered packet handler delegates.
- /// This work can be cancelled by calling <see cref="ShutdownServer"/>.
- /// </summary>
- /// <returns>The task representing the connection work.</returns>
- public Task RunServerAsync()
- {
- logger.LogMessage("Starting stream acceptor task...");
- Task acceptorThread =
- Task.Factory.StartNew(AcceptorWork, ServerShutdownToken, ServerShutdownToken, TaskCreationOptions.LongRunning,
- TaskScheduler.Default).Result;
-
- logger.LogMessage("Starting datagram listener task...");
- Task datagramListenerThread =
- Task.Factory.StartNew(DatagramListenerWork, ServerShutdownToken, ServerShutdownToken, TaskCreationOptions.LongRunning,
- TaskScheduler.Default);
-
- logger.LogMessage("Starting incoming packet handler task...");
- Task incomingPacketHandlerThread =
- Task.Factory.StartNew(IncomingPacketHandlerWork, ServerShutdownToken, ServerShutdownToken, TaskCreationOptions.LongRunning,
- TaskScheduler.Default);
-
- logger.LogMessage("Starting request packet invocation task...");
- Task requestHandlerInvocationThread =
- Task.Factory.StartNew(RequestHandlerInvocationWork, ServerShutdownToken, ServerShutdownToken, TaskCreationOptions.LongRunning,
- TaskScheduler.Default).Result;
-
- logger.LogMessage("Starting outgoing packet handler task...");
- Task outgoingPacketHandlerThread =
- Task.Factory.StartNew(OutgoingPacketHandlerWork, ServerShutdownToken, ServerShutdownToken, TaskCreationOptions.LongRunning,
- TaskScheduler.Default);
-
- return Task.WhenAll(acceptorThread, datagramListenerThread,
- incomingPacketHandlerThread, requestHandlerInvocationThread, outgoingPacketHandlerThread);
- }
-
- /// <summary>
- /// Shuts down the connection, and releases managed and unmanaged resources.
- /// </summary>
- public void ShutdownServer()
- {
- logger.LogMessage("Signalling shutdown to all client connection handlers...");
- serverShutdownTokenSource.Cancel();
- }
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/ConnectionBase.cs b/NetSharp/NetSharp/ConnectionBase.cs
@@ -1,466 +0,0 @@
-using System;
-using System.Buffers;
-using System.Data;
-using System.IO;
-using System.Net;
-using System.Net.Sockets;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.Extensions.ObjectPool;
-using NetSharp.Logging;
-using NetSharp.Packets;
-using NetSharp.Utils;
-
-namespace NetSharp
-{
- /// <summary>
- /// Implements low-level network access on top of which the rest of the connection is built upon.
- /// </summary>
- public sealed partial class Connection : IDisposable
- {
- /// <summary>
- /// Represents any remote endpoint for datagram operations.
- /// </summary>
- private static readonly EndPoint AnyRemoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
-
- private readonly ObjectPool<SocketAsyncEventArgs> clientSocketArgsPool;
-
- private readonly Socket datagramSocket;
-
- private readonly ObjectPool<SocketAsyncEventArgs> receiveArgsPool;
-
- private readonly ArrayPool<byte> receiveFromBufferPool;
-
- private readonly ObjectPool<SocketAsyncEventArgs> sendArgsPool;
-
- private readonly ArrayPool<byte> sendToBufferPool;
-
- private readonly CancellationTokenSource serverShutdownTokenSource;
-
- private readonly Socket streamSocket;
-
- /// <summary>
- /// Disposes of the managed and unmanaged resources held by this instance.
- /// </summary>
- /// <param name="disposing">Whether this method is called by <see cref="Dispose()"/> or by the finaliser.</param>
- private void Dispose(bool disposing)
- {
- if (disposing)
- {
- serverShutdownTokenSource.Cancel();
- serverShutdownTokenSource.Dispose();
-
- streamSocket.Dispose();
- datagramSocket.Dispose();
- }
- }
-
- /// <summary>
- /// Provides an awaitable wrapper around an asynchronous socket accept operation.
- /// </summary>
- /// <param name="serverSocket">The socket which should be used to accept an incoming connection attempt.</param>
- /// <param name="cancellationToken">The cancellation token to observe for the operation.</param>
- /// <returns>The accepted socket.</returns>
- private async Task<Socket> DoAcceptAsync(Socket serverSocket, CancellationToken cancellationToken = default)
- {
- TaskCompletionSource<Socket> tcs = new TaskCompletionSource<Socket>();
-
- cancellationToken.Register(() => tcs.SetCanceled());
-
- Task<Socket> task = serverSocket.AcceptAsync();
- Task<Socket> completedTask = await Task.WhenAny(task, tcs.Task);
-
- if (completedTask == task)
- {
- Socket result = await task;
-
- tcs.SetResult(result);
- }
-
- return await tcs.Task;
- }
-
- /// <summary>
- /// Provides an awaitable wrapper around an asynchronous socket connect operation.
- /// </summary>
- /// <param name="socket">The socket which should asynchronously connect to the remote endpoint.</param>
- /// <param name="remoteEndPoint">The remote endpoint to which the socket should connect.</param>
- /// <param name="cancellationToken">The cancellation token to observe for the operation.</param>
- private async Task DoConnectAsync(Socket socket, EndPoint remoteEndPoint, CancellationToken cancellationToken = default)
- {
- TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
-
- cancellationToken.Register(() => tcs.SetCanceled());
-
- Task task = socket.ConnectAsync(remoteEndPoint);
- Task completedTask = await Task.WhenAny(task, tcs.Task);
-
- if (completedTask == task)
- {
- await task;
- tcs.SetResult(true);
- }
-
- await tcs.Task;
- }
-
- /// <summary>
- /// Provides an awaitable wrapper around an asynchronous socket disconnect operation.
- /// </summary>
- /// <param name="connectedSocket">The socket which should asynchronously disconnect from its remote endpoint.</param>
- /// <param name="cancellationToken">The cancellation token to observe for the operation.</param>
- private Task DoDisconnectAsync(Socket connectedSocket, CancellationToken cancellationToken = default)
- {
- return Task.Factory.StartNew(() =>
- {
- connectedSocket.Disconnect(true);
- }, cancellationToken);
- }
-
- /// <summary>
- /// Provides an awaitable wrapper around an asynchronous socket receive operation.
- /// </summary>
- /// <param name="listenerSocket">The socket which should receive data from the remote endpoint.</param>
- /// <param name="remoteEndPoint">The remove endpoint from which data should be received.</param>
- /// <param name="socketFlags">The socket flags associated with the receive operation.</param>
- /// <param name="inputBuffer">The memory buffer into which received data will be stored.</param>
- /// <param name="cancellationToken">The cancellation token to observe for the operation.</param>
- /// <returns>The result of the receive operation from the remote endpoint.</returns>
- private Task<TransmissionResult> DoReceiveFromAsync(Socket listenerSocket, EndPoint remoteEndPoint, SocketFlags socketFlags,
- Memory<byte> inputBuffer, CancellationToken cancellationToken = default)
- {
- TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>();
-
- byte[] rentedReceiveFromBuffer = receiveFromBufferPool.Rent(NetworkPacket.PacketSize);
- Memory<byte> rentedReceiveFromBufferMemory = new Memory<byte>(rentedReceiveFromBuffer);
-
- SocketAsyncEventArgs clientArgs = receiveArgsPool.Get();
- clientArgs.SetBuffer(rentedReceiveFromBufferMemory);
- clientArgs.SocketFlags = socketFlags;
- clientArgs.RemoteEndPoint = remoteEndPoint;
- clientArgs.UserToken = new AsyncReadToken(rentedReceiveFromBuffer, inputBuffer, tcs, cancellationToken);
-
- // if the receive operation doesn't complete synchronously, returns the awaitable task
- if (listenerSocket.ReceiveFromAsync(clientArgs)) return tcs.Task;
-
- clientArgs.MemoryBuffer.CopyTo(inputBuffer);
-
- TransmissionResult result = new TransmissionResult(clientArgs);
-
- receiveFromBufferPool.Return(rentedReceiveFromBuffer, true);
- receiveArgsPool.Return(clientArgs);
-
- return Task.FromResult(result);
- }
-
- /// <summary>
- /// Provides an awaitable wrapper around an asynchronous socket send operation.
- /// </summary>
- /// <param name="transmitterSocket">The socket which should send the data to the remote endpoint.</param>
- /// <param name="remoteEndPoint">The remote endpoint to which data should be written.</param>
- /// <param name="socketFlags">The socket flags associated with the send operation.</param>
- /// <param name="outputBuffer">The data buffer which should be sent.</param>
- /// <param name="cancellationToken">The cancellation token to observe for the operation.</param>
- /// <returns>The result of the send operation to the remote endpoint.</returns>
- private ValueTask<int> DoSendToAsync(Socket transmitterSocket, EndPoint remoteEndPoint, SocketFlags socketFlags,
- Memory<byte> outputBuffer, CancellationToken cancellationToken = default)
- {
- TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
-
- byte[] rentedSendToBuffer = sendToBufferPool.Rent(NetworkPacket.PacketSize);
- Memory<byte> rentedSendToBufferMemory = new Memory<byte>(rentedSendToBuffer);
-
- outputBuffer.CopyTo(rentedSendToBufferMemory);
-
- SocketAsyncEventArgs clientArgs = sendArgsPool.Get();
- clientArgs.SetBuffer(rentedSendToBufferMemory);
- clientArgs.SocketFlags = socketFlags;
- clientArgs.RemoteEndPoint = remoteEndPoint;
- clientArgs.UserToken = new AsyncWriteToken(rentedSendToBuffer, tcs, cancellationToken);
-
- /* NOT WORKING, NEED SOLUTION AT SOME POINT!!!
- // register cleanup action for when the cancellation token is thrown
- cancellationToken.Register(() =>
- {
- tcs.SetCanceled();
-
- sendBufferPool.Return(rentedSendToBuffer, true);
-
- //TODO this is probably a hideous solution. find a better one
- args.Completed -= HandleIOCompleted;
- args.Dispose();
-
- SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
- newArgs.Completed += HandleIOCompleted;
- sendAsyncEventArgsPool.Return(newArgs);
- });
- */
-
- // if the send operation doesn't complete synchronously, return the awaitable task
- if (transmitterSocket.SendToAsync(clientArgs)) return new ValueTask<int>(tcs.Task);
-
- int result = clientArgs.BytesTransferred;
-
- sendToBufferPool.Return(rentedSendToBuffer, true);
- sendArgsPool.Return(clientArgs);
-
- return new ValueTask<int>(result);
- }
-
- private void HandleIOCompleted(object? sender, SocketAsyncEventArgs args)
- {
- switch (args.LastOperation)
- {
- case SocketAsyncOperation.SendTo:
- AsyncWriteToken asyncSendToToken = (AsyncWriteToken)args.UserToken;
-
- if (asyncSendToToken.CancellationToken.IsCancellationRequested)
- {
- asyncSendToToken.CompletionSource.SetCanceled();
- }
- else
- {
- if (args.SocketError != SocketError.Success)
- {
- asyncSendToToken.CompletionSource.SetException(
- new SocketException((int)args.SocketError));
- }
- else
- {
- asyncSendToToken.CompletionSource.SetResult(args.BytesTransferred);
- }
- }
-
- sendToBufferPool.Return(asyncSendToToken.RentedBuffer, true);
- sendArgsPool.Return(args);
-
- break;
-
- case SocketAsyncOperation.ReceiveFrom:
- AsyncReadToken asyncReceiveFromToken = (AsyncReadToken)args.UserToken;
-
- if (asyncReceiveFromToken.CancellationToken.IsCancellationRequested)
- {
- asyncReceiveFromToken.CompletionSource.SetCanceled();
- }
- else
- {
- if (args.SocketError != SocketError.Success)
- {
- asyncReceiveFromToken.CompletionSource.SetException(
- new SocketException((int)args.SocketError));
- }
- else if (args.BytesTransferred <= 0)
- {
- TransmissionResult result = new TransmissionResult(args);
-
- asyncReceiveFromToken.CompletionSource.SetResult(result);
- }
- else
- {
- args.MemoryBuffer.CopyTo(asyncReceiveFromToken.UserBuffer);
-
- TransmissionResult result = new TransmissionResult(args);
-
- asyncReceiveFromToken.CompletionSource.SetResult(result);
- }
- }
-
- receiveFromBufferPool.Return(asyncReceiveFromToken.RentedBuffer, true);
- receiveArgsPool.Return(args);
-
- break;
-
- default:
- throw new InvalidOperationException(
- $"The {nameof(Connection)} class doesn't support the {args.LastOperation} operation.");
- }
- }
-
- private readonly struct AsyncReadToken
- {
- public readonly CancellationToken CancellationToken;
- public readonly TaskCompletionSource<TransmissionResult> CompletionSource;
- public readonly byte[] RentedBuffer;
- public readonly Memory<byte> UserBuffer;
-
- public AsyncReadToken(byte[] rentedBuffer, Memory<byte> userBuffer, TaskCompletionSource<TransmissionResult> tcs,
- CancellationToken cancellationToken = default)
- {
- RentedBuffer = rentedBuffer;
- UserBuffer = userBuffer;
-
- CompletionSource = tcs;
- CancellationToken = cancellationToken;
- }
- }
-
- private readonly struct AsyncWriteToken
- {
- public readonly CancellationToken CancellationToken;
- public readonly TaskCompletionSource<int> CompletionSource;
- public readonly byte[] RentedBuffer;
-
- public AsyncWriteToken(byte[] rentedBuffer, TaskCompletionSource<int> tcs,
- CancellationToken cancellationToken = default)
- {
- RentedBuffer = rentedBuffer;
-
- CompletionSource = tcs;
- CancellationToken = cancellationToken;
- }
- }
-
- /// <summary>
- /// The maximum number of stream connection that will be accepted.
- /// </summary>
- /// TODO change this to a configurable builder option
- public const int MaximumConnectionBacklog = 10;
-
- /// <summary>
- /// The maximum number of packets that will be stored before older packets start to be dropped.
- /// </summary>
- /// TODO change this to a configurable builder option
- public const int MaximumPacketBacklog = 64;
-
- /// <inheritdoc />
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- public Task<TransmissionResult> ReceiveAsync(Memory<byte> inputBuffer, SocketFlags flags, TimeSpan timeout)
- {
- using CancellationTokenSource timeoutCancellationTokenSource = new CancellationTokenSource(timeout);
- using CancellationTokenSource cts =
- CancellationTokenSource.CreateLinkedTokenSource(timeoutCancellationTokenSource.Token, ServerShutdownToken);
-
- return DoReceiveFromAsync(streamSocket, streamSocket.RemoteEndPoint, flags, inputBuffer, cts.Token);
- }
-
- public Task<TransmissionResult> ReceiveFromAsync(EndPoint remoteEndPoint, Memory<byte> inputBuffer, SocketFlags flags, TimeSpan timeout)
- {
- using CancellationTokenSource timeoutCancellationTokenSource = new CancellationTokenSource(timeout);
- using CancellationTokenSource cts =
- CancellationTokenSource.CreateLinkedTokenSource(timeoutCancellationTokenSource.Token, ServerShutdownToken);
-
- return DoReceiveFromAsync(datagramSocket, remoteEndPoint, flags, inputBuffer, cts.Token);
- }
-
- public ValueTask<int> SendAsync(Memory<byte> outputBuffer, SocketFlags flags, TimeSpan timeout)
- {
- using CancellationTokenSource timeoutCancellationTokenSource = new CancellationTokenSource(timeout);
- using CancellationTokenSource cts =
- CancellationTokenSource.CreateLinkedTokenSource(timeoutCancellationTokenSource.Token, ServerShutdownToken);
-
- return DoSendToAsync(streamSocket, streamSocket.RemoteEndPoint, flags, outputBuffer, cts.Token);
- }
-
- public ValueTask<int> SendToAsync(EndPoint remoteEndPoint, Memory<byte> outputBuffer, SocketFlags flags, TimeSpan timeout)
- {
- using CancellationTokenSource timeoutCancellationTokenSource = new CancellationTokenSource(timeout);
- using CancellationTokenSource cts =
- CancellationTokenSource.CreateLinkedTokenSource(timeoutCancellationTokenSource.Token, ServerShutdownToken);
-
- return DoSendToAsync(datagramSocket, remoteEndPoint, flags, outputBuffer, cts.Token);
- }
-
- /// <summary>
- /// Configures the logger to log messages to the given stream (or to <see cref="Stream.Null"/> if <c>null</c>) and
- /// to only log messages that are of severity <paramref name="minimumLoggedSeverity"/> or higher.
- /// </summary>
- /// <param name="loggingStream">The stream to which messages will be logged.</param>
- /// <param name="minimumLoggedSeverity">The minimum severity a message must be to be logged.</param>
- public void SetLoggingStream(Stream? loggingStream, LogLevel minimumLoggedSeverity = LogLevel.Info)
- {
- lock (loggerLockObject)
- {
- logger = new Logger(loggingStream ?? Stream.Null, minimumLoggedSeverity);
- }
- }
-
- /// <summary>
- /// Attempts to asynchronously bind the underlying socket to the given local endpoint. Does not block.
- /// If the timeout is exceeded the binding attempt is aborted and the method returns false.
- /// </summary>
- /// <param name="localEndPoint">The local endpoint to bind to.</param>
- /// <param name="timeout">The timeout within which to attempt the binding.</param>
- /// <returns>Whether the binding was successful or not.</returns>
- public async Task<bool> TryBindAsync(EndPoint localEndPoint, TimeSpan timeout)
- {
- using CancellationTokenSource timeoutCancellationTokenSource = new CancellationTokenSource(timeout);
- using CancellationTokenSource cts =
- CancellationTokenSource.CreateLinkedTokenSource(timeoutCancellationTokenSource.Token, ServerShutdownToken);
-
- try
- {
- return await Task.Run(() =>
- {
- streamSocket.Bind(localEndPoint);
- datagramSocket.Bind(localEndPoint);
-
- return true;
- }, cts.Token);
- }
- catch (TaskCanceledException)
- {
- return false;
- }
- catch (SocketException ex)
- {
- logger.LogException($"Socket exception on binding socket to {localEndPoint}:", ex);
- return false;
- }
- }
-
- public async Task<bool> TryConnectAsync(EndPoint remoteEndPoint, TimeSpan timeout)
- {
- using CancellationTokenSource timeoutCancellationTokenSource = new CancellationTokenSource(timeout);
- using CancellationTokenSource cts =
- CancellationTokenSource.CreateLinkedTokenSource(timeoutCancellationTokenSource.Token, ServerShutdownToken);
-
- try
- {
- await DoConnectAsync(streamSocket, remoteEndPoint, cts.Token);
-
- return true;
- }
- catch (TaskCanceledException)
- {
- return false;
- }
- catch (SocketException ex)
- {
- logger.LogException($"Socket exception on connecting socket to {remoteEndPoint}:", ex);
- return false;
- }
- }
-
- public async Task<bool> TryDisconnectAsync(TimeSpan timeout)
- {
- using CancellationTokenSource timeoutCancellationTokenSource = new CancellationTokenSource(timeout);
- using CancellationTokenSource cts =
- CancellationTokenSource.CreateLinkedTokenSource(timeoutCancellationTokenSource.Token, ServerShutdownToken);
-
- try
- {
- await DoDisconnectAsync(streamSocket, cts.Token);
-
- streamSocket.Shutdown(SocketShutdown.Both);
- streamSocket.Close(1);
-
- return true;
- }
- catch (TaskCanceledException)
- {
- return false;
- }
- catch (SocketException ex)
- {
- logger.LogException($"Socket exception on disconnecting socket:", ex);
- return false;
- }
- }
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/ConnectionBuilder.cs b/NetSharp/NetSharp/ConnectionBuilder.cs
@@ -1,191 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Net.Sockets;
-using System.Security.Cryptography;
-using NetSharp.Logging;
-using NetSharp.Packets;
-using NetSharp.Pipelines;
-
-namespace NetSharp
-{
- /// <summary>
- /// Allows for configuring and subsequently building a <see cref="Connection"/> instance.
- /// </summary>
- public sealed class ConnectionBuilder
- {
- private static readonly LoggingSettings DefaultLoggingSettings =
- new LoggingSettings(Stream.Null, LogLevel.Warn);
-
- private static readonly PoolingSettings DefaultPoolingSettings =
- new PoolingSettings(10, false);
-
- private readonly List<Func<Memory<byte>, Memory<byte>>> incomingPipelineStages =
- new List<Func<Memory<byte>, Memory<byte>>>();
-
- private readonly List<Func<Memory<byte>, Memory<byte>>> outgoingPipelineStages =
- new List<Func<Memory<byte>, Memory<byte>>>();
-
- private LoggingSettings? loggingSettings;
- private PoolingSettings? poolingSettings;
-
- /// <summary>
- /// The number of stages in the currently configured incoming packet pipeline.
- /// </summary>
- public int IncomingPacketPipelineStageCount
- {
- get { return incomingPipelineStages.Count; }
- }
-
- /// <summary>
- /// The number of stages in the currently configured outgoing packet pipeline.
- /// </summary>
- public int OutgoingPacketPipelineStageCount
- {
- get { return outgoingPipelineStages.Count; }
- }
-
- /// <summary>
- /// Returns a new <see cref="Connection"/> instance with the current configuration.
- /// </summary>
- /// <returns>The configured <see cref="Connection"/> instance.</returns>
- public Connection Build()
- {
- PacketPipelineBuilder<Memory<byte>, Memory<byte>, NetworkPacket> incomingPipelineBuilder =
- new PacketPipelineBuilder<Memory<byte>, Memory<byte>, NetworkPacket>();
-
- incomingPipelineBuilder.WithInputStage(memory => memory);
- foreach (Func<Memory<byte>, Memory<byte>> stage in incomingPipelineStages)
- {
- incomingPipelineBuilder = incomingPipelineBuilder.WithIntermediateStage(stage);
- }
-
- incomingPipelineBuilder.WithOutputStage(NetworkPacket.Deserialise);
-
- PacketPipelineBuilder<NetworkPacket, Memory<byte>, Memory<byte>> outgoingPipelineBuilder =
- new PacketPipelineBuilder<NetworkPacket, Memory<byte>, Memory<byte>>();
-
- outgoingPipelineBuilder.WithInputStage(NetworkPacket.Serialise);
- foreach (Func<Memory<byte>, Memory<byte>> stage in outgoingPipelineStages)
- {
- outgoingPipelineBuilder = outgoingPipelineBuilder.WithIntermediateStage(stage);
- }
-
- outgoingPipelineBuilder.WithOutputStage(memory => memory);
-
- Connection connection = new Connection(
- incomingPipelineBuilder.Build(),
- outgoingPipelineBuilder.Build(),
- poolingSettings?.ObjectPoolSize ?? DefaultPoolingSettings.ObjectPoolSize,
- poolingSettings?.PreallocateBuffers ?? DefaultPoolingSettings.PreallocateBuffers,
- loggingSettings?.LoggingStream ?? DefaultLoggingSettings.LoggingStream,
- loggingSettings?.MinimumLevel ?? DefaultLoggingSettings.MinimumLevel);
-
- return connection;
- }
-
- /// <summary>
- /// Adds an extra pipeline stage to the currently configured incoming packet pipeline, at the given index.
- /// </summary>
- /// <param name="transform">
- /// The transformation that should be applied when a packet passes through the pipeline.
- /// </param>
- /// <param name="index">The position in the pipeline at which to place the transform.</param>
- /// <returns>The builder instance for further configuration.</returns>
- public ConnectionBuilder WithIncomingPipelineStage(in Func<Memory<byte>, Memory<byte>> transform, int index)
- {
- incomingPipelineStages.Insert(index, transform);
- return this;
- }
-
- /// <summary>
- /// Sets the logging settings for the currently configured connection.
- /// </summary>
- /// <param name="settings">The logging settings to use.</param>
- /// <returns>The builder instance for further configuration.</returns>
- public ConnectionBuilder WithLogging(LoggingSettings settings)
- {
- loggingSettings = settings;
- return this;
- }
-
- /// <summary>
- /// Adds an extra pipeline stage to the currently configured outgoing packet pipeline, at the given index.
- /// </summary>
- /// <param name="transform">
- /// The transformation that should be applied when a packet passes through the pipeline.
- /// </param>
- /// <param name="index">The position in the pipeline at which to place the transform.</param>
- /// <returns>The builder instance for further configuration.</returns>
- public ConnectionBuilder WithOutgoingPipelineStage(in Func<Memory<byte>, Memory<byte>> transform, int index)
- {
- outgoingPipelineStages.Insert(index, transform);
- return this;
- }
-
- /// <summary>
- /// Sets the pooling settings for the currently configured connection.
- /// </summary>
- /// <param name="settings">The pooling settings to use.</param>
- /// <returns>The builder instance for further configuration.</returns>
- public ConnectionBuilder WithPooling(PoolingSettings settings)
- {
- poolingSettings = settings;
- return this;
- }
-
- /// <summary>
- /// Holds settings for configuring a connection's logging.
- /// </summary>
- public readonly struct LoggingSettings
- {
- /// <summary>
- /// The stream to which messages will be logged.
- /// </summary>
- public readonly Stream LoggingStream;
-
- /// <summary>
- /// The minimum severity that a log message must have to be recorded.
- /// </summary>
- public readonly LogLevel MinimumLevel;
-
- /// <summary>
- /// Initialises a new instance of the <see cref="LoggingStream"/> struct.
- /// </summary>
- /// <param name="stream">The stream to which messages will be logged..</param>
- /// <param name="minimumLevel">The minimum severity that a log message must have to be recorded.</param>
- public LoggingSettings(Stream stream, LogLevel minimumLevel)
- {
- LoggingStream = stream;
- MinimumLevel = minimumLevel;
- }
- }
-
- /// <summary>
- /// Holds settings for configuring a connection's buffer pooling.
- /// </summary>
- public readonly struct PoolingSettings
- {
- /// <summary>
- /// The number of objects that will be held in the object pools.
- /// </summary>
- public readonly int ObjectPoolSize;
-
- /// <summary>
- /// Whether the buffers for receiving messages should be preallocated.
- /// </summary>
- public readonly bool PreallocateBuffers;
-
- /// <summary>
- /// Initialises a new instance of the <see cref="PoolingSettings"/> struct.
- /// </summary>
- /// <param name="poolSize">The number of objects that will be held in the object pools.</param>
- /// <param name="preallocateBuffers">Whether the buffers for receiving messages should be preallocated.</param>
- public PoolingSettings(int poolSize, bool preallocateBuffers)
- {
- ObjectPoolSize = poolSize;
- PreallocateBuffers = preallocateBuffers;
- }
- }
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/Builtin/ConnectPacket.cs b/NetSharp/NetSharp/Deprecated/Builtin/ConnectPacket.cs
@@ -0,0 +1,32 @@
+using System;
+
+namespace NetSharp.Deprecated.Builtin
+{
+ /// <summary>
+ /// A simple connection request packet for the UDP protocol.
+ /// </summary>
+ [PacketTypeId(1)]
+ internal class ConnectPacket : IRequestPacket
+ {
+ /// <inheritdoc />
+ public void AfterDeserialisation()
+ {
+ }
+
+ /// <inheritdoc />
+ public void BeforeSerialisation()
+ {
+ }
+
+ /// <inheritdoc />
+ public void Deserialise(ReadOnlyMemory<byte> serialisedObject)
+ {
+ }
+
+ /// <inheritdoc />
+ public Memory<byte> Serialise()
+ {
+ return Memory<byte>.Empty;
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/Builtin/ConnectResponsePacket.cs b/NetSharp/NetSharp/Deprecated/Builtin/ConnectResponsePacket.cs
@@ -0,0 +1,35 @@
+using System;
+
+namespace NetSharp.Deprecated.Builtin
+{
+ /// <summary>
+ /// A response packet for the <see cref="ConnectPacket"/>.
+ /// </summary>
+ [PacketTypeId(2)]
+ internal class ConnectResponsePacket : IResponsePacket<ConnectPacket>
+ {
+ /// <inheritdoc />
+ public ConnectPacket RequestPacket { get; set; } = new ConnectPacket();
+
+ /// <inheritdoc />
+ public void AfterDeserialisation()
+ {
+ }
+
+ /// <inheritdoc />
+ public void BeforeSerialisation()
+ {
+ }
+
+ /// <inheritdoc />
+ public void Deserialise(ReadOnlyMemory<byte> serialisedObject)
+ {
+ }
+
+ /// <inheritdoc />
+ public Memory<byte> Serialise()
+ {
+ return Memory<byte>.Empty;
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/Builtin/DataPacket.cs b/NetSharp/NetSharp/Deprecated/Builtin/DataPacket.cs
@@ -0,0 +1,55 @@
+using System;
+
+namespace NetSharp.Deprecated.Builtin
+{
+ /// <summary>
+ /// A simple data transfer packet, that allows for the transmission of an arbitrary number of frames.
+ /// </summary>
+ [PacketTypeId(5)]
+ public class DataPacket : IRequestPacket
+ {
+ /// <summary>
+ /// The data that should be transferred across the network.
+ /// </summary>
+ public Memory<byte> RequestBuffer;
+
+ /// <summary>
+ /// Initialises a new instance of the <see cref="DataPacket"/> class.
+ /// </summary>
+ public DataPacket()
+ {
+ RequestBuffer = new byte[0];
+ }
+
+ /// <summary>
+ /// Initialises a new instance of the <see cref="DataPacket"/> class.
+ /// </summary>
+ /// <param name="buffer">The data that this request packet should contain.</param>
+ public DataPacket(Memory<byte> buffer)
+ {
+ RequestBuffer = buffer;
+ }
+
+ /// <inheritdoc />
+ public void AfterDeserialisation()
+ {
+ }
+
+ /// <inheritdoc />
+ public void BeforeSerialisation()
+ {
+ }
+
+ /// <inheritdoc />
+ public void Deserialise(ReadOnlyMemory<byte> serialisedObject)
+ {
+ RequestBuffer = serialisedObject.ToArray();
+ }
+
+ /// <inheritdoc />
+ public Memory<byte> Serialise()
+ {
+ return RequestBuffer;
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/Builtin/DataResponsePacket.cs b/NetSharp/NetSharp/Deprecated/Builtin/DataResponsePacket.cs
@@ -0,0 +1,58 @@
+using System;
+
+namespace NetSharp.Deprecated.Builtin
+{
+ /// <summary>
+ /// A response packet for the <see cref="DataPacket"/>.
+ /// </summary>
+ [PacketTypeId(6)]
+ public class DataResponsePacket : IResponsePacket<DataPacket>
+ {
+ /// <summary>
+ /// The data that should be transferred across the network.
+ /// </summary>
+ public Memory<byte> ResponseBuffer;
+
+ /// <summary>
+ /// Initialises a new instance of the <see cref="DataResponsePacket"/> class.
+ /// </summary>
+ public DataResponsePacket()
+ {
+ ResponseBuffer = new byte[0];
+ }
+
+ /// <summary>
+ /// Initialises a new instance of the <see cref="DataResponsePacket"/> class.
+ /// </summary>
+ /// <param name="buffer">The data that this response packet should contain.</param>
+ public DataResponsePacket(Memory<byte> buffer)
+ {
+ ResponseBuffer = buffer;
+ }
+
+ /// <inheritdoc />
+ public DataPacket RequestPacket { get; internal set; } = new DataPacket();
+
+ /// <inheritdoc />
+ public void AfterDeserialisation()
+ {
+ }
+
+ /// <inheritdoc />
+ public void BeforeSerialisation()
+ {
+ }
+
+ /// <inheritdoc />
+ public void Deserialise(ReadOnlyMemory<byte> serialisedObject)
+ {
+ ResponseBuffer = serialisedObject.ToArray();
+ }
+
+ /// <inheritdoc />
+ public Memory<byte> Serialise()
+ {
+ return ResponseBuffer;
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/Builtin/DisconnectPacket.cs b/NetSharp/NetSharp/Deprecated/Builtin/DisconnectPacket.cs
@@ -0,0 +1,32 @@
+using System;
+
+namespace NetSharp.Deprecated.Builtin
+{
+ /// <summary>
+ /// A simple disconnect packet for the UDP protocol.
+ /// </summary>
+ [PacketTypeId(0)]
+ internal class DisconnectPacket : IRequestPacket
+ {
+ /// <inheritdoc />
+ public void AfterDeserialisation()
+ {
+ }
+
+ /// <inheritdoc />
+ public void BeforeSerialisation()
+ {
+ }
+
+ /// <inheritdoc />
+ public void Deserialise(ReadOnlyMemory<byte> serialisedObject)
+ {
+ }
+
+ /// <inheritdoc />
+ public Memory<byte> Serialise()
+ {
+ return Memory<byte>.Empty;
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/Builtin/PingPacket.cs b/NetSharp/NetSharp/Deprecated/Builtin/PingPacket.cs
@@ -0,0 +1,32 @@
+using System;
+
+namespace NetSharp.Deprecated.Builtin
+{
+ /// <summary>
+ /// A simple ping request packet for heartbeat monitoring and RTT measurement.
+ /// </summary>
+ [PacketTypeId(3)]
+ public class PingPacket : IRequestPacket
+ {
+ /// <inheritdoc />
+ public void AfterDeserialisation()
+ {
+ }
+
+ /// <inheritdoc />
+ public void BeforeSerialisation()
+ {
+ }
+
+ /// <inheritdoc />
+ public void Deserialise(ReadOnlyMemory<byte> serialisedObject)
+ {
+ }
+
+ /// <inheritdoc />
+ public Memory<byte> Serialise()
+ {
+ return Memory<byte>.Empty;
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/Builtin/PingResponsePacket.cs b/NetSharp/NetSharp/Deprecated/Builtin/PingResponsePacket.cs
@@ -0,0 +1,35 @@
+using System;
+
+namespace NetSharp.Deprecated.Builtin
+{
+ /// <summary>
+ /// A response packet for the <see cref="PingPacket"/>.
+ /// </summary>
+ [PacketTypeId(4)]
+ public class PingResponsePacket : IResponsePacket<PingPacket>
+ {
+ /// <inheritdoc />
+ public PingPacket RequestPacket { get; internal set; } = new PingPacket();
+
+ /// <inheritdoc />
+ public void AfterDeserialisation()
+ {
+ }
+
+ /// <inheritdoc />
+ public void BeforeSerialisation()
+ {
+ }
+
+ /// <inheritdoc />
+ public void Deserialise(ReadOnlyMemory<byte> serialisedObject)
+ {
+ }
+
+ /// <inheritdoc />
+ public Memory<byte> Serialise()
+ {
+ return Memory<byte>.Empty;
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/Builtin/SimpleDataPacket.cs b/NetSharp/NetSharp/Deprecated/Builtin/SimpleDataPacket.cs
@@ -0,0 +1,55 @@
+using System;
+
+namespace NetSharp.Deprecated.Builtin
+{
+ /// <summary>
+ /// A simple one-time-use data transfer packet, that allows for the transmission of an arbitrary number of frames.
+ /// </summary>
+ [PacketTypeId(7)]
+ public class SimpleDataPacket : IRequestPacket
+ {
+ /// <summary>
+ /// The data that should be transferred across the network.
+ /// </summary>
+ public Memory<byte> RequestBuffer;
+
+ /// <summary>
+ /// Initialises a new instance of the <see cref="SimpleDataPacket"/> class.
+ /// </summary>
+ public SimpleDataPacket()
+ {
+ RequestBuffer = new byte[0];
+ }
+
+ /// <summary>
+ /// Initialises a new instance of the <see cref="SimpleDataPacket"/> class.
+ /// </summary>
+ /// <param name="buffer">The data that this request packet should contain.</param>
+ public SimpleDataPacket(Memory<byte> buffer)
+ {
+ RequestBuffer = buffer;
+ }
+
+ /// <inheritdoc />
+ public void AfterDeserialisation()
+ {
+ }
+
+ /// <inheritdoc />
+ public void BeforeSerialisation()
+ {
+ }
+
+ /// <inheritdoc />
+ public void Deserialise(ReadOnlyMemory<byte> serialisedObject)
+ {
+ RequestBuffer = serialisedObject.ToArray();
+ }
+
+ /// <inheritdoc />
+ public Memory<byte> Serialise()
+ {
+ return RequestBuffer;
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/Client.cs b/NetSharp/NetSharp/Deprecated/Client.cs
@@ -1,10 +1,11 @@
-using System;
+using NetSharp.Deprecated.Builtin;
+
+using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
-using NetSharp.Packets.Builtin;
namespace NetSharp.Deprecated
{
diff --git a/NetSharp/NetSharp/Deprecated/Connection.cs b/NetSharp/NetSharp/Deprecated/Connection.cs
@@ -0,0 +1,353 @@
+using Microsoft.Extensions.ObjectPool;
+
+using NetSharp.Utils;
+
+using System;
+using System.Buffers;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Channels;
+using System.Threading.Tasks;
+
+namespace NetSharp.Deprecated
+{
+ /// <summary>
+ /// Encapsulates a connection capable of receiving packets and responding to them with registered packet handlers.
+ /// </summary>
+ public sealed partial class Connection : IDisposable
+ {
+ private readonly HashSet<EndPoint> datagramConnections;
+ private readonly Channel<(EndPoint origin, Memory<byte> packet)> incomingPacketChannel;
+
+ /// <summary>
+ /// Pipeline to convert incoming byte buffers to <see cref="NetworkPacket"/> instances.
+ /// </summary>
+ private readonly PacketPipeline<Memory<byte>, Memory<byte>, NetworkPacket> incomingPacketPipeline;
+
+ /// <summary>
+ /// Lock synchronisation object for the <see cref="logger"/> variable.
+ /// </summary>
+ private readonly object loggerLockObject = new object();
+
+ private readonly Channel<(EndPoint destination, NetworkPacket packet)> outgoingPacketChannel;
+
+ /// <summary>
+ /// Pipeline to convert outgoing <see cref="NetworkPacket"/> instances to a byte buffer for sending.
+ /// </summary>
+ private readonly PacketPipeline<NetworkPacket, Memory<byte>, Memory<byte>> outgoingPacketPipeline;
+
+ private readonly Channel<(EndPoint origin, IRequestPacket request)> requestChannel;
+
+ /// <summary>
+ /// Cancellation token which allows observing the shutdown of the server. It is set when <see cref="ShutdownServer"/> is called.
+ /// </summary>
+ private readonly CancellationToken ServerShutdownToken;
+
+ private readonly ConcurrentDictionary<EndPoint, Socket> streamConnections;
+
+ /// <summary>
+ /// A logger object allowing for writing debug messages to an output stream.
+ /// </summary>
+ private Logger logger;
+
+ /// <summary>
+ /// Destroys a <see cref="Connection"/> class instance, freeing all managed resources.
+ /// </summary>
+ ~Connection()
+ {
+ Dispose(false);
+ }
+
+ private async Task AcceptorWork(object shutdownToken)
+ {
+ CancellationToken cancellationToken = (CancellationToken)shutdownToken;
+
+ logger.LogMessage("Started stream acceptor task.");
+
+ async Task StreamListenerWork(object clientArgsObj)
+ {
+ Socket clientSocket = (Socket)clientArgsObj;
+ EndPoint clientEndPoint = clientSocket.RemoteEndPoint;
+
+ logger.LogMessage($"Client handler started for {clientEndPoint}");
+
+ while (!cancellationToken.IsCancellationRequested)
+ {
+ // TODO: implement receive buffer pooling
+ byte[] receiveBuffer = new byte[NetworkPacket.PacketSize];
+ Memory<byte> receiveBufferMemory = new Memory<byte>(receiveBuffer);
+
+ TransmissionResult result =
+ await DoReceiveFromAsync(clientSocket, clientEndPoint, SocketFlags.None, receiveBufferMemory, cancellationToken);
+
+ if (result.Count == 0)
+ {
+ break;
+ }
+
+ await incomingPacketChannel.Writer.WriteAsync((result.RemoteEndPoint, receiveBufferMemory),
+ cancellationToken);
+ }
+
+ logger.LogMessage($"Client handler stopped for {clientEndPoint}");
+
+ await DoDisconnectAsync(clientSocket, cancellationToken);
+
+ clientSocket.Shutdown(SocketShutdown.Both);
+ clientSocket.Close(1);
+ }
+
+ streamSocket.Listen(MaximumConnectionBacklog);
+
+ while (!cancellationToken.IsCancellationRequested)
+ {
+ Socket clientSocket = await DoAcceptAsync(streamSocket, cancellationToken);
+
+ if (!streamConnections.ContainsKey(clientSocket.RemoteEndPoint))
+ {
+ streamConnections[clientSocket.RemoteEndPoint] = clientSocket;
+
+ await Task.Factory.StartNew(StreamListenerWork, streamConnections[clientSocket.RemoteEndPoint], ServerShutdownToken);
+ }
+ else
+ {
+ logger.LogWarning($"Accepted duplicate connection from {clientSocket.RemoteEndPoint}");
+ }
+ }
+
+ logger.LogMessage("Stopped stream acceptor task.");
+ }
+
+ private async Task DatagramListenerWork(object shutdownToken)
+ {
+ CancellationToken cancellationToken = (CancellationToken)shutdownToken;
+
+ logger.LogMessage("Started datagram listener task.");
+
+ while (!cancellationToken.IsCancellationRequested)
+ {
+ // TODO: implement receive buffer pooling
+ byte[] receiveBuffer = new byte[NetworkPacket.PacketSize];
+ Memory<byte> receiveBufferMemory = new Memory<byte>(receiveBuffer);
+
+ TransmissionResult result =
+ await DoReceiveFromAsync(datagramSocket, AnyRemoteEndPoint, SocketFlags.None,
+ receiveBufferMemory, cancellationToken);
+
+ if (!datagramConnections.Contains(result.RemoteEndPoint))
+ {
+ datagramConnections.Add(result.RemoteEndPoint);
+ }
+
+ await incomingPacketChannel.Writer.WriteAsync((result.RemoteEndPoint, receiveBufferMemory), cancellationToken);
+ }
+
+ logger.LogMessage("Stopped datagram listener task.");
+ }
+
+ private async Task IncomingPacketHandlerWork(object shutdownToken)
+ {
+ CancellationToken cancellationToken = (CancellationToken)shutdownToken;
+
+ logger.LogMessage("Started incoming packet handler task.");
+
+ while (!cancellationToken.IsCancellationRequested)
+ {
+ (EndPoint origin, Memory<byte> packet) =
+ await incomingPacketChannel.Reader.ReadAsync(cancellationToken);
+
+ NetworkPacket deserialisedRequest = incomingPacketPipeline.ProcessPacket(packet);
+
+ // TODO implement deserialisation according to registered packet deserialisers
+
+ // TODO: write to requestChannel, not to outgoingPacketChannel
+ await outgoingPacketChannel.Writer.WriteAsync((origin, deserialisedRequest), cancellationToken);
+ }
+
+ logger.LogMessage("Stopped incoming packet handler task.");
+ }
+
+ private async Task OutgoingPacketHandlerWork(object shutdownToken)
+ {
+ CancellationToken cancellationToken = (CancellationToken)shutdownToken;
+
+ logger.LogMessage("Started outgoing packet handler task.");
+
+ while (!cancellationToken.IsCancellationRequested)
+ {
+ (EndPoint destination, NetworkPacket packet) =
+ await outgoingPacketChannel.Reader.ReadAsync(cancellationToken);
+
+ Memory<byte> serialisedResponse = outgoingPacketPipeline.ProcessPacket(packet);
+
+ if (streamConnections.ContainsKey(destination))
+ {
+ Socket streamConnection = streamConnections[destination];
+
+ await DoSendToAsync(streamConnection, destination, SocketFlags.None,
+ serialisedResponse, cancellationToken);
+ }
+ else if (datagramConnections.Contains(destination))
+ {
+ await DoSendToAsync(datagramSocket, destination, SocketFlags.None,
+ serialisedResponse, cancellationToken);
+ }
+ else
+ {
+ logger.LogWarning($"Packet destined for unknown destination: {destination}");
+ }
+ }
+
+ logger.LogMessage("Stopped outgoing packet handler task.");
+ }
+
+ private async Task RequestHandlerInvocationWork(object shutdownToken)
+ {
+ CancellationToken cancellationToken = (CancellationToken)shutdownToken;
+
+ logger.LogMessage("Started request handler invocation task.");
+
+ while (!cancellationToken.IsCancellationRequested)
+ {
+ (EndPoint origin, IRequestPacket request) = await requestChannel.Reader.ReadAsync(cancellationToken);
+
+ // TODO: implement proper request handling, and conversion to IResponsePacket<IRequestPacke>
+
+ NetworkPacket serialisedResponsePacket = new NetworkPacket();
+
+ await outgoingPacketChannel.Writer.WriteAsync((origin, serialisedResponsePacket), cancellationToken);
+ }
+
+ logger.LogMessage("Stopped request handler invocation task.");
+ }
+
+ internal Connection(
+ PacketPipeline<Memory<byte>, Memory<byte>, NetworkPacket> incomingPacketPipeline,
+ PacketPipeline<NetworkPacket, Memory<byte>, Memory<byte>> outgoingPacketPipeline,
+ int objectPoolSize = 10, bool preallocateBuffers = false, Stream? loggingStream = default,
+ LogLevel minimumLoggedSeverity = LogLevel.Info)
+ {
+ serverShutdownTokenSource = new CancellationTokenSource();
+ ServerShutdownToken = serverShutdownTokenSource.Token;
+
+ streamSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ datagramSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
+
+ sendToBufferPool = ArrayPool<byte>.Create(NetworkPacket.PacketSize, objectPoolSize);
+ receiveFromBufferPool = ArrayPool<byte>.Create(NetworkPacket.PacketSize, objectPoolSize);
+
+ clientSocketArgsPool =
+ new LeakTrackingObjectPool<SocketAsyncEventArgs>(
+ new DefaultObjectPool<SocketAsyncEventArgs>(new DefaultPooledObjectPolicy<SocketAsyncEventArgs>(),
+ objectPoolSize));
+ receiveArgsPool =
+ new LeakTrackingObjectPool<SocketAsyncEventArgs>(
+ new DefaultObjectPool<SocketAsyncEventArgs>(new DefaultPooledObjectPolicy<SocketAsyncEventArgs>(),
+ objectPoolSize));
+ sendArgsPool =
+ new LeakTrackingObjectPool<SocketAsyncEventArgs>(
+ new DefaultObjectPool<SocketAsyncEventArgs>(new DefaultPooledObjectPolicy<SocketAsyncEventArgs>(),
+ objectPoolSize));
+
+ for (int i = 0; i < objectPoolSize; i++)
+ {
+ SocketAsyncEventArgs clientArgs = new SocketAsyncEventArgs();
+ clientArgs.Completed += HandleIOCompleted;
+ clientSocketArgsPool.Return(clientArgs);
+
+ SocketAsyncEventArgs receiveArgs = new SocketAsyncEventArgs();
+ receiveArgs.Completed += HandleIOCompleted;
+ receiveArgsPool.Return(receiveArgs);
+
+ SocketAsyncEventArgs sendArgs = new SocketAsyncEventArgs();
+ sendArgs.Completed += HandleIOCompleted;
+ sendArgsPool.Return(sendArgs);
+ }
+
+ if (preallocateBuffers)
+ {
+ //TODO: Preallocate buffers someday
+ }
+
+ streamConnections = new ConcurrentDictionary<EndPoint, Socket>();
+ datagramConnections = new HashSet<EndPoint>();
+
+ this.incomingPacketPipeline = incomingPacketPipeline;
+ BoundedChannelOptions incomingChannelOptions = new BoundedChannelOptions(MaximumPacketBacklog)
+ {
+ FullMode = BoundedChannelFullMode.DropOldest,
+ SingleReader = true,
+ SingleWriter = false,
+ };
+ incomingPacketChannel = Channel.CreateBounded<(EndPoint origin, Memory<byte> packet)>(incomingChannelOptions);
+
+ BoundedChannelOptions requestChannelOptions = new BoundedChannelOptions(MaximumPacketBacklog)
+ {
+ FullMode = BoundedChannelFullMode.DropOldest,
+ SingleReader = true,
+ SingleWriter = true,
+ };
+ requestChannel = Channel.CreateBounded<(EndPoint origin, IRequestPacket request)>(requestChannelOptions);
+
+ this.outgoingPacketPipeline = outgoingPacketPipeline;
+ BoundedChannelOptions outgoingChannelOptions = new BoundedChannelOptions(MaximumPacketBacklog)
+ {
+ FullMode = BoundedChannelFullMode.DropOldest,
+ SingleReader = true,
+ SingleWriter = true,
+ };
+ outgoingPacketChannel = Channel.CreateBounded<(EndPoint destination, NetworkPacket packet)>(outgoingChannelOptions);
+
+ logger = new Logger(loggingStream ?? Stream.Null, minimumLoggedSeverity);
+ }
+
+ /// <summary>
+ /// Makes the connection listen for incoming request packets, and handle them according to registered packet handler delegates.
+ /// This work can be cancelled by calling <see cref="ShutdownServer"/>.
+ /// </summary>
+ /// <returns>The task representing the connection work.</returns>
+ public Task RunServerAsync()
+ {
+ logger.LogMessage("Starting stream acceptor task...");
+ Task acceptorThread =
+ Task.Factory.StartNew(AcceptorWork, ServerShutdownToken, ServerShutdownToken, TaskCreationOptions.LongRunning,
+ TaskScheduler.Default).Result;
+
+ logger.LogMessage("Starting datagram listener task...");
+ Task datagramListenerThread =
+ Task.Factory.StartNew(DatagramListenerWork, ServerShutdownToken, ServerShutdownToken, TaskCreationOptions.LongRunning,
+ TaskScheduler.Default);
+
+ logger.LogMessage("Starting incoming packet handler task...");
+ Task incomingPacketHandlerThread =
+ Task.Factory.StartNew(IncomingPacketHandlerWork, ServerShutdownToken, ServerShutdownToken, TaskCreationOptions.LongRunning,
+ TaskScheduler.Default);
+
+ logger.LogMessage("Starting request packet invocation task...");
+ Task requestHandlerInvocationThread =
+ Task.Factory.StartNew(RequestHandlerInvocationWork, ServerShutdownToken, ServerShutdownToken, TaskCreationOptions.LongRunning,
+ TaskScheduler.Default).Result;
+
+ logger.LogMessage("Starting outgoing packet handler task...");
+ Task outgoingPacketHandlerThread =
+ Task.Factory.StartNew(OutgoingPacketHandlerWork, ServerShutdownToken, ServerShutdownToken, TaskCreationOptions.LongRunning,
+ TaskScheduler.Default);
+
+ return Task.WhenAll(acceptorThread, datagramListenerThread,
+ incomingPacketHandlerThread, requestHandlerInvocationThread, outgoingPacketHandlerThread);
+ }
+
+ /// <summary>
+ /// Shuts down the connection, and releases managed and unmanaged resources.
+ /// </summary>
+ public void ShutdownServer()
+ {
+ logger.LogMessage("Signalling shutdown to all client connection handlers...");
+ serverShutdownTokenSource.Cancel();
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/ConnectionBase.cs b/NetSharp/NetSharp/Deprecated/ConnectionBase.cs
@@ -0,0 +1,465 @@
+using Microsoft.Extensions.ObjectPool;
+
+using NetSharp.Utils;
+
+using System;
+using System.Buffers;
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace NetSharp.Deprecated
+{
+ /// <summary>
+ /// Implements low-level network access on top of which the rest of the connection is built upon.
+ /// </summary>
+ public sealed partial class Connection : IDisposable
+ {
+ /// <summary>
+ /// Represents any remote endpoint for datagram operations.
+ /// </summary>
+ private static readonly EndPoint AnyRemoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
+
+ private readonly ObjectPool<SocketAsyncEventArgs> clientSocketArgsPool;
+
+ private readonly Socket datagramSocket;
+
+ private readonly ObjectPool<SocketAsyncEventArgs> receiveArgsPool;
+
+ private readonly ArrayPool<byte> receiveFromBufferPool;
+
+ private readonly ObjectPool<SocketAsyncEventArgs> sendArgsPool;
+
+ private readonly ArrayPool<byte> sendToBufferPool;
+
+ private readonly CancellationTokenSource serverShutdownTokenSource;
+
+ private readonly Socket streamSocket;
+
+ /// <summary>
+ /// Disposes of the managed and unmanaged resources held by this instance.
+ /// </summary>
+ /// <param name="disposing">Whether this method is called by <see cref="Dispose()"/> or by the finaliser.</param>
+ private void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ serverShutdownTokenSource.Cancel();
+ serverShutdownTokenSource.Dispose();
+
+ streamSocket.Dispose();
+ datagramSocket.Dispose();
+ }
+ }
+
+ /// <summary>
+ /// Provides an awaitable wrapper around an asynchronous socket accept operation.
+ /// </summary>
+ /// <param name="serverSocket">The socket which should be used to accept an incoming connection attempt.</param>
+ /// <param name="cancellationToken">The cancellation token to observe for the operation.</param>
+ /// <returns>The accepted socket.</returns>
+ private async Task<Socket> DoAcceptAsync(Socket serverSocket, CancellationToken cancellationToken = default)
+ {
+ TaskCompletionSource<Socket> tcs = new TaskCompletionSource<Socket>();
+
+ cancellationToken.Register(() => tcs.SetCanceled());
+
+ Task<Socket> task = serverSocket.AcceptAsync();
+ Task<Socket> completedTask = await Task.WhenAny(task, tcs.Task);
+
+ if (completedTask == task)
+ {
+ Socket result = await task;
+
+ tcs.SetResult(result);
+ }
+
+ return await tcs.Task;
+ }
+
+ /// <summary>
+ /// Provides an awaitable wrapper around an asynchronous socket connect operation.
+ /// </summary>
+ /// <param name="socket">The socket which should asynchronously connect to the remote endpoint.</param>
+ /// <param name="remoteEndPoint">The remote endpoint to which the socket should connect.</param>
+ /// <param name="cancellationToken">The cancellation token to observe for the operation.</param>
+ private async Task DoConnectAsync(Socket socket, EndPoint remoteEndPoint, CancellationToken cancellationToken = default)
+ {
+ TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
+
+ cancellationToken.Register(() => tcs.SetCanceled());
+
+ Task task = socket.ConnectAsync(remoteEndPoint);
+ Task completedTask = await Task.WhenAny(task, tcs.Task);
+
+ if (completedTask == task)
+ {
+ await task;
+ tcs.SetResult(true);
+ }
+
+ await tcs.Task;
+ }
+
+ /// <summary>
+ /// Provides an awaitable wrapper around an asynchronous socket disconnect operation.
+ /// </summary>
+ /// <param name="connectedSocket">The socket which should asynchronously disconnect from its remote endpoint.</param>
+ /// <param name="cancellationToken">The cancellation token to observe for the operation.</param>
+ private Task DoDisconnectAsync(Socket connectedSocket, CancellationToken cancellationToken = default)
+ {
+ return Task.Factory.StartNew(() =>
+ {
+ connectedSocket.Disconnect(true);
+ }, cancellationToken);
+ }
+
+ /// <summary>
+ /// Provides an awaitable wrapper around an asynchronous socket receive operation.
+ /// </summary>
+ /// <param name="listenerSocket">The socket which should receive data from the remote endpoint.</param>
+ /// <param name="remoteEndPoint">The remove endpoint from which data should be received.</param>
+ /// <param name="socketFlags">The socket flags associated with the receive operation.</param>
+ /// <param name="inputBuffer">The memory buffer into which received data will be stored.</param>
+ /// <param name="cancellationToken">The cancellation token to observe for the operation.</param>
+ /// <returns>The result of the receive operation from the remote endpoint.</returns>
+ private Task<TransmissionResult> DoReceiveFromAsync(Socket listenerSocket, EndPoint remoteEndPoint, SocketFlags socketFlags,
+ Memory<byte> inputBuffer, CancellationToken cancellationToken = default)
+ {
+ TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>();
+
+ byte[] rentedReceiveFromBuffer = receiveFromBufferPool.Rent(NetworkPacket.PacketSize);
+ Memory<byte> rentedReceiveFromBufferMemory = new Memory<byte>(rentedReceiveFromBuffer);
+
+ SocketAsyncEventArgs clientArgs = receiveArgsPool.Get();
+ clientArgs.SetBuffer(rentedReceiveFromBufferMemory);
+ clientArgs.SocketFlags = socketFlags;
+ clientArgs.RemoteEndPoint = remoteEndPoint;
+ clientArgs.UserToken = new AsyncReadToken(rentedReceiveFromBuffer, inputBuffer, tcs, cancellationToken);
+
+ // if the receive operation doesn't complete synchronously, returns the awaitable task
+ if (listenerSocket.ReceiveFromAsync(clientArgs)) return tcs.Task;
+
+ clientArgs.MemoryBuffer.CopyTo(inputBuffer);
+
+ TransmissionResult result = new TransmissionResult(clientArgs);
+
+ receiveFromBufferPool.Return(rentedReceiveFromBuffer, true);
+ receiveArgsPool.Return(clientArgs);
+
+ return Task.FromResult(result);
+ }
+
+ /// <summary>
+ /// Provides an awaitable wrapper around an asynchronous socket send operation.
+ /// </summary>
+ /// <param name="transmitterSocket">The socket which should send the data to the remote endpoint.</param>
+ /// <param name="remoteEndPoint">The remote endpoint to which data should be written.</param>
+ /// <param name="socketFlags">The socket flags associated with the send operation.</param>
+ /// <param name="outputBuffer">The data buffer which should be sent.</param>
+ /// <param name="cancellationToken">The cancellation token to observe for the operation.</param>
+ /// <returns>The result of the send operation to the remote endpoint.</returns>
+ private ValueTask<int> DoSendToAsync(Socket transmitterSocket, EndPoint remoteEndPoint, SocketFlags socketFlags,
+ Memory<byte> outputBuffer, CancellationToken cancellationToken = default)
+ {
+ TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
+
+ byte[] rentedSendToBuffer = sendToBufferPool.Rent(NetworkPacket.PacketSize);
+ Memory<byte> rentedSendToBufferMemory = new Memory<byte>(rentedSendToBuffer);
+
+ outputBuffer.CopyTo(rentedSendToBufferMemory);
+
+ SocketAsyncEventArgs clientArgs = sendArgsPool.Get();
+ clientArgs.SetBuffer(rentedSendToBufferMemory);
+ clientArgs.SocketFlags = socketFlags;
+ clientArgs.RemoteEndPoint = remoteEndPoint;
+ clientArgs.UserToken = new AsyncWriteToken(rentedSendToBuffer, tcs, cancellationToken);
+
+ /* NOT WORKING, NEED SOLUTION AT SOME POINT!!!
+ // register cleanup action for when the cancellation token is thrown
+ cancellationToken.Register(() =>
+ {
+ tcs.SetCanceled();
+
+ sendBufferPool.Return(rentedSendToBuffer, true);
+
+ //TODO this is probably a hideous solution. find a better one
+ args.Completed -= HandleIOCompleted;
+ args.Dispose();
+
+ SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
+ newArgs.Completed += HandleIOCompleted;
+ sendAsyncEventArgsPool.Return(newArgs);
+ });
+ */
+
+ // if the send operation doesn't complete synchronously, return the awaitable task
+ if (transmitterSocket.SendToAsync(clientArgs)) return new ValueTask<int>(tcs.Task);
+
+ int result = clientArgs.BytesTransferred;
+
+ sendToBufferPool.Return(rentedSendToBuffer, true);
+ sendArgsPool.Return(clientArgs);
+
+ return new ValueTask<int>(result);
+ }
+
+ private void HandleIOCompleted(object? sender, SocketAsyncEventArgs args)
+ {
+ switch (args.LastOperation)
+ {
+ case SocketAsyncOperation.SendTo:
+ AsyncWriteToken asyncSendToToken = (AsyncWriteToken)args.UserToken;
+
+ if (asyncSendToToken.CancellationToken.IsCancellationRequested)
+ {
+ asyncSendToToken.CompletionSource.SetCanceled();
+ }
+ else
+ {
+ if (args.SocketError != SocketError.Success)
+ {
+ asyncSendToToken.CompletionSource.SetException(
+ new SocketException((int)args.SocketError));
+ }
+ else
+ {
+ asyncSendToToken.CompletionSource.SetResult(args.BytesTransferred);
+ }
+ }
+
+ sendToBufferPool.Return(asyncSendToToken.RentedBuffer, true);
+ sendArgsPool.Return(args);
+
+ break;
+
+ case SocketAsyncOperation.ReceiveFrom:
+ AsyncReadToken asyncReceiveFromToken = (AsyncReadToken)args.UserToken;
+
+ if (asyncReceiveFromToken.CancellationToken.IsCancellationRequested)
+ {
+ asyncReceiveFromToken.CompletionSource.SetCanceled();
+ }
+ else
+ {
+ if (args.SocketError != SocketError.Success)
+ {
+ asyncReceiveFromToken.CompletionSource.SetException(
+ new SocketException((int)args.SocketError));
+ }
+ else if (args.BytesTransferred <= 0)
+ {
+ TransmissionResult result = new TransmissionResult(args);
+
+ asyncReceiveFromToken.CompletionSource.SetResult(result);
+ }
+ else
+ {
+ args.MemoryBuffer.CopyTo(asyncReceiveFromToken.UserBuffer);
+
+ TransmissionResult result = new TransmissionResult(args);
+
+ asyncReceiveFromToken.CompletionSource.SetResult(result);
+ }
+ }
+
+ receiveFromBufferPool.Return(asyncReceiveFromToken.RentedBuffer, true);
+ receiveArgsPool.Return(args);
+
+ break;
+
+ default:
+ throw new InvalidOperationException(
+ $"The {nameof(Connection)} class doesn't support the {args.LastOperation} operation.");
+ }
+ }
+
+ private readonly struct AsyncReadToken
+ {
+ public readonly CancellationToken CancellationToken;
+ public readonly TaskCompletionSource<TransmissionResult> CompletionSource;
+ public readonly byte[] RentedBuffer;
+ public readonly Memory<byte> UserBuffer;
+
+ public AsyncReadToken(byte[] rentedBuffer, Memory<byte> userBuffer, TaskCompletionSource<TransmissionResult> tcs,
+ CancellationToken cancellationToken = default)
+ {
+ RentedBuffer = rentedBuffer;
+ UserBuffer = userBuffer;
+
+ CompletionSource = tcs;
+ CancellationToken = cancellationToken;
+ }
+ }
+
+ private readonly struct AsyncWriteToken
+ {
+ public readonly CancellationToken CancellationToken;
+ public readonly TaskCompletionSource<int> CompletionSource;
+ public readonly byte[] RentedBuffer;
+
+ public AsyncWriteToken(byte[] rentedBuffer, TaskCompletionSource<int> tcs,
+ CancellationToken cancellationToken = default)
+ {
+ RentedBuffer = rentedBuffer;
+
+ CompletionSource = tcs;
+ CancellationToken = cancellationToken;
+ }
+ }
+
+ /// <summary>
+ /// The maximum number of stream connection that will be accepted.
+ /// </summary>
+ /// TODO change this to a configurable builder option
+ public const int MaximumConnectionBacklog = 10;
+
+ /// <summary>
+ /// The maximum number of packets that will be stored before older packets start to be dropped.
+ /// </summary>
+ /// TODO change this to a configurable builder option
+ public const int MaximumPacketBacklog = 64;
+
+ /// <inheritdoc />
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ public Task<TransmissionResult> ReceiveAsync(Memory<byte> inputBuffer, SocketFlags flags, TimeSpan timeout)
+ {
+ using CancellationTokenSource timeoutCancellationTokenSource = new CancellationTokenSource(timeout);
+ using CancellationTokenSource cts =
+ CancellationTokenSource.CreateLinkedTokenSource(timeoutCancellationTokenSource.Token, ServerShutdownToken);
+
+ return DoReceiveFromAsync(streamSocket, streamSocket.RemoteEndPoint, flags, inputBuffer, cts.Token);
+ }
+
+ public Task<TransmissionResult> ReceiveFromAsync(EndPoint remoteEndPoint, Memory<byte> inputBuffer, SocketFlags flags, TimeSpan timeout)
+ {
+ using CancellationTokenSource timeoutCancellationTokenSource = new CancellationTokenSource(timeout);
+ using CancellationTokenSource cts =
+ CancellationTokenSource.CreateLinkedTokenSource(timeoutCancellationTokenSource.Token, ServerShutdownToken);
+
+ return DoReceiveFromAsync(datagramSocket, remoteEndPoint, flags, inputBuffer, cts.Token);
+ }
+
+ public ValueTask<int> SendAsync(Memory<byte> outputBuffer, SocketFlags flags, TimeSpan timeout)
+ {
+ using CancellationTokenSource timeoutCancellationTokenSource = new CancellationTokenSource(timeout);
+ using CancellationTokenSource cts =
+ CancellationTokenSource.CreateLinkedTokenSource(timeoutCancellationTokenSource.Token, ServerShutdownToken);
+
+ return DoSendToAsync(streamSocket, streamSocket.RemoteEndPoint, flags, outputBuffer, cts.Token);
+ }
+
+ public ValueTask<int> SendToAsync(EndPoint remoteEndPoint, Memory<byte> outputBuffer, SocketFlags flags, TimeSpan timeout)
+ {
+ using CancellationTokenSource timeoutCancellationTokenSource = new CancellationTokenSource(timeout);
+ using CancellationTokenSource cts =
+ CancellationTokenSource.CreateLinkedTokenSource(timeoutCancellationTokenSource.Token, ServerShutdownToken);
+
+ return DoSendToAsync(datagramSocket, remoteEndPoint, flags, outputBuffer, cts.Token);
+ }
+
+ /// <summary>
+ /// Configures the logger to log messages to the given stream (or to <see cref="Stream.Null"/> if <c>null</c>) and
+ /// to only log messages that are of severity <paramref name="minimumLoggedSeverity"/> or higher.
+ /// </summary>
+ /// <param name="loggingStream">The stream to which messages will be logged.</param>
+ /// <param name="minimumLoggedSeverity">The minimum severity a message must be to be logged.</param>
+ public void SetLoggingStream(Stream? loggingStream, LogLevel minimumLoggedSeverity = LogLevel.Info)
+ {
+ lock (loggerLockObject)
+ {
+ logger = new Logger(loggingStream ?? Stream.Null, minimumLoggedSeverity);
+ }
+ }
+
+ /// <summary>
+ /// Attempts to asynchronously bind the underlying socket to the given local endpoint. Does not block.
+ /// If the timeout is exceeded the binding attempt is aborted and the method returns false.
+ /// </summary>
+ /// <param name="localEndPoint">The local endpoint to bind to.</param>
+ /// <param name="timeout">The timeout within which to attempt the binding.</param>
+ /// <returns>Whether the binding was successful or not.</returns>
+ public async Task<bool> TryBindAsync(EndPoint localEndPoint, TimeSpan timeout)
+ {
+ using CancellationTokenSource timeoutCancellationTokenSource = new CancellationTokenSource(timeout);
+ using CancellationTokenSource cts =
+ CancellationTokenSource.CreateLinkedTokenSource(timeoutCancellationTokenSource.Token, ServerShutdownToken);
+
+ try
+ {
+ return await Task.Run(() =>
+ {
+ streamSocket.Bind(localEndPoint);
+ datagramSocket.Bind(localEndPoint);
+
+ return true;
+ }, cts.Token);
+ }
+ catch (TaskCanceledException)
+ {
+ return false;
+ }
+ catch (SocketException ex)
+ {
+ logger.LogException($"Socket exception on binding socket to {localEndPoint}:", ex);
+ return false;
+ }
+ }
+
+ public async Task<bool> TryConnectAsync(EndPoint remoteEndPoint, TimeSpan timeout)
+ {
+ using CancellationTokenSource timeoutCancellationTokenSource = new CancellationTokenSource(timeout);
+ using CancellationTokenSource cts =
+ CancellationTokenSource.CreateLinkedTokenSource(timeoutCancellationTokenSource.Token, ServerShutdownToken);
+
+ try
+ {
+ await DoConnectAsync(streamSocket, remoteEndPoint, cts.Token);
+
+ return true;
+ }
+ catch (TaskCanceledException)
+ {
+ return false;
+ }
+ catch (SocketException ex)
+ {
+ logger.LogException($"Socket exception on connecting socket to {remoteEndPoint}:", ex);
+ return false;
+ }
+ }
+
+ public async Task<bool> TryDisconnectAsync(TimeSpan timeout)
+ {
+ using CancellationTokenSource timeoutCancellationTokenSource = new CancellationTokenSource(timeout);
+ using CancellationTokenSource cts =
+ CancellationTokenSource.CreateLinkedTokenSource(timeoutCancellationTokenSource.Token, ServerShutdownToken);
+
+ try
+ {
+ await DoDisconnectAsync(streamSocket, cts.Token);
+
+ streamSocket.Shutdown(SocketShutdown.Both);
+ streamSocket.Close(1);
+
+ return true;
+ }
+ catch (TaskCanceledException)
+ {
+ return false;
+ }
+ catch (SocketException ex)
+ {
+ logger.LogException($"Socket exception on disconnecting socket:", ex);
+ return false;
+ }
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/ConnectionBuilder.cs b/NetSharp/NetSharp/Deprecated/ConnectionBuilder.cs
@@ -0,0 +1,186 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace NetSharp.Deprecated
+{
+ /// <summary>
+ /// Allows for configuring and subsequently building a <see cref="Connection"/> instance.
+ /// </summary>
+ public sealed class ConnectionBuilder
+ {
+ private static readonly LoggingSettings DefaultLoggingSettings =
+ new LoggingSettings(Stream.Null, LogLevel.Warn);
+
+ private static readonly PoolingSettings DefaultPoolingSettings =
+ new PoolingSettings(10, false);
+
+ private readonly List<Func<Memory<byte>, Memory<byte>>> incomingPipelineStages =
+ new List<Func<Memory<byte>, Memory<byte>>>();
+
+ private readonly List<Func<Memory<byte>, Memory<byte>>> outgoingPipelineStages =
+ new List<Func<Memory<byte>, Memory<byte>>>();
+
+ private LoggingSettings? loggingSettings;
+ private PoolingSettings? poolingSettings;
+
+ /// <summary>
+ /// The number of stages in the currently configured incoming packet pipeline.
+ /// </summary>
+ public int IncomingPacketPipelineStageCount
+ {
+ get { return incomingPipelineStages.Count; }
+ }
+
+ /// <summary>
+ /// The number of stages in the currently configured outgoing packet pipeline.
+ /// </summary>
+ public int OutgoingPacketPipelineStageCount
+ {
+ get { return outgoingPipelineStages.Count; }
+ }
+
+ /// <summary>
+ /// Returns a new <see cref="Connection"/> instance with the current configuration.
+ /// </summary>
+ /// <returns>The configured <see cref="Connection"/> instance.</returns>
+ public Connection Build()
+ {
+ PacketPipelineBuilder<Memory<byte>, Memory<byte>, NetworkPacket> incomingPipelineBuilder =
+ new PacketPipelineBuilder<Memory<byte>, Memory<byte>, NetworkPacket>();
+
+ incomingPipelineBuilder.WithInputStage(memory => memory);
+ foreach (Func<Memory<byte>, Memory<byte>> stage in incomingPipelineStages)
+ {
+ incomingPipelineBuilder = incomingPipelineBuilder.WithIntermediateStage(stage);
+ }
+
+ incomingPipelineBuilder.WithOutputStage(NetworkPacket.Deserialise);
+
+ PacketPipelineBuilder<NetworkPacket, Memory<byte>, Memory<byte>> outgoingPipelineBuilder =
+ new PacketPipelineBuilder<NetworkPacket, Memory<byte>, Memory<byte>>();
+
+ outgoingPipelineBuilder.WithInputStage(NetworkPacket.Serialise);
+ foreach (Func<Memory<byte>, Memory<byte>> stage in outgoingPipelineStages)
+ {
+ outgoingPipelineBuilder = outgoingPipelineBuilder.WithIntermediateStage(stage);
+ }
+
+ outgoingPipelineBuilder.WithOutputStage(memory => memory);
+
+ Connection connection = new Connection(
+ incomingPipelineBuilder.Build(),
+ outgoingPipelineBuilder.Build(),
+ poolingSettings?.ObjectPoolSize ?? DefaultPoolingSettings.ObjectPoolSize,
+ poolingSettings?.PreallocateBuffers ?? DefaultPoolingSettings.PreallocateBuffers,
+ loggingSettings?.LoggingStream ?? DefaultLoggingSettings.LoggingStream,
+ loggingSettings?.MinimumLevel ?? DefaultLoggingSettings.MinimumLevel);
+
+ return connection;
+ }
+
+ /// <summary>
+ /// Adds an extra pipeline stage to the currently configured incoming packet pipeline, at the given index.
+ /// </summary>
+ /// <param name="transform">
+ /// The transformation that should be applied when a packet passes through the pipeline.
+ /// </param>
+ /// <param name="index">The position in the pipeline at which to place the transform.</param>
+ /// <returns>The builder instance for further configuration.</returns>
+ public ConnectionBuilder WithIncomingPipelineStage(in Func<Memory<byte>, Memory<byte>> transform, int index)
+ {
+ incomingPipelineStages.Insert(index, transform);
+ return this;
+ }
+
+ /// <summary>
+ /// Sets the logging settings for the currently configured connection.
+ /// </summary>
+ /// <param name="settings">The logging settings to use.</param>
+ /// <returns>The builder instance for further configuration.</returns>
+ public ConnectionBuilder WithLogging(LoggingSettings settings)
+ {
+ loggingSettings = settings;
+ return this;
+ }
+
+ /// <summary>
+ /// Adds an extra pipeline stage to the currently configured outgoing packet pipeline, at the given index.
+ /// </summary>
+ /// <param name="transform">
+ /// The transformation that should be applied when a packet passes through the pipeline.
+ /// </param>
+ /// <param name="index">The position in the pipeline at which to place the transform.</param>
+ /// <returns>The builder instance for further configuration.</returns>
+ public ConnectionBuilder WithOutgoingPipelineStage(in Func<Memory<byte>, Memory<byte>> transform, int index)
+ {
+ outgoingPipelineStages.Insert(index, transform);
+ return this;
+ }
+
+ /// <summary>
+ /// Sets the pooling settings for the currently configured connection.
+ /// </summary>
+ /// <param name="settings">The pooling settings to use.</param>
+ /// <returns>The builder instance for further configuration.</returns>
+ public ConnectionBuilder WithPooling(PoolingSettings settings)
+ {
+ poolingSettings = settings;
+ return this;
+ }
+
+ /// <summary>
+ /// Holds settings for configuring a connection's logging.
+ /// </summary>
+ public readonly struct LoggingSettings
+ {
+ /// <summary>
+ /// The stream to which messages will be logged.
+ /// </summary>
+ public readonly Stream LoggingStream;
+
+ /// <summary>
+ /// The minimum severity that a log message must have to be recorded.
+ /// </summary>
+ public readonly LogLevel MinimumLevel;
+
+ /// <summary>
+ /// Initialises a new instance of the <see cref="LoggingStream"/> struct.
+ /// </summary>
+ /// <param name="stream">The stream to which messages will be logged..</param>
+ /// <param name="minimumLevel">The minimum severity that a log message must have to be recorded.</param>
+ public LoggingSettings(Stream stream, LogLevel minimumLevel)
+ {
+ LoggingStream = stream;
+ MinimumLevel = minimumLevel;
+ }
+ }
+
+ /// <summary>
+ /// Holds settings for configuring a connection's buffer pooling.
+ /// </summary>
+ public readonly struct PoolingSettings
+ {
+ /// <summary>
+ /// The number of objects that will be held in the object pools.
+ /// </summary>
+ public readonly int ObjectPoolSize;
+
+ /// <summary>
+ /// Whether the buffers for receiving messages should be preallocated.
+ /// </summary>
+ public readonly bool PreallocateBuffers;
+
+ /// <summary>
+ /// Initialises a new instance of the <see cref="PoolingSettings"/> struct.
+ /// </summary>
+ /// <param name="poolSize">The number of objects that will be held in the object pools.</param>
+ /// <param name="preallocateBuffers">Whether the buffers for receiving messages should be preallocated.</param>
+ public PoolingSettings(int poolSize, bool preallocateBuffers)
+ {
+ ObjectPoolSize = poolSize;
+ PreallocateBuffers = preallocateBuffers;
+ }
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/ConnectionBuilderExtensions.cs b/NetSharp/NetSharp/Deprecated/ConnectionBuilderExtensions.cs
@@ -0,0 +1,27 @@
+using System;
+using System.IO;
+
+namespace NetSharp.Deprecated
+{
+ /// <summary>
+ /// Provides additional methods and functionality to the <see cref="ConnectionBuilder"/> class.
+ /// </summary>
+ public static class ConnectionBuilderExtensions
+ {
+ public static ConnectionBuilder AppendIncomingPipelineStage(this ConnectionBuilder instance,
+ in Func<Memory<byte>, Memory<byte>> transform)
+ => instance.WithIncomingPipelineStage(transform, instance.IncomingPacketPipelineStageCount);
+
+ public static ConnectionBuilder AppendOutgoingPipelineStage(this ConnectionBuilder instance,
+ in Func<Memory<byte>, Memory<byte>> transform)
+ => instance.WithOutgoingPipelineStage(transform, instance.OutgoingPacketPipelineStageCount);
+
+ public static ConnectionBuilder WithLogging(this ConnectionBuilder instance,
+ Stream loggingStream, LogLevel minimumLogLevel)
+ => instance.WithLogging(new ConnectionBuilder.LoggingSettings(loggingStream, minimumLogLevel));
+
+ public static ConnectionBuilder WithPooling(this ConnectionBuilder instance,
+ int poolSize, bool preallocateBuffers)
+ => instance.WithPooling(new ConnectionBuilder.PoolingSettings(poolSize, preallocateBuffers));
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/ConnectionExtensions.cs b/NetSharp/NetSharp/Deprecated/ConnectionExtensions.cs
@@ -0,0 +1,73 @@
+using NetSharp.Utils;
+
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace NetSharp.Deprecated
+{
+ /// <summary>
+ /// Provides additional methods and functionality to the <see cref="Connection"/> class.
+ /// </summary>
+ public static class ConnectionExtensions
+ {
+ public static Task<TransmissionResult> ReceiveAsync(this Connection instance,
+ EndPoint remoteEndPoint, Memory<byte> inputBuffer, SocketFlags flags)
+ => instance.ReceiveAsync(inputBuffer, flags, Timeout.InfiniteTimeSpan);
+
+ public static Task<TransmissionResult> ReceiveFromAsync(this Connection instance,
+ EndPoint remoteEndPoint, Memory<byte> inputBuffer, SocketFlags flags)
+ => instance.ReceiveFromAsync(remoteEndPoint, inputBuffer, flags, Timeout.InfiniteTimeSpan);
+
+ public static ValueTask<int> SendAsync(this Connection instance,
+ EndPoint remoteEndPoint, Memory<byte> outputBuffer, SocketFlags flags)
+ => instance.SendAsync(outputBuffer, flags, Timeout.InfiniteTimeSpan);
+
+ public static ValueTask<int> SendToAsync(this Connection instance,
+ EndPoint remoteEndPoint, Memory<byte> outputBuffer, SocketFlags flags)
+ => instance.SendToAsync(remoteEndPoint, outputBuffer, flags, Timeout.InfiniteTimeSpan);
+
+ /// <summary>
+ /// Attempts to synchronously bind the underlying socket to the given local endpoint. Blocks.
+ /// If the timeout is exceeded the binding attempt is aborted and the method returns false.
+ /// </summary>
+ /// <param name="localEndPoint">The local endpoint to bind to.</param>
+ /// <param name="timeout">The timeout within which to attempt the binding.</param>
+ /// <returns>Whether the binding was successful or not.</returns>
+ public static bool TryBind(this Connection instance,
+ EndPoint localEndPoint, TimeSpan timeout)
+ => instance.TryBindAsync(localEndPoint, timeout).Result;
+
+ public static bool TryBind(this Connection instance,
+ EndPoint localEndPoint)
+ => instance.TryBindAsync(localEndPoint, Timeout.InfiniteTimeSpan).Result;
+
+ public static Task<bool> TryBindAsync(this Connection instance,
+ EndPoint localEndPoint)
+ => instance.TryBindAsync(localEndPoint, Timeout.InfiniteTimeSpan);
+
+ public static bool TryConnect(this Connection instance,
+ EndPoint remoteEndPoint)
+ => instance.TryConnectAsync(remoteEndPoint, Timeout.InfiniteTimeSpan).Result;
+
+ public static bool TryConnect(this Connection instance,
+ EndPoint remoteEndPoint, TimeSpan timeout)
+ => instance.TryConnectAsync(remoteEndPoint, timeout).Result;
+
+ public static Task<bool> TryConnectAsync(this Connection instance,
+ EndPoint remoteEndPoint)
+ => instance.TryConnectAsync(remoteEndPoint, Timeout.InfiniteTimeSpan);
+
+ public static bool TryDisconnect(this Connection instance)
+ => instance.TryDisconnectAsync(Timeout.InfiniteTimeSpan).Result;
+
+ public static bool TryDisconnect(this Connection instance,
+ TimeSpan timeout)
+ => instance.TryDisconnectAsync(timeout).Result;
+
+ public static Task<bool> TryDisconnectAsync(this Connection instance)
+ => instance.TryDisconnectAsync(Timeout.InfiniteTimeSpan);
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/Constants.cs b/NetSharp/NetSharp/Deprecated/Constants.cs
@@ -0,0 +1,15 @@
+namespace NetSharp.Deprecated
+{
+ /// <summary>
+ /// Holds internal default configurations and constants.
+ /// </summary>
+ internal static class Constants
+ {
+ /// <summary>
+ /// The default port over which a connection is made.
+ /// </summary>
+ internal const int DefaultPort = 12374;
+
+ internal const int MaximumUdpPacketBytes = 65507;
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/CryptographyHelpers.cs b/NetSharp/NetSharp/Deprecated/CryptographyHelpers.cs
@@ -0,0 +1,96 @@
+using System;
+using System.IO;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace NetSharp.Deprecated
+{
+ internal static class CryptographyHelpers
+ {
+ #region Settings
+
+ private static string _hash = "SHA1";
+ private static int _iterations = 2;
+ private static int _keySize = 256;
+ private static string _salt = "aselrias38490a32"; // Random
+ private static string _vector = "8947az34awl34kjq"; // Random
+
+ #endregion Settings
+
+ public static string Decrypt(byte[] value, string password)
+ {
+ return Decrypt<AesManaged>(value, password);
+ }
+
+ public static string Decrypt<T>(byte[] value, string password) where T : SymmetricAlgorithm, new()
+ {
+ byte[] vectorBytes = Encoding.ASCII.GetBytes(_vector); // GetBytes<ASCIIEncoding>(_vector);
+ byte[] saltBytes = Encoding.ASCII.GetBytes(_salt); // GetBytes<ASCIIEncoding>(_salt);
+ byte[] valueBytes = value;
+
+ byte[] decrypted;
+ int decryptedByteCount = 0;
+
+ using (T cipher = new T())
+ {
+ PasswordDeriveBytes _passwordBytes = new PasswordDeriveBytes(password, saltBytes, _hash, _iterations);
+ byte[] keyBytes = _passwordBytes.GetBytes(_keySize / 8);
+
+ cipher.Mode = CipherMode.CBC;
+
+ try
+ {
+ using (ICryptoTransform decryptor = cipher.CreateDecryptor(keyBytes, vectorBytes))
+ {
+ using MemoryStream from = new MemoryStream(valueBytes);
+ using CryptoStream reader = new CryptoStream(@from, decryptor, CryptoStreamMode.Read);
+
+ decrypted = new byte[valueBytes.Length];
+ decryptedByteCount = reader.Read(decrypted, 0, decrypted.Length);
+ }
+ }
+ catch (Exception ex)
+ {
+ return String.Empty;
+ }
+
+ cipher.Clear();
+ }
+ return Encoding.UTF8.GetString(decrypted, 0, decryptedByteCount);
+ }
+
+ public static byte[] Encrypt(string value, string password)
+ {
+ return Encrypt<AesManaged>(value, password);
+ }
+
+ public static byte[] Encrypt<T>(string value, string password) where T : SymmetricAlgorithm, new()
+ {
+ byte[] vectorBytes = Encoding.ASCII.GetBytes(_vector); // GetBytes<ASCIIEncoding>(_vector);
+ byte[] saltBytes = Encoding.ASCII.GetBytes(_salt); // GetBytes<ASCIIEncoding>(_salt);
+ byte[] valueBytes = Encoding.UTF8.GetBytes(value); // GetBytes<UTF8Encoding>(value);
+
+ byte[] encrypted;
+ using (T cipher = new T())
+ {
+ PasswordDeriveBytes _passwordBytes =
+ new PasswordDeriveBytes(password, saltBytes, _hash, _iterations);
+ byte[] keyBytes = _passwordBytes.GetBytes(_keySize / 8);
+
+ cipher.Mode = CipherMode.CBC;
+
+ using (ICryptoTransform encryptor = cipher.CreateEncryptor(keyBytes, vectorBytes))
+ {
+ using MemoryStream to = new MemoryStream();
+ using CryptoStream writer = new CryptoStream(to, encryptor, CryptoStreamMode.Write);
+
+ writer.Write(valueBytes, 0, valueBytes.Length);
+ writer.FlushFinalBlock();
+ encrypted = to.ToArray();
+ }
+ cipher.Clear();
+ }
+ return encrypted;
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/Logger.cs b/NetSharp/NetSharp/Deprecated/Logger.cs
@@ -0,0 +1,194 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace NetSharp.Deprecated
+{
+ /// <summary>
+ /// Specifies the severity level of a log message.
+ /// </summary>
+ public enum LogLevel
+ {
+ /// <summary>
+ /// The logged message contains some information. Lowest severity.
+ /// </summary>
+ Info,
+
+ /// <summary>
+ /// The logged message contains a warning. Higher severity.
+ /// </summary>
+ Warn,
+
+ /// <summary>
+ /// The logged message contains details about an error. Higher severity.
+ /// </summary>
+ Error,
+
+ /// <summary>
+ /// The logged message contains details about an exception. Highest severity.
+ /// </summary>
+ Exception
+ }
+
+ /// <summary>
+ /// A simple logger capable of writing text to a stream.
+ /// </summary>
+ public readonly struct Logger : IDisposable
+ {
+ /// <summary>
+ /// The stream to which messages will be logged.
+ /// </summary>
+ private readonly Stream loggingStream;
+
+ /// <summary>
+ /// The minimum severity that log messages need to be logged to the underlying stream.
+ /// </summary>
+ private readonly LogLevel minimumSeverity;
+
+ /// <summary>
+ /// The text writer we will use to log messages to the underlying stream.
+ /// </summary>
+ private readonly StreamWriter writer;
+
+ /// <summary>
+ /// Initialises a new instance of the <see cref="Logger"/> struct.
+ /// </summary>
+ /// <param name="outputStream">The stream that the logger instance should log messages to.</param>
+ /// <param name="minimumLogSeverity">The minimum log level that will be logged to the output stream.</param>
+ public Logger(Stream outputStream, LogLevel minimumLogSeverity = LogLevel.Info)
+ {
+ loggingStream = outputStream;
+ writer = new StreamWriter(loggingStream, Encoding.Default) { AutoFlush = true };
+
+ minimumSeverity = minimumLogSeverity;
+ }
+
+ /// <inheritdoc />
+ public void Dispose()
+ {
+ loggingStream.Dispose();
+ writer.Dispose();
+ }
+
+ /// <summary>
+ /// Logs a message to the underlying stream, along with the given exception and at the given severity.
+ /// </summary>
+ /// <param name="message">The message that should be logged.</param>
+ /// <param name="exception">The exception that occurred (if any).</param>
+ /// <param name="severity">The severity of the message that is being logged.</param>
+ public void Log(string message, Exception? exception, LogLevel severity)
+ {
+ if (severity < minimumSeverity) return;
+
+ string severityTag = severity switch
+ {
+ LogLevel.Info => "Info ",
+ LogLevel.Warn => "Warn ",
+ LogLevel.Error => "Error",
+ LogLevel.Exception => "Excep",
+ _ => "Info "
+ };
+
+ writer.WriteLine($"[{severityTag}] {message} {exception}");
+ }
+
+ /// <summary>
+ /// Logs a message asynchronously to the underlying stream, along with the given exception and at the given severity.
+ /// </summary>
+ /// <param name="message">The message that should be logged.</param>
+ /// <param name="exception">The exception that occurred (if any).</param>
+ /// <param name="severity">The severity of the message that is being logged.</param>
+ public async Task LogAsync(string message, Exception? exception, LogLevel severity)
+ {
+ if (loggingStream.Equals(Stream.Null))
+ {
+ // ignore log request if the underlying stream is null
+ return;
+ }
+
+ if (!exception?.Equals(default) ?? false)
+ {
+ severity = LogLevel.Exception;
+ }
+
+ if (severity >= minimumSeverity)
+ {
+ string severityTag = severity switch
+ {
+ LogLevel.Info => "Info ",
+ LogLevel.Warn => "Warn ",
+ LogLevel.Error => "Error",
+ LogLevel.Exception => "Excep",
+ _ => "Info "
+ };
+
+ await writer.WriteLineAsync($"[{severityTag}] {message} {exception}");
+ }
+ }
+
+ /// <summary>
+ /// Logs an error to the underlying stream, with severity <see cref="LogLevel.Info"/>.
+ /// </summary>
+ /// <param name="message">The error that should be logged.</param>
+ public void LogError(string message) => Log(message, null, LogLevel.Error);
+
+ /// <summary>
+ /// Logs an error to the underlying stream asynchronously, with severity <see cref="LogLevel.Error"/>.
+ /// </summary>
+ /// <param name="message">The error that should be logged.</param>
+ public async Task LogErrorAsync(string message) => await LogAsync(message, null, LogLevel.Error);
+
+ /// <summary>
+ /// Logs an exception to the underlying stream, with severity <see cref="LogLevel.Exception"/>.
+ /// </summary>
+ /// <param name="exception">The exception that should be logged.</param>
+ public void LogException(Exception exception) => Log("", exception, LogLevel.Exception);
+
+ /// <summary>
+ /// Logs an exception to the underlying stream, along with a short debug message, with severity
+ /// <see cref="LogLevel.Exception"/>.
+ /// </summary>
+ /// <param name="message">The debug message that should be logged with the exception.</param>
+ /// <param name="exception">The exception that should be logged.</param>
+ public void LogException(string message, Exception exception) => Log(message, exception, LogLevel.Exception);
+
+ /// <summary>
+ /// Logs an exception to the underlying stream asynchronously, with severity <see cref="LogLevel.Exception"/>.
+ /// </summary>
+ /// <param name="exception">The exception that should be logged.</param>
+ public async Task LogExceptionAsync(Exception exception) => await LogAsync("", exception, LogLevel.Exception);
+
+ /// <summary>
+ /// Logs an exception to the underlying stream asynchronously, along with a short debug message, with severity
+ /// <see cref="LogLevel.Exception"/>.
+ /// </summary>
+ /// <param name="message">The debug message that should be logged with the exception.</param>
+ /// <param name="exception">The exception that should be logged.</param>
+ public async Task LogExceptionAsync(string message, Exception exception) => await LogAsync(message, exception, LogLevel.Exception);
+
+ /// <summary>
+ /// Logs a message to the underlying stream, with severity <see cref="LogLevel.Info"/>.
+ /// </summary>
+ /// <param name="message">The message that should be logged.</param>
+ public void LogMessage(string message) => Log(message, null, LogLevel.Info);
+
+ /// <summary>
+ /// Logs a message to the underlying stream asynchronously, with severity <see cref="LogLevel.Info"/>.
+ /// </summary>
+ /// <param name="message">The message that should be logged.</param>
+ public async Task LogMessageAsync(string message) => await LogAsync(message, null, LogLevel.Info);
+
+ /// <summary>
+ /// Logs a warning to the underlying stream, with severity <see cref="LogLevel.Info"/>.
+ /// </summary>
+ /// <param name="message">The warning that should be logged.</param>
+ public void LogWarning(string message) => Log(message, null, LogLevel.Warn);
+
+ /// <summary>
+ /// Logs a warning to the underlying stream asynchronously, with severity <see cref="LogLevel.Warn"/>.
+ /// </summary>
+ /// <param name="message">The warning that should be logged.</param>
+ public async Task LogWarningAsync(string message) => await LogAsync(message, null, LogLevel.Warn);
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/NetworkErrorCode.cs b/NetSharp/NetSharp/Deprecated/NetworkErrorCode.cs
@@ -0,0 +1,18 @@
+namespace NetSharp.Deprecated
+{
+ /// <summary>
+ /// Enumerates the possible error codes for network operations, being held in the packet.
+ /// </summary>
+ public enum NetworkErrorCode : uint
+ {
+ /// <summary>
+ /// Signifies that there was no error during transmission.
+ /// </summary>
+ Ok = 0,
+
+ /// <summary>
+ /// A generic error occurred during packet transmission.
+ /// </summary>
+ Error = 1 << 1,
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/NetworkPacket.cs b/NetSharp/NetSharp/Deprecated/NetworkPacket.cs
@@ -0,0 +1,218 @@
+using NetSharp.Deprecated.Conversion;
+
+using System;
+
+namespace NetSharp.Deprecated
+{
+ /// <summary>
+ /// Represents a low-level packet that is transmitted over the network.
+ /// </summary>
+ public readonly struct NetworkPacket
+ {
+ /// <summary>
+ /// Initialises a new instance of the <see cref="NetworkPacket"/> struct.
+ /// </summary>
+ /// <param name="data">The data that should be transmitted in the packet.</param>
+ /// <param name="header">The header for the packet.</param>
+ /// <param name="footer">The footer for the packet.</param>
+ private NetworkPacket(ReadOnlyMemory<byte> data, NetworkPacketHeader header, NetworkPacketFooter footer)
+ {
+ Header = header;
+
+ DataBuffer = data;
+
+ Footer = footer;
+ }
+
+ /// <summary>
+ /// The number of bytes allocated in each packet for user data.
+ /// </summary>
+ public const int DataSegmentSize = PacketSize - HeaderSize - FooterSize;
+
+ /// <summary>
+ /// The number of bytes taken up in each packet by its footer.
+ /// </summary>
+ public const int FooterSize = NetworkPacketFooter.Size;
+
+ /// <summary>
+ /// The number of bytes taken up in each packet by its header.
+ /// </summary>
+ public const int HeaderSize = NetworkPacketHeader.Size;
+
+ /// <summary>
+ /// The size of each packet, including its header, footer, and data segment.
+ /// </summary>
+ public const int PacketSize = 4096;
+
+ /// <summary>
+ /// The data held in this packet.
+ /// </summary>
+ public readonly ReadOnlyMemory<byte> DataBuffer;
+
+ public readonly NetworkPacketFooter Footer;
+ public readonly NetworkPacketHeader Header;
+
+ /// <summary>
+ /// Initialises a new instance of the <see cref="NetworkPacket"/> struct.
+ /// </summary>
+ /// <param name="data">The data that should be transmitted in the packet.</param>
+ /// <param name="dataLength">The number of bytes that are held in the given data buffer.</param>
+ /// <param name="type">The packet type.</param>
+ /// <param name="errorCode">The error code associated with this transmission.</param>
+ /// <param name="hasSucceedingPacket">Whether this packet has a succeeding packet in the packet chain.</param>
+ public NetworkPacket(ReadOnlyMemory<byte> data, int dataLength, uint type, NetworkErrorCode errorCode, bool hasSucceedingPacket)
+ {
+ Header = new NetworkPacketHeader(type, errorCode, dataLength);
+
+ DataBuffer = data;
+
+ Footer = new NetworkPacketFooter(hasSucceedingPacket);
+ }
+
+ /// <summary>
+ /// Deserialises the given buffer into a packet instance.
+ /// </summary>
+ /// <param name="buffer">The byte buffer to serialise.</param>
+ /// <returns>The deserialised packet instance.</returns>
+ public static NetworkPacket Deserialise(Memory<byte> buffer)
+ {
+ Span<byte> serialisedPacketHeader = buffer.Slice(0, HeaderSize).Span;
+ NetworkPacketHeader header = NetworkPacketHeader.Deserialise(serialisedPacketHeader);
+
+ Span<byte> serialisedPacketFooter = buffer.Slice(HeaderSize + DataSegmentSize, FooterSize).Span;
+ NetworkPacketFooter footer = NetworkPacketFooter.Deserialise(serialisedPacketFooter);
+
+ Memory<byte> serialisedInstanceData = buffer.Slice(HeaderSize, DataSegmentSize);
+
+ return new NetworkPacket(serialisedInstanceData, header, footer);
+ }
+
+ /// <summary>
+ /// Serialises the given packet instance to a new byte buffer.
+ /// </summary>
+ /// <param name="instance">The packet instance to serialise.</param>
+ /// <returns>The byte buffer that represents the packet instance.</returns>
+ public static Memory<byte> Serialise(NetworkPacket instance)
+ {
+ byte[] buffer = new byte[PacketSize];
+ SerialiseToBuffer(buffer, instance);
+ return buffer;
+ }
+
+ /// <summary>
+ /// Serialises the given packet instance into the given byte buffer.
+ /// </summary>
+ /// <param name="buffer">
+ /// The buffer to which the instance should be serialised. Must be at least of size <see cref="PacketSize"/>.
+ /// </param>
+ /// <param name="instance">The packet instance to serialise.</param>
+ /// <exception cref="ArgumentException">Thrown if the given buffer is too small.</exception>
+ public static void SerialiseToBuffer(Memory<byte> buffer, NetworkPacket instance)
+ {
+ if (buffer.Length < PacketSize)
+ {
+ throw new ArgumentException("Given buffer is too small to serialise the packet instance into.", nameof(buffer));
+ }
+
+ Span<byte> serialisedPacketHeader = buffer.Slice(0, HeaderSize).Span;
+ NetworkPacketHeader.Serialise(serialisedPacketHeader, instance.Header);
+
+ Span<byte> serialisedPacketFooter = buffer.Slice(HeaderSize + DataSegmentSize, FooterSize).Span;
+ NetworkPacketFooter.Serialise(serialisedPacketFooter, instance.Footer);
+
+ Memory<byte> serialisedInstanceData = buffer.Slice(HeaderSize, DataSegmentSize);
+ instance.DataBuffer.CopyTo(serialisedInstanceData);
+ }
+ }
+
+ // TODO: Document
+ public readonly struct NetworkPacketFooter
+ {
+ private const int PacketHasNextStart = 0;
+
+ /// <summary>
+ /// The number of bytes taken up by a packet footer.
+ /// </summary>
+ public const int Size = sizeof(bool);
+
+ public readonly bool HasSucceedingPacket;
+
+ public NetworkPacketFooter(bool hasSucceedingPacket)
+ {
+ HasSucceedingPacket = hasSucceedingPacket;
+ }
+
+ public static NetworkPacketFooter Deserialise(Span<byte> buffer)
+ {
+ Span<byte> serialisedHasNextFlag = buffer.Slice(PacketHasNextStart, sizeof(bool));
+
+ return new NetworkPacketFooter(
+ EndianAwareBitConverter.ToBoolean(serialisedHasNextFlag));
+ }
+
+ public static void Serialise(Span<byte> buffer, NetworkPacketFooter instance)
+ {
+ Span<byte> serialisedHasNextFlag = buffer.Slice(PacketHasNextStart, sizeof(bool));
+
+ EndianAwareBitConverter.GetBytes(instance.HasSucceedingPacket).CopyTo(serialisedHasNextFlag);
+ }
+ }
+
+ // TODO: Document
+ public readonly struct NetworkPacketHeader
+ {
+ private const int PacketDataLengthStart = 2 * sizeof(uint);
+ private const int PacketErrorCodeStart = sizeof(uint);
+ private const int PacketTypeStart = 0;
+
+ /// <summary>
+ /// The number of bytes taken up by a packet header.
+ /// </summary>
+ public const int Size = sizeof(uint) + sizeof(uint) + sizeof(int);
+
+ /// <summary>
+ /// The number of bytes of data held in the packet.
+ /// </summary>
+ public readonly int DataLength;
+
+ /// <summary>
+ /// The error code for this packet.
+ /// </summary>
+ public readonly NetworkErrorCode ErrorCode;
+
+ /// <summary>
+ /// The packet type.
+ /// </summary>
+ public readonly uint Type;
+
+ public NetworkPacketHeader(uint packetType, NetworkErrorCode packetErrorCode, int packetDataLength)
+ {
+ Type = packetType;
+ ErrorCode = packetErrorCode;
+ DataLength = packetDataLength;
+ }
+
+ public static NetworkPacketHeader Deserialise(Span<byte> buffer)
+ {
+ Span<byte> serialisedType = buffer.Slice(PacketTypeStart, sizeof(uint));
+ Span<byte> serialisedErrorCode = buffer.Slice(PacketErrorCodeStart, sizeof(uint));
+ Span<byte> serialisedDataLength = buffer.Slice(PacketDataLengthStart, sizeof(int));
+
+ return new NetworkPacketHeader(
+ EndianAwareBitConverter.ToUInt32(serialisedType),
+ (NetworkErrorCode)EndianAwareBitConverter.ToUInt32(serialisedErrorCode),
+ EndianAwareBitConverter.ToInt32(serialisedDataLength));
+ }
+
+ public static void Serialise(Span<byte> buffer, NetworkPacketHeader instance)
+ {
+ Span<byte> serialisedType = buffer.Slice(PacketTypeStart, sizeof(uint));
+ Span<byte> serialisedErrorCode = buffer.Slice(PacketErrorCodeStart, sizeof(uint));
+ Span<byte> serialisedDataLength = buffer.Slice(PacketDataLengthStart, sizeof(int));
+
+ EndianAwareBitConverter.GetBytes(instance.Type).CopyTo(serialisedType);
+ EndianAwareBitConverter.GetBytes((uint)instance.ErrorCode).CopyTo(serialisedErrorCode);
+ EndianAwareBitConverter.GetBytes(instance.DataLength).CopyTo(serialisedDataLength);
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/PacketPipeline.cs b/NetSharp/NetSharp/Deprecated/PacketPipeline.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace NetSharp.Deprecated
+{
+ /// <summary>
+ /// Represents a pipeline of transformations that packets must undergo.
+ /// </summary>
+ /// <typeparam name="TInput">The type of packet the pipeline receives.</typeparam>
+ /// <typeparam name="TIntermediate">The type of packet the pipeline internally handles.</typeparam>
+ /// <typeparam name="TOutput">The type of packet the pipeline outputs.</typeparam>
+ // TODO: Implement a packet pipeline, with multiple transform stages to allow encryption, compression, and various other bytewise manipulation stages.
+ internal readonly struct PacketPipeline<TInput, TIntermediate, TOutput>
+ {
+ private readonly PacketPipelineStage<TInput, TIntermediate> pipelineInputStage;
+ private readonly IReadOnlyCollection<PacketPipelineStage<TIntermediate, TIntermediate>> pipelineIntermediateStages;
+ private readonly PacketPipelineStage<TIntermediate, TOutput> pipelineOutputStage;
+
+ internal PacketPipeline(
+ PacketPipelineStage<TInput, TIntermediate> firstStage,
+ PacketPipelineStage<TIntermediate, TOutput> lastStage,
+ IReadOnlyCollection<PacketPipelineStage<TIntermediate, TIntermediate>> intermediateStages)
+ {
+ pipelineInputStage = firstStage;
+ pipelineOutputStage = lastStage;
+
+ pipelineIntermediateStages = intermediateStages;
+ }
+
+ /// <summary>
+ /// Passes the given packet through the pipeline.
+ /// </summary>
+ /// <param name="inputPacket">The incoming packet.</param>
+ /// <returns>The outgoing transformed packet.</returns>
+ internal TOutput ProcessPacket(TInput inputPacket)
+ {
+ TIntermediate intermediatePacket = pipelineInputStage.Process(inputPacket);
+
+ intermediatePacket = pipelineIntermediateStages.Aggregate(intermediatePacket, (current, stage) => stage.Process(current));
+
+ return pipelineOutputStage.Process(intermediatePacket);
+ }
+ }
+
+ /// <summary>
+ /// Represents a single transformation applied to a packet traveling through the pipeline.
+ /// </summary>
+ /// <typeparam name="TInput">The type the transformation takes as input.</typeparam>
+ /// <typeparam name="TOutput">The type the transformation produces as output.</typeparam>
+ internal readonly struct PacketPipelineStage<TInput, TOutput>
+ {
+ private readonly Func<TInput, TOutput> stageDelegate;
+
+ internal PacketPipelineStage(in Func<TInput, TOutput> stageProcessingDelegate)
+ {
+ stageDelegate = stageProcessingDelegate;
+ }
+
+ internal TOutput Process(TInput input)
+ {
+ return stageDelegate(input);
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/PacketPipelineBuilder.cs b/NetSharp/NetSharp/Deprecated/PacketPipelineBuilder.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Collections.Generic;
+
+namespace NetSharp.Deprecated
+{
+ /// <summary>
+ /// Allows for configuring and subsequently building a <see cref="PacketPipeline{TInput,TIntermediate,TOutput}"/> instance.
+ /// </summary>
+ /// <typeparam name="TInput">The type of packet that will be submitted to the pipeline.</typeparam>
+ /// <typeparam name="TIntermediate">The type of packet that will be handled internally by the pipeline.</typeparam>
+ /// <typeparam name="TOutput">The type of packet that will be requested from the pipeline.</typeparam>
+ internal sealed class PacketPipelineBuilder<TInput, TIntermediate, TOutput>
+ {
+ private readonly List<PacketPipelineStage<TIntermediate, TIntermediate>> intermediateStages;
+
+ private PacketPipelineStage<TInput, TIntermediate>? inputStage;
+ private PacketPipelineStage<TIntermediate, TOutput>? outputStage;
+
+ internal PacketPipelineBuilder()
+ {
+ intermediateStages = new List<PacketPipelineStage<TIntermediate, TIntermediate>>();
+ }
+
+ /// <summary>
+ /// Returns the currently configured <see cref="PacketPipeline{TInput,TIntermediate,TOutput}"/> instance.
+ /// </summary>
+ /// <returns>The configured <see cref="PacketPipeline{TInput,TIntermediate,TOutput}"/> instance.</returns>
+ /// <exception cref="ArgumentNullException">
+ /// Thrown when either <see cref="WithInputStage"/> or <see cref="WithOutputStage"/> have not been called.
+ /// </exception>
+ internal PacketPipeline<TInput, TIntermediate, TOutput> Build()
+ {
+ if (inputStage == null)
+ {
+ throw new ArgumentNullException(nameof(inputStage), $"{nameof(WithInputStage)} has not been called.");
+ }
+
+ if (outputStage == null)
+ {
+ throw new ArgumentNullException(nameof(outputStage), $"{nameof(WithOutputStage)} has not been called.");
+ }
+
+ return new PacketPipeline<TInput, TIntermediate, TOutput>(inputStage.Value, outputStage.Value, intermediateStages);
+ }
+
+ /// <summary>
+ /// Configures the input stage for the pipeline.
+ /// </summary>
+ /// <param name="stage">
+ /// The transformation that should be applied to incoming packets, to convert them from the <typeparamref name="TInput"/>
+ /// type to the <typeparamref name="TIntermediate"/> type that the pipeline handles internally.
+ /// </param>
+ /// <returns>The builder instance for further configuration.</returns>
+ internal PacketPipelineBuilder<TInput, TIntermediate, TOutput> WithInputStage(in Func<TInput, TIntermediate> stage)
+ {
+ inputStage = new PacketPipelineStage<TInput, TIntermediate>(in stage);
+ return this;
+ }
+
+ /// <summary>
+ /// Adds the given intermediate stage to the pipeline.
+ /// </summary>
+ /// <param name="stage">
+ /// The transformation that should be applied to packets traveling through the pipeline.
+ /// </param>
+ /// <returns>The builder instance for further configuration.</returns>
+ internal PacketPipelineBuilder<TInput, TIntermediate, TOutput> WithIntermediateStage(in Func<TIntermediate, TIntermediate> stage)
+ {
+ intermediateStages.Add(new PacketPipelineStage<TIntermediate, TIntermediate>(in stage));
+ return this;
+ }
+
+ /// <summary>
+ /// Configures the output stage for the pipeline.
+ /// </summary>
+ /// <param name="stage">
+ /// The transformation that should be applied to outgoing packets, to convert them from the
+ /// <typeparamref name="TIntermediate"/> type used internally to the <typeparamref name="TOutput"/> type.
+ /// </param>
+ /// <returns>The builder instance for further configuration.</returns>
+ internal PacketPipelineBuilder<TInput, TIntermediate, TOutput> WithOutputStage(in Func<TIntermediate, TOutput> stage)
+ {
+ outputStage = new PacketPipelineStage<TIntermediate, TOutput>(in stage);
+ return this;
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/PacketRegistry.cs b/NetSharp/NetSharp/Deprecated/PacketRegistry.cs
@@ -0,0 +1,285 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+namespace NetSharp.Deprecated
+{
+ /// <summary>
+ /// Provides method of registering request packets and their relevant response packets, as well as mapping their ids.
+ /// </summary>
+ internal static class PacketRegistry
+ {
+ /// <summary>
+ /// The start id for automatically generated packet type ids. Any custom packet type ids lower than this value
+ /// that come from external assemblies will be incremented by this value, to ensure that there are no clashes.
+ /// </summary>
+ private const uint AutomaticPacketTypeIdStartPoint = 100;
+
+ /// <summary>
+ /// The lock object for synchronising access to the <see cref="currentAutomaticPacketTypeIdCounter"/> field.
+ /// </summary>
+ private static readonly object currentAutomaticPacketTypeIdCounterLockObject = new object();
+
+ /// <summary>
+ /// Maps a packet type id to its relevant packet type, and vice-versa.
+ /// </summary>
+ private static readonly BiDictionary<uint, Type> idToPacketTypeMap;
+
+ /// <summary>
+ /// The assembly that represents the library, where all of the builtin packets are defined.
+ /// </summary>
+ private static readonly Assembly LibraryAssembly = Assembly.GetAssembly(typeof(PacketRegistry));
+
+ /// <summary>
+ /// Maps a request packet to its relevant response packet, and vice-versa.
+ /// </summary>
+ private static readonly BiDictionary<Type, Type> requestToResponseMap;
+
+ /// <summary>
+ /// The current id for registered packets.
+ /// </summary>
+ private static uint currentAutomaticPacketTypeIdCounter = AutomaticPacketTypeIdStartPoint;
+
+ /// <summary>
+ /// Fetches the packet type id of the given packet type. If the packet type is declared outside of the library
+ /// assembly, then its value is incremented by the <see cref="AutomaticPacketTypeIdStartPoint"/> value. This ensure that
+ /// there are no clashes between the packet type ids of packets declared in the library and external packets.
+ /// </summary>
+ /// <param name="packetType">The packet type whose id should be fetched.</param>
+ /// <returns>The id of the given packet type.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static uint GetNewPacketTypeId(Type packetType)
+ {
+ uint packetTypeId;
+
+ if (packetType.Assembly != LibraryAssembly)
+ {
+ lock (currentAutomaticPacketTypeIdCounterLockObject)
+ {
+ packetTypeId = currentAutomaticPacketTypeIdCounter++;
+ }
+ }
+ else
+ {
+ PacketTypeIdAttribute customPacketTypeIdAttribute =
+ (PacketTypeIdAttribute)packetType.GetCustomAttributes(typeof(PacketTypeIdAttribute)).First();
+
+ packetTypeId = customPacketTypeIdAttribute.Id;
+ }
+
+ return packetTypeId;
+ }
+
+ /// <summary>
+ /// Deregisters the given packet type from the registry.
+ /// </summary>
+ /// <param name="requestPacketType">The request packet type to deregister, if it is registered.</param>
+ /// <param name="responsePacketType">The response packet associated with the request packet.</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static void DeregisterPacketType(Type requestPacketType, Type? responsePacketType)
+ {
+ if (idToPacketTypeMap.ContainsValue(requestPacketType))
+ {
+ idToPacketTypeMap.TryClearKey(requestPacketType, out _);
+ }
+
+ // if the given response packet is null, then skip deregistering a response packet type
+ if (responsePacketType == default) return;
+
+ if (!idToPacketTypeMap.ContainsValue(responsePacketType))
+ {
+ idToPacketTypeMap.TryClearKey(responsePacketType, out _);
+ }
+
+ if (!requestToResponseMap.ContainsValue(requestPacketType))
+ {
+ requestToResponseMap.TryClearKey(requestPacketType, out _);
+ }
+ }
+
+ /// <summary>
+ /// Deregisters the given packet types from the registry.
+ /// </summary>
+ /// <param name="requestToResponsePacketTypeMap">The list of packet types to deregister, if they are registered.</param>
+ internal static void DeregisterPacketTypes(Dictionary<Type, Type?> requestToResponsePacketTypeMap)
+ {
+ foreach ((Type requestPacketType, Type? responsePacketType) in requestToResponsePacketTypeMap)
+ {
+ DeregisterPacketType(requestPacketType, responsePacketType);
+ }
+ }
+
+ /// <summary>
+ /// Returns the packet type id associated with the given packet type.
+ /// </summary>
+ /// <param name="packetType">The packet type whose id to fetch.</param>
+ /// <returns>The id of the packet type given.</returns>
+ internal static uint GetPacketId(Type packetType) => idToPacketTypeMap[packetType];
+
+ /// <summary>
+ /// Returns the packet type id associated with the given packet type.
+ /// </summary>
+ /// <typeparam name="TPacket">The packet type whose id to fetch.</typeparam>
+ /// <returns>The id of the packet type given.</returns>
+ internal static uint GetPacketId<TPacket>() where TPacket : IPacket => idToPacketTypeMap[typeof(TPacket)];
+
+ /// <summary>
+ /// Returns the packet type associated with the given id.
+ /// </summary>
+ /// <param name="packetTypeId">The packet id whose mapped type to fetch.</param>
+ /// <returns>The packet type mapped by the given id.</returns>
+ internal static Type GetPacketType(uint packetTypeId) => idToPacketTypeMap[packetTypeId];
+
+ /// <summary>
+ /// Returns the type of request packet mapped by the given response packet type.
+ /// </summary>
+ /// <typeparam name="TResponse">The response packet type whose request packet type to fetch.</typeparam>
+ /// <returns>The request packet type, <c>null</c> if no type is mapped.</returns>
+ internal static Type GetRequestPacketType<TResponse>() where TResponse : IResponsePacket<IRequestPacket>
+ {
+ requestToResponseMap.TryGetKey(typeof(TResponse), out Type requestPacketType);
+
+ return requestPacketType;
+ }
+
+ /// <summary>
+ /// Returns the type of request packet mapped by the given response packet type.
+ /// </summary>
+ /// <param name="responsePacketType">The response packet type whose request packet type to fetch.</param>
+ /// <returns>The request packet type, <c>null</c> if no type is mapped.</returns>
+ internal static Type GetRequestPacketType(Type responsePacketType)
+ {
+ requestToResponseMap.TryGetKey(responsePacketType, out Type requestPacketType);
+
+ return requestPacketType;
+ }
+
+ /// <summary>
+ /// Returns the type of response packet mapped by the given request packet type.
+ /// </summary>
+ /// <typeparam name="TRequest">The request packet type whose response packet type to fetch.</typeparam>
+ /// <returns>The response packet type, <c>null</c> if no type is mapped.</returns>
+ internal static Type? GetResponsePacketType<TRequest>() where TRequest : IRequestPacket
+ {
+ return requestToResponseMap.TryGetValue(typeof(TRequest), out Type responsePacketType) ? responsePacketType : default;
+ }
+
+ /// <summary>
+ /// Returns the type of response packet mapped by the given request packet type.
+ /// </summary>
+ /// <param name="requestPacketType">The request packet type whose response packet type to fetch.</param>
+ /// <returns>The response packet type, <c>null</c> if no type is mapped.</returns>
+ internal static Type? GetResponsePacketType(Type requestPacketType)
+ {
+ return requestToResponseMap.TryGetValue(requestPacketType, out Type responsePacketType) ? responsePacketType : default;
+ }
+
+ /// <summary>
+ /// Rebuilds the packet registry, by registering every <see cref="IPacket"/> inheritor in the given assemblies.
+ /// </summary>
+ /// <param name="packetSourceAssemblies">
+ /// The assemblies from which the packet types to register are sourced.
+ /// </param>
+ internal static void RegisterPacketSourceAssemblies(params Assembly[] packetSourceAssemblies)
+ {
+ foreach (Assembly assembly in packetSourceAssemblies)
+ {
+ RegisterPacketSourceAssembly(assembly);
+ }
+ }
+
+ /// <summary>
+ /// Registers all the <see cref="IPacket"/> implementors in the given assembly.
+ /// </summary>
+ /// <param name="packetSourceAssembly">The assembly whose packet types to register.</param>
+ //[MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static void RegisterPacketSourceAssembly(Assembly packetSourceAssembly)
+ {
+ Dictionary<Type, Type?> requestToResponseTypeMap = new Dictionary<Type, Type?>();
+
+ foreach (Type type in packetSourceAssembly.DefinedTypes)
+ {
+ foreach (Type interfaceType in type.GetInterfaces())
+ {
+ if (!typeof(IPacket).IsAssignableFrom(interfaceType) || interfaceType == typeof(IPacket))
+ {
+ continue;
+ }
+
+ if (interfaceType == typeof(IRequestPacket))
+ {
+ requestToResponseTypeMap[type] = default;
+ }
+ else //if (interfaceType == typeof(IResponsePacket<>))
+ {
+ Type handledRequestType = interfaceType.GetGenericArguments()[0];
+
+ requestToResponseTypeMap[handledRequestType] = type;
+ }
+ }
+ }
+
+ RegisterPacketTypes(requestToResponseTypeMap);
+ }
+
+ /// <summary>
+ /// Registers the given packet type to the registry.
+ /// </summary>
+ /// <param name="requestPacketType">The request packet type to register, if it is not registered.</param>
+ /// <param name="responsePacketType">The response packet associated with the request packet.</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static void RegisterPacketType(Type requestPacketType, Type? responsePacketType)
+ {
+ if (!idToPacketTypeMap.ContainsValue(requestPacketType))
+ {
+ uint requestPacketTypeId = GetNewPacketTypeId(requestPacketType);
+
+ idToPacketTypeMap.TrySetValue(requestPacketTypeId, requestPacketType);
+ }
+
+ // if the given response packet is null, then skip registering a response packet type
+ if (responsePacketType == default) return;
+
+ if (!idToPacketTypeMap.ContainsValue(responsePacketType))
+ {
+ uint responsePacketTypeId = GetNewPacketTypeId(responsePacketType);
+
+ idToPacketTypeMap.TrySetValue(responsePacketTypeId, responsePacketType);
+ }
+
+ if (!requestToResponseMap.ContainsValue(requestPacketType))
+ {
+ requestToResponseMap.TrySetValue(requestPacketType, responsePacketType);
+ }
+ }
+
+ /// <summary>
+ /// Registers the given packet types to the registry.
+ /// </summary>
+ /// <param name="requestToResponsePacketTypeMap">
+ /// The dictionary mapping the request packet types to register, to their relevant response packet types.
+ /// The response packet type can be null; then the request packet type is treated as a 'simple' packet.
+ /// </param>
+ internal static void RegisterPacketTypes(Dictionary<Type, Type?> requestToResponsePacketTypeMap)
+ {
+ foreach ((Type requestPacketType, Type? responsePacketType) in requestToResponsePacketTypeMap)
+ {
+ RegisterPacketType(requestPacketType, responsePacketType);
+ }
+ }
+
+ /// <summary>
+ /// Initialises a new instance of the <see cref="PacketRegistry"/> class.
+ /// </summary>
+ static PacketRegistry()
+ {
+ idToPacketTypeMap = new BiDictionary<uint, Type>();
+
+ requestToResponseMap = new BiDictionary<Type, Type>();
+
+ RegisterPacketSourceAssembly(LibraryAssembly);
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/PacketTypeIdAttribute.cs b/NetSharp/NetSharp/Deprecated/PacketTypeIdAttribute.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace NetSharp.Deprecated
+{
+ /// <summary>
+ /// Allows the placing of a custom packet type on a class or struct. This is used if the class or struct
+ /// inherits from <see cref="IRequestPacket"/> or <see cref="IResponsePacket{TReq}"/>.
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
+ internal sealed class PacketTypeIdAttribute : Attribute
+ {
+ /// <summary>
+ /// Initialises a new instance of the <see cref="PacketTypeIdAttribute"/> attribute.
+ /// </summary>
+ /// <param name="type">The custom type id that the decorated packet type should have.</param>
+ internal PacketTypeIdAttribute(uint type)
+ {
+ Id = type;
+ }
+
+ /// <summary>
+ /// The custom type id that the decorated packet type should have. This overrides the automatically generated id.
+ /// </summary>
+ internal uint Id { get; }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/RemoteSocketClient.cs b/NetSharp/NetSharp/Deprecated/RemoteSocketClient.cs
@@ -0,0 +1,73 @@
+using Microsoft.Extensions.ObjectPool;
+
+using NetSharp.Utils;
+
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace NetSharp.Deprecated
+{
+ public class RemoteSocketClient : IDisposable
+ {
+ private readonly ObjectPool<SocketAsyncEventArgs> transmissionArgsPool;
+
+ protected readonly Socket transmitterSocket;
+
+ internal RemoteSocketClient(Socket clientSocket)
+ {
+ transmitterSocket = clientSocket;
+
+ transmissionArgsPool = new DefaultObjectPool<SocketAsyncEventArgs>(new DefaultPooledObjectPolicy<SocketAsyncEventArgs>());
+ }
+
+ /// <inheritdoc />
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// <summary>
+ /// Implementation of dispose pattern.
+ /// </summary>
+ /// <param name="disposing">
+ /// Whether this method is being called by the object finalizer, or by the <see cref="Dispose()"/> method.
+ /// </param>
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ transmitterSocket.Dispose();
+ }
+ }
+
+ public async ValueTask<TransmissionResult> ReceiveAsync(EndPoint remoteEndPoint, SocketFlags receiveFlags, Memory<byte> receiveBuffer,
+ CancellationToken cancellationToken = default)
+ {
+ SocketAsyncEventArgs transmissionArgs = transmissionArgsPool.Get();
+
+ TransmissionResult receiveResult = await SocketOperations.ReceiveFromAsync(transmissionArgs, transmitterSocket,
+ remoteEndPoint, receiveFlags, receiveBuffer, cancellationToken);
+
+ transmissionArgsPool.Return(transmissionArgs);
+
+ return receiveResult;
+ }
+
+ public async ValueTask<TransmissionResult> SendAsync(EndPoint remoteEndPoint, SocketFlags sendFlags, Memory<byte> sendBuffer,
+ CancellationToken cancellationToken = default)
+ {
+ SocketAsyncEventArgs transmissionArgs = transmissionArgsPool.Get();
+
+ TransmissionResult sendResult = await SocketOperations.SendToAsync(transmissionArgs, transmitterSocket,
+ remoteEndPoint, sendFlags, sendBuffer, cancellationToken);
+
+ transmissionArgsPool.Return(transmissionArgs);
+
+ return sendResult;
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/RingBuffer.cs b/NetSharp/NetSharp/Deprecated/RingBuffer.cs
@@ -0,0 +1,48 @@
+namespace NetSharp.Deprecated
+{
+ public class RingBuffer<T>
+ {
+ private readonly T[] buffer;
+
+ private int currentIndex;
+
+ public RingBuffer(int capacity)
+ {
+ buffer = new T[capacity];
+
+ Capacity = capacity;
+ Count = 0;
+ }
+
+ public int Capacity { get; }
+
+ public int Count { get; }
+
+ public T Pop()
+ {
+ T removedItem = buffer[currentIndex--];
+
+ currentIndex = currentIndex < 0 ? currentIndex + Capacity : currentIndex;
+
+ return removedItem;
+ }
+
+ public bool Push(T newItem, out T removedItem)
+ {
+ bool overwroteItem = false;
+ removedItem = default;
+
+ if (buffer[currentIndex] != null)
+ {
+ removedItem = buffer[currentIndex];
+ overwroteItem = true;
+ }
+
+ buffer[currentIndex] = newItem;
+
+ currentIndex = (currentIndex + 1) % Capacity;
+
+ return overwroteItem;
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/SerialisedPacket.cs b/NetSharp/NetSharp/Deprecated/SerialisedPacket.cs
@@ -1,5 +1,4 @@
using System;
-using NetSharp.Packets;
namespace NetSharp.Deprecated
{
diff --git a/NetSharp/NetSharp/Deprecated/Server.cs b/NetSharp/NetSharp/Deprecated/Server.cs
@@ -1,12 +1,12 @@
-using System;
+using NetSharp.Deprecated.Builtin;
+
+using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
-using NetSharp.Packets;
-using NetSharp.Packets.Builtin;
namespace NetSharp.Deprecated
{
diff --git a/NetSharp/NetSharp/Deprecated/ServerClientConnection.cs b/NetSharp/NetSharp/Deprecated/ServerClientConnection.cs
@@ -2,8 +2,6 @@
using System.IO;
using System.Net;
using System.Runtime.CompilerServices;
-using NetSharp.Logging;
-using NetSharp.Utils;
namespace NetSharp.Deprecated
{
diff --git a/NetSharp/NetSharp/Deprecated/ServerExtensions.cs b/NetSharp/NetSharp/Deprecated/ServerExtensions.cs
@@ -1,6 +1,5 @@
using System.Net;
using System.Threading.Tasks;
-using NetSharp.Utils;
namespace NetSharp.Deprecated
{
diff --git a/NetSharp/NetSharp/Deprecated/SocketAcceptor.cs b/NetSharp/NetSharp/Deprecated/SocketAcceptor.cs
@@ -0,0 +1,281 @@
+using Microsoft.Extensions.ObjectPool;
+
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace NetSharp.Deprecated
+{
+ /// <summary>
+ /// Helper class providing awaitable wrappers around asynchronous Accept, Connect, and Disconnect operations.
+ /// </summary>
+ public sealed class SocketAcceptor
+ {
+ private readonly ObjectPool<SocketAsyncEventArgs> acceptAsyncEventArgsPool;
+ private readonly ObjectPool<SocketAsyncEventArgs> connectAsyncEventArgsPool;
+ private readonly ObjectPool<SocketAsyncEventArgs> disconnectAsyncEventArgsPool;
+
+ private void HandleIOCompleted(object? sender, SocketAsyncEventArgs args)
+ {
+ switch (args.LastOperation)
+ {
+ case SocketAsyncOperation.Accept:
+ AsyncAcceptToken asyncAcceptToken = (AsyncAcceptToken)args.UserToken;
+
+ if (asyncAcceptToken.CancellationToken.IsCancellationRequested)
+ {
+ asyncAcceptToken.CompletionSource.SetCanceled();
+ }
+ else
+ {
+ if (args.SocketError != SocketError.Success)
+ {
+ asyncAcceptToken.CompletionSource.SetException(
+ new SocketException((int)args.SocketError));
+ }
+ else
+ {
+ asyncAcceptToken.CompletionSource.SetResult(args.AcceptSocket);
+ }
+ }
+
+ acceptAsyncEventArgsPool.Return(args);
+
+ break;
+
+ case SocketAsyncOperation.Connect:
+ AsyncConnectToken asyncConnectToken = (AsyncConnectToken)args.UserToken;
+
+ if (asyncConnectToken.CancellationToken.IsCancellationRequested)
+ {
+ asyncConnectToken.CompletionSource.SetCanceled();
+ }
+ else
+ {
+ if (args.SocketError != SocketError.Success)
+ {
+ asyncConnectToken.CompletionSource.SetException(
+ new SocketException((int)args.SocketError));
+ }
+ else
+ {
+ asyncConnectToken.CompletionSource.SetResult(true);
+ }
+ }
+
+ connectAsyncEventArgsPool.Return(args);
+
+ break;
+
+ case SocketAsyncOperation.Disconnect:
+ AsyncDisconnectToken asyncDisconnectToken = (AsyncDisconnectToken)args.UserToken;
+
+ if (asyncDisconnectToken.CancellationToken.IsCancellationRequested)
+ {
+ asyncDisconnectToken.CompletionSource.SetCanceled();
+ }
+ else
+ {
+ if (args.SocketError != SocketError.Success)
+ {
+ asyncDisconnectToken.CompletionSource.SetException(
+ new SocketException((int)args.SocketError));
+ }
+ else
+ {
+ asyncDisconnectToken.CompletionSource.SetResult(true);
+ }
+ }
+
+ disconnectAsyncEventArgsPool.Return(args);
+
+ break;
+
+ default:
+ throw new InvalidOperationException(
+ $"The {nameof(SocketAcceptor)} class doesn't support the {args.LastOperation} operation.");
+ }
+ }
+
+ private readonly struct AsyncAcceptToken
+ {
+ public readonly CancellationToken CancellationToken;
+ public readonly TaskCompletionSource<Socket> CompletionSource;
+
+ public AsyncAcceptToken(TaskCompletionSource<Socket> tcs, CancellationToken cancellationToken = default)
+ {
+ CompletionSource = tcs;
+ CancellationToken = cancellationToken;
+ }
+ }
+
+ private readonly struct AsyncConnectToken
+ {
+ public readonly CancellationToken CancellationToken;
+ public readonly TaskCompletionSource<bool> CompletionSource;
+
+ public AsyncConnectToken(TaskCompletionSource<bool> tcs, CancellationToken cancellationToken = default)
+ {
+ CompletionSource = tcs;
+ CancellationToken = cancellationToken;
+ }
+ }
+
+ private readonly struct AsyncDisconnectToken
+ {
+ public readonly CancellationToken CancellationToken;
+ public readonly TaskCompletionSource<bool> CompletionSource;
+
+ public AsyncDisconnectToken(TaskCompletionSource<bool> tcs, CancellationToken cancellationToken = default)
+ {
+ CompletionSource = tcs;
+ CancellationToken = cancellationToken;
+ }
+ }
+
+ internal SocketAcceptor(int maxPooledObjects = 10)
+ {
+ acceptAsyncEventArgsPool =
+ new DefaultObjectPool<SocketAsyncEventArgs>(new DefaultPooledObjectPolicy<SocketAsyncEventArgs>(),
+ maxPooledObjects);
+
+ connectAsyncEventArgsPool =
+ new DefaultObjectPool<SocketAsyncEventArgs>(new DefaultPooledObjectPolicy<SocketAsyncEventArgs>(),
+ maxPooledObjects);
+
+ disconnectAsyncEventArgsPool =
+ new DefaultObjectPool<SocketAsyncEventArgs>(new DefaultPooledObjectPolicy<SocketAsyncEventArgs>(),
+ maxPooledObjects);
+
+ for (int i = 0; i < maxPooledObjects; i++)
+ {
+ SocketAsyncEventArgs acceptArgs = new SocketAsyncEventArgs();
+ acceptArgs.Completed += HandleIOCompleted;
+ acceptAsyncEventArgsPool.Return(acceptArgs);
+
+ SocketAsyncEventArgs connectArgs = new SocketAsyncEventArgs();
+ connectArgs.Completed += HandleIOCompleted;
+ connectAsyncEventArgsPool.Return(connectArgs);
+
+ SocketAsyncEventArgs disconnectArgs = new SocketAsyncEventArgs();
+ disconnectArgs.Completed += HandleIOCompleted;
+ connectAsyncEventArgsPool.Return(disconnectArgs);
+ }
+ }
+
+ /// <summary>
+ /// Provides an awaitable wrapper around an asynchronous socket accept operation.
+ /// </summary>
+ /// <param name="socket">The socket which should be used to accept an incoming connection attempt.</param>
+ /// <param name="cancellationToken">The cancellation token to observe for the operation.</param>
+ /// <returns>The accepted socket.</returns>
+ public Task<Socket> AcceptAsync(Socket socket, CancellationToken cancellationToken = default)
+ {
+ TaskCompletionSource<Socket> tcs = new TaskCompletionSource<Socket>();
+
+ SocketAsyncEventArgs args = acceptAsyncEventArgsPool.Get();
+ args.UserToken = new AsyncAcceptToken(tcs, cancellationToken);
+
+ /*
+ // register cleanup action for when the cancellation token is thrown
+ cancellationToken.Register(() =>
+ {
+ tcs.SetCanceled();
+
+ //TODO this is probably a hideous solution. find a better one
+ args.Completed -= HandleIOCompleted;
+ args.Dispose();
+
+ SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
+ newArgs.Completed += HandleIOCompleted;
+ acceptAsyncEventArgsPool.Return(newArgs);
+ });
+ */
+
+ // if the accept operation doesn't complete synchronously, return the awaitable task
+ if (socket.AcceptAsync(args)) return tcs.Task;
+
+ Socket result = args.AcceptSocket;
+
+ acceptAsyncEventArgsPool.Return(args);
+
+ return Task.FromResult(result);
+ }
+
+ /// <summary>
+ /// Provides an awaitable wrapper around an asynchronous socket connect operation.
+ /// </summary>
+ /// <param name="socket">The socket which should asynchronously connect to the remote endpoint.</param>
+ /// <param name="remoteEndPoint">The remote endpoint to which the socket should connect.</param>
+ /// <param name="cancellationToken">The cancellation token to observe for the operation.</param>
+ public Task ConnectAsync(Socket socket, EndPoint remoteEndPoint, CancellationToken cancellationToken = default)
+ {
+ TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
+
+ SocketAsyncEventArgs args = connectAsyncEventArgsPool.Get();
+ args.RemoteEndPoint = remoteEndPoint;
+ args.UserToken = new AsyncConnectToken(tcs, cancellationToken);
+
+ /*
+ // register cleanup action for when the cancellation token is thrown
+ cancellationToken.Register(() =>
+ {
+ tcs.SetCanceled();
+
+ //TODO this is probably a hideous solution. find a better one
+ args.Completed -= HandleIOCompleted;
+ args.Dispose();
+
+ SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
+ newArgs.Completed += HandleIOCompleted;
+ connectAsyncEventArgsPool.Return(newArgs);
+ });
+ */
+
+ // if the connect operation doesn't complete synchronously, return the awaitable task
+ if (socket.ConnectAsync(args)) return tcs.Task;
+
+ connectAsyncEventArgsPool.Return(args);
+
+ return Task.CompletedTask;
+ }
+
+ /// <summary>
+ /// Provides an awaitable wrapper around an asynchronous socket disconnect operation.
+ /// </summary>
+ /// <param name="socket">The socket which should asynchronously disconnect from its remote endpoint.</param>
+ /// <param name="cancellationToken">The cancellation token to observe for the operation.</param>
+ public Task DisconnectAsync(Socket socket, CancellationToken cancellationToken = default)
+ {
+ TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
+
+ SocketAsyncEventArgs args = connectAsyncEventArgsPool.Get();
+ args.UserToken = new AsyncDisconnectToken(tcs, cancellationToken);
+
+ /*
+ // register cleanup action for when the cancellation token is thrown
+ cancellationToken.Register(() =>
+ {
+ tcs.SetCanceled();
+
+ //TODO this is probably a hideous solution. find a better one
+ args.Completed -= HandleIOCompleted;
+ args.Dispose();
+
+ SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
+ newArgs.Completed += HandleIOCompleted;
+ disconnectAsyncEventArgsPool.Return(newArgs);
+ });
+ */
+
+ // if the disconnect operation doesn't complete synchronously, return the awaitable task
+ if (socket.DisconnectAsync(args)) return tcs.Task;
+
+ connectAsyncEventArgsPool.Return(args);
+
+ return Task.CompletedTask;
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/SocketClient.cs b/NetSharp/NetSharp/Deprecated/SocketClient.cs
@@ -0,0 +1,132 @@
+using Microsoft.Extensions.ObjectPool;
+
+using NetSharp.Utils;
+
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace NetSharp.Deprecated
+{
+ public class SocketClient : IDisposable
+ {
+ private readonly ObjectPool<SocketAsyncEventArgs> transmissionArgsPool;
+
+ /// <summary>
+ /// Destroys a socket client instance.
+ /// </summary>
+ ~SocketClient()
+ {
+ Dispose(false);
+ }
+
+ protected readonly Socket transmitterSocket;
+
+ /// <summary>
+ /// Implementation of dispose pattern.
+ /// </summary>
+ /// <param name="disposing">
+ /// Whether this method is being called by the object finalizer, or by the <see cref="Dispose()"/> method.
+ /// </param>
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ transmitterSocket.Dispose();
+ }
+ }
+
+ public SocketClient(AddressFamily transmitterAddressFamily, SocketType transmitterSocketType,
+ ProtocolType transmitterProtocolType)
+ {
+ transmitterSocket = new Socket(transmitterAddressFamily, transmitterSocketType, transmitterProtocolType);
+
+ transmissionArgsPool = new DefaultObjectPool<SocketAsyncEventArgs>(new DefaultPooledObjectPolicy<SocketAsyncEventArgs>());
+ }
+
+ /// <inheritdoc />
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ public async ValueTask<TransmissionResult> ReceiveAsync(EndPoint remoteEndPoint, SocketFlags receiveFlags, Memory<byte> receiveBuffer,
+ CancellationToken cancellationToken = default)
+ {
+ SocketAsyncEventArgs transmissionArgs = transmissionArgsPool.Get();
+
+ TransmissionResult receiveResult =
+ await SocketOperations.ReceiveFromAsync(transmissionArgs, transmitterSocket,
+ remoteEndPoint, receiveFlags, receiveBuffer, cancellationToken).ConfigureAwait(false);
+
+ transmissionArgsPool.Return(transmissionArgs);
+
+ return receiveResult;
+ }
+
+ public async ValueTask<TransmissionResult> SendAsync(EndPoint remoteEndPoint, SocketFlags sendFlags, Memory<byte> sendBuffer,
+ CancellationToken cancellationToken = default)
+ {
+ SocketAsyncEventArgs transmissionArgs = transmissionArgsPool.Get();
+
+ TransmissionResult sendResult =
+ await SocketOperations.SendToAsync(transmissionArgs, transmitterSocket,
+ remoteEndPoint, sendFlags, sendBuffer, cancellationToken).ConfigureAwait(false);
+
+ transmissionArgsPool.Return(transmissionArgs);
+
+ return sendResult;
+ }
+
+ public Task<bool> TryBindAsync(EndPoint localEndPoint, TimeSpan timeout)
+ {
+ using CancellationTokenSource cts = new CancellationTokenSource(timeout);
+
+ try
+ {
+ return Task.Run(() =>
+ {
+ transmitterSocket.Bind(localEndPoint);
+
+ return true;
+ }, cts.Token);
+ }
+ catch (TaskCanceledException)
+ {
+ return Task.FromResult(false);
+ }
+ catch (SocketException ex)
+ {
+ Console.WriteLine($"Socket exception on binding socket to {localEndPoint}: {ex}");
+ return Task.FromResult(false);
+ }
+ }
+
+ public Task<bool> TryConnectAsync(EndPoint remoteEndPoint, TimeSpan timeout)
+ {
+ using CancellationTokenSource cts = new CancellationTokenSource(timeout);
+
+ try
+ {
+ return Task.Run(() =>
+ {
+ transmitterSocket.Connect(remoteEndPoint);
+
+ return true;
+ }, cts.Token);
+ }
+ catch (TaskCanceledException)
+ {
+ return Task.FromResult(false);
+ }
+ catch (SocketException ex)
+ {
+ Console.WriteLine($"Socket exception on connecting to {remoteEndPoint}: {ex}");
+ return Task.FromResult(false);
+ }
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/SocketOperationTokens.cs b/NetSharp/NetSharp/Deprecated/SocketOperationTokens.cs
@@ -0,0 +1,80 @@
+using NetSharp.Utils;
+
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace NetSharp.Deprecated
+{
+ internal readonly struct AsyncAcceptToken
+ {
+ public readonly CancellationToken CancellationToken;
+ public readonly TaskCompletionSource<Socket> CompletionSource;
+
+ public AsyncAcceptToken(in TaskCompletionSource<Socket> tcs, in CancellationToken cancellationToken = default)
+ {
+ CompletionSource = tcs;
+ CancellationToken = cancellationToken;
+ }
+ }
+
+ internal readonly struct AsyncConnectToken
+ {
+ public readonly CancellationToken CancellationToken;
+ public readonly TaskCompletionSource<Socket> CompletionSource;
+
+ public AsyncConnectToken(in TaskCompletionSource<Socket> tcs, in CancellationToken cancellationToken = default)
+ {
+ CompletionSource = tcs;
+ CancellationToken = cancellationToken;
+ }
+ }
+
+ internal readonly struct AsyncDisconnectToken
+ {
+ public readonly CancellationToken CancellationToken;
+ public readonly TaskCompletionSource<bool> CompletionSource;
+
+ public AsyncDisconnectToken(in TaskCompletionSource<bool> tcs, in CancellationToken cancellationToken = default)
+ {
+ CompletionSource = tcs;
+ CancellationToken = cancellationToken;
+ }
+ }
+
+ internal readonly struct AsyncReadToken
+ {
+ public readonly CancellationToken CancellationToken;
+ public readonly TaskCompletionSource<TransmissionResult> CompletionSource;
+
+ public AsyncReadToken(in TaskCompletionSource<TransmissionResult> tcs, in CancellationToken cancellationToken = default)
+ {
+ CompletionSource = tcs;
+ CancellationToken = cancellationToken;
+ }
+ }
+
+ internal readonly struct AsyncWriteToken
+ {
+ public readonly CancellationToken CancellationToken;
+ public readonly TaskCompletionSource<TransmissionResult> CompletionSource;
+
+ public AsyncWriteToken(in TaskCompletionSource<TransmissionResult> tcs, in CancellationToken cancellationToken = default)
+ {
+ CompletionSource = tcs;
+ CancellationToken = cancellationToken;
+ }
+ }
+
+ internal readonly struct AsyncReadFromToken
+ {
+ public readonly CancellationToken CancellationToken;
+ public readonly TaskCompletionSource<TransmissionResult> CompletionSource;
+
+ public AsyncReadFromToken(in TaskCompletionSource<TransmissionResult> tcs, in CancellationToken cancellationToken = default)
+ {
+ CompletionSource = tcs;
+ CancellationToken = cancellationToken;
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/SocketOperations.cs b/NetSharp/NetSharp/Deprecated/SocketOperations.cs
@@ -0,0 +1,469 @@
+using NetSharp.Utils;
+
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace NetSharp.Deprecated
+{
+ /// <summary>
+ /// Provides helper awaitable functions for wrapping the <see cref="SocketAsyncEventArgs"/> pattern.
+ /// </summary>
+ public static class SocketOperations
+ {
+ private static void HandleIOCompleted(object? sender, SocketAsyncEventArgs args)
+ {
+ args.Completed -= HandleIOCompleted;
+
+ switch (args.LastOperation)
+ {
+ case SocketAsyncOperation.Receive:
+ AsyncReadToken asyncReceiveToken = (AsyncReadToken)args.UserToken;
+
+ if (asyncReceiveToken.CancellationToken.IsCancellationRequested)
+ {
+ asyncReceiveToken.CompletionSource.SetCanceled();
+ }
+ else
+ {
+ if (args.SocketError != SocketError.Success)
+ {
+ asyncReceiveToken.CompletionSource.SetException(
+ new SocketException((int)args.SocketError));
+ }
+ else if (args.BytesTransferred > 0)
+ {
+ TransmissionResult result = new TransmissionResult(args);
+
+ asyncReceiveToken.CompletionSource.SetResult(result);
+ }
+ else
+ {
+ asyncReceiveToken.CompletionSource.SetException(
+ new Exception($"Receive method received 0 bytes from remote endpoint!"));
+ }
+ }
+
+ break;
+
+ case SocketAsyncOperation.ReceiveFrom:
+ AsyncReadFromToken asyncReceiveFromToken = (AsyncReadFromToken)args.UserToken;
+
+ if (asyncReceiveFromToken.CancellationToken.IsCancellationRequested)
+ {
+ asyncReceiveFromToken.CompletionSource.SetCanceled();
+ }
+ else
+ {
+ if (args.SocketError != SocketError.Success)
+ {
+ asyncReceiveFromToken.CompletionSource.SetException(
+ new SocketException((int)args.SocketError));
+ }
+ else
+ {
+ TransmissionResult result = new TransmissionResult(args);
+
+ asyncReceiveFromToken.CompletionSource.SetResult(result);
+ }
+ }
+
+ break;
+
+ case SocketAsyncOperation.Send:
+ AsyncWriteToken asyncSendToken = (AsyncWriteToken)args.UserToken;
+
+ if (asyncSendToken.CancellationToken.IsCancellationRequested)
+ {
+ asyncSendToken.CompletionSource.SetCanceled();
+ }
+ else
+ {
+ if (args.SocketError != SocketError.Success)
+ {
+ asyncSendToken.CompletionSource.SetException(
+ new SocketException((int)args.SocketError));
+ }
+ else
+ {
+ TransmissionResult result = new TransmissionResult(args);
+
+ asyncSendToken.CompletionSource.SetResult(result);
+ }
+ }
+
+ break;
+
+ case SocketAsyncOperation.SendTo:
+ AsyncWriteToToken asyncSendToToken = (AsyncWriteToToken)args.UserToken;
+
+ if (asyncSendToToken.CancellationToken.IsCancellationRequested)
+ {
+ asyncSendToToken.CompletionSource.SetCanceled();
+ }
+ else
+ {
+ if (args.SocketError != SocketError.Success)
+ {
+ asyncSendToToken.CompletionSource.SetException(
+ new SocketException((int)args.SocketError));
+ }
+ else
+ {
+ TransmissionResult result = new TransmissionResult(args);
+
+ asyncSendToToken.CompletionSource.SetResult(result);
+ }
+ }
+
+ break;
+
+ case SocketAsyncOperation.Accept:
+ AsyncAcceptToken asyncAcceptToken = (AsyncAcceptToken)args.UserToken;
+
+ if (asyncAcceptToken.CancellationToken.IsCancellationRequested)
+ {
+ asyncAcceptToken.CompletionSource.SetCanceled();
+ }
+ else
+ {
+ if (args.SocketError != SocketError.Success)
+ {
+ asyncAcceptToken.CompletionSource.SetException(
+ new SocketException((int)args.SocketError));
+ }
+ else
+ {
+ asyncAcceptToken.CompletionSource.SetResult(args.AcceptSocket);
+ }
+ }
+
+ break;
+
+ case SocketAsyncOperation.Connect:
+ AsyncConnectToken asyncConnectToken = (AsyncConnectToken)args.UserToken;
+
+ if (asyncConnectToken.CancellationToken.IsCancellationRequested)
+ {
+ asyncConnectToken.CompletionSource.SetCanceled();
+ }
+ else
+ {
+ if (args.SocketError != SocketError.Success)
+ {
+ asyncConnectToken.CompletionSource.SetException(
+ new SocketException((int)args.SocketError));
+ }
+ else
+ {
+ asyncConnectToken.CompletionSource.SetResult(args.ConnectSocket);
+ }
+ }
+
+ break;
+
+ case SocketAsyncOperation.Disconnect:
+ AsyncDisconnectToken asyncDisconnectToken = (AsyncDisconnectToken)args.UserToken;
+
+ if (asyncDisconnectToken.CancellationToken.IsCancellationRequested)
+ {
+ asyncDisconnectToken.CompletionSource.SetCanceled();
+ }
+ else
+ {
+ if (args.SocketError != SocketError.Success)
+ {
+ asyncDisconnectToken.CompletionSource.SetException(
+ new SocketException((int)args.SocketError));
+ }
+ else
+ {
+ asyncDisconnectToken.CompletionSource.SetResult(true);
+ }
+ }
+
+ break;
+
+ default:
+ throw new InvalidOperationException(
+ $"{nameof(SocketOperations)} doesn't support the {args.LastOperation} operation.");
+ }
+ }
+
+ private readonly struct AsyncWriteToToken
+ {
+ public readonly CancellationToken CancellationToken;
+ public readonly TaskCompletionSource<TransmissionResult> CompletionSource;
+
+ public AsyncWriteToToken(in TaskCompletionSource<TransmissionResult> tcs, in CancellationToken cancellationToken = default)
+ {
+ CompletionSource = tcs;
+ CancellationToken = cancellationToken;
+ }
+ }
+
+ public static ValueTask<Socket> AcceptAsync(SocketAsyncEventArgs clientAcceptArgs, Socket socket,
+ CancellationToken cancellationToken = default)
+ {
+ TaskCompletionSource<Socket> tcs = new TaskCompletionSource<Socket>();
+
+ clientAcceptArgs.UserToken = new AsyncAcceptToken(tcs, cancellationToken);
+
+ clientAcceptArgs.Completed += HandleIOCompleted;
+
+ /*
+ // register cleanup action for when the cancellation token is thrown
+ cancellationToken.Register(() =>
+ {
+ tcs.SetCanceled();
+
+ //TODO this is probably a hideous solution. find a better one
+ args.Completed -= HandleIOCompleted;
+ args.Dispose();
+
+ SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
+ newArgs.Completed += HandleIOCompleted;
+ acceptAsyncEventArgsPool.Return(newArgs);
+ });
+ */
+
+ // if the accept operation doesn't complete synchronously, return the awaitable task
+ if (socket.AcceptAsync(clientAcceptArgs)) return new ValueTask<Socket>(tcs.Task);
+
+ Socket result = clientAcceptArgs.AcceptSocket;
+ clientAcceptArgs.Completed -= HandleIOCompleted;
+
+ return new ValueTask<Socket>(result);
+ }
+
+ public static ValueTask<Socket> ConnectAsync(SocketAsyncEventArgs clientConnectArgs, Socket socket, EndPoint remoteEndPoint,
+ CancellationToken cancellationToken = default)
+ {
+ TaskCompletionSource<Socket> tcs = new TaskCompletionSource<Socket>();
+
+ clientConnectArgs.RemoteEndPoint = remoteEndPoint;
+ clientConnectArgs.UserToken = new AsyncConnectToken(tcs, cancellationToken);
+
+ clientConnectArgs.Completed += HandleIOCompleted;
+
+ /*
+ // register cleanup action for when the cancellation token is thrown
+ cancellationToken.Register(() =>
+ {
+ tcs.SetCanceled();
+
+ //TODO this is probably a hideous solution. find a better one
+ args.Completed -= HandleIOCompleted;
+ args.Dispose();
+
+ SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
+ newArgs.Completed += HandleIOCompleted;
+ connectAsyncEventArgsPool.Return(newArgs);
+ });
+ */
+
+ // if the connect operation doesn't complete synchronously, return the awaitable task
+ if (socket.ConnectAsync(clientConnectArgs)) return new ValueTask<Socket>(tcs.Task);
+
+ Socket result = clientConnectArgs.ConnectSocket;
+ clientConnectArgs.Completed -= HandleIOCompleted;
+
+ return new ValueTask<Socket>(result);
+ }
+
+ public static ValueTask DisconnectAsync(SocketAsyncEventArgs clientDisconnectArgs, Socket socket,
+ CancellationToken cancellationToken = default)
+ {
+ TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
+
+ clientDisconnectArgs.UserToken = new AsyncDisconnectToken(tcs, cancellationToken);
+
+ clientDisconnectArgs.Completed += HandleIOCompleted;
+
+ /*
+ // register cleanup action for when the cancellation token is thrown
+ cancellationToken.Register(() =>
+ {
+ tcs.SetCanceled();
+
+ //TODO this is probably a hideous solution. find a better one
+ args.Completed -= HandleIOCompleted;
+ args.Dispose();
+
+ SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
+ newArgs.Completed += HandleIOCompleted;
+ disconnectAsyncEventArgsPool.Return(newArgs);
+ });
+ */
+
+ // if the disconnect operation doesn't complete synchronously, return the awaitable task
+ if (socket.DisconnectAsync(clientDisconnectArgs)) return new ValueTask(tcs.Task);
+
+ clientDisconnectArgs.Completed -= HandleIOCompleted;
+
+ return new ValueTask();
+ }
+
+ public static ValueTask<TransmissionResult> ReceiveAsync(SocketAsyncEventArgs socketArgs, Socket socket, EndPoint remoteEndPoint,
+ SocketFlags socketFlags, Memory<byte> inputBuffer, CancellationToken cancellationToken = default)
+ {
+ TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>();
+
+ socketArgs.SetBuffer(inputBuffer);
+ socketArgs.SocketFlags = socketFlags;
+ socketArgs.RemoteEndPoint = remoteEndPoint;
+ socketArgs.UserToken = new AsyncReadToken(tcs, cancellationToken);
+
+ socketArgs.Completed += HandleIOCompleted;
+
+ /*
+ // register cleanup action for when the cancellation token is thrown
+ cancellationToken.Register(() =>
+ {
+ tcs.SetCanceled();
+
+ receiveBufferPool.Return(rentedReceiveFromBuffer, true);
+
+ //TODO this is probably a hideous solution. find a better one
+ args.Completed -= HandleIOCompleted;
+ args.Dispose();
+
+ SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
+ newArgs.Completed += HandleIOCompleted;
+ receiveAsyncEventArgsPool.Return(newArgs);
+ });
+ */
+
+ // if the receive operation doesn't complete synchronously, returns the awaitable task
+ if (socket.ReceiveAsync(socketArgs)) return new ValueTask<TransmissionResult>(tcs.Task);
+
+ socketArgs.Completed -= HandleIOCompleted;
+
+ TransmissionResult result = new TransmissionResult(socketArgs);
+
+ return new ValueTask<TransmissionResult>(result);
+ }
+
+ public static ValueTask<TransmissionResult> ReceiveFromAsync(SocketAsyncEventArgs socketArgs, Socket socket, EndPoint remoteEndPoint,
+ SocketFlags socketFlags, Memory<byte> inputBuffer, CancellationToken cancellationToken = default)
+ {
+ TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>();
+
+ socketArgs.SetBuffer(inputBuffer);
+ socketArgs.SocketFlags = socketFlags;
+ socketArgs.RemoteEndPoint = remoteEndPoint;
+ socketArgs.UserToken = new AsyncReadFromToken(tcs, cancellationToken);
+
+ socketArgs.Completed += HandleIOCompleted;
+
+ /*
+ // register cleanup action for when the cancellation token is thrown
+ cancellationToken.Register(() =>
+ {
+ tcs.SetCanceled();
+
+ receiveBufferPool.Return(rentedReceiveFromBuffer, true);
+
+ //TODO this is probably a hideous solution. find a better one
+ args.Completed -= HandleIOCompleted;
+ args.Dispose();
+
+ SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
+ newArgs.Completed += HandleIOCompleted;
+ receiveAsyncEventArgsPool.Return(newArgs);
+ });
+ */
+
+ // if the receive operation doesn't complete synchronously, returns the awaitable task
+ if (socket.ReceiveFromAsync(socketArgs)) return new ValueTask<TransmissionResult>(tcs.Task);
+
+ socketArgs.Completed -= HandleIOCompleted;
+
+ TransmissionResult result = new TransmissionResult(socketArgs);
+
+ return new ValueTask<TransmissionResult>(result);
+ }
+
+ public static ValueTask<TransmissionResult> SendAsync(SocketAsyncEventArgs socketArgs, Socket socket, EndPoint remoteEndPoint,
+ SocketFlags socketFlags, Memory<byte> outputBuffer, CancellationToken cancellationToken = default)
+ {
+ TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>();
+
+ socketArgs.SetBuffer(outputBuffer);
+ socketArgs.SocketFlags = socketFlags;
+ socketArgs.RemoteEndPoint = remoteEndPoint;
+ socketArgs.UserToken = new AsyncWriteToken(tcs, cancellationToken);
+
+ socketArgs.Completed += HandleIOCompleted;
+
+ /*
+ // register cleanup action for when the cancellation token is thrown
+ cancellationToken.Register(() =>
+ {
+ tcs.SetCanceled();
+
+ sendBufferPool.Return(rentedSendToBuffer, true);
+
+ //TODO this is probably a hideous solution. find a better one
+ args.Completed -= HandleIOCompleted;
+ args.Dispose();
+
+ SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
+ newArgs.Completed += HandleIOCompleted;
+ sendAsyncEventArgsPool.Return(newArgs);
+ });
+ */
+
+ // if the send operation doesn't complete synchronously, return the awaitable task
+ if (socket.SendAsync(socketArgs)) return new ValueTask<TransmissionResult>(tcs.Task);
+
+ socketArgs.Completed -= HandleIOCompleted;
+
+ TransmissionResult result = new TransmissionResult(socketArgs);
+
+ return new ValueTask<TransmissionResult>(result);
+ }
+
+ public static ValueTask<TransmissionResult> SendToAsync(SocketAsyncEventArgs socketArgs, Socket socket, EndPoint remoteEndPoint,
+ SocketFlags socketFlags, Memory<byte> outputBuffer, CancellationToken cancellationToken = default)
+ {
+ TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>();
+
+ socketArgs.SetBuffer(outputBuffer);
+ socketArgs.SocketFlags = socketFlags;
+ socketArgs.RemoteEndPoint = remoteEndPoint;
+ socketArgs.UserToken = new AsyncWriteToToken(tcs, cancellationToken);
+
+ socketArgs.Completed += HandleIOCompleted;
+
+ /*
+ // register cleanup action for when the cancellation token is thrown
+ cancellationToken.Register(() =>
+ {
+ tcs.SetCanceled();
+
+ sendBufferPool.Return(rentedSendToBuffer, true);
+
+ //TODO this is probably a hideous solution. find a better one
+ args.Completed -= HandleIOCompleted;
+ args.Dispose();
+
+ SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
+ newArgs.Completed += HandleIOCompleted;
+ sendAsyncEventArgsPool.Return(newArgs);
+ });
+ */
+
+ // if the send operation doesn't complete synchronously, return the awaitable task
+ if (socket.SendToAsync(socketArgs)) return new ValueTask<TransmissionResult>(tcs.Task);
+
+ socketArgs.Completed -= HandleIOCompleted;
+
+ TransmissionResult result = new TransmissionResult(socketArgs);
+
+ return new ValueTask<TransmissionResult>(result);
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/SocketReader.cs b/NetSharp/NetSharp/Deprecated/SocketReader.cs
@@ -0,0 +1,153 @@
+using Microsoft.Extensions.ObjectPool;
+
+using NetSharp.Utils;
+
+using System;
+using System.Buffers;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace NetSharp.Deprecated
+{
+ /// <summary>
+ /// Helper class providing awaitable wrappers around asynchronous Receive and ReceiveFrom operations.
+ /// </summary>
+ public sealed class SocketReader
+ {
+ private readonly int PacketBufferLength;
+ private readonly ObjectPool<SocketAsyncEventArgs> receiveFromAsyncEventArgsPool;
+ private readonly ArrayPool<byte> receiveFromBufferPool;
+
+ private void HandleIOCompleted(object? sender, SocketAsyncEventArgs args)
+ {
+ switch (args.LastOperation)
+ {
+ case SocketAsyncOperation.ReceiveFrom:
+ AsyncReadToken asyncReceiveFromToken = (AsyncReadToken)args.UserToken;
+
+ if (asyncReceiveFromToken.CancellationToken.IsCancellationRequested)
+ {
+ asyncReceiveFromToken.CompletionSource.SetCanceled();
+ }
+ else
+ {
+ if (args.SocketError != SocketError.Success)
+ {
+ asyncReceiveFromToken.CompletionSource.SetException(
+ new SocketException((int)args.SocketError));
+ }
+ else
+ {
+ args.MemoryBuffer.CopyTo(asyncReceiveFromToken.UserBuffer);
+
+ TransmissionResult result = new TransmissionResult(args);
+
+ asyncReceiveFromToken.CompletionSource.SetResult(result);
+ }
+ }
+
+ receiveFromBufferPool.Return(asyncReceiveFromToken.RentedBuffer, true);
+ receiveFromAsyncEventArgsPool.Return(args);
+
+ break;
+
+ default:
+ throw new InvalidOperationException(
+ $"The {nameof(SocketReader)} class doesn't support the {args.LastOperation} operation.");
+ }
+ }
+
+ private readonly struct AsyncReadToken
+ {
+ public readonly CancellationToken CancellationToken;
+ public readonly TaskCompletionSource<TransmissionResult> CompletionSource;
+ public readonly byte[] RentedBuffer;
+ public readonly Memory<byte> UserBuffer;
+
+ public AsyncReadToken(byte[] rentedBuffer, Memory<byte> userBuffer, TaskCompletionSource<TransmissionResult> tcs,
+ CancellationToken cancellationToken = default)
+ {
+ RentedBuffer = rentedBuffer;
+ UserBuffer = userBuffer;
+
+ CompletionSource = tcs;
+ CancellationToken = cancellationToken;
+ }
+ }
+
+ internal SocketReader(int packetBufferLength = NetworkPacket.PacketSize, int maxPooledObjects = 10,
+ bool preallocateBuffers = false)
+ {
+ PacketBufferLength = packetBufferLength;
+
+ receiveFromBufferPool = ArrayPool<byte>.Create(packetBufferLength, maxPooledObjects);
+
+ receiveFromAsyncEventArgsPool =
+ new DefaultObjectPool<SocketAsyncEventArgs>(new DefaultPooledObjectPolicy<SocketAsyncEventArgs>(),
+ maxPooledObjects);
+
+ for (int i = 0; i < maxPooledObjects; i++)
+ {
+ SocketAsyncEventArgs receiveFromArgs = new SocketAsyncEventArgs();
+ receiveFromArgs.Completed += HandleIOCompleted;
+ receiveFromAsyncEventArgsPool.Return(receiveFromArgs);
+ }
+ }
+
+ /// <summary>
+ /// Provides an awaitable wrapper around an asynchronous socket receive operation.
+ /// </summary>
+ /// <param name="socket">The socket which should receive data from the remote endpoint.</param>
+ /// <param name="remoteEndPoint">The remove endpoint from which data should be received.</param>
+ /// <param name="socketFlags">The socket flags associated with the receive operation.</param>
+ /// <param name="inputBuffer">The memory buffer into which received data will be stored.</param>
+ /// <param name="cancellationToken">The cancellation token to observe for the operation.</param>
+ /// <returns>The result of the receive operation.</returns>
+ public Task<TransmissionResult> ReceiveFromAsync(Socket socket, EndPoint remoteEndPoint, SocketFlags socketFlags,
+ Memory<byte> inputBuffer, CancellationToken cancellationToken = default)
+ {
+ TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>();
+
+ byte[] rentedReceiveFromBuffer = receiveFromBufferPool.Rent(PacketBufferLength);
+ Memory<byte> rentedReceiveFromBufferMemory = new Memory<byte>(rentedReceiveFromBuffer);
+
+ SocketAsyncEventArgs args = receiveFromAsyncEventArgsPool.Get();
+ args.SetBuffer(rentedReceiveFromBufferMemory);
+ args.SocketFlags = socketFlags;
+ args.RemoteEndPoint = remoteEndPoint;
+ args.UserToken = new AsyncReadToken(rentedReceiveFromBuffer, inputBuffer, tcs, cancellationToken);
+
+ /*
+ // register cleanup action for when the cancellation token is thrown
+ cancellationToken.Register(() =>
+ {
+ tcs.SetCanceled();
+
+ receiveBufferPool.Return(rentedReceiveFromBuffer, true);
+
+ //TODO this is probably a hideous solution. find a better one
+ args.Completed -= HandleIOCompleted;
+ args.Dispose();
+
+ SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
+ newArgs.Completed += HandleIOCompleted;
+ receiveAsyncEventArgsPool.Return(newArgs);
+ });
+ */
+
+ // if the receive operation doesn't complete synchronously, returns the awaitable task
+ if (socket.ReceiveFromAsync(args)) return tcs.Task;
+
+ args.MemoryBuffer.CopyTo(inputBuffer);
+
+ TransmissionResult result = new TransmissionResult(args);
+
+ receiveFromBufferPool.Return(rentedReceiveFromBuffer, true);
+ receiveFromAsyncEventArgsPool.Return(args);
+
+ return Task.FromResult(result);
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/SocketServer.cs b/NetSharp/NetSharp/Deprecated/SocketServer.cs
@@ -0,0 +1,121 @@
+using Microsoft.Extensions.ObjectPool;
+
+using NetSharp.Utils;
+
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace NetSharp.Deprecated
+{
+ public class SocketServer : IDisposable
+ {
+ private readonly ObjectPool<SocketAsyncEventArgs> transmissionArgsPool;
+
+ /// <summary>
+ /// Destroys a socket server instance.
+ /// </summary>
+ ~SocketServer()
+ {
+ Dispose(false);
+ }
+
+ /// <summary>
+ /// The socket which should be used to listen for incoming data and to send outgoing data.
+ /// </summary>
+ protected readonly Socket listenerSocket;
+
+ /// <summary>
+ /// Implementation of dispose pattern.
+ /// </summary>
+ /// <param name="disposing">
+ /// Whether this method is being called by the object finalizer, or by the <see cref="Dispose()"/> method.
+ /// </param>
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ listenerSocket.Dispose();
+ }
+ }
+
+ public SocketServer(AddressFamily listenerAddressFamily, SocketType listenerSocketType,
+ ProtocolType listenerProtocolType)
+ {
+ listenerSocket = new Socket(listenerAddressFamily, listenerSocketType, listenerProtocolType);
+
+ transmissionArgsPool = new DefaultObjectPool<SocketAsyncEventArgs>(new DefaultPooledObjectPolicy<SocketAsyncEventArgs>());
+ }
+
+ /// <inheritdoc />
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ public async ValueTask<TransmissionResult> ReceiveAsync(EndPoint remoteEndPoint, SocketFlags receiveFlags, Memory<byte> receiveBuffer,
+ CancellationToken cancellationToken = default)
+ {
+ SocketAsyncEventArgs transmissionArgs = transmissionArgsPool.Get();
+
+ TransmissionResult receiveResult =
+ await SocketOperations.ReceiveFromAsync(transmissionArgs, listenerSocket, remoteEndPoint, receiveFlags,
+ receiveBuffer, cancellationToken).ConfigureAwait(false);
+
+ transmissionArgsPool.Return(transmissionArgs);
+
+ return receiveResult;
+ }
+
+ public async ValueTask<TransmissionResult> SendAsync(EndPoint remoteEndPoint, SocketFlags sendFlags, Memory<byte> sendBuffer,
+ CancellationToken cancellationToken = default)
+ {
+ SocketAsyncEventArgs transmissionArgs = transmissionArgsPool.Get();
+
+ TransmissionResult sendResult =
+ await SocketOperations.SendToAsync(transmissionArgs, listenerSocket, remoteEndPoint, sendFlags,
+ sendBuffer, cancellationToken).ConfigureAwait(false);
+
+ transmissionArgsPool.Return(transmissionArgs);
+
+ return sendResult;
+ }
+
+ public async Task<RemoteSocketClient> AcceptAsync(CancellationToken cancellationToken = default)
+ {
+ using SocketAsyncEventArgs clientAcceptArgs = new SocketAsyncEventArgs();
+
+ Socket clientSocket = await SocketOperations
+ .AcceptAsync(clientAcceptArgs, listenerSocket, cancellationToken).ConfigureAwait(false);
+
+ return new RemoteSocketClient(clientSocket);
+ }
+
+ public Task<bool> TryBindAsync(EndPoint localEndPoint, TimeSpan timeout)
+ {
+ using CancellationTokenSource cts = new CancellationTokenSource(timeout);
+
+ try
+ {
+ return Task.Run(() =>
+ {
+ listenerSocket.Bind(localEndPoint);
+
+ return true;
+ }, cts.Token);
+ }
+ catch (TaskCanceledException)
+ {
+ return Task.FromResult(false);
+ }
+ catch (SocketException ex)
+ {
+ Console.WriteLine($"Socket exception on binding socket to {localEndPoint}: {ex}");
+ return Task.FromResult(false);
+ }
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/SocketWriter.cs b/NetSharp/NetSharp/Deprecated/SocketWriter.cs
@@ -0,0 +1,144 @@
+using Microsoft.Extensions.ObjectPool;
+
+using System;
+using System.Buffers;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace NetSharp.Deprecated
+{
+ /// <summary>
+ /// Helper class providing awaitable wrappers around asynchronous Send and SendTo operations.
+ /// </summary>
+ public sealed class SocketWriter
+ {
+ private readonly int PacketBufferLength;
+ private readonly ObjectPool<SocketAsyncEventArgs> sendToAsyncEventArgsPool;
+ private readonly ArrayPool<byte> sendToBufferPool;
+
+ private void HandleIOCompleted(object? sender, SocketAsyncEventArgs args)
+ {
+ switch (args.LastOperation)
+ {
+ case SocketAsyncOperation.SendTo:
+ AsyncWriteToken asyncSendToToken = (AsyncWriteToken)args.UserToken;
+
+ if (asyncSendToToken.CancellationToken.IsCancellationRequested)
+ {
+ asyncSendToToken.CompletionSource.SetCanceled();
+ }
+ else
+ {
+ if (args.SocketError != SocketError.Success)
+ {
+ asyncSendToToken.CompletionSource.SetException(
+ new SocketException((int)args.SocketError));
+ }
+ else
+ {
+ asyncSendToToken.CompletionSource.SetResult(args.BytesTransferred);
+ }
+ }
+
+ sendToBufferPool.Return(asyncSendToToken.RentedBuffer, true);
+ sendToAsyncEventArgsPool.Return(args);
+ break;
+
+ default:
+ throw new InvalidOperationException(
+ $"The {nameof(SocketWriter)} class doesn't support the {args.LastOperation} operation.");
+ }
+ }
+
+ private readonly struct AsyncWriteToken
+ {
+ public readonly CancellationToken CancellationToken;
+ public readonly TaskCompletionSource<int> CompletionSource;
+ public readonly byte[] RentedBuffer;
+
+ public AsyncWriteToken(byte[] rentedBuffer, TaskCompletionSource<int> tcs,
+ CancellationToken cancellationToken = default)
+ {
+ RentedBuffer = rentedBuffer;
+
+ CompletionSource = tcs;
+ CancellationToken = cancellationToken;
+ }
+ }
+
+ internal SocketWriter(int packetBufferLength = NetworkPacket.PacketSize, int maxPooledObjects = 10,
+ bool preallocateBuffers = false)
+ {
+ PacketBufferLength = packetBufferLength;
+
+ sendToBufferPool = ArrayPool<byte>.Create(packetBufferLength, maxPooledObjects);
+
+ sendToAsyncEventArgsPool =
+ new DefaultObjectPool<SocketAsyncEventArgs>(new DefaultPooledObjectPolicy<SocketAsyncEventArgs>(),
+ maxPooledObjects);
+
+ for (int i = 0; i < maxPooledObjects; i++)
+ {
+ SocketAsyncEventArgs sendToArgs = new SocketAsyncEventArgs();
+ sendToArgs.Completed += HandleIOCompleted;
+ sendToAsyncEventArgsPool.Return(sendToArgs);
+ }
+ }
+
+ /// <summary>
+ /// Provides an awaitable wrapper around an asynchronous socket send operation.
+ /// </summary>
+ /// <param name="socket">The socket which should send the data to the remote endpoint.</param>
+ /// <param name="remoteEndPoint">The remote endpoint to which data should be written.</param>
+ /// <param name="socketFlags">The socket flags associated with the send operation.</param>
+ /// <param name="outputBuffer">The data buffer which should be sent.</param>
+ /// <param name="cancellationToken">The cancellation token to observe for the operation.</param>
+ /// <returns>The number of bytes of data which were written to the remote endpoint.</returns>
+ public ValueTask<int> SendToAsync(Socket socket, EndPoint remoteEndPoint, SocketFlags socketFlags,
+ Memory<byte> outputBuffer, CancellationToken cancellationToken = default)
+ {
+ TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
+
+ byte[] rentedSendToBuffer = sendToBufferPool.Rent(PacketBufferLength);
+ Memory<byte> rentedSendToBufferMemory = new Memory<byte>(rentedSendToBuffer);
+
+ outputBuffer.CopyTo(rentedSendToBufferMemory);
+
+ SocketAsyncEventArgs args = sendToAsyncEventArgsPool.Get();
+ args.SetBuffer(rentedSendToBufferMemory);
+ args.SocketFlags = socketFlags;
+ args.RemoteEndPoint = remoteEndPoint;
+ args.UserToken = new AsyncWriteToken(rentedSendToBuffer, tcs, cancellationToken);
+
+ /*
+ // register cleanup action for when the cancellation token is thrown
+ cancellationToken.Register(() =>
+ {
+ tcs.SetCanceled();
+
+ sendBufferPool.Return(rentedSendToBuffer, true);
+
+ //TODO this is probably a hideous solution. find a better one
+ args.Completed -= HandleIOCompleted;
+ args.Dispose();
+
+ SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
+ newArgs.Completed += HandleIOCompleted;
+ sendAsyncEventArgsPool.Return(newArgs);
+ });
+ */
+
+ // if the send operation doesn't complete synchronously, return the awaitable task
+ if (socket.SendToAsync(args)) return new ValueTask<int>(tcs.Task);
+
+ int result = args.BytesTransferred;
+
+ sendToBufferPool.Return(rentedSendToBuffer, true);
+ sendToAsyncEventArgsPool.Return(args);
+
+ return new ValueTask<int>(result);
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Deprecated/TcpClient.cs b/NetSharp/NetSharp/Deprecated/TcpClient.cs
@@ -1,8 +1,8 @@
-using System;
+using NetSharp.Deprecated.Builtin;
+
+using System;
using System.Net.Sockets;
using System.Threading.Tasks;
-using NetSharp.Packets;
-using NetSharp.Packets.Builtin;
namespace NetSharp.Deprecated
{
diff --git a/NetSharp/NetSharp/Deprecated/TcpServer.cs b/NetSharp/NetSharp/Deprecated/TcpServer.cs
@@ -1,11 +1,11 @@
-using System;
+using NetSharp.Deprecated.Builtin;
+
+using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using NetSharp.Packets;
-using NetSharp.Packets.Builtin;
namespace NetSharp.Deprecated
{
diff --git a/NetSharp/NetSharp/Deprecated/UdpClient.cs b/NetSharp/NetSharp/Deprecated/UdpClient.cs
@@ -1,8 +1,8 @@
-using System;
+using NetSharp.Deprecated.Builtin;
+
+using System;
using System.Net.Sockets;
using System.Threading.Tasks;
-using NetSharp.Packets;
-using NetSharp.Packets.Builtin;
namespace NetSharp.Deprecated
{
diff --git a/NetSharp/NetSharp/Deprecated/UdpServer.cs b/NetSharp/NetSharp/Deprecated/UdpServer.cs
@@ -1,4 +1,6 @@
-using System;
+using NetSharp.Deprecated.Builtin;
+
+using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
@@ -6,8 +8,6 @@ using System.Text;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
-using NetSharp.Packets;
-using NetSharp.Packets.Builtin;
namespace NetSharp.Deprecated
{
diff --git a/NetSharp/NetSharp/Extensions/ConnectionBuilderExtensions.cs b/NetSharp/NetSharp/Extensions/ConnectionBuilderExtensions.cs
@@ -1,29 +0,0 @@
-using System;
-using System.IO;
-using System.Net.Sockets;
-using NetSharp.Logging;
-
-namespace NetSharp.Extensions
-{
- /// <summary>
- /// Provides additional methods and functionality to the <see cref="ConnectionBuilder"/> class.
- /// </summary>
- public static class ConnectionBuilderExtensions
- {
- public static ConnectionBuilder AppendIncomingPipelineStage(this ConnectionBuilder instance,
- in Func<Memory<byte>, Memory<byte>> transform)
- => instance.WithIncomingPipelineStage(transform, instance.IncomingPacketPipelineStageCount);
-
- public static ConnectionBuilder AppendOutgoingPipelineStage(this ConnectionBuilder instance,
- in Func<Memory<byte>, Memory<byte>> transform)
- => instance.WithOutgoingPipelineStage(transform, instance.OutgoingPacketPipelineStageCount);
-
- public static ConnectionBuilder WithLogging(this ConnectionBuilder instance,
- Stream loggingStream, LogLevel minimumLogLevel)
- => instance.WithLogging(new ConnectionBuilder.LoggingSettings(loggingStream, minimumLogLevel));
-
- public static ConnectionBuilder WithPooling(this ConnectionBuilder instance,
- int poolSize, bool preallocateBuffers)
- => instance.WithPooling(new ConnectionBuilder.PoolingSettings(poolSize, preallocateBuffers));
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Extensions/ConnectionExtensions.cs b/NetSharp/NetSharp/Extensions/ConnectionExtensions.cs
@@ -1,72 +0,0 @@
-using System;
-using System.Net;
-using System.Net.Sockets;
-using System.Threading;
-using System.Threading.Tasks;
-using NetSharp.Utils;
-
-namespace NetSharp.Extensions
-{
- /// <summary>
- /// Provides additional methods and functionality to the <see cref="Connection"/> class.
- /// </summary>
- public static class ConnectionExtensions
- {
- public static Task<TransmissionResult> ReceiveAsync(this Connection instance,
- EndPoint remoteEndPoint, Memory<byte> inputBuffer, SocketFlags flags)
- => instance.ReceiveAsync(inputBuffer, flags, Timeout.InfiniteTimeSpan);
-
- public static Task<TransmissionResult> ReceiveFromAsync(this Connection instance,
- EndPoint remoteEndPoint, Memory<byte> inputBuffer, SocketFlags flags)
- => instance.ReceiveFromAsync(remoteEndPoint, inputBuffer, flags, Timeout.InfiniteTimeSpan);
-
- public static ValueTask<int> SendAsync(this Connection instance,
- EndPoint remoteEndPoint, Memory<byte> outputBuffer, SocketFlags flags)
- => instance.SendAsync(outputBuffer, flags, Timeout.InfiniteTimeSpan);
-
- public static ValueTask<int> SendToAsync(this Connection instance,
- EndPoint remoteEndPoint, Memory<byte> outputBuffer, SocketFlags flags)
- => instance.SendToAsync(remoteEndPoint, outputBuffer, flags, Timeout.InfiniteTimeSpan);
-
- /// <summary>
- /// Attempts to synchronously bind the underlying socket to the given local endpoint. Blocks.
- /// If the timeout is exceeded the binding attempt is aborted and the method returns false.
- /// </summary>
- /// <param name="localEndPoint">The local endpoint to bind to.</param>
- /// <param name="timeout">The timeout within which to attempt the binding.</param>
- /// <returns>Whether the binding was successful or not.</returns>
- public static bool TryBind(this Connection instance,
- EndPoint localEndPoint, TimeSpan timeout)
- => instance.TryBindAsync(localEndPoint, timeout).Result;
-
- public static bool TryBind(this Connection instance,
- EndPoint localEndPoint)
- => instance.TryBindAsync(localEndPoint, Timeout.InfiniteTimeSpan).Result;
-
- public static Task<bool> TryBindAsync(this Connection instance,
- EndPoint localEndPoint)
- => instance.TryBindAsync(localEndPoint, Timeout.InfiniteTimeSpan);
-
- public static bool TryConnect(this Connection instance,
- EndPoint remoteEndPoint)
- => instance.TryConnectAsync(remoteEndPoint, Timeout.InfiniteTimeSpan).Result;
-
- public static bool TryConnect(this Connection instance,
- EndPoint remoteEndPoint, TimeSpan timeout)
- => instance.TryConnectAsync(remoteEndPoint, timeout).Result;
-
- public static Task<bool> TryConnectAsync(this Connection instance,
- EndPoint remoteEndPoint)
- => instance.TryConnectAsync(remoteEndPoint, Timeout.InfiniteTimeSpan);
-
- public static bool TryDisconnect(this Connection instance)
- => instance.TryDisconnectAsync(Timeout.InfiniteTimeSpan).Result;
-
- public static bool TryDisconnect(this Connection instance,
- TimeSpan timeout)
- => instance.TryDisconnectAsync(timeout).Result;
-
- public static Task<bool> TryDisconnectAsync(this Connection instance)
- => instance.TryDisconnectAsync(Timeout.InfiniteTimeSpan);
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Logging/Logger.cs b/NetSharp/NetSharp/Logging/Logger.cs
@@ -1,194 +0,0 @@
-using System;
-using System.IO;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace NetSharp.Logging
-{
- /// <summary>
- /// Specifies the severity level of a log message.
- /// </summary>
- public enum LogLevel
- {
- /// <summary>
- /// The logged message contains some information. Lowest severity.
- /// </summary>
- Info,
-
- /// <summary>
- /// The logged message contains a warning. Higher severity.
- /// </summary>
- Warn,
-
- /// <summary>
- /// The logged message contains details about an error. Higher severity.
- /// </summary>
- Error,
-
- /// <summary>
- /// The logged message contains details about an exception. Highest severity.
- /// </summary>
- Exception
- }
-
- /// <summary>
- /// A simple logger capable of writing text to a stream.
- /// </summary>
- public readonly struct Logger : IDisposable
- {
- /// <summary>
- /// The stream to which messages will be logged.
- /// </summary>
- private readonly Stream loggingStream;
-
- /// <summary>
- /// The minimum severity that log messages need to be logged to the underlying stream.
- /// </summary>
- private readonly LogLevel minimumSeverity;
-
- /// <summary>
- /// The text writer we will use to log messages to the underlying stream.
- /// </summary>
- private readonly StreamWriter writer;
-
- /// <summary>
- /// Initialises a new instance of the <see cref="Logger"/> struct.
- /// </summary>
- /// <param name="outputStream">The stream that the logger instance should log messages to.</param>
- /// <param name="minimumLogSeverity">The minimum log level that will be logged to the output stream.</param>
- public Logger(Stream outputStream, LogLevel minimumLogSeverity = LogLevel.Info)
- {
- loggingStream = outputStream;
- writer = new StreamWriter(loggingStream, Encoding.Default) { AutoFlush = true };
-
- minimumSeverity = minimumLogSeverity;
- }
-
- /// <inheritdoc />
- public void Dispose()
- {
- loggingStream.Dispose();
- writer.Dispose();
- }
-
- /// <summary>
- /// Logs a message to the underlying stream, along with the given exception and at the given severity.
- /// </summary>
- /// <param name="message">The message that should be logged.</param>
- /// <param name="exception">The exception that occurred (if any).</param>
- /// <param name="severity">The severity of the message that is being logged.</param>
- public void Log(string message, Exception? exception, LogLevel severity)
- {
- if (severity < minimumSeverity) return;
-
- string severityTag = severity switch
- {
- LogLevel.Info => "Info ",
- LogLevel.Warn => "Warn ",
- LogLevel.Error => "Error",
- LogLevel.Exception => "Excep",
- _ => "Info "
- };
-
- writer.WriteLine($"[{severityTag}] {message} {exception}");
- }
-
- /// <summary>
- /// Logs a message asynchronously to the underlying stream, along with the given exception and at the given severity.
- /// </summary>
- /// <param name="message">The message that should be logged.</param>
- /// <param name="exception">The exception that occurred (if any).</param>
- /// <param name="severity">The severity of the message that is being logged.</param>
- public async Task LogAsync(string message, Exception? exception, LogLevel severity)
- {
- if (loggingStream.Equals(Stream.Null))
- {
- // ignore log request if the underlying stream is null
- return;
- }
-
- if (!exception?.Equals(default) ?? false)
- {
- severity = LogLevel.Exception;
- }
-
- if (severity >= minimumSeverity)
- {
- string severityTag = severity switch
- {
- LogLevel.Info => "Info ",
- LogLevel.Warn => "Warn ",
- LogLevel.Error => "Error",
- LogLevel.Exception => "Excep",
- _ => "Info "
- };
-
- await writer.WriteLineAsync($"[{severityTag}] {message} {exception}");
- }
- }
-
- /// <summary>
- /// Logs an error to the underlying stream, with severity <see cref="LogLevel.Info"/>.
- /// </summary>
- /// <param name="message">The error that should be logged.</param>
- public void LogError(string message) => Log(message, null, LogLevel.Error);
-
- /// <summary>
- /// Logs an error to the underlying stream asynchronously, with severity <see cref="LogLevel.Error"/>.
- /// </summary>
- /// <param name="message">The error that should be logged.</param>
- public async Task LogErrorAsync(string message) => await LogAsync(message, null, LogLevel.Error);
-
- /// <summary>
- /// Logs an exception to the underlying stream, with severity <see cref="LogLevel.Exception"/>.
- /// </summary>
- /// <param name="exception">The exception that should be logged.</param>
- public void LogException(Exception exception) => Log("", exception, LogLevel.Exception);
-
- /// <summary>
- /// Logs an exception to the underlying stream, along with a short debug message, with severity
- /// <see cref="LogLevel.Exception"/>.
- /// </summary>
- /// <param name="message">The debug message that should be logged with the exception.</param>
- /// <param name="exception">The exception that should be logged.</param>
- public void LogException(string message, Exception exception) => Log(message, exception, LogLevel.Exception);
-
- /// <summary>
- /// Logs an exception to the underlying stream asynchronously, with severity <see cref="LogLevel.Exception"/>.
- /// </summary>
- /// <param name="exception">The exception that should be logged.</param>
- public async Task LogExceptionAsync(Exception exception) => await LogAsync("", exception, LogLevel.Exception);
-
- /// <summary>
- /// Logs an exception to the underlying stream asynchronously, along with a short debug message, with severity
- /// <see cref="LogLevel.Exception"/>.
- /// </summary>
- /// <param name="message">The debug message that should be logged with the exception.</param>
- /// <param name="exception">The exception that should be logged.</param>
- public async Task LogExceptionAsync(string message, Exception exception) => await LogAsync(message, exception, LogLevel.Exception);
-
- /// <summary>
- /// Logs a message to the underlying stream, with severity <see cref="LogLevel.Info"/>.
- /// </summary>
- /// <param name="message">The message that should be logged.</param>
- public void LogMessage(string message) => Log(message, null, LogLevel.Info);
-
- /// <summary>
- /// Logs a message to the underlying stream asynchronously, with severity <see cref="LogLevel.Info"/>.
- /// </summary>
- /// <param name="message">The message that should be logged.</param>
- public async Task LogMessageAsync(string message) => await LogAsync(message, null, LogLevel.Info);
-
- /// <summary>
- /// Logs a warning to the underlying stream, with severity <see cref="LogLevel.Info"/>.
- /// </summary>
- /// <param name="message">The warning that should be logged.</param>
- public void LogWarning(string message) => Log(message, null, LogLevel.Warn);
-
- /// <summary>
- /// Logs a warning to the underlying stream asynchronously, with severity <see cref="LogLevel.Warn"/>.
- /// </summary>
- /// <param name="message">The warning that should be logged.</param>
- public async Task LogWarningAsync(string message) => await LogAsync(message, null, LogLevel.Warn);
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/NetSharp.csproj b/NetSharp/NetSharp/NetSharp.csproj
@@ -17,12 +17,14 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
- <PackageReference Include="Microsoft.Extensions.ObjectPool" Version="3.1.2" />
- <PackageReference Include="System.Threading.Channels" Version="4.7.0" />
+ <Compile Remove="Interfaces\**" />
+ <EmbeddedResource Remove="Interfaces\**" />
+ <None Remove="Interfaces\**" />
</ItemGroup>
<ItemGroup>
- <Folder Include="Interfaces\" />
+ <PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
+ <PackageReference Include="Microsoft.Extensions.ObjectPool" Version="3.1.2" />
+ <PackageReference Include="System.Threading.Channels" Version="4.7.0" />
</ItemGroup>
</Project>
\ No newline at end of file
diff --git a/NetSharp/NetSharp/NetSharp.xml b/NetSharp/NetSharp/NetSharp.xml
@@ -4,242 +4,198 @@
<name>NetSharp</name>
</assembly>
<members>
- <member name="T:NetSharp.Connection">
+ <member name="T:NetSharp.Deprecated.Builtin.ConnectPacket">
<summary>
- Encapsulates a connection capable of receiving packets and responding to them with registered packet handlers.
- </summary>
- <summary>
- Implements low-level network access on top of which the rest of the connection is built upon.
+ A simple connection request packet for the UDP protocol.
</summary>
</member>
- <member name="F:NetSharp.Connection.incomingPacketPipeline">
- <summary>
- Pipeline to convert incoming byte buffers to <see cref="T:NetSharp.Packets.NetworkPacket"/> instances.
- </summary>
+ <member name="M:NetSharp.Deprecated.Builtin.ConnectPacket.AfterDeserialisation">
+ <inheritdoc />
</member>
- <member name="F:NetSharp.Connection.loggerLockObject">
- <summary>
- Lock synchronisation object for the <see cref="F:NetSharp.Connection.logger"/> variable.
- </summary>
+ <member name="M:NetSharp.Deprecated.Builtin.ConnectPacket.BeforeSerialisation">
+ <inheritdoc />
</member>
- <member name="F:NetSharp.Connection.outgoingPacketPipeline">
- <summary>
- Pipeline to convert outgoing <see cref="T:NetSharp.Packets.NetworkPacket"/> instances to a byte buffer for sending.
- </summary>
+ <member name="M:NetSharp.Deprecated.Builtin.ConnectPacket.Deserialise(System.ReadOnlyMemory{System.Byte})">
+ <inheritdoc />
</member>
- <member name="F:NetSharp.Connection.ServerShutdownToken">
- <summary>
- Cancellation token which allows observing the shutdown of the server. It is set when <see cref="M:NetSharp.Connection.ShutdownServer"/> is called.
- </summary>
+ <member name="M:NetSharp.Deprecated.Builtin.ConnectPacket.Serialise">
+ <inheritdoc />
</member>
- <member name="F:NetSharp.Connection.logger">
+ <member name="T:NetSharp.Deprecated.Builtin.ConnectResponsePacket">
<summary>
- A logger object allowing for writing debug messages to an output stream.
+ A response packet for the <see cref="T:NetSharp.Deprecated.Builtin.ConnectPacket"/>.
</summary>
</member>
- <member name="M:NetSharp.Connection.Finalize">
- <summary>
- Destroys a <see cref="T:NetSharp.Connection"/> class instance, freeing all managed resources.
- </summary>
+ <member name="P:NetSharp.Deprecated.Builtin.ConnectResponsePacket.RequestPacket">
+ <inheritdoc />
</member>
- <member name="M:NetSharp.Connection.RunServerAsync">
- <summary>
- Makes the connection listen for incoming request packets, and handle them according to registered packet handler delegates.
- This work can be cancelled by calling <see cref="M:NetSharp.Connection.ShutdownServer"/>.
- </summary>
- <returns>The task representing the connection work.</returns>
+ <member name="M:NetSharp.Deprecated.Builtin.ConnectResponsePacket.AfterDeserialisation">
+ <inheritdoc />
</member>
- <member name="M:NetSharp.Connection.ShutdownServer">
- <summary>
- Shuts down the connection, and releases managed and unmanaged resources.
- </summary>
+ <member name="M:NetSharp.Deprecated.Builtin.ConnectResponsePacket.BeforeSerialisation">
+ <inheritdoc />
</member>
- <member name="F:NetSharp.Connection.AnyRemoteEndPoint">
- <summary>
- Represents any remote endpoint for datagram operations.
- </summary>
+ <member name="M:NetSharp.Deprecated.Builtin.ConnectResponsePacket.Deserialise(System.ReadOnlyMemory{System.Byte})">
+ <inheritdoc />
</member>
- <member name="M:NetSharp.Connection.Dispose(System.Boolean)">
- <summary>
- Disposes of the managed and unmanaged resources held by this instance.
- </summary>
- <param name="disposing">Whether this method is called by <see cref="M:NetSharp.Connection.Dispose"/> or by the finaliser.</param>
+ <member name="M:NetSharp.Deprecated.Builtin.ConnectResponsePacket.Serialise">
+ <inheritdoc />
</member>
- <member name="M:NetSharp.Connection.DoAcceptAsync(System.Net.Sockets.Socket,System.Threading.CancellationToken)">
+ <member name="T:NetSharp.Deprecated.Builtin.DataPacket">
<summary>
- Provides an awaitable wrapper around an asynchronous socket accept operation.
+ A simple data transfer packet, that allows for the transmission of an arbitrary number of frames.
</summary>
- <param name="serverSocket">The socket which should be used to accept an incoming connection attempt.</param>
- <param name="cancellationToken">The cancellation token to observe for the operation.</param>
- <returns>The accepted socket.</returns>
</member>
- <member name="M:NetSharp.Connection.DoConnectAsync(System.Net.Sockets.Socket,System.Net.EndPoint,System.Threading.CancellationToken)">
+ <member name="F:NetSharp.Deprecated.Builtin.DataPacket.RequestBuffer">
<summary>
- Provides an awaitable wrapper around an asynchronous socket connect operation.
+ The data that should be transferred across the network.
</summary>
- <param name="socket">The socket which should asynchronously connect to the remote endpoint.</param>
- <param name="remoteEndPoint">The remote endpoint to which the socket should connect.</param>
- <param name="cancellationToken">The cancellation token to observe for the operation.</param>
</member>
- <member name="M:NetSharp.Connection.DoDisconnectAsync(System.Net.Sockets.Socket,System.Threading.CancellationToken)">
+ <member name="M:NetSharp.Deprecated.Builtin.DataPacket.#ctor">
<summary>
- Provides an awaitable wrapper around an asynchronous socket disconnect operation.
+ Initialises a new instance of the <see cref="T:NetSharp.Deprecated.Builtin.DataPacket"/> class.
</summary>
- <param name="connectedSocket">The socket which should asynchronously disconnect from its remote endpoint.</param>
- <param name="cancellationToken">The cancellation token to observe for the operation.</param>
</member>
- <member name="M:NetSharp.Connection.DoReceiveFromAsync(System.Net.Sockets.Socket,System.Net.EndPoint,System.Net.Sockets.SocketFlags,System.Memory{System.Byte},System.Threading.CancellationToken)">
+ <member name="M:NetSharp.Deprecated.Builtin.DataPacket.#ctor(System.Memory{System.Byte})">
<summary>
- Provides an awaitable wrapper around an asynchronous socket receive operation.
+ Initialises a new instance of the <see cref="T:NetSharp.Deprecated.Builtin.DataPacket"/> class.
</summary>
- <param name="listenerSocket">The socket which should receive data from the remote endpoint.</param>
- <param name="remoteEndPoint">The remove endpoint from which data should be received.</param>
- <param name="socketFlags">The socket flags associated with the receive operation.</param>
- <param name="inputBuffer">The memory buffer into which received data will be stored.</param>
- <param name="cancellationToken">The cancellation token to observe for the operation.</param>
- <returns>The result of the receive operation from the remote endpoint.</returns>
+ <param name="buffer">The data that this request packet should contain.</param>
</member>
- <member name="M:NetSharp.Connection.DoSendToAsync(System.Net.Sockets.Socket,System.Net.EndPoint,System.Net.Sockets.SocketFlags,System.Memory{System.Byte},System.Threading.CancellationToken)">
- <summary>
- Provides an awaitable wrapper around an asynchronous socket send operation.
- </summary>
- <param name="transmitterSocket">The socket which should send the data to the remote endpoint.</param>
- <param name="remoteEndPoint">The remote endpoint to which data should be written.</param>
- <param name="socketFlags">The socket flags associated with the send operation.</param>
- <param name="outputBuffer">The data buffer which should be sent.</param>
- <param name="cancellationToken">The cancellation token to observe for the operation.</param>
- <returns>The result of the send operation to the remote endpoint.</returns>
+ <member name="M:NetSharp.Deprecated.Builtin.DataPacket.AfterDeserialisation">
+ <inheritdoc />
</member>
- <member name="F:NetSharp.Connection.MaximumConnectionBacklog">
- <summary>
- The maximum number of stream connection that will be accepted.
- </summary>
- TODO change this to a configurable builder option
+ <member name="M:NetSharp.Deprecated.Builtin.DataPacket.BeforeSerialisation">
+ <inheritdoc />
</member>
- <member name="F:NetSharp.Connection.MaximumPacketBacklog">
- <summary>
- The maximum number of packets that will be stored before older packets start to be dropped.
- </summary>
- TODO change this to a configurable builder option
+ <member name="M:NetSharp.Deprecated.Builtin.DataPacket.Deserialise(System.ReadOnlyMemory{System.Byte})">
+ <inheritdoc />
</member>
- <member name="M:NetSharp.Connection.Dispose">
+ <member name="M:NetSharp.Deprecated.Builtin.DataPacket.Serialise">
<inheritdoc />
</member>
- <member name="M:NetSharp.Connection.SetLoggingStream(System.IO.Stream,NetSharp.Logging.LogLevel)">
+ <member name="T:NetSharp.Deprecated.Builtin.DataResponsePacket">
<summary>
- Configures the logger to log messages to the given stream (or to <see cref="F:System.IO.Stream.Null"/> if <c>null</c>) and
- to only log messages that are of severity <paramref name="minimumLoggedSeverity"/> or higher.
+ A response packet for the <see cref="T:NetSharp.Deprecated.Builtin.DataPacket"/>.
</summary>
- <param name="loggingStream">The stream to which messages will be logged.</param>
- <param name="minimumLoggedSeverity">The minimum severity a message must be to be logged.</param>
</member>
- <member name="M:NetSharp.Connection.TryBindAsync(System.Net.EndPoint,System.TimeSpan)">
+ <member name="F:NetSharp.Deprecated.Builtin.DataResponsePacket.ResponseBuffer">
<summary>
- Attempts to asynchronously bind the underlying socket to the given local endpoint. Does not block.
- If the timeout is exceeded the binding attempt is aborted and the method returns false.
+ The data that should be transferred across the network.
</summary>
- <param name="localEndPoint">The local endpoint to bind to.</param>
- <param name="timeout">The timeout within which to attempt the binding.</param>
- <returns>Whether the binding was successful or not.</returns>
</member>
- <member name="T:NetSharp.ConnectionBuilder">
+ <member name="M:NetSharp.Deprecated.Builtin.DataResponsePacket.#ctor">
<summary>
- Allows for configuring and subsequently building a <see cref="T:NetSharp.Connection"/> instance.
+ Initialises a new instance of the <see cref="T:NetSharp.Deprecated.Builtin.DataResponsePacket"/> class.
</summary>
</member>
- <member name="P:NetSharp.ConnectionBuilder.IncomingPacketPipelineStageCount">
+ <member name="M:NetSharp.Deprecated.Builtin.DataResponsePacket.#ctor(System.Memory{System.Byte})">
<summary>
- The number of stages in the currently configured incoming packet pipeline.
+ Initialises a new instance of the <see cref="T:NetSharp.Deprecated.Builtin.DataResponsePacket"/> class.
</summary>
+ <param name="buffer">The data that this response packet should contain.</param>
</member>
- <member name="P:NetSharp.ConnectionBuilder.OutgoingPacketPipelineStageCount">
- <summary>
- The number of stages in the currently configured outgoing packet pipeline.
- </summary>
+ <member name="P:NetSharp.Deprecated.Builtin.DataResponsePacket.RequestPacket">
+ <inheritdoc />
</member>
- <member name="M:NetSharp.ConnectionBuilder.Build">
- <summary>
- Returns a new <see cref="T:NetSharp.Connection"/> instance with the current configuration.
- </summary>
- <returns>The configured <see cref="T:NetSharp.Connection"/> instance.</returns>
+ <member name="M:NetSharp.Deprecated.Builtin.DataResponsePacket.AfterDeserialisation">
+ <inheritdoc />
</member>
- <member name="M:NetSharp.ConnectionBuilder.WithIncomingPipelineStage(System.Func{System.Memory{System.Byte},System.Memory{System.Byte}}@,System.Int32)">
- <summary>
- Adds an extra pipeline stage to the currently configured incoming packet pipeline, at the given index.
- </summary>
- <param name="transform">
- The transformation that should be applied when a packet passes through the pipeline.
- </param>
- <param name="index">The position in the pipeline at which to place the transform.</param>
- <returns>The builder instance for further configuration.</returns>
+ <member name="M:NetSharp.Deprecated.Builtin.DataResponsePacket.BeforeSerialisation">
+ <inheritdoc />
</member>
- <member name="M:NetSharp.ConnectionBuilder.WithLogging(NetSharp.ConnectionBuilder.LoggingSettings)">
- <summary>
- Sets the logging settings for the currently configured connection.
- </summary>
- <param name="settings">The logging settings to use.</param>
- <returns>The builder instance for further configuration.</returns>
+ <member name="M:NetSharp.Deprecated.Builtin.DataResponsePacket.Deserialise(System.ReadOnlyMemory{System.Byte})">
+ <inheritdoc />
</member>
- <member name="M:NetSharp.ConnectionBuilder.WithOutgoingPipelineStage(System.Func{System.Memory{System.Byte},System.Memory{System.Byte}}@,System.Int32)">
- <summary>
- Adds an extra pipeline stage to the currently configured outgoing packet pipeline, at the given index.
- </summary>
- <param name="transform">
- The transformation that should be applied when a packet passes through the pipeline.
- </param>
- <param name="index">The position in the pipeline at which to place the transform.</param>
- <returns>The builder instance for further configuration.</returns>
+ <member name="M:NetSharp.Deprecated.Builtin.DataResponsePacket.Serialise">
+ <inheritdoc />
</member>
- <member name="M:NetSharp.ConnectionBuilder.WithPooling(NetSharp.ConnectionBuilder.PoolingSettings)">
+ <member name="T:NetSharp.Deprecated.Builtin.DisconnectPacket">
<summary>
- Sets the pooling settings for the currently configured connection.
+ A simple disconnect packet for the UDP protocol.
</summary>
- <param name="settings">The pooling settings to use.</param>
- <returns>The builder instance for further configuration.</returns>
</member>
- <member name="T:NetSharp.ConnectionBuilder.LoggingSettings">
- <summary>
- Holds settings for configuring a connection's logging.
- </summary>
+ <member name="M:NetSharp.Deprecated.Builtin.DisconnectPacket.AfterDeserialisation">
+ <inheritdoc />
</member>
- <member name="F:NetSharp.ConnectionBuilder.LoggingSettings.LoggingStream">
- <summary>
- The stream to which messages will be logged.
- </summary>
+ <member name="M:NetSharp.Deprecated.Builtin.DisconnectPacket.BeforeSerialisation">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.Builtin.DisconnectPacket.Deserialise(System.ReadOnlyMemory{System.Byte})">
+ <inheritdoc />
</member>
- <member name="F:NetSharp.ConnectionBuilder.LoggingSettings.MinimumLevel">
+ <member name="M:NetSharp.Deprecated.Builtin.DisconnectPacket.Serialise">
+ <inheritdoc />
+ </member>
+ <member name="T:NetSharp.Deprecated.Builtin.PingPacket">
<summary>
- The minimum severity that a log message must have to be recorded.
+ A simple ping request packet for heartbeat monitoring and RTT measurement.
</summary>
</member>
- <member name="M:NetSharp.ConnectionBuilder.LoggingSettings.#ctor(System.IO.Stream,NetSharp.Logging.LogLevel)">
+ <member name="M:NetSharp.Deprecated.Builtin.PingPacket.AfterDeserialisation">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.Builtin.PingPacket.BeforeSerialisation">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.Builtin.PingPacket.Deserialise(System.ReadOnlyMemory{System.Byte})">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.Builtin.PingPacket.Serialise">
+ <inheritdoc />
+ </member>
+ <member name="T:NetSharp.Deprecated.Builtin.PingResponsePacket">
<summary>
- Initialises a new instance of the <see cref="F:NetSharp.ConnectionBuilder.LoggingSettings.LoggingStream"/> struct.
+ A response packet for the <see cref="T:NetSharp.Deprecated.Builtin.PingPacket"/>.
</summary>
- <param name="stream">The stream to which messages will be logged..</param>
- <param name="minimumLevel">The minimum severity that a log message must have to be recorded.</param>
</member>
- <member name="T:NetSharp.ConnectionBuilder.PoolingSettings">
+ <member name="P:NetSharp.Deprecated.Builtin.PingResponsePacket.RequestPacket">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.Builtin.PingResponsePacket.AfterDeserialisation">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.Builtin.PingResponsePacket.BeforeSerialisation">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.Builtin.PingResponsePacket.Deserialise(System.ReadOnlyMemory{System.Byte})">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.Builtin.PingResponsePacket.Serialise">
+ <inheritdoc />
+ </member>
+ <member name="T:NetSharp.Deprecated.Builtin.SimpleDataPacket">
<summary>
- Holds settings for configuring a connection's buffer pooling.
+ A simple one-time-use data transfer packet, that allows for the transmission of an arbitrary number of frames.
</summary>
</member>
- <member name="F:NetSharp.ConnectionBuilder.PoolingSettings.ObjectPoolSize">
+ <member name="F:NetSharp.Deprecated.Builtin.SimpleDataPacket.RequestBuffer">
<summary>
- The number of objects that will be held in the object pools.
+ The data that should be transferred across the network.
</summary>
</member>
- <member name="F:NetSharp.ConnectionBuilder.PoolingSettings.PreallocateBuffers">
+ <member name="M:NetSharp.Deprecated.Builtin.SimpleDataPacket.#ctor">
<summary>
- Whether the buffers for receiving messages should be preallocated.
+ Initialises a new instance of the <see cref="T:NetSharp.Deprecated.Builtin.SimpleDataPacket"/> class.
</summary>
</member>
- <member name="M:NetSharp.ConnectionBuilder.PoolingSettings.#ctor(System.Int32,System.Boolean)">
+ <member name="M:NetSharp.Deprecated.Builtin.SimpleDataPacket.#ctor(System.Memory{System.Byte})">
<summary>
- Initialises a new instance of the <see cref="T:NetSharp.ConnectionBuilder.PoolingSettings"/> struct.
+ Initialises a new instance of the <see cref="T:NetSharp.Deprecated.Builtin.SimpleDataPacket"/> class.
</summary>
- <param name="poolSize">The number of objects that will be held in the object pools.</param>
- <param name="preallocateBuffers">Whether the buffers for receiving messages should be preallocated.</param>
+ <param name="buffer">The data that this request packet should contain.</param>
+ </member>
+ <member name="M:NetSharp.Deprecated.Builtin.SimpleDataPacket.AfterDeserialisation">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.Builtin.SimpleDataPacket.BeforeSerialisation">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.Builtin.SimpleDataPacket.Deserialise(System.ReadOnlyMemory{System.Byte})">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.Builtin.SimpleDataPacket.Serialise">
+ <inheritdoc />
</member>
<member name="T:NetSharp.Deprecated.Client">
<summary>
@@ -510,1565 +466,1512 @@
<param name="remotePort">The remote port to connect over.</param>
<returns>Whether the connection was successful or not.</returns>
</member>
- <member name="T:NetSharp.Deprecated.DefaultSocketOptions">
+ <member name="T:NetSharp.Deprecated.Connection">
<summary>
- Allows for manipulation of socket options.
+ Encapsulates a connection capable of receiving packets and responding to them with registered packet handlers.
+ </summary>
+ <summary>
+ Implements low-level network access on top of which the rest of the connection is built upon.
</summary>
</member>
- <member name="M:NetSharp.Deprecated.DefaultSocketOptions.#ctor(System.Net.Sockets.Socket@)">
- <inheritdoc />
- </member>
- <member name="P:NetSharp.Deprecated.DefaultSocketOptions.HopLimit">
- <inheritdoc />
- <exception cref="T:System.NotSupportedException">
- This property is not supported when using the default socket option manager.
- </exception>
- </member>
- <member name="P:NetSharp.Deprecated.DefaultSocketOptions.IsRoutingEnabled">
- <inheritdoc />
- <exception cref="T:System.NotSupportedException">
- This property is not supported when using the default socket option manager.
- </exception>
- </member>
- <member name="P:NetSharp.Deprecated.DefaultSocketOptions.UseLoopback">
- <inheritdoc />
- <exception cref="T:System.NotSupportedException">
- This property is not supported when using the default socket option manager.
- </exception>
+ <member name="F:NetSharp.Deprecated.Connection.incomingPacketPipeline">
+ <summary>
+ Pipeline to convert incoming byte buffers to <see cref="T:NetSharp.Deprecated.NetworkPacket"/> instances.
+ </summary>
</member>
- <member name="T:NetSharp.Deprecated.IClient">
+ <member name="F:NetSharp.Deprecated.Connection.loggerLockObject">
<summary>
- Describes a client capable of asynchronous communication with an <see cref="T:NetSharp.Deprecated.IServer"/> connection.
+ Lock synchronisation object for the <see cref="F:NetSharp.Deprecated.Connection.logger"/> variable.
</summary>
</member>
- <member name="E:NetSharp.Deprecated.IClient.Connected">
+ <member name="F:NetSharp.Deprecated.Connection.outgoingPacketPipeline">
<summary>
- Signifies that a connection with the remote endpoint has been made.
+ Pipeline to convert outgoing <see cref="T:NetSharp.Deprecated.NetworkPacket"/> instances to a byte buffer for sending.
</summary>
</member>
- <member name="E:NetSharp.Deprecated.IClient.Disconnected">
+ <member name="F:NetSharp.Deprecated.Connection.ServerShutdownToken">
<summary>
- Signifies that the connection with the remote endpoint was severed.
+ Cancellation token which allows observing the shutdown of the server. It is set when <see cref="M:NetSharp.Deprecated.Connection.ShutdownServer"/> is called.
</summary>
</member>
- <member name="M:NetSharp.Deprecated.IClient.SendBytesAsync(System.Byte[],System.TimeSpan)">
+ <member name="F:NetSharp.Deprecated.Connection.logger">
<summary>
- Sends the given byte buffer to the connected remote endpoint asynchronously. Does not block, and observes
- a timeout of the given length.
- timeout.
+ A logger object allowing for writing debug messages to an output stream.
</summary>
- <param name="buffer">The bytes that should be sent to the connected remote endpoint.</param>
- <param name="timeout">The timeout after which to cancel the transmission attempt.</param>
- <returns>Whether the transmission attempt was successful.</returns>
</member>
- <member name="M:NetSharp.Deprecated.IClient.SendBytesWithResponseAsync(System.Byte[],System.TimeSpan)">
+ <member name="M:NetSharp.Deprecated.Connection.Finalize">
<summary>
- Sends the given byte buffer to the connected remote endpoint and waits for the response asynchronously.
- Does not block, and observes a timeout of the given length.
- timeout.
+ Destroys a <see cref="T:NetSharp.Deprecated.Connection"/> class instance, freeing all managed resources.
</summary>
- <param name="buffer">The bytes that should be sent to the connected remote endpoint.</param>
- <param name="timeout">
- The timeout after which to cancel the transmission attempt. This timeout is reused by both the 'send' and
- 'receive' parts of the transmission attempt, such that the maximum timeout is equal to 2 times the given
- value.
- </param>
- <returns>The byte buffer received as a response to the sent buffer.</returns>
</member>
- <member name="M:NetSharp.Deprecated.IClient.SendComplexAsync``2(``0,System.TimeSpan)">
+ <member name="M:NetSharp.Deprecated.Connection.RunServerAsync">
<summary>
- Sends the given request and listens for a response of the given type asynchronously. Does not block.
- Cancels the operation if the given timeout is exceeded
+ Makes the connection listen for incoming request packets, and handle them according to registered packet handler delegates.
+ This work can be cancelled by calling <see cref="M:NetSharp.Deprecated.Connection.ShutdownServer"/>.
</summary>
- <typeparam name="Req">The type of request packet to send.</typeparam>
- <typeparam name="Rep">The type of response packet to receive.</typeparam>
- <param name="request">The request packet to send.</param>
- <param name="timeout">The timeout for which to wait for the operation to complete.</param>
- <returns>The received instance.</returns>
+ <returns>The task representing the connection work.</returns>
</member>
- <member name="M:NetSharp.Deprecated.IClient.SendSimpleAsync``1(``0,System.TimeSpan)">
+ <member name="M:NetSharp.Deprecated.Connection.ShutdownServer">
<summary>
- Sends the given request asynchronously without listening for a response, not blocking until it is sent.
- Cancels the operation if the given timeout is exceeded.
+ Shuts down the connection, and releases managed and unmanaged resources.
</summary>
- <typeparam name="Req">The type of request packet to send.</typeparam>
- <param name="request">The request packet to send.</param>
- <param name="timeout">The timeout for which to wait for the operation to complete.</param>
- <returns>Whether the transmission attempt was successful.</returns>
</member>
- <member name="M:NetSharp.Deprecated.IClient.TryBindAsync(System.Net.IPAddress,System.Nullable{System.Int32},System.TimeSpan)">
+ <member name="F:NetSharp.Deprecated.Connection.AnyRemoteEndPoint">
<summary>
- Attempts to asynchronously bind the underlying socket to the given local address and port. Does not block.
- If the timeout is exceeded the binding attempt is aborted and the method returns false.
+ Represents any remote endpoint for datagram operations.
</summary>
- <param name="localAddress">The local IP address to bind to. Null if any IP address will suffice.</param>
- <param name="localPort">The local port to bind to. Null if any port will suffice.</param>
- <param name="timeout">The timeout within which to attempt the binding.</param>
- <returns>Whether the binding was successful or not.</returns>
</member>
- <member name="M:NetSharp.Deprecated.IClient.TryConnectAsync(System.Net.IPAddress,System.Int32,System.TimeSpan)">
+ <member name="M:NetSharp.Deprecated.Connection.Dispose(System.Boolean)">
<summary>
- Attempts to connect asynchronously to the remote <see cref="T:NetSharp.Deprecated.Server"/> at the given <see cref="T:System.Net.IPAddress"/>
- and over the given port. If the timeout is exceeded the connection attempt is aborted and the method returns false.
- </summary>
- <param name="remoteAddress">The remote IP address to connect to.</param>
- <param name="remotePort">The remote port to connect over.</param>
- <param name="timeout">The timeout within which to attempt the connection.</param>
- <returns>Whether the connection was successful or not.</returns>
- </member>
- <member name="T:NetSharp.Deprecated.INetworkSerialisable">
- <summary>
- Describes an object that can be serialised to be sent across the network.
- </summary>
- </member>
- <member name="M:NetSharp.Deprecated.INetworkSerialisable.Deserialise(System.ReadOnlyMemory{System.Byte})">
- <summary>
- Deserialises the object instance from a byte array.
- </summary>
- <param name="serialisedObject">The memory containing the serialised object instance.</param>
- </member>
- <member name="M:NetSharp.Deprecated.INetworkSerialisable.Serialise">
- <summary>
- Serialises the object instance into a byte array.
+ Disposes of the managed and unmanaged resources held by this instance.
</summary>
- <returns>The memory containing the serialised object instance.</returns>
+ <param name="disposing">Whether this method is called by <see cref="M:NetSharp.Deprecated.Connection.Dispose"/> or by the finaliser.</param>
</member>
- <member name="T:NetSharp.Deprecated.IPacket">
+ <member name="M:NetSharp.Deprecated.Connection.DoAcceptAsync(System.Net.Sockets.Socket,System.Threading.CancellationToken)">
<summary>
- Describes the methods and properties that every packet
+ Provides an awaitable wrapper around an asynchronous socket accept operation.
</summary>
+ <param name="serverSocket">The socket which should be used to accept an incoming connection attempt.</param>
+ <param name="cancellationToken">The cancellation token to observe for the operation.</param>
+ <returns>The accepted socket.</returns>
</member>
- <member name="M:NetSharp.Deprecated.IPacket.AfterDeserialisation">
+ <member name="M:NetSharp.Deprecated.Connection.DoConnectAsync(System.Net.Sockets.Socket,System.Net.EndPoint,System.Threading.CancellationToken)">
<summary>
- Allows for custom fields to be converted from their serialised format, after being received from the network.
+ Provides an awaitable wrapper around an asynchronous socket connect operation.
</summary>
+ <param name="socket">The socket which should asynchronously connect to the remote endpoint.</param>
+ <param name="remoteEndPoint">The remote endpoint to which the socket should connect.</param>
+ <param name="cancellationToken">The cancellation token to observe for the operation.</param>
</member>
- <member name="M:NetSharp.Deprecated.IPacket.BeforeSerialisation">
+ <member name="M:NetSharp.Deprecated.Connection.DoDisconnectAsync(System.Net.Sockets.Socket,System.Threading.CancellationToken)">
<summary>
- Allows for custom fields to be converted into another format prior to being sent via the network.
+ Provides an awaitable wrapper around an asynchronous socket disconnect operation.
</summary>
+ <param name="connectedSocket">The socket which should asynchronously disconnect from its remote endpoint.</param>
+ <param name="cancellationToken">The cancellation token to observe for the operation.</param>
</member>
- <member name="T:NetSharp.Deprecated.IPacketHandler">
+ <member name="M:NetSharp.Deprecated.Connection.DoReceiveFromAsync(System.Net.Sockets.Socket,System.Net.EndPoint,System.Net.Sockets.SocketFlags,System.Memory{System.Byte},System.Threading.CancellationToken)">
<summary>
- Describes a class capable of registering and deregistering packet handlers, and capable of
- handling incoming packets according to the currently registered packet handlers.
+ Provides an awaitable wrapper around an asynchronous socket receive operation.
</summary>
+ <param name="listenerSocket">The socket which should receive data from the remote endpoint.</param>
+ <param name="remoteEndPoint">The remove endpoint from which data should be received.</param>
+ <param name="socketFlags">The socket flags associated with the receive operation.</param>
+ <param name="inputBuffer">The memory buffer into which received data will be stored.</param>
+ <param name="cancellationToken">The cancellation token to observe for the operation.</param>
+ <returns>The result of the receive operation from the remote endpoint.</returns>
</member>
- <member name="M:NetSharp.Deprecated.IPacketHandler.TryDeregisterComplexPacketHandler``2(NetSharp.Deprecated.ComplexPacketHandler{``0,``1}@)">
+ <member name="M:NetSharp.Deprecated.Connection.DoSendToAsync(System.Net.Sockets.Socket,System.Net.EndPoint,System.Net.Sockets.SocketFlags,System.Memory{System.Byte},System.Threading.CancellationToken)">
<summary>
- Attempts to deregister the complex packet handler delegate for all packets of the given type. If a handler
- method doesn't exist for the given packet type, <paramref name="oldHandlerDelegate"/> will be <c>default</c>.
+ Provides an awaitable wrapper around an asynchronous socket send operation.
</summary>
- <typeparam name="Req">The type of request packet for which to deregister the handler delegate.</typeparam>
- <typeparam name="Rep">The type of response packet that is generated by the delegate method.</typeparam>
- <param name="oldHandlerDelegate">The old handler delegate method that was previously registered.</param>
- <returns>Whether the packet handler delegate was successfully deregistered.</returns>
+ <param name="transmitterSocket">The socket which should send the data to the remote endpoint.</param>
+ <param name="remoteEndPoint">The remote endpoint to which data should be written.</param>
+ <param name="socketFlags">The socket flags associated with the send operation.</param>
+ <param name="outputBuffer">The data buffer which should be sent.</param>
+ <param name="cancellationToken">The cancellation token to observe for the operation.</param>
+ <returns>The result of the send operation to the remote endpoint.</returns>
</member>
- <member name="M:NetSharp.Deprecated.IPacketHandler.TryDeregisterSimplePacketHandler``1(NetSharp.Deprecated.SimplePacketHandler{``0}@)">
+ <member name="F:NetSharp.Deprecated.Connection.MaximumConnectionBacklog">
<summary>
- Attempts to deregister the simple packet handler delegate for all packets of the given type. If a handler
- method doesn't exist for the given packet type, <paramref name="oldHandlerDelegate"/> will be <c>default</c>.
+ The maximum number of stream connection that will be accepted.
</summary>
- <typeparam name="Req">The type of request packet for which to deregister the handler delegate.</typeparam>
- <param name="oldHandlerDelegate">The old handler delegate method that was previously registered.</param>
- <returns>Whether the packet handler delegate was successfully deregistered.</returns>
+ TODO change this to a configurable builder option
</member>
- <member name="M:NetSharp.Deprecated.IPacketHandler.TryRegisterComplexPacketHandler``2(NetSharp.Deprecated.ComplexPacketHandler{``0,``1})">
+ <member name="F:NetSharp.Deprecated.Connection.MaximumPacketBacklog">
<summary>
- Attempts to register a complex packet handler delegate for all packets of the given type. If a handler
- method already exists for the given packet type, it will be updated and replaced with the given one.
+ The maximum number of packets that will be stored before older packets start to be dropped.
</summary>
- <typeparam name="Req">The type of request packet for which to register the handler delegate.</typeparam>
- <typeparam name="Rep">The type of response packet that is generated by the delegate method.</typeparam>
- <param name="handlerDelegate">The delegate method to register as the complex packet handler.</param>
- <returns>Whether the packet handler delegate was successfully registered.</returns>
+ TODO change this to a configurable builder option
</member>
- <member name="M:NetSharp.Deprecated.IPacketHandler.TryRegisterSimplePacketHandler``1(NetSharp.Deprecated.SimplePacketHandler{``0})">
- <summary>
- Attempts to register a simple packet handler delegate for all packets of the given type. If a handler
- method already exists for the given packet type, it will be updated and replaced with the given one.
- </summary>
- <typeparam name="Req">The type of request packet for which to register the handler delegate.</typeparam>
- <param name="handlerDelegate">The delegate method to register as the simple packet handler.</param>
- <returns>Whether the packet handler delegate was successfully registered.</returns>
+ <member name="M:NetSharp.Deprecated.Connection.Dispose">
+ <inheritdoc />
</member>
- <member name="T:NetSharp.Deprecated.IRequestPacket">
+ <member name="M:NetSharp.Deprecated.Connection.SetLoggingStream(System.IO.Stream,NetSharp.Deprecated.LogLevel)">
<summary>
- Describes a request packet.
+ Configures the logger to log messages to the given stream (or to <see cref="F:System.IO.Stream.Null"/> if <c>null</c>) and
+ to only log messages that are of severity <paramref name="minimumLoggedSeverity"/> or higher.
</summary>
+ <param name="loggingStream">The stream to which messages will be logged.</param>
+ <param name="minimumLoggedSeverity">The minimum severity a message must be to be logged.</param>
</member>
- <member name="T:NetSharp.Deprecated.IResponsePacket`1">
+ <member name="M:NetSharp.Deprecated.Connection.TryBindAsync(System.Net.EndPoint,System.TimeSpan)">
<summary>
- Describes a response packet to a request packet.
+ Attempts to asynchronously bind the underlying socket to the given local endpoint. Does not block.
+ If the timeout is exceeded the binding attempt is aborted and the method returns false.
</summary>
- <typeparam name="TReq">The request packet that this type is a response to.</typeparam>
+ <param name="localEndPoint">The local endpoint to bind to.</param>
+ <param name="timeout">The timeout within which to attempt the binding.</param>
+ <returns>Whether the binding was successful or not.</returns>
</member>
- <member name="P:NetSharp.Deprecated.IResponsePacket`1.RequestPacket">
+ <member name="T:NetSharp.Deprecated.ConnectionBuilder">
<summary>
- The request packet that was handled with this response packet.
+ Allows for configuring and subsequently building a <see cref="T:NetSharp.Deprecated.Connection"/> instance.
</summary>
</member>
- <member name="T:NetSharp.Deprecated.IServer">
+ <member name="P:NetSharp.Deprecated.ConnectionBuilder.IncomingPacketPipelineStageCount">
<summary>
- Describes a server capable of asynchronously handling multiple <see cref="T:NetSharp.Deprecated.IClient"/> connections at once.
+ The number of stages in the currently configured incoming packet pipeline.
</summary>
</member>
- <member name="E:NetSharp.Deprecated.IServer.ClientConnected">
+ <member name="P:NetSharp.Deprecated.ConnectionBuilder.OutgoingPacketPipelineStageCount">
<summary>
- Signifies that a connection with a remote endpoint has been made.
- </summary>
- </member>
- <member name="E:NetSharp.Deprecated.IServer.ClientDisconnected">
- <summary>
- Signifies that a connection with a remote endpoint has been lost.
+ The number of stages in the currently configured outgoing packet pipeline.
</summary>
</member>
- <member name="E:NetSharp.Deprecated.IServer.ServerStarted">
+ <member name="M:NetSharp.Deprecated.ConnectionBuilder.Build">
<summary>
- Signifies that the server was started and clients will start being accepted.
+ Returns a new <see cref="T:NetSharp.Deprecated.Connection"/> instance with the current configuration.
</summary>
+ <returns>The configured <see cref="T:NetSharp.Deprecated.Connection"/> instance.</returns>
</member>
- <member name="E:NetSharp.Deprecated.IServer.ServerStopped">
+ <member name="M:NetSharp.Deprecated.ConnectionBuilder.WithIncomingPipelineStage(System.Func{System.Memory{System.Byte},System.Memory{System.Byte}}@,System.Int32)">
<summary>
- Signifies that the server was stopped and clients will stop being accepted.
+ Adds an extra pipeline stage to the currently configured incoming packet pipeline, at the given index.
</summary>
+ <param name="transform">
+ The transformation that should be applied when a packet passes through the pipeline.
+ </param>
+ <param name="index">The position in the pipeline at which to place the transform.</param>
+ <returns>The builder instance for further configuration.</returns>
</member>
- <member name="M:NetSharp.Deprecated.IServer.RunAsync(System.Net.EndPoint)">
+ <member name="M:NetSharp.Deprecated.ConnectionBuilder.WithLogging(NetSharp.Deprecated.ConnectionBuilder.LoggingSettings)">
<summary>
- Starts the server asynchronously and starts accepting client connections. Does not block.
+ Sets the logging settings for the currently configured connection.
</summary>
- <param name="localEndPoint">The local endpoint to bind to.</param>
+ <param name="settings">The logging settings to use.</param>
+ <returns>The builder instance for further configuration.</returns>
</member>
- <member name="M:NetSharp.Deprecated.IServer.Shutdown">
+ <member name="M:NetSharp.Deprecated.ConnectionBuilder.WithOutgoingPipelineStage(System.Func{System.Memory{System.Byte},System.Memory{System.Byte}}@,System.Int32)">
<summary>
- Shuts down the server.
+ Adds an extra pipeline stage to the currently configured outgoing packet pipeline, at the given index.
</summary>
+ <param name="transform">
+ The transformation that should be applied when a packet passes through the pipeline.
+ </param>
+ <param name="index">The position in the pipeline at which to place the transform.</param>
+ <returns>The builder instance for further configuration.</returns>
</member>
- <member name="M:NetSharp.Deprecated.SerialisedPacket.From``1(``0)">
+ <member name="M:NetSharp.Deprecated.ConnectionBuilder.WithPooling(NetSharp.Deprecated.ConnectionBuilder.PoolingSettings)">
<summary>
- Serialises the given serialisable packet instance and returns the <see cref="T:NetSharp.Deprecated.SerialisedPacket"/> instance
- that was generated. This method invokes <see cref="M:NetSharp.Deprecated.IPacket.BeforeSerialisation"/>.
+ Sets the pooling settings for the currently configured connection.
</summary>
- <typeparam name="T">The packet type that will be serialised.</typeparam>
- <param name="serialisable">The packet instance that should be serialised.</param>
- <returns>The serialised instance.</returns>
+ <param name="settings">The pooling settings to use.</param>
+ <returns>The builder instance for further configuration.</returns>
</member>
- <member name="M:NetSharp.Deprecated.SerialisedPacket.To``1(NetSharp.Deprecated.SerialisedPacket@)">
+ <member name="T:NetSharp.Deprecated.ConnectionBuilder.LoggingSettings">
<summary>
- Deserialises and returns a packet instance of the given type from the <see cref="T:NetSharp.Deprecated.SerialisedPacket"/> instance
- that was given. This method invokes <see cref="M:NetSharp.Deprecated.IPacket.AfterDeserialisation"/>.
+ Holds settings for configuring a connection's logging.
</summary>
- <typeparam name="T">The packet type to which the packet should be deserialised.</typeparam>
- <param name="instance">The serialised packet instance that should be deserialised.</param>
- <returns>The deserialised instance.</returns>
</member>
- <member name="T:NetSharp.Deprecated.ComplexPacketHandler`2">
+ <member name="F:NetSharp.Deprecated.ConnectionBuilder.LoggingSettings.LoggingStream">
<summary>
- Represents a method that receives a request packet of the given type (<typeparamref name="TReq"/>) and
- handles the request, returning a response packet of the given type (<typeparamref name="TRep"/>).
+ The stream to which messages will be logged.
</summary>
- <typeparam name="TReq">The type of request packet handled by this delegate method.</typeparam>
- <typeparam name="TRep">The type of response packet returned by this delegate method.</typeparam>
- <param name="requestPacket">The request packet that should be handled by this delegate method.</param>
- <param name="remoteEndPoint">The remote endpoint from which the request originated.</param>
- <returns>The response packet to send back to the remote endpoint from which the request originated.</returns>
</member>
- <member name="T:NetSharp.Deprecated.SimplePacketHandler`1">
+ <member name="F:NetSharp.Deprecated.ConnectionBuilder.LoggingSettings.MinimumLevel">
<summary>
- Represents a method that receives a simple request packet of the given type (<typeparamref name="TReq"/>) and
- handles the request, not returning any response packets.
+ The minimum severity that a log message must have to be recorded.
</summary>
- <typeparam name="TReq">The type of request packet handled by this delegate method.</typeparam>
- <param name="requestPacket">The request packet that should be handled by this delegate method.</param>
- <param name="remoteEndPoint">The remote endpoint from which the request originated.</param>
</member>
- <member name="T:NetSharp.Deprecated.Server">
+ <member name="M:NetSharp.Deprecated.ConnectionBuilder.LoggingSettings.#ctor(System.IO.Stream,NetSharp.Deprecated.LogLevel)">
<summary>
- Provides methods for handling connected <see cref="T:NetSharp.Deprecated.IClient"/> instances.
+ Initialises a new instance of the <see cref="F:NetSharp.Deprecated.ConnectionBuilder.LoggingSettings.LoggingStream"/> struct.
</summary>
+ <param name="stream">The stream to which messages will be logged..</param>
+ <param name="minimumLevel">The minimum severity that a log message must have to be recorded.</param>
</member>
- <member name="F:NetSharp.Deprecated.Server.complexPacketHandlers">
+ <member name="T:NetSharp.Deprecated.ConnectionBuilder.PoolingSettings">
<summary>
- Maps a packet type id to the complex packet handler for that packet type.
+ Holds settings for configuring a connection's buffer pooling.
</summary>
</member>
- <member name="F:NetSharp.Deprecated.Server.requestPacketDeserialisers">
+ <member name="F:NetSharp.Deprecated.ConnectionBuilder.PoolingSettings.ObjectPoolSize">
<summary>
- Maps a packet type id to the raw packet deserialiser that deserialises raw packets to
- <see cref="T:NetSharp.Deprecated.IRequestPacket"/> implementors.
+ The number of objects that will be held in the object pools.
</summary>
</member>
- <member name="F:NetSharp.Deprecated.Server.serverShutdownCancellationTokenSource">
+ <member name="F:NetSharp.Deprecated.ConnectionBuilder.PoolingSettings.PreallocateBuffers">
<summary>
- Cancellation token source to stop handling client sockets when the server should be shut down.
+ Whether the buffers for receiving messages should be preallocated.
</summary>
</member>
- <member name="F:NetSharp.Deprecated.Server.simplePacketHandlers">
+ <member name="M:NetSharp.Deprecated.ConnectionBuilder.PoolingSettings.#ctor(System.Int32,System.Boolean)">
<summary>
- Maps a packet type id to the simple packet handler for that packet type.
+ Initialises a new instance of the <see cref="T:NetSharp.Deprecated.ConnectionBuilder.PoolingSettings"/> struct.
</summary>
+ <param name="poolSize">The number of objects that will be held in the object pools.</param>
+ <param name="preallocateBuffers">Whether the buffers for receiving messages should be preallocated.</param>
</member>
- <member name="M:NetSharp.Deprecated.Server.#ctor">
+ <member name="T:NetSharp.Deprecated.ConnectionBuilderExtensions">
<summary>
- Initialises a new instance of the <see cref="T:NetSharp.Deprecated.Server"/> class.
+ Provides additional methods and functionality to the <see cref="T:NetSharp.Deprecated.ConnectionBuilder"/> class.
</summary>
</member>
- <member name="M:NetSharp.Deprecated.Server.Finalize">
+ <member name="T:NetSharp.Deprecated.ConnectionExtensions">
<summary>
- Destroys an instance of the <see cref="T:NetSharp.Deprecated.Server"/> class.
+ Provides additional methods and functionality to the <see cref="T:NetSharp.Deprecated.Connection"/> class.
</summary>
</member>
- <member name="T:NetSharp.Deprecated.Server.RawRequestPacketDeserialiser">
+ <member name="M:NetSharp.Deprecated.ConnectionExtensions.TryBind(NetSharp.Deprecated.Connection,System.Net.EndPoint,System.TimeSpan)">
<summary>
- Represents a method that receives a raw packet, and deserialises it into an <see cref="T:NetSharp.Deprecated.IRequestPacket"/> implementor.
+ Attempts to synchronously bind the underlying socket to the given local endpoint. Blocks.
+ If the timeout is exceeded the binding attempt is aborted and the method returns false.
</summary>
- <param name="rawPacket">The raw packet that was received from the network.</param>
- <returns>The deserialised instance of the packet.</returns>
+ <param name="localEndPoint">The local endpoint to bind to.</param>
+ <param name="timeout">The timeout within which to attempt the binding.</param>
+ <returns>Whether the binding was successful or not.</returns>
</member>
- <member name="M:NetSharp.Deprecated.Server.RegisterInternalPacketHandlers">
+ <member name="T:NetSharp.Deprecated.Constants">
<summary>
- Registers packet handlers for every internal library packet.
+ Holds internal default configurations and constants.
</summary>
</member>
- <member name="F:NetSharp.Deprecated.Server.PendingConnectionBacklog">
+ <member name="F:NetSharp.Deprecated.Constants.DefaultPort">
<summary>
- The maximum number of connections that are allowed in the connection backlog.
+ The default port over which a connection is made.
</summary>
</member>
- <member name="F:NetSharp.Deprecated.Server.DefaultNetworkOperationTimeout">
+ <member name="T:NetSharp.Deprecated.DefaultSocketOptions">
<summary>
- The default timeout value for all network operations.
+ Allows for manipulation of socket options.
</summary>
</member>
- <member name="F:NetSharp.Deprecated.Server.serverShutdownCancellationToken">
- <summary>
- The cancellation token that will be set when the server must be shut down.
- </summary>
+ <member name="M:NetSharp.Deprecated.DefaultSocketOptions.#ctor(System.Net.Sockets.Socket@)">
+ <inheritdoc />
</member>
- <member name="F:NetSharp.Deprecated.Server.socket">
- <summary>
- The <see cref="T:System.Net.Sockets.Socket"/> underlying the connection.
- </summary>
+ <member name="P:NetSharp.Deprecated.DefaultSocketOptions.HopLimit">
+ <inheritdoc />
+ <exception cref="T:System.NotSupportedException">
+ This property is not supported when using the default socket option manager.
+ </exception>
</member>
- <member name="F:NetSharp.Deprecated.Server.socketOptions">
- <summary>
- Backing field for the <see cref="P:NetSharp.Deprecated.Server.SocketOptions"/> property.
- </summary>
+ <member name="P:NetSharp.Deprecated.DefaultSocketOptions.IsRoutingEnabled">
+ <inheritdoc />
+ <exception cref="T:System.NotSupportedException">
+ This property is not supported when using the default socket option manager.
+ </exception>
</member>
- <member name="F:NetSharp.Deprecated.Server.runServer">
- <summary>
- Whether the server should be ran.
- </summary>
+ <member name="P:NetSharp.Deprecated.DefaultSocketOptions.UseLoopback">
+ <inheritdoc />
+ <exception cref="T:System.NotSupportedException">
+ This property is not supported when using the default socket option manager.
+ </exception>
</member>
- <member name="M:NetSharp.Deprecated.Server.#ctor(System.Net.Sockets.SocketType,System.Net.Sockets.ProtocolType)">
+ <member name="T:NetSharp.Deprecated.IClient">
<summary>
- Initialises a new instance of the <see cref="T:NetSharp.Deprecated.Server"/> class.
+ Describes a client capable of asynchronous communication with an <see cref="T:NetSharp.Deprecated.IServer"/> connection.
</summary>
- <param name="socketType">The socket type for the underlying socket.</param>
- <param name="protocolType">The protocol type for the underlying socket.</param>
- <param name="socketManager">The <see cref="!:Utils.Socket_Options.SocketOptions"/> implementation to use.</param>
</member>
- <member name="M:NetSharp.Deprecated.Server.#ctor(System.Net.Sockets.SocketType,System.Net.Sockets.ProtocolType,System.TimeSpan)">
+ <member name="E:NetSharp.Deprecated.IClient.Connected">
<summary>
- Initialises a new instance of the <see cref="T:NetSharp.Deprecated.Server"/> class.
+ Signifies that a connection with the remote endpoint has been made.
</summary>
- <param name="socketType">The socket type for the underlying socket.</param>
- <param name="protocolType">The protocol type for the underlying socket.</param>
- <param name="socketManager">The <see cref="!:Utils.Socket_Options.SocketOptions"/> manager to use.</param>
- <param name="networkOperationTimeout">The timeout value for send and receive operations over the network.</param>
</member>
- <member name="M:NetSharp.Deprecated.Server.DeserialiseRequestPacket(System.UInt32,NetSharp.Deprecated.SerialisedPacket@)">
+ <member name="E:NetSharp.Deprecated.IClient.Disconnected">
<summary>
- Deserialises the given <see cref="T:NetSharp.Packets.NetworkPacket"/> struct into an <see cref="T:NetSharp.Deprecated.IRequestPacket"/> implementor.
+ Signifies that the connection with the remote endpoint was severed.
</summary>
- <param name="packetType">The type id of packet that we should deserialise to.</param>
- <param name="rawRequestPacket">The packet that should be deserialised.</param>
- <returns>The deserialised packet instance, cast to the <see cref="T:NetSharp.Deprecated.IRequestPacket"/> interface.</returns>
</member>
- <member name="M:NetSharp.Deprecated.Server.Dispose(System.Boolean)">
+ <member name="M:NetSharp.Deprecated.IClient.SendBytesAsync(System.Byte[],System.TimeSpan)">
<summary>
- Disposes of this <see cref="T:NetSharp.Deprecated.Server"/> instance.
+ Sends the given byte buffer to the connected remote endpoint asynchronously. Does not block, and observes
+ a timeout of the given length.
+ timeout.
</summary>
- <param name="disposing">Whether this instance is being disposed.</param>
+ <param name="buffer">The bytes that should be sent to the connected remote endpoint.</param>
+ <param name="timeout">The timeout after which to cancel the transmission attempt.</param>
+ <returns>Whether the transmission attempt was successful.</returns>
</member>
- <member name="M:NetSharp.Deprecated.Server.DoHandleClientAsync(System.Object)">
+ <member name="M:NetSharp.Deprecated.IClient.SendBytesWithResponseAsync(System.Byte[],System.TimeSpan)">
<summary>
- Provides a task that represents the handling of a client. Calls the abstract <see cref="M:NetSharp.Deprecated.Server.HandleClientAsync(NetSharp.Deprecated.Server.ClientHandlerArgs,System.Threading.CancellationToken)"/> method.
+ Sends the given byte buffer to the connected remote endpoint and waits for the response asynchronously.
+ Does not block, and observes a timeout of the given length.
+ timeout.
</summary>
- <param name="clientHandlerArgsObj">The object representing the passed <see cref="T:NetSharp.Deprecated.Server.ClientHandlerArgs"/> instance.</param>
+ <param name="buffer">The bytes that should be sent to the connected remote endpoint.</param>
+ <param name="timeout">
+ The timeout after which to cancel the transmission attempt. This timeout is reused by both the 'send' and
+ 'receive' parts of the transmission attempt, such that the maximum timeout is equal to 2 times the given
+ value.
+ </param>
+ <returns>The byte buffer received as a response to the sent buffer.</returns>
</member>
- <member name="M:NetSharp.Deprecated.Server.HandleClientAsync(NetSharp.Deprecated.Server.ClientHandlerArgs,System.Threading.CancellationToken)">
+ <member name="M:NetSharp.Deprecated.IClient.SendComplexAsync``2(``0,System.TimeSpan)">
<summary>
- Handles a client asynchronously.
+ Sends the given request and listens for a response of the given type asynchronously. Does not block.
+ Cancels the operation if the given timeout is exceeded
</summary>
- <param name="args">The client handler arguments that should be passed to the client handler.</param>
- <param name="cancellationToken">Cancellation token set when the server is shutting down.</param>
+ <typeparam name="Req">The type of request packet to send.</typeparam>
+ <typeparam name="Rep">The type of response packet to receive.</typeparam>
+ <param name="request">The request packet to send.</param>
+ <param name="timeout">The timeout for which to wait for the operation to complete.</param>
+ <returns>The received instance.</returns>
</member>
- <member name="M:NetSharp.Deprecated.Server.HandleRequestPacket(System.UInt32,NetSharp.Deprecated.IRequestPacket@,System.Net.EndPoint@)">
+ <member name="M:NetSharp.Deprecated.IClient.SendSimpleAsync``1(``0,System.TimeSpan)">
<summary>
- Handles the given request packet with a registered packet handler. In this case, a complex packet handler
- will override any registered simple packet handlers.
+ Sends the given request asynchronously without listening for a response, not blocking until it is sent.
+ Cancels the operation if the given timeout is exceeded.
</summary>
- <param name="packetType">The type id of the packet that we should handle.</param>
- <param name="requestPacket">The packet instance that should be handled.</param>
- <param name="remoteEndPoint">The remote endpoint from which the request packet originated.</param>
- <returns>The response packet that should be sent back to the remote endpoint.</returns>
+ <typeparam name="Req">The type of request packet to send.</typeparam>
+ <param name="request">The request packet to send.</param>
+ <param name="timeout">The timeout for which to wait for the operation to complete.</param>
+ <returns>Whether the transmission attempt was successful.</returns>
</member>
- <member name="M:NetSharp.Deprecated.Server.OnClientConnected(System.Net.EndPoint)">
+ <member name="M:NetSharp.Deprecated.IClient.TryBindAsync(System.Net.IPAddress,System.Nullable{System.Int32},System.TimeSpan)">
<summary>
- Invokes the <see cref="E:NetSharp.Deprecated.Server.ClientConnected"/> event.
+ Attempts to asynchronously bind the underlying socket to the given local address and port. Does not block.
+ If the timeout is exceeded the binding attempt is aborted and the method returns false.
</summary>
- <param name="remoteEndPoint">The remote endpoint with which a connection was made.</param>
+ <param name="localAddress">The local IP address to bind to. Null if any IP address will suffice.</param>
+ <param name="localPort">The local port to bind to. Null if any port will suffice.</param>
+ <param name="timeout">The timeout within which to attempt the binding.</param>
+ <returns>Whether the binding was successful or not.</returns>
</member>
- <member name="M:NetSharp.Deprecated.Server.OnClientDisconnected(System.Net.EndPoint)">
+ <member name="M:NetSharp.Deprecated.IClient.TryConnectAsync(System.Net.IPAddress,System.Int32,System.TimeSpan)">
<summary>
- Invokes the <see cref="E:NetSharp.Deprecated.Server.ClientDisconnected"/> event.
+ Attempts to connect asynchronously to the remote <see cref="T:NetSharp.Deprecated.Server"/> at the given <see cref="T:System.Net.IPAddress"/>
+ and over the given port. If the timeout is exceeded the connection attempt is aborted and the method returns false.
</summary>
- <param name="remoteEndPoint">The remote endpoint with which a connection was lost.</param>
+ <param name="remoteAddress">The remote IP address to connect to.</param>
+ <param name="remotePort">The remote port to connect over.</param>
+ <param name="timeout">The timeout within which to attempt the connection.</param>
+ <returns>Whether the connection was successful or not.</returns>
</member>
- <member name="M:NetSharp.Deprecated.Server.OnServerStarted">
+ <member name="T:NetSharp.Deprecated.INetworkSerialisable">
<summary>
- Invokes the <see cref="E:NetSharp.Deprecated.Server.ServerStarted"/> event.
+ Describes an object that can be serialised to be sent across the network.
</summary>
</member>
- <member name="M:NetSharp.Deprecated.Server.OnServerStopped">
+ <member name="M:NetSharp.Deprecated.INetworkSerialisable.Deserialise(System.ReadOnlyMemory{System.Byte})">
<summary>
- Invokes the <see cref="E:NetSharp.Deprecated.Server.ServerStopped"/> event.
+ Deserialises the object instance from a byte array.
</summary>
+ <param name="serialisedObject">The memory containing the serialised object instance.</param>
</member>
- <member name="M:NetSharp.Deprecated.Server.TryBind(System.Net.EndPoint,System.TimeSpan)">
+ <member name="M:NetSharp.Deprecated.INetworkSerialisable.Serialise">
<summary>
- Attempts to synchronously bind the underlying socket to the given local endpoint. Blocks.
- If the timeout is exceeded the binding attempt is aborted and the method returns false.
+ Serialises the object instance into a byte array.
</summary>
- <param name="localEndPoint">The local endpoint to bind to.</param>
- <param name="timeout">The timeout within which to attempt the binding.</param>
- <returns>Whether the binding was successful or not.</returns>
+ <returns>The memory containing the serialised object instance.</returns>
</member>
- <member name="M:NetSharp.Deprecated.Server.TryBindAsync(System.Net.EndPoint,System.TimeSpan)">
+ <member name="T:NetSharp.Deprecated.IPacket">
<summary>
- Attempts to asynchronously bind the underlying socket to the given local endpoint. Does not block.
- If the timeout is exceeded the binding attempt is aborted and the method returns false.
+ Describes the methods and properties that every packet
</summary>
- <param name="localEndPoint">The local endpoint to bind to.</param>
- <param name="timeout">The timeout within which to attempt the binding.</param>
- <returns>Whether the binding was successful or not.</returns>
</member>
- <member name="T:NetSharp.Deprecated.Server.ClientHandlerArgs">
+ <member name="M:NetSharp.Deprecated.IPacket.AfterDeserialisation">
<summary>
- Holds information about the arguments passed to every client handler task.
+ Allows for custom fields to be converted from their serialised format, after being received from the network.
</summary>
</member>
- <member name="M:NetSharp.Deprecated.Server.ClientHandlerArgs.#ctor(System.Net.EndPoint,System.Net.Sockets.Socket)">
+ <member name="M:NetSharp.Deprecated.IPacket.BeforeSerialisation">
<summary>
- Initialises a new instance of the <see cref="T:NetSharp.Deprecated.Server.ClientHandlerArgs"/> struct.
+ Allows for custom fields to be converted into another format prior to being sent via the network.
</summary>
- <param name="remoteEndPoint">The remote endpoint of the client that should be handled.</param>
- <param name="handlerSocket">The handler socket of the client that should be handled.</param>
</member>
- <member name="F:NetSharp.Deprecated.Server.ClientHandlerArgs.ClientEndPoint">
+ <member name="T:NetSharp.Deprecated.IPacketHandler">
<summary>
- The remote endpoint for the client being handled.
+ Describes a class capable of registering and deregistering packet handlers, and capable of
+ handling incoming packets according to the currently registered packet handlers.
</summary>
</member>
- <member name="F:NetSharp.Deprecated.Server.ClientHandlerArgs.ClientSocket">
+ <member name="M:NetSharp.Deprecated.IPacketHandler.TryDeregisterComplexPacketHandler``2(NetSharp.Deprecated.ComplexPacketHandler{``0,``1}@)">
<summary>
- The client handler socket for the client being handled. Is only set if using TCP.
+ Attempts to deregister the complex packet handler delegate for all packets of the given type. If a handler
+ method doesn't exist for the given packet type, <paramref name="oldHandlerDelegate"/> will be <c>default</c>.
</summary>
+ <typeparam name="Req">The type of request packet for which to deregister the handler delegate.</typeparam>
+ <typeparam name="Rep">The type of response packet that is generated by the delegate method.</typeparam>
+ <param name="oldHandlerDelegate">The old handler delegate method that was previously registered.</param>
+ <returns>Whether the packet handler delegate was successfully deregistered.</returns>
</member>
- <member name="M:NetSharp.Deprecated.Server.ClientHandlerArgs.ForTcpClientHandler(System.Net.Sockets.Socket@)">
+ <member name="M:NetSharp.Deprecated.IPacketHandler.TryDeregisterSimplePacketHandler``1(NetSharp.Deprecated.SimplePacketHandler{``0}@)">
<summary>
- Constructs a new instance of the <see cref="T:NetSharp.Deprecated.Server.ClientHandlerArgs"/> for a TCP client.
+ Attempts to deregister the simple packet handler delegate for all packets of the given type. If a handler
+ method doesn't exist for the given packet type, <paramref name="oldHandlerDelegate"/> will be <c>default</c>.
</summary>
- <returns>A new instance of the <see cref="T:NetSharp.Deprecated.Server.ClientHandlerArgs"/>, setup for a TCP client.</returns>
+ <typeparam name="Req">The type of request packet for which to deregister the handler delegate.</typeparam>
+ <param name="oldHandlerDelegate">The old handler delegate method that was previously registered.</param>
+ <returns>Whether the packet handler delegate was successfully deregistered.</returns>
</member>
- <member name="M:NetSharp.Deprecated.Server.ClientHandlerArgs.ForUdpClientHandler(System.Net.EndPoint@)">
+ <member name="M:NetSharp.Deprecated.IPacketHandler.TryRegisterComplexPacketHandler``2(NetSharp.Deprecated.ComplexPacketHandler{``0,``1})">
<summary>
- Constructs a new instance of the <see cref="T:NetSharp.Deprecated.Server.ClientHandlerArgs"/> for a UDP client.
+ Attempts to register a complex packet handler delegate for all packets of the given type. If a handler
+ method already exists for the given packet type, it will be updated and replaced with the given one.
</summary>
- <returns>A new instance of the <see cref="T:NetSharp.Deprecated.Server.ClientHandlerArgs"/>, setup for a UDP client.</returns>
+ <typeparam name="Req">The type of request packet for which to register the handler delegate.</typeparam>
+ <typeparam name="Rep">The type of response packet that is generated by the delegate method.</typeparam>
+ <param name="handlerDelegate">The delegate method to register as the complex packet handler.</param>
+ <returns>Whether the packet handler delegate was successfully registered.</returns>
</member>
- <member name="E:NetSharp.Deprecated.Server.ClientConnected">
+ <member name="M:NetSharp.Deprecated.IPacketHandler.TryRegisterSimplePacketHandler``1(NetSharp.Deprecated.SimplePacketHandler{``0})">
<summary>
- Signifies that a connection with a remote endpoint has been made.
+ Attempts to register a simple packet handler delegate for all packets of the given type. If a handler
+ method already exists for the given packet type, it will be updated and replaced with the given one.
</summary>
+ <typeparam name="Req">The type of request packet for which to register the handler delegate.</typeparam>
+ <param name="handlerDelegate">The delegate method to register as the simple packet handler.</param>
+ <returns>Whether the packet handler delegate was successfully registered.</returns>
</member>
- <member name="E:NetSharp.Deprecated.Server.ClientDisconnected">
+ <member name="T:NetSharp.Deprecated.IRequestPacket">
<summary>
- Signifies that a connection with a remote endpoint has been lost.
+ Describes a request packet.
</summary>
</member>
- <member name="E:NetSharp.Deprecated.Server.ServerStarted">
+ <member name="T:NetSharp.Deprecated.IResponsePacket`1">
<summary>
- Signifies that the server was started and clients will start being accepted.
+ Describes a response packet to a request packet.
</summary>
+ <typeparam name="TReq">The request packet that this type is a response to.</typeparam>
</member>
- <member name="E:NetSharp.Deprecated.Server.ServerStopped">
+ <member name="P:NetSharp.Deprecated.IResponsePacket`1.RequestPacket">
<summary>
- Signifies that the server was stopped and clients will stop being accepted.
+ The request packet that was handled with this response packet.
</summary>
</member>
- <member name="P:NetSharp.Deprecated.Server.NetworkOperationTimeout">
+ <member name="T:NetSharp.Deprecated.IServer">
<summary>
- The timeout value for network operations such as sending bytes or receiving bytes over the network.
+ Describes a server capable of asynchronously handling multiple <see cref="T:NetSharp.Deprecated.IClient"/> connections at once.
</summary>
</member>
- <member name="P:NetSharp.Deprecated.Server.SocketOptions">
+ <member name="E:NetSharp.Deprecated.IServer.ClientConnected">
<summary>
- The configured socket options for the underlying connection.
+ Signifies that a connection with a remote endpoint has been made.
</summary>
</member>
- <member name="M:NetSharp.Deprecated.Server.RunAsync(System.Net.EndPoint)">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Deprecated.Server.Shutdown">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Deprecated.Server.TryDeregisterComplexPacketHandler``2(NetSharp.Deprecated.ComplexPacketHandler{``0,``1}@)">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Deprecated.Server.TryDeregisterSimplePacketHandler``1(NetSharp.Deprecated.SimplePacketHandler{``0}@)">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Deprecated.Server.TryRegisterComplexPacketHandler``2(NetSharp.Deprecated.ComplexPacketHandler{``0,``1})">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Deprecated.Server.TryRegisterSimplePacketHandler``1(NetSharp.Deprecated.SimplePacketHandler{``0})">
- <inheritdoc />
- </member>
- <member name="T:NetSharp.Deprecated.ServerClientConnection">
+ <member name="E:NetSharp.Deprecated.IServer.ClientDisconnected">
<summary>
- Base class for connections, holding methods shared between the <see cref="T:NetSharp.Deprecated.Client"/> and <see cref="T:NetSharp.Deprecated.Server"/> classes.
+ Signifies that a connection with a remote endpoint has been lost.
</summary>
</member>
- <member name="F:NetSharp.Deprecated.ServerClientConnection.logger">
+ <member name="E:NetSharp.Deprecated.IServer.ServerStarted">
<summary>
- The logger to which the server can log messages.
+ Signifies that the server was started and clients will start being accepted.
</summary>
</member>
- <member name="M:NetSharp.Deprecated.ServerClientConnection.#ctor">
+ <member name="E:NetSharp.Deprecated.IServer.ServerStopped">
<summary>
- Initialises a new instance of the <see cref="T:NetSharp.Deprecated.ServerClientConnection"/> class.
+ Signifies that the server was stopped and clients will stop being accepted.
</summary>
</member>
- <member name="M:NetSharp.Deprecated.ServerClientConnection.Dispose(System.Boolean)">
+ <member name="M:NetSharp.Deprecated.IServer.RunAsync(System.Net.EndPoint)">
<summary>
- Disposes of this <see cref="T:NetSharp.Deprecated.ServerClientConnection"/> instance.
+ Starts the server asynchronously and starts accepting client connections. Does not block.
</summary>
- <param name="disposing">Whether this instance is being disposed.</param>
+ <param name="localEndPoint">The local endpoint to bind to.</param>
</member>
- <member name="M:NetSharp.Deprecated.ServerClientConnection.OnBytesReceived(System.Net.EndPoint,System.Int32)">
+ <member name="M:NetSharp.Deprecated.IServer.Shutdown">
<summary>
- Invokes the <see cref="E:NetSharp.Deprecated.ServerClientConnection.BytesReceived"/> event.
+ Shuts down the server.
</summary>
- <param name="remoteEndPoint">The remote endpoint from which the bytes were received.</param>
- <param name="bytesReceived">The number of bytes that were received from the remote endpoint.</param>
</member>
- <member name="M:NetSharp.Deprecated.ServerClientConnection.OnBytesSent(System.Net.EndPoint,System.Int32)">
+ <member name="T:NetSharp.Deprecated.LogLevel">
<summary>
- Invokes the <see cref="E:NetSharp.Deprecated.ServerClientConnection.BytesSent"/> event.
+ Specifies the severity level of a log message.
</summary>
- <param name="remoteEndPoint">The remote endpoint to which the bytes were sent.</param>
- <param name="bytesSent">The number of bytes that were sent to the remote endpoint.</param>
</member>
- <member name="E:NetSharp.Deprecated.ServerClientConnection.BytesReceived">
+ <member name="F:NetSharp.Deprecated.LogLevel.Info">
<summary>
- Signifies that some data has been received from the remote endpoint.
+ The logged message contains some information. Lowest severity.
</summary>
</member>
- <member name="E:NetSharp.Deprecated.ServerClientConnection.BytesSent">
+ <member name="F:NetSharp.Deprecated.LogLevel.Warn">
<summary>
- Signifies that some data was sent to the remote endpoint.
+ The logged message contains a warning. Higher severity.
</summary>
</member>
- <member name="M:NetSharp.Deprecated.ServerClientConnection.ChangeLoggingStream(System.IO.Stream,NetSharp.Logging.LogLevel)">
+ <member name="F:NetSharp.Deprecated.LogLevel.Error">
<summary>
- Makes the client log to the given stream.
+ The logged message contains details about an error. Higher severity.
</summary>
- <param name="loggingStream">The stream that new messages should be logged to.</param>
- <param name="minimumMessageSeverityLevel">
- The minimum severity level that new messages must have to be logged to the stream.
- </param>
- </member>
- <member name="M:NetSharp.Deprecated.ServerClientConnection.Dispose">
- <inheritdoc />
</member>
- <member name="T:NetSharp.Deprecated.ServerExtensions">
+ <member name="F:NetSharp.Deprecated.LogLevel.Exception">
<summary>
- Provides additional methods and functionality to the <see cref="T:NetSharp.Deprecated.Server"/> class.
+ The logged message contains details about an exception. Highest severity.
</summary>
</member>
- <member name="M:NetSharp.Deprecated.ServerExtensions.Run(NetSharp.Deprecated.Server,System.Net.IPAddress,System.Int32)">
+ <member name="T:NetSharp.Deprecated.Logger">
<summary>
- Starts the server synchronously and starts accepting client connections. Blocks.
+ A simple logger capable of writing text to a stream.
</summary>
- <param name="instance">The instance on which this extension method should be called.</param>
- <param name="localAddress">The local IP address to bind to.</param>
- <param name="localPort">The local port to bind to.</param>
</member>
- <member name="M:NetSharp.Deprecated.ServerExtensions.Run(NetSharp.Deprecated.Server,System.Net.IPAddress)">
+ <member name="F:NetSharp.Deprecated.Logger.loggingStream">
<summary>
- Starts the server synchronously and starts accepting client connections. Blocks. Uses the default connection port.
+ The stream to which messages will be logged.
</summary>
- <param name="instance">The instance on which this extension method should be called.</param>
- <param name="localAddress">The local IP address to bind to.</param>
</member>
- <member name="M:NetSharp.Deprecated.ServerExtensions.RunAsync(NetSharp.Deprecated.Server,System.Net.IPAddress)">
+ <member name="F:NetSharp.Deprecated.Logger.minimumSeverity">
<summary>
- Starts the server asynchronously and starts accepting client connections. Does not block. Uses the default
- connection port.
+ The minimum severity that log messages need to be logged to the underlying stream.
</summary>
- <param name="instance">The instance on which this extension method should be called.</param>
- <param name="localAddress">The local IP address to bind to.</param>
</member>
- <member name="M:NetSharp.Deprecated.ServerExtensions.RunAsync(NetSharp.Deprecated.Server,System.Net.IPAddress,System.Int32)">
+ <member name="F:NetSharp.Deprecated.Logger.writer">
<summary>
- Starts the server asynchronously and starts accepting client connections. Does not block.
+ The text writer we will use to log messages to the underlying stream.
</summary>
- <param name="instance">The instance on which this extension method should be called.</param>
- <param name="localAddress">The local IP address to bind to.</param>
- <param name="localPort">The local port to bind to.</param>
</member>
- <member name="T:NetSharp.Deprecated.SocketOptions">
+ <member name="M:NetSharp.Deprecated.Logger.#ctor(System.IO.Stream,NetSharp.Deprecated.LogLevel)">
<summary>
- Allows for manipulation of socket options.
+ Initialises a new instance of the <see cref="T:NetSharp.Deprecated.Logger"/> struct.
</summary>
+ <param name="outputStream">The stream that the logger instance should log messages to.</param>
+ <param name="minimumLogSeverity">The minimum log level that will be logged to the output stream.</param>
</member>
- <member name="F:NetSharp.Deprecated.SocketOptions.managedSocket">
+ <member name="M:NetSharp.Deprecated.Logger.Dispose">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.Logger.Log(System.String,System.Exception,NetSharp.Deprecated.LogLevel)">
<summary>
- The <see cref="T:System.Net.Sockets.Socket"/> instance whose settings are being managed.
+ Logs a message to the underlying stream, along with the given exception and at the given severity.
</summary>
+ <param name="message">The message that should be logged.</param>
+ <param name="exception">The exception that occurred (if any).</param>
+ <param name="severity">The severity of the message that is being logged.</param>
</member>
- <member name="M:NetSharp.Deprecated.SocketOptions.#ctor(System.Net.Sockets.Socket@)">
+ <member name="M:NetSharp.Deprecated.Logger.LogAsync(System.String,System.Exception,NetSharp.Deprecated.LogLevel)">
<summary>
- Initialises a new instance of the <see cref="T:NetSharp.Deprecated.SocketOptions"/> class.
+ Logs a message asynchronously to the underlying stream, along with the given exception and at the given severity.
</summary>
- <param name="socket">The <see cref="T:System.Net.Sockets.Socket"/> instance whose options should be managed.</param>
+ <param name="message">The message that should be logged.</param>
+ <param name="exception">The exception that occurred (if any).</param>
+ <param name="severity">The severity of the message that is being logged.</param>
</member>
- <member name="P:NetSharp.Deprecated.SocketOptions.DualMode">
+ <member name="M:NetSharp.Deprecated.Logger.LogError(System.String)">
<summary>
- Whether this <see cref="T:System.Net.Sockets.Socket"/> can operate in dual IPv4 / IPv6 mode.
+ Logs an error to the underlying stream, with severity <see cref="F:NetSharp.Deprecated.LogLevel.Info"/>.
</summary>
+ <param name="message">The error that should be logged.</param>
</member>
- <member name="P:NetSharp.Deprecated.SocketOptions.ForceFlush">
+ <member name="M:NetSharp.Deprecated.Logger.LogErrorAsync(System.String)">
<summary>
- Whether sending a packet flushes underlying <see cref="T:System.Net.Sockets.NetworkStream"/>.
+ Logs an error to the underlying stream asynchronously, with severity <see cref="F:NetSharp.Deprecated.LogLevel.Error"/>.
</summary>
- <remarks>
- This value is only used in a <see cref="T:System.Net.Sockets.TcpClient"/> instance, which uses a <see cref="T:System.Net.Sockets.NetworkStream"/>
- to send and receive data. A <see cref="T:System.Net.Sockets.UdpClient"/> is unaffected by this value.
- </remarks>
+ <param name="message">The error that should be logged.</param>
</member>
- <member name="P:NetSharp.Deprecated.SocketOptions.Fragment">
+ <member name="M:NetSharp.Deprecated.Logger.LogException(System.Exception)">
<summary>
- Whether this <see cref="T:System.Net.Sockets.Socket"/> is allowed to fragment frames that are too large to send in one go.
+ Logs an exception to the underlying stream, with severity <see cref="F:NetSharp.Deprecated.LogLevel.Exception"/>.
</summary>
+ <param name="exception">The exception that should be logged.</param>
</member>
- <member name="P:NetSharp.Deprecated.SocketOptions.HopLimit">
+ <member name="M:NetSharp.Deprecated.Logger.LogException(System.String,System.Exception)">
<summary>
- The hop limit for packets sent by this <see cref="T:System.Net.Sockets.Socket"/>. Comparable to IPv4s TTL (Time To Live).
+ Logs an exception to the underlying stream, along with a short debug message, with severity
+ <see cref="F:NetSharp.Deprecated.LogLevel.Exception"/>.
</summary>
+ <param name="message">The debug message that should be logged with the exception.</param>
+ <param name="exception">The exception that should be logged.</param>
</member>
- <member name="P:NetSharp.Deprecated.SocketOptions.IsChecksumEnabled">
+ <member name="M:NetSharp.Deprecated.Logger.LogExceptionAsync(System.Exception)">
<summary>
- Whether a checksum should be created for each UDP packet sent.
+ Logs an exception to the underlying stream asynchronously, with severity <see cref="F:NetSharp.Deprecated.LogLevel.Exception"/>.
</summary>
+ <param name="exception">The exception that should be logged.</param>
</member>
- <member name="P:NetSharp.Deprecated.SocketOptions.IsRoutingEnabled">
+ <member name="M:NetSharp.Deprecated.Logger.LogExceptionAsync(System.String,System.Exception)">
<summary>
- Whether the packet should be sent directly to its destination or allowed to be routed through multiple destinations
- first.
+ Logs an exception to the underlying stream asynchronously, along with a short debug message, with severity
+ <see cref="F:NetSharp.Deprecated.LogLevel.Exception"/>.
</summary>
+ <param name="message">The debug message that should be logged with the exception.</param>
+ <param name="exception">The exception that should be logged.</param>
</member>
- <member name="P:NetSharp.Deprecated.SocketOptions.LocalEndPoint">
+ <member name="M:NetSharp.Deprecated.Logger.LogMessage(System.String)">
<summary>
- The local <see cref="T:System.Net.EndPoint"/> for the <see cref="F:NetSharp.Deprecated.SocketOptions.managedSocket"/>.
+ Logs a message to the underlying stream, with severity <see cref="F:NetSharp.Deprecated.LogLevel.Info"/>.
</summary>
+ <param name="message">The message that should be logged.</param>
</member>
- <member name="P:NetSharp.Deprecated.SocketOptions.LocalIPEndPoint">
+ <member name="M:NetSharp.Deprecated.Logger.LogMessageAsync(System.String)">
<summary>
- The local <see cref="T:System.Net.IPEndPoint"/> for this <see cref="T:System.Net.Sockets.Socket"/> instance.
+ Logs a message to the underlying stream asynchronously, with severity <see cref="F:NetSharp.Deprecated.LogLevel.Info"/>.
</summary>
+ <param name="message">The message that should be logged.</param>
</member>
- <member name="P:NetSharp.Deprecated.SocketOptions.RemoteEndPoint">
+ <member name="M:NetSharp.Deprecated.Logger.LogWarning(System.String)">
<summary>
- The remote <see cref="T:System.Net.EndPoint"/> for the <see cref="F:NetSharp.Deprecated.SocketOptions.managedSocket"/>.
+ Logs a warning to the underlying stream, with severity <see cref="F:NetSharp.Deprecated.LogLevel.Info"/>.
</summary>
+ <param name="message">The warning that should be logged.</param>
</member>
- <member name="P:NetSharp.Deprecated.SocketOptions.RemoteIPEndPoint">
+ <member name="M:NetSharp.Deprecated.Logger.LogWarningAsync(System.String)">
<summary>
- The remote <see cref="T:System.Net.IPEndPoint"/> that this <see cref="T:System.Net.Sockets.Socket"/> instance communicates with.
+ Logs a warning to the underlying stream asynchronously, with severity <see cref="F:NetSharp.Deprecated.LogLevel.Warn"/>.
</summary>
+ <param name="message">The warning that should be logged.</param>
</member>
- <member name="P:NetSharp.Deprecated.SocketOptions.Ttl">
+ <member name="T:NetSharp.Deprecated.NetworkErrorCode">
<summary>
- The 'Time To Live' for this <see cref="T:System.Net.Sockets.Socket"/>.
+ Enumerates the possible error codes for network operations, being held in the packet.
</summary>
</member>
- <member name="P:NetSharp.Deprecated.SocketOptions.UseLoopback">
+ <member name="F:NetSharp.Deprecated.NetworkErrorCode.Ok">
<summary>
- Whether this <see cref="T:System.Net.Sockets.Socket"/> should use a loopback address and bypass hardware.
+ Signifies that there was no error during transmission.
</summary>
</member>
- <member name="T:NetSharp.Deprecated.TcpClient">
+ <member name="F:NetSharp.Deprecated.NetworkErrorCode.Error">
<summary>
- Provides methods for TCP communication with a connected <see cref="T:NetSharp.Deprecated.TcpServer"/> instance.
+ A generic error occurred during packet transmission.
</summary>
</member>
- <member name="M:NetSharp.Deprecated.TcpClient.#ctor">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Deprecated.TcpClient.SendBytesAsync(System.Byte[],System.TimeSpan)">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Deprecated.TcpClient.SendBytesWithResponseAsync(System.Byte[],System.TimeSpan)">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Deprecated.TcpClient.SendComplexAsync``2(``0,System.TimeSpan)">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Deprecated.TcpClient.SendSimpleAsync``1(``0,System.TimeSpan)">
- <inheritdoc />
- </member>
- <member name="T:NetSharp.Deprecated.TcpServer">
+ <member name="T:NetSharp.Deprecated.NetworkPacket">
<summary>
- Provides methods for TCP communication with connected <see cref="T:NetSharp.Deprecated.TcpClient"/> instances.
+ Represents a low-level packet that is transmitted over the network.
</summary>
</member>
- <member name="M:NetSharp.Deprecated.TcpServer.HandleClientAsync(NetSharp.Deprecated.Server.ClientHandlerArgs,System.Threading.CancellationToken)">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Deprecated.TcpServer.#ctor(System.TimeSpan)">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Deprecated.TcpServer.#ctor">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Deprecated.TcpServer.RunAsync(System.Net.EndPoint)">
- <inheritdoc />
- </member>
- <member name="T:NetSharp.Deprecated.TcpSocketOptions">
+ <member name="M:NetSharp.Deprecated.NetworkPacket.#ctor(System.ReadOnlyMemory{System.Byte},NetSharp.Deprecated.NetworkPacketHeader,NetSharp.Deprecated.NetworkPacketFooter)">
<summary>
- Allows for manipulation of TCP socket options.
+ Initialises a new instance of the <see cref="T:NetSharp.Deprecated.NetworkPacket"/> struct.
</summary>
+ <param name="data">The data that should be transmitted in the packet.</param>
+ <param name="header">The header for the packet.</param>
+ <param name="footer">The footer for the packet.</param>
</member>
- <member name="M:NetSharp.Deprecated.TcpSocketOptions.#ctor(System.Net.Sockets.Socket@)">
- <inheritdoc />
- </member>
- <member name="P:NetSharp.Deprecated.TcpSocketOptions.HopLimit">
- <inheritdoc />
- </member>
- <member name="P:NetSharp.Deprecated.TcpSocketOptions.IsRoutingEnabled">
- <inheritdoc />
- </member>
- <member name="P:NetSharp.Deprecated.TcpSocketOptions.UseLoopback">
- <inheritdoc />
- </member>
- <member name="T:NetSharp.Deprecated.UdpClient">
+ <member name="F:NetSharp.Deprecated.NetworkPacket.DataSegmentSize">
<summary>
- Provides methods for UDP communication with a connected <see cref="T:NetSharp.Deprecated.UdpServer"/> instance.
+ The number of bytes allocated in each packet for user data.
</summary>
</member>
- <member name="M:NetSharp.Deprecated.UdpClient.#ctor">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Deprecated.UdpClient.SendBytesAsync(System.Byte[],System.TimeSpan)">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Deprecated.UdpClient.SendBytesWithResponseAsync(System.Byte[],System.TimeSpan)">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Deprecated.UdpClient.SendComplexAsync``2(``0,System.TimeSpan)">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Deprecated.UdpClient.SendSimpleAsync``1(``0,System.TimeSpan)">
- <inheritdoc />
- </member>
- <member name="T:NetSharp.Deprecated.UdpServer">
+ <member name="F:NetSharp.Deprecated.NetworkPacket.FooterSize">
<summary>
- Provides methods for UDP communication with connected <see cref="T:NetSharp.Deprecated.UdpClient"/> instances.
+ The number of bytes taken up in each packet by its footer.
</summary>
</member>
- <member name="F:NetSharp.Deprecated.UdpServer.clientChannelOptions">
+ <member name="F:NetSharp.Deprecated.NetworkPacket.HeaderSize">
<summary>
- The options that should be applied to every channel created to handle a client.
+ The number of bytes taken up in each packet by its header.
</summary>
</member>
- <member name="F:NetSharp.Deprecated.UdpServer.activeClients">
+ <member name="F:NetSharp.Deprecated.NetworkPacket.PacketSize">
<summary>
- Holds currently connected and active clients, as well as their current received packet queues.
+ The size of each packet, including its header, footer, and data segment.
</summary>
</member>
- <member name="M:NetSharp.Deprecated.UdpServer.HandleClientAsync(NetSharp.Deprecated.Server.ClientHandlerArgs,System.Threading.CancellationToken)">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Deprecated.UdpServer.#ctor(System.TimeSpan)">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Deprecated.UdpServer.#ctor">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Deprecated.UdpServer.RunAsync(System.Net.EndPoint)">
- <inheritdoc />
- </member>
- <member name="T:NetSharp.Deprecated.UdpSocketOptions">
+ <member name="F:NetSharp.Deprecated.NetworkPacket.DataBuffer">
<summary>
- Allows for manipulation of UDP socket options.
+ The data held in this packet.
</summary>
</member>
- <member name="M:NetSharp.Deprecated.UdpSocketOptions.#ctor(System.Net.Sockets.Socket@)">
- <inheritdoc />
+ <member name="M:NetSharp.Deprecated.NetworkPacket.#ctor(System.ReadOnlyMemory{System.Byte},System.Int32,System.UInt32,NetSharp.Deprecated.NetworkErrorCode,System.Boolean)">
+ <summary>
+ Initialises a new instance of the <see cref="T:NetSharp.Deprecated.NetworkPacket"/> struct.
+ </summary>
+ <param name="data">The data that should be transmitted in the packet.</param>
+ <param name="dataLength">The number of bytes that are held in the given data buffer.</param>
+ <param name="type">The packet type.</param>
+ <param name="errorCode">The error code associated with this transmission.</param>
+ <param name="hasSucceedingPacket">Whether this packet has a succeeding packet in the packet chain.</param>
</member>
- <member name="P:NetSharp.Deprecated.UdpSocketOptions.HopLimit">
- <inheritdoc />
+ <member name="M:NetSharp.Deprecated.NetworkPacket.Deserialise(System.Memory{System.Byte})">
+ <summary>
+ Deserialises the given buffer into a packet instance.
+ </summary>
+ <param name="buffer">The byte buffer to serialise.</param>
+ <returns>The deserialised packet instance.</returns>
</member>
- <member name="P:NetSharp.Deprecated.UdpSocketOptions.IsRoutingEnabled">
- <inheritdoc />
+ <member name="M:NetSharp.Deprecated.NetworkPacket.Serialise(NetSharp.Deprecated.NetworkPacket)">
+ <summary>
+ Serialises the given packet instance to a new byte buffer.
+ </summary>
+ <param name="instance">The packet instance to serialise.</param>
+ <returns>The byte buffer that represents the packet instance.</returns>
</member>
- <member name="P:NetSharp.Deprecated.UdpSocketOptions.UseLoopback">
- <inheritdoc />
+ <member name="M:NetSharp.Deprecated.NetworkPacket.SerialiseToBuffer(System.Memory{System.Byte},NetSharp.Deprecated.NetworkPacket)">
+ <summary>
+ Serialises the given packet instance into the given byte buffer.
+ </summary>
+ <param name="buffer">
+ The buffer to which the instance should be serialised. Must be at least of size <see cref="F:NetSharp.Deprecated.NetworkPacket.PacketSize"/>.
+ </param>
+ <param name="instance">The packet instance to serialise.</param>
+ <exception cref="T:System.ArgumentException">Thrown if the given buffer is too small.</exception>
</member>
- <member name="T:NetSharp.Extensions.ConnectionBuilderExtensions">
+ <member name="F:NetSharp.Deprecated.NetworkPacketFooter.Size">
<summary>
- Provides additional methods and functionality to the <see cref="T:NetSharp.ConnectionBuilder"/> class.
+ The number of bytes taken up by a packet footer.
</summary>
</member>
- <member name="T:NetSharp.Extensions.ConnectionExtensions">
+ <member name="F:NetSharp.Deprecated.NetworkPacketHeader.Size">
<summary>
- Provides additional methods and functionality to the <see cref="T:NetSharp.Connection"/> class.
+ The number of bytes taken up by a packet header.
</summary>
</member>
- <member name="M:NetSharp.Extensions.ConnectionExtensions.TryBind(NetSharp.Connection,System.Net.EndPoint,System.TimeSpan)">
+ <member name="F:NetSharp.Deprecated.NetworkPacketHeader.DataLength">
<summary>
- Attempts to synchronously bind the underlying socket to the given local endpoint. Blocks.
- If the timeout is exceeded the binding attempt is aborted and the method returns false.
+ The number of bytes of data held in the packet.
</summary>
- <param name="localEndPoint">The local endpoint to bind to.</param>
- <param name="timeout">The timeout within which to attempt the binding.</param>
- <returns>Whether the binding was successful or not.</returns>
</member>
- <member name="T:NetSharp.Logging.LogLevel">
+ <member name="F:NetSharp.Deprecated.NetworkPacketHeader.ErrorCode">
<summary>
- Specifies the severity level of a log message.
+ The error code for this packet.
</summary>
</member>
- <member name="F:NetSharp.Logging.LogLevel.Info">
+ <member name="F:NetSharp.Deprecated.NetworkPacketHeader.Type">
<summary>
- The logged message contains some information. Lowest severity.
+ The packet type.
</summary>
</member>
- <member name="F:NetSharp.Logging.LogLevel.Warn">
+ <member name="T:NetSharp.Deprecated.PacketPipeline`3">
<summary>
- The logged message contains a warning. Higher severity.
+ Represents a pipeline of transformations that packets must undergo.
</summary>
+ <typeparam name="TInput">The type of packet the pipeline receives.</typeparam>
+ <typeparam name="TIntermediate">The type of packet the pipeline internally handles.</typeparam>
+ <typeparam name="TOutput">The type of packet the pipeline outputs.</typeparam>
</member>
- <member name="F:NetSharp.Logging.LogLevel.Error">
+ <member name="M:NetSharp.Deprecated.PacketPipeline`3.ProcessPacket(`0)">
<summary>
- The logged message contains details about an error. Higher severity.
+ Passes the given packet through the pipeline.
</summary>
+ <param name="inputPacket">The incoming packet.</param>
+ <returns>The outgoing transformed packet.</returns>
</member>
- <member name="F:NetSharp.Logging.LogLevel.Exception">
+ <member name="T:NetSharp.Deprecated.PacketPipelineStage`2">
<summary>
- The logged message contains details about an exception. Highest severity.
+ Represents a single transformation applied to a packet traveling through the pipeline.
</summary>
+ <typeparam name="TInput">The type the transformation takes as input.</typeparam>
+ <typeparam name="TOutput">The type the transformation produces as output.</typeparam>
</member>
- <member name="T:NetSharp.Logging.Logger">
+ <member name="T:NetSharp.Deprecated.PacketPipelineBuilder`3">
<summary>
- A simple logger capable of writing text to a stream.
+ Allows for configuring and subsequently building a <see cref="T:NetSharp.Deprecated.PacketPipeline`3"/> instance.
</summary>
+ <typeparam name="TInput">The type of packet that will be submitted to the pipeline.</typeparam>
+ <typeparam name="TIntermediate">The type of packet that will be handled internally by the pipeline.</typeparam>
+ <typeparam name="TOutput">The type of packet that will be requested from the pipeline.</typeparam>
</member>
- <member name="F:NetSharp.Logging.Logger.loggingStream">
+ <member name="M:NetSharp.Deprecated.PacketPipelineBuilder`3.Build">
<summary>
- The stream to which messages will be logged.
+ Returns the currently configured <see cref="T:NetSharp.Deprecated.PacketPipeline`3"/> instance.
</summary>
+ <returns>The configured <see cref="T:NetSharp.Deprecated.PacketPipeline`3"/> instance.</returns>
+ <exception cref="T:System.ArgumentNullException">
+ Thrown when either <see cref="M:NetSharp.Deprecated.PacketPipelineBuilder`3.WithInputStage(System.Func{`0,`1}@)"/> or <see cref="M:NetSharp.Deprecated.PacketPipelineBuilder`3.WithOutputStage(System.Func{`1,`2}@)"/> have not been called.
+ </exception>
</member>
- <member name="F:NetSharp.Logging.Logger.minimumSeverity">
+ <member name="M:NetSharp.Deprecated.PacketPipelineBuilder`3.WithInputStage(System.Func{`0,`1}@)">
<summary>
- The minimum severity that log messages need to be logged to the underlying stream.
+ Configures the input stage for the pipeline.
</summary>
+ <param name="stage">
+ The transformation that should be applied to incoming packets, to convert them from the <typeparamref name="TInput"/>
+ type to the <typeparamref name="TIntermediate"/> type that the pipeline handles internally.
+ </param>
+ <returns>The builder instance for further configuration.</returns>
</member>
- <member name="F:NetSharp.Logging.Logger.writer">
+ <member name="M:NetSharp.Deprecated.PacketPipelineBuilder`3.WithIntermediateStage(System.Func{`1,`1}@)">
<summary>
- The text writer we will use to log messages to the underlying stream.
+ Adds the given intermediate stage to the pipeline.
</summary>
+ <param name="stage">
+ The transformation that should be applied to packets traveling through the pipeline.
+ </param>
+ <returns>The builder instance for further configuration.</returns>
</member>
- <member name="M:NetSharp.Logging.Logger.#ctor(System.IO.Stream,NetSharp.Logging.LogLevel)">
+ <member name="M:NetSharp.Deprecated.PacketPipelineBuilder`3.WithOutputStage(System.Func{`1,`2}@)">
<summary>
- Initialises a new instance of the <see cref="T:NetSharp.Logging.Logger"/> struct.
+ Configures the output stage for the pipeline.
</summary>
- <param name="outputStream">The stream that the logger instance should log messages to.</param>
- <param name="minimumLogSeverity">The minimum log level that will be logged to the output stream.</param>
- </member>
- <member name="M:NetSharp.Logging.Logger.Dispose">
- <inheritdoc />
+ <param name="stage">
+ The transformation that should be applied to outgoing packets, to convert them from the
+ <typeparamref name="TIntermediate"/> type used internally to the <typeparamref name="TOutput"/> type.
+ </param>
+ <returns>The builder instance for further configuration.</returns>
</member>
- <member name="M:NetSharp.Logging.Logger.Log(System.String,System.Exception,NetSharp.Logging.LogLevel)">
+ <member name="T:NetSharp.Deprecated.PacketRegistry">
<summary>
- Logs a message to the underlying stream, along with the given exception and at the given severity.
+ Provides method of registering request packets and their relevant response packets, as well as mapping their ids.
</summary>
- <param name="message">The message that should be logged.</param>
- <param name="exception">The exception that occurred (if any).</param>
- <param name="severity">The severity of the message that is being logged.</param>
</member>
- <member name="M:NetSharp.Logging.Logger.LogAsync(System.String,System.Exception,NetSharp.Logging.LogLevel)">
+ <member name="F:NetSharp.Deprecated.PacketRegistry.AutomaticPacketTypeIdStartPoint">
<summary>
- Logs a message asynchronously to the underlying stream, along with the given exception and at the given severity.
+ The start id for automatically generated packet type ids. Any custom packet type ids lower than this value
+ that come from external assemblies will be incremented by this value, to ensure that there are no clashes.
</summary>
- <param name="message">The message that should be logged.</param>
- <param name="exception">The exception that occurred (if any).</param>
- <param name="severity">The severity of the message that is being logged.</param>
</member>
- <member name="M:NetSharp.Logging.Logger.LogError(System.String)">
+ <member name="F:NetSharp.Deprecated.PacketRegistry.currentAutomaticPacketTypeIdCounterLockObject">
<summary>
- Logs an error to the underlying stream, with severity <see cref="F:NetSharp.Logging.LogLevel.Info"/>.
+ The lock object for synchronising access to the <see cref="F:NetSharp.Deprecated.PacketRegistry.currentAutomaticPacketTypeIdCounter"/> field.
</summary>
- <param name="message">The error that should be logged.</param>
</member>
- <member name="M:NetSharp.Logging.Logger.LogErrorAsync(System.String)">
+ <member name="F:NetSharp.Deprecated.PacketRegistry.idToPacketTypeMap">
<summary>
- Logs an error to the underlying stream asynchronously, with severity <see cref="F:NetSharp.Logging.LogLevel.Error"/>.
+ Maps a packet type id to its relevant packet type, and vice-versa.
</summary>
- <param name="message">The error that should be logged.</param>
</member>
- <member name="M:NetSharp.Logging.Logger.LogException(System.Exception)">
+ <member name="F:NetSharp.Deprecated.PacketRegistry.LibraryAssembly">
<summary>
- Logs an exception to the underlying stream, with severity <see cref="F:NetSharp.Logging.LogLevel.Exception"/>.
+ The assembly that represents the library, where all of the builtin packets are defined.
</summary>
- <param name="exception">The exception that should be logged.</param>
</member>
- <member name="M:NetSharp.Logging.Logger.LogException(System.String,System.Exception)">
+ <member name="F:NetSharp.Deprecated.PacketRegistry.requestToResponseMap">
<summary>
- Logs an exception to the underlying stream, along with a short debug message, with severity
- <see cref="F:NetSharp.Logging.LogLevel.Exception"/>.
+ Maps a request packet to its relevant response packet, and vice-versa.
</summary>
- <param name="message">The debug message that should be logged with the exception.</param>
- <param name="exception">The exception that should be logged.</param>
</member>
- <member name="M:NetSharp.Logging.Logger.LogExceptionAsync(System.Exception)">
+ <member name="F:NetSharp.Deprecated.PacketRegistry.currentAutomaticPacketTypeIdCounter">
<summary>
- Logs an exception to the underlying stream asynchronously, with severity <see cref="F:NetSharp.Logging.LogLevel.Exception"/>.
+ The current id for registered packets.
</summary>
- <param name="exception">The exception that should be logged.</param>
</member>
- <member name="M:NetSharp.Logging.Logger.LogExceptionAsync(System.String,System.Exception)">
+ <member name="M:NetSharp.Deprecated.PacketRegistry.GetNewPacketTypeId(System.Type)">
<summary>
- Logs an exception to the underlying stream asynchronously, along with a short debug message, with severity
- <see cref="F:NetSharp.Logging.LogLevel.Exception"/>.
+ Fetches the packet type id of the given packet type. If the packet type is declared outside of the library
+ assembly, then its value is incremented by the <see cref="F:NetSharp.Deprecated.PacketRegistry.AutomaticPacketTypeIdStartPoint"/> value. This ensure that
+ there are no clashes between the packet type ids of packets declared in the library and external packets.
</summary>
- <param name="message">The debug message that should be logged with the exception.</param>
- <param name="exception">The exception that should be logged.</param>
+ <param name="packetType">The packet type whose id should be fetched.</param>
+ <returns>The id of the given packet type.</returns>
</member>
- <member name="M:NetSharp.Logging.Logger.LogMessage(System.String)">
+ <member name="M:NetSharp.Deprecated.PacketRegistry.DeregisterPacketType(System.Type,System.Type)">
<summary>
- Logs a message to the underlying stream, with severity <see cref="F:NetSharp.Logging.LogLevel.Info"/>.
+ Deregisters the given packet type from the registry.
</summary>
- <param name="message">The message that should be logged.</param>
+ <param name="requestPacketType">The request packet type to deregister, if it is registered.</param>
+ <param name="responsePacketType">The response packet associated with the request packet.</param>
</member>
- <member name="M:NetSharp.Logging.Logger.LogMessageAsync(System.String)">
+ <member name="M:NetSharp.Deprecated.PacketRegistry.DeregisterPacketTypes(System.Collections.Generic.Dictionary{System.Type,System.Type})">
<summary>
- Logs a message to the underlying stream asynchronously, with severity <see cref="F:NetSharp.Logging.LogLevel.Info"/>.
+ Deregisters the given packet types from the registry.
</summary>
- <param name="message">The message that should be logged.</param>
+ <param name="requestToResponsePacketTypeMap">The list of packet types to deregister, if they are registered.</param>
</member>
- <member name="M:NetSharp.Logging.Logger.LogWarning(System.String)">
+ <member name="M:NetSharp.Deprecated.PacketRegistry.GetPacketId(System.Type)">
<summary>
- Logs a warning to the underlying stream, with severity <see cref="F:NetSharp.Logging.LogLevel.Info"/>.
+ Returns the packet type id associated with the given packet type.
</summary>
- <param name="message">The warning that should be logged.</param>
+ <param name="packetType">The packet type whose id to fetch.</param>
+ <returns>The id of the packet type given.</returns>
</member>
- <member name="M:NetSharp.Logging.Logger.LogWarningAsync(System.String)">
+ <member name="M:NetSharp.Deprecated.PacketRegistry.GetPacketId``1">
<summary>
- Logs a warning to the underlying stream asynchronously, with severity <see cref="F:NetSharp.Logging.LogLevel.Warn"/>.
+ Returns the packet type id associated with the given packet type.
</summary>
- <param name="message">The warning that should be logged.</param>
+ <typeparam name="TPacket">The packet type whose id to fetch.</typeparam>
+ <returns>The id of the packet type given.</returns>
</member>
- <member name="T:NetSharp.Packets.Builtin.ConnectPacket">
+ <member name="M:NetSharp.Deprecated.PacketRegistry.GetPacketType(System.UInt32)">
<summary>
- A simple connection request packet for the UDP protocol.
+ Returns the packet type associated with the given id.
</summary>
+ <param name="packetTypeId">The packet id whose mapped type to fetch.</param>
+ <returns>The packet type mapped by the given id.</returns>
</member>
- <member name="M:NetSharp.Packets.Builtin.ConnectPacket.AfterDeserialisation">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Packets.Builtin.ConnectPacket.BeforeSerialisation">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Packets.Builtin.ConnectPacket.Deserialise(System.ReadOnlyMemory{System.Byte})">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Packets.Builtin.ConnectPacket.Serialise">
- <inheritdoc />
- </member>
- <member name="T:NetSharp.Packets.Builtin.ConnectResponsePacket">
+ <member name="M:NetSharp.Deprecated.PacketRegistry.GetRequestPacketType``1">
<summary>
- A response packet for the <see cref="T:NetSharp.Packets.Builtin.ConnectPacket"/>.
+ Returns the type of request packet mapped by the given response packet type.
</summary>
+ <typeparam name="TResponse">The response packet type whose request packet type to fetch.</typeparam>
+ <returns>The request packet type, <c>null</c> if no type is mapped.</returns>
</member>
- <member name="P:NetSharp.Packets.Builtin.ConnectResponsePacket.RequestPacket">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Packets.Builtin.ConnectResponsePacket.AfterDeserialisation">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Packets.Builtin.ConnectResponsePacket.BeforeSerialisation">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Packets.Builtin.ConnectResponsePacket.Deserialise(System.ReadOnlyMemory{System.Byte})">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Packets.Builtin.ConnectResponsePacket.Serialise">
- <inheritdoc />
- </member>
- <member name="T:NetSharp.Packets.Builtin.DataPacket">
+ <member name="M:NetSharp.Deprecated.PacketRegistry.GetRequestPacketType(System.Type)">
<summary>
- A simple data transfer packet, that allows for the transmission of an arbitrary number of frames.
+ Returns the type of request packet mapped by the given response packet type.
</summary>
+ <param name="responsePacketType">The response packet type whose request packet type to fetch.</param>
+ <returns>The request packet type, <c>null</c> if no type is mapped.</returns>
</member>
- <member name="F:NetSharp.Packets.Builtin.DataPacket.RequestBuffer">
+ <member name="M:NetSharp.Deprecated.PacketRegistry.GetResponsePacketType``1">
<summary>
- The data that should be transferred across the network.
+ Returns the type of response packet mapped by the given request packet type.
</summary>
+ <typeparam name="TRequest">The request packet type whose response packet type to fetch.</typeparam>
+ <returns>The response packet type, <c>null</c> if no type is mapped.</returns>
</member>
- <member name="M:NetSharp.Packets.Builtin.DataPacket.#ctor">
+ <member name="M:NetSharp.Deprecated.PacketRegistry.GetResponsePacketType(System.Type)">
<summary>
- Initialises a new instance of the <see cref="T:NetSharp.Packets.Builtin.DataPacket"/> class.
+ Returns the type of response packet mapped by the given request packet type.
</summary>
+ <param name="requestPacketType">The request packet type whose response packet type to fetch.</param>
+ <returns>The response packet type, <c>null</c> if no type is mapped.</returns>
</member>
- <member name="M:NetSharp.Packets.Builtin.DataPacket.#ctor(System.Memory{System.Byte})">
+ <member name="M:NetSharp.Deprecated.PacketRegistry.RegisterPacketSourceAssemblies(System.Reflection.Assembly[])">
<summary>
- Initialises a new instance of the <see cref="T:NetSharp.Packets.Builtin.DataPacket"/> class.
+ Rebuilds the packet registry, by registering every <see cref="T:NetSharp.Deprecated.IPacket"/> inheritor in the given assemblies.
</summary>
- <param name="buffer">The data that this request packet should contain.</param>
- </member>
- <member name="M:NetSharp.Packets.Builtin.DataPacket.AfterDeserialisation">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Packets.Builtin.DataPacket.BeforeSerialisation">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Packets.Builtin.DataPacket.Deserialise(System.ReadOnlyMemory{System.Byte})">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Packets.Builtin.DataPacket.Serialise">
- <inheritdoc />
+ <param name="packetSourceAssemblies">
+ The assemblies from which the packet types to register are sourced.
+ </param>
</member>
- <member name="T:NetSharp.Packets.Builtin.DataResponsePacket">
+ <member name="M:NetSharp.Deprecated.PacketRegistry.RegisterPacketSourceAssembly(System.Reflection.Assembly)">
<summary>
- A response packet for the <see cref="T:NetSharp.Packets.Builtin.DataPacket"/>.
+ Registers all the <see cref="T:NetSharp.Deprecated.IPacket"/> implementors in the given assembly.
</summary>
+ <param name="packetSourceAssembly">The assembly whose packet types to register.</param>
</member>
- <member name="F:NetSharp.Packets.Builtin.DataResponsePacket.ResponseBuffer">
+ <member name="M:NetSharp.Deprecated.PacketRegistry.RegisterPacketType(System.Type,System.Type)">
<summary>
- The data that should be transferred across the network.
+ Registers the given packet type to the registry.
</summary>
+ <param name="requestPacketType">The request packet type to register, if it is not registered.</param>
+ <param name="responsePacketType">The response packet associated with the request packet.</param>
</member>
- <member name="M:NetSharp.Packets.Builtin.DataResponsePacket.#ctor">
+ <member name="M:NetSharp.Deprecated.PacketRegistry.RegisterPacketTypes(System.Collections.Generic.Dictionary{System.Type,System.Type})">
<summary>
- Initialises a new instance of the <see cref="T:NetSharp.Packets.Builtin.DataResponsePacket"/> class.
+ Registers the given packet types to the registry.
</summary>
+ <param name="requestToResponsePacketTypeMap">
+ The dictionary mapping the request packet types to register, to their relevant response packet types.
+ The response packet type can be null; then the request packet type is treated as a 'simple' packet.
+ </param>
</member>
- <member name="M:NetSharp.Packets.Builtin.DataResponsePacket.#ctor(System.Memory{System.Byte})">
+ <member name="M:NetSharp.Deprecated.PacketRegistry.#cctor">
<summary>
- Initialises a new instance of the <see cref="T:NetSharp.Packets.Builtin.DataResponsePacket"/> class.
+ Initialises a new instance of the <see cref="T:NetSharp.Deprecated.PacketRegistry"/> class.
</summary>
- <param name="buffer">The data that this response packet should contain.</param>
</member>
- <member name="P:NetSharp.Packets.Builtin.DataResponsePacket.RequestPacket">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Packets.Builtin.DataResponsePacket.AfterDeserialisation">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Packets.Builtin.DataResponsePacket.BeforeSerialisation">
- <inheritdoc />
- </member>
- <member name="M:NetSharp.Packets.Builtin.DataResponsePacket.Deserialise(System.ReadOnlyMemory{System.Byte})">
- <inheritdoc />
+ <member name="T:NetSharp.Deprecated.PacketTypeIdAttribute">
+ <summary>
+ Allows the placing of a custom packet type on a class or struct. This is used if the class or struct
+ inherits from <see cref="T:NetSharp.Deprecated.IRequestPacket"/> or <see cref="T:NetSharp.Deprecated.IResponsePacket`1"/>.
+ </summary>
</member>
- <member name="M:NetSharp.Packets.Builtin.DataResponsePacket.Serialise">
- <inheritdoc />
+ <member name="M:NetSharp.Deprecated.PacketTypeIdAttribute.#ctor(System.UInt32)">
+ <summary>
+ Initialises a new instance of the <see cref="T:NetSharp.Deprecated.PacketTypeIdAttribute"/> attribute.
+ </summary>
+ <param name="type">The custom type id that the decorated packet type should have.</param>
</member>
- <member name="T:NetSharp.Packets.Builtin.DisconnectPacket">
+ <member name="P:NetSharp.Deprecated.PacketTypeIdAttribute.Id">
<summary>
- A simple disconnect packet for the UDP protocol.
+ The custom type id that the decorated packet type should have. This overrides the automatically generated id.
</summary>
</member>
- <member name="M:NetSharp.Packets.Builtin.DisconnectPacket.AfterDeserialisation">
+ <member name="M:NetSharp.Deprecated.RemoteSocketClient.Dispose">
<inheritdoc />
</member>
- <member name="M:NetSharp.Packets.Builtin.DisconnectPacket.BeforeSerialisation">
- <inheritdoc />
+ <member name="M:NetSharp.Deprecated.RemoteSocketClient.Dispose(System.Boolean)">
+ <summary>
+ Implementation of dispose pattern.
+ </summary>
+ <param name="disposing">
+ Whether this method is being called by the object finalizer, or by the <see cref="M:NetSharp.Deprecated.RemoteSocketClient.Dispose"/> method.
+ </param>
</member>
- <member name="M:NetSharp.Packets.Builtin.DisconnectPacket.Deserialise(System.ReadOnlyMemory{System.Byte})">
- <inheritdoc />
+ <member name="M:NetSharp.Deprecated.SerialisedPacket.From``1(``0)">
+ <summary>
+ Serialises the given serialisable packet instance and returns the <see cref="T:NetSharp.Deprecated.SerialisedPacket"/> instance
+ that was generated. This method invokes <see cref="M:NetSharp.Deprecated.IPacket.BeforeSerialisation"/>.
+ </summary>
+ <typeparam name="T">The packet type that will be serialised.</typeparam>
+ <param name="serialisable">The packet instance that should be serialised.</param>
+ <returns>The serialised instance.</returns>
</member>
- <member name="M:NetSharp.Packets.Builtin.DisconnectPacket.Serialise">
- <inheritdoc />
+ <member name="M:NetSharp.Deprecated.SerialisedPacket.To``1(NetSharp.Deprecated.SerialisedPacket@)">
+ <summary>
+ Deserialises and returns a packet instance of the given type from the <see cref="T:NetSharp.Deprecated.SerialisedPacket"/> instance
+ that was given. This method invokes <see cref="M:NetSharp.Deprecated.IPacket.AfterDeserialisation"/>.
+ </summary>
+ <typeparam name="T">The packet type to which the packet should be deserialised.</typeparam>
+ <param name="instance">The serialised packet instance that should be deserialised.</param>
+ <returns>The deserialised instance.</returns>
</member>
- <member name="T:NetSharp.Packets.Builtin.PingPacket">
+ <member name="T:NetSharp.Deprecated.ComplexPacketHandler`2">
<summary>
- A simple ping request packet for heartbeat monitoring and RTT measurement.
+ Represents a method that receives a request packet of the given type (<typeparamref name="TReq"/>) and
+ handles the request, returning a response packet of the given type (<typeparamref name="TRep"/>).
</summary>
+ <typeparam name="TReq">The type of request packet handled by this delegate method.</typeparam>
+ <typeparam name="TRep">The type of response packet returned by this delegate method.</typeparam>
+ <param name="requestPacket">The request packet that should be handled by this delegate method.</param>
+ <param name="remoteEndPoint">The remote endpoint from which the request originated.</param>
+ <returns>The response packet to send back to the remote endpoint from which the request originated.</returns>
</member>
- <member name="M:NetSharp.Packets.Builtin.PingPacket.AfterDeserialisation">
- <inheritdoc />
+ <member name="T:NetSharp.Deprecated.SimplePacketHandler`1">
+ <summary>
+ Represents a method that receives a simple request packet of the given type (<typeparamref name="TReq"/>) and
+ handles the request, not returning any response packets.
+ </summary>
+ <typeparam name="TReq">The type of request packet handled by this delegate method.</typeparam>
+ <param name="requestPacket">The request packet that should be handled by this delegate method.</param>
+ <param name="remoteEndPoint">The remote endpoint from which the request originated.</param>
</member>
- <member name="M:NetSharp.Packets.Builtin.PingPacket.BeforeSerialisation">
- <inheritdoc />
+ <member name="T:NetSharp.Deprecated.Server">
+ <summary>
+ Provides methods for handling connected <see cref="T:NetSharp.Deprecated.IClient"/> instances.
+ </summary>
</member>
- <member name="M:NetSharp.Packets.Builtin.PingPacket.Deserialise(System.ReadOnlyMemory{System.Byte})">
- <inheritdoc />
+ <member name="F:NetSharp.Deprecated.Server.complexPacketHandlers">
+ <summary>
+ Maps a packet type id to the complex packet handler for that packet type.
+ </summary>
</member>
- <member name="M:NetSharp.Packets.Builtin.PingPacket.Serialise">
- <inheritdoc />
+ <member name="F:NetSharp.Deprecated.Server.requestPacketDeserialisers">
+ <summary>
+ Maps a packet type id to the raw packet deserialiser that deserialises raw packets to
+ <see cref="T:NetSharp.Deprecated.IRequestPacket"/> implementors.
+ </summary>
</member>
- <member name="T:NetSharp.Packets.Builtin.PingResponsePacket">
+ <member name="F:NetSharp.Deprecated.Server.serverShutdownCancellationTokenSource">
<summary>
- A response packet for the <see cref="T:NetSharp.Packets.Builtin.PingPacket"/>.
+ Cancellation token source to stop handling client sockets when the server should be shut down.
</summary>
</member>
- <member name="P:NetSharp.Packets.Builtin.PingResponsePacket.RequestPacket">
- <inheritdoc />
+ <member name="F:NetSharp.Deprecated.Server.simplePacketHandlers">
+ <summary>
+ Maps a packet type id to the simple packet handler for that packet type.
+ </summary>
</member>
- <member name="M:NetSharp.Packets.Builtin.PingResponsePacket.AfterDeserialisation">
- <inheritdoc />
+ <member name="M:NetSharp.Deprecated.Server.#ctor">
+ <summary>
+ Initialises a new instance of the <see cref="T:NetSharp.Deprecated.Server"/> class.
+ </summary>
</member>
- <member name="M:NetSharp.Packets.Builtin.PingResponsePacket.BeforeSerialisation">
- <inheritdoc />
+ <member name="M:NetSharp.Deprecated.Server.Finalize">
+ <summary>
+ Destroys an instance of the <see cref="T:NetSharp.Deprecated.Server"/> class.
+ </summary>
</member>
- <member name="M:NetSharp.Packets.Builtin.PingResponsePacket.Deserialise(System.ReadOnlyMemory{System.Byte})">
- <inheritdoc />
+ <member name="T:NetSharp.Deprecated.Server.RawRequestPacketDeserialiser">
+ <summary>
+ Represents a method that receives a raw packet, and deserialises it into an <see cref="T:NetSharp.Deprecated.IRequestPacket"/> implementor.
+ </summary>
+ <param name="rawPacket">The raw packet that was received from the network.</param>
+ <returns>The deserialised instance of the packet.</returns>
</member>
- <member name="M:NetSharp.Packets.Builtin.PingResponsePacket.Serialise">
- <inheritdoc />
+ <member name="M:NetSharp.Deprecated.Server.RegisterInternalPacketHandlers">
+ <summary>
+ Registers packet handlers for every internal library packet.
+ </summary>
</member>
- <member name="T:NetSharp.Packets.Builtin.SimpleDataPacket">
+ <member name="F:NetSharp.Deprecated.Server.PendingConnectionBacklog">
<summary>
- A simple one-time-use data transfer packet, that allows for the transmission of an arbitrary number of frames.
+ The maximum number of connections that are allowed in the connection backlog.
</summary>
</member>
- <member name="F:NetSharp.Packets.Builtin.SimpleDataPacket.RequestBuffer">
+ <member name="F:NetSharp.Deprecated.Server.DefaultNetworkOperationTimeout">
<summary>
- The data that should be transferred across the network.
+ The default timeout value for all network operations.
</summary>
</member>
- <member name="M:NetSharp.Packets.Builtin.SimpleDataPacket.#ctor">
+ <member name="F:NetSharp.Deprecated.Server.serverShutdownCancellationToken">
<summary>
- Initialises a new instance of the <see cref="T:NetSharp.Packets.Builtin.SimpleDataPacket"/> class.
+ The cancellation token that will be set when the server must be shut down.
</summary>
</member>
- <member name="M:NetSharp.Packets.Builtin.SimpleDataPacket.#ctor(System.Memory{System.Byte})">
+ <member name="F:NetSharp.Deprecated.Server.socket">
<summary>
- Initialises a new instance of the <see cref="T:NetSharp.Packets.Builtin.SimpleDataPacket"/> class.
+ The <see cref="T:System.Net.Sockets.Socket"/> underlying the connection.
</summary>
- <param name="buffer">The data that this request packet should contain.</param>
</member>
- <member name="M:NetSharp.Packets.Builtin.SimpleDataPacket.AfterDeserialisation">
- <inheritdoc />
+ <member name="F:NetSharp.Deprecated.Server.socketOptions">
+ <summary>
+ Backing field for the <see cref="P:NetSharp.Deprecated.Server.SocketOptions"/> property.
+ </summary>
</member>
- <member name="M:NetSharp.Packets.Builtin.SimpleDataPacket.BeforeSerialisation">
- <inheritdoc />
+ <member name="F:NetSharp.Deprecated.Server.runServer">
+ <summary>
+ Whether the server should be ran.
+ </summary>
</member>
- <member name="M:NetSharp.Packets.Builtin.SimpleDataPacket.Deserialise(System.ReadOnlyMemory{System.Byte})">
- <inheritdoc />
+ <member name="M:NetSharp.Deprecated.Server.#ctor(System.Net.Sockets.SocketType,System.Net.Sockets.ProtocolType)">
+ <summary>
+ Initialises a new instance of the <see cref="T:NetSharp.Deprecated.Server"/> class.
+ </summary>
+ <param name="socketType">The socket type for the underlying socket.</param>
+ <param name="protocolType">The protocol type for the underlying socket.</param>
+ <param name="socketManager">The <see cref="!:Utils.Socket_Options.SocketOptions"/> implementation to use.</param>
</member>
- <member name="M:NetSharp.Packets.Builtin.SimpleDataPacket.Serialise">
- <inheritdoc />
+ <member name="M:NetSharp.Deprecated.Server.#ctor(System.Net.Sockets.SocketType,System.Net.Sockets.ProtocolType,System.TimeSpan)">
+ <summary>
+ Initialises a new instance of the <see cref="T:NetSharp.Deprecated.Server"/> class.
+ </summary>
+ <param name="socketType">The socket type for the underlying socket.</param>
+ <param name="protocolType">The protocol type for the underlying socket.</param>
+ <param name="socketManager">The <see cref="!:Utils.Socket_Options.SocketOptions"/> manager to use.</param>
+ <param name="networkOperationTimeout">The timeout value for send and receive operations over the network.</param>
</member>
- <member name="T:NetSharp.Packets.NetworkErrorCode">
+ <member name="M:NetSharp.Deprecated.Server.DeserialiseRequestPacket(System.UInt32,NetSharp.Deprecated.SerialisedPacket@)">
<summary>
- Enumerates the possible error codes for network operations, being held in the packet.
+ Deserialises the given <see cref="T:NetSharp.Deprecated.NetworkPacket"/> struct into an <see cref="T:NetSharp.Deprecated.IRequestPacket"/> implementor.
</summary>
+ <param name="packetType">The type id of packet that we should deserialise to.</param>
+ <param name="rawRequestPacket">The packet that should be deserialised.</param>
+ <returns>The deserialised packet instance, cast to the <see cref="T:NetSharp.Deprecated.IRequestPacket"/> interface.</returns>
</member>
- <member name="F:NetSharp.Packets.NetworkErrorCode.Ok">
+ <member name="M:NetSharp.Deprecated.Server.Dispose(System.Boolean)">
<summary>
- Signifies that there was no error during transmission.
+ Disposes of this <see cref="T:NetSharp.Deprecated.Server"/> instance.
</summary>
+ <param name="disposing">Whether this instance is being disposed.</param>
</member>
- <member name="F:NetSharp.Packets.NetworkErrorCode.Error">
+ <member name="M:NetSharp.Deprecated.Server.DoHandleClientAsync(System.Object)">
<summary>
- A generic error occurred during packet transmission.
+ Provides a task that represents the handling of a client. Calls the abstract <see cref="M:NetSharp.Deprecated.Server.HandleClientAsync(NetSharp.Deprecated.Server.ClientHandlerArgs,System.Threading.CancellationToken)"/> method.
</summary>
+ <param name="clientHandlerArgsObj">The object representing the passed <see cref="T:NetSharp.Deprecated.Server.ClientHandlerArgs"/> instance.</param>
</member>
- <member name="T:NetSharp.Packets.NetworkPacket">
+ <member name="M:NetSharp.Deprecated.Server.HandleClientAsync(NetSharp.Deprecated.Server.ClientHandlerArgs,System.Threading.CancellationToken)">
<summary>
- Represents a low-level packet that is transmitted over the network.
+ Handles a client asynchronously.
</summary>
+ <param name="args">The client handler arguments that should be passed to the client handler.</param>
+ <param name="cancellationToken">Cancellation token set when the server is shutting down.</param>
</member>
- <member name="M:NetSharp.Packets.NetworkPacket.#ctor(System.ReadOnlyMemory{System.Byte},NetSharp.Packets.NetworkPacketHeader,NetSharp.Packets.NetworkPacketFooter)">
+ <member name="M:NetSharp.Deprecated.Server.HandleRequestPacket(System.UInt32,NetSharp.Deprecated.IRequestPacket@,System.Net.EndPoint@)">
<summary>
- Initialises a new instance of the <see cref="T:NetSharp.Packets.NetworkPacket"/> struct.
+ Handles the given request packet with a registered packet handler. In this case, a complex packet handler
+ will override any registered simple packet handlers.
</summary>
- <param name="data">The data that should be transmitted in the packet.</param>
- <param name="header">The header for the packet.</param>
- <param name="footer">The footer for the packet.</param>
+ <param name="packetType">The type id of the packet that we should handle.</param>
+ <param name="requestPacket">The packet instance that should be handled.</param>
+ <param name="remoteEndPoint">The remote endpoint from which the request packet originated.</param>
+ <returns>The response packet that should be sent back to the remote endpoint.</returns>
</member>
- <member name="F:NetSharp.Packets.NetworkPacket.DataSegmentSize">
+ <member name="M:NetSharp.Deprecated.Server.OnClientConnected(System.Net.EndPoint)">
<summary>
- The number of bytes allocated in each packet for user data.
+ Invokes the <see cref="E:NetSharp.Deprecated.Server.ClientConnected"/> event.
</summary>
+ <param name="remoteEndPoint">The remote endpoint with which a connection was made.</param>
</member>
- <member name="F:NetSharp.Packets.NetworkPacket.FooterSize">
+ <member name="M:NetSharp.Deprecated.Server.OnClientDisconnected(System.Net.EndPoint)">
<summary>
- The number of bytes taken up in each packet by its footer.
+ Invokes the <see cref="E:NetSharp.Deprecated.Server.ClientDisconnected"/> event.
</summary>
+ <param name="remoteEndPoint">The remote endpoint with which a connection was lost.</param>
</member>
- <member name="F:NetSharp.Packets.NetworkPacket.HeaderSize">
+ <member name="M:NetSharp.Deprecated.Server.OnServerStarted">
<summary>
- The number of bytes taken up in each packet by its header.
+ Invokes the <see cref="E:NetSharp.Deprecated.Server.ServerStarted"/> event.
</summary>
</member>
- <member name="F:NetSharp.Packets.NetworkPacket.PacketSize">
+ <member name="M:NetSharp.Deprecated.Server.OnServerStopped">
<summary>
- The size of each packet, including its header, footer, and data segment.
+ Invokes the <see cref="E:NetSharp.Deprecated.Server.ServerStopped"/> event.
</summary>
</member>
- <member name="F:NetSharp.Packets.NetworkPacket.DataBuffer">
+ <member name="M:NetSharp.Deprecated.Server.TryBind(System.Net.EndPoint,System.TimeSpan)">
<summary>
- The data held in this packet.
+ Attempts to synchronously bind the underlying socket to the given local endpoint. Blocks.
+ If the timeout is exceeded the binding attempt is aborted and the method returns false.
</summary>
+ <param name="localEndPoint">The local endpoint to bind to.</param>
+ <param name="timeout">The timeout within which to attempt the binding.</param>
+ <returns>Whether the binding was successful or not.</returns>
</member>
- <member name="M:NetSharp.Packets.NetworkPacket.#ctor(System.ReadOnlyMemory{System.Byte},System.Int32,System.UInt32,NetSharp.Packets.NetworkErrorCode,System.Boolean)">
+ <member name="M:NetSharp.Deprecated.Server.TryBindAsync(System.Net.EndPoint,System.TimeSpan)">
<summary>
- Initialises a new instance of the <see cref="T:NetSharp.Packets.NetworkPacket"/> struct.
+ Attempts to asynchronously bind the underlying socket to the given local endpoint. Does not block.
+ If the timeout is exceeded the binding attempt is aborted and the method returns false.
</summary>
- <param name="data">The data that should be transmitted in the packet.</param>
- <param name="dataLength">The number of bytes that are held in the given data buffer.</param>
- <param name="type">The packet type.</param>
- <param name="errorCode">The error code associated with this transmission.</param>
- <param name="hasSucceedingPacket">Whether this packet has a succeeding packet in the packet chain.</param>
+ <param name="localEndPoint">The local endpoint to bind to.</param>
+ <param name="timeout">The timeout within which to attempt the binding.</param>
+ <returns>Whether the binding was successful or not.</returns>
</member>
- <member name="M:NetSharp.Packets.NetworkPacket.Deserialise(System.Memory{System.Byte})">
+ <member name="T:NetSharp.Deprecated.Server.ClientHandlerArgs">
<summary>
- Deserialises the given buffer into a packet instance.
+ Holds information about the arguments passed to every client handler task.
</summary>
- <param name="buffer">The byte buffer to serialise.</param>
- <returns>The deserialised packet instance.</returns>
</member>
- <member name="M:NetSharp.Packets.NetworkPacket.Serialise(NetSharp.Packets.NetworkPacket)">
+ <member name="M:NetSharp.Deprecated.Server.ClientHandlerArgs.#ctor(System.Net.EndPoint,System.Net.Sockets.Socket)">
<summary>
- Serialises the given packet instance to a new byte buffer.
+ Initialises a new instance of the <see cref="T:NetSharp.Deprecated.Server.ClientHandlerArgs"/> struct.
</summary>
- <param name="instance">The packet instance to serialise.</param>
- <returns>The byte buffer that represents the packet instance.</returns>
+ <param name="remoteEndPoint">The remote endpoint of the client that should be handled.</param>
+ <param name="handlerSocket">The handler socket of the client that should be handled.</param>
</member>
- <member name="M:NetSharp.Packets.NetworkPacket.SerialiseToBuffer(System.Memory{System.Byte},NetSharp.Packets.NetworkPacket)">
+ <member name="F:NetSharp.Deprecated.Server.ClientHandlerArgs.ClientEndPoint">
<summary>
- Serialises the given packet instance into the given byte buffer.
+ The remote endpoint for the client being handled.
</summary>
- <param name="buffer">
- The buffer to which the instance should be serialised. Must be at least of size <see cref="F:NetSharp.Packets.NetworkPacket.PacketSize"/>.
- </param>
- <param name="instance">The packet instance to serialise.</param>
- <exception cref="T:System.ArgumentException">Thrown if the given buffer is too small.</exception>
</member>
- <member name="F:NetSharp.Packets.NetworkPacketFooter.Size">
+ <member name="F:NetSharp.Deprecated.Server.ClientHandlerArgs.ClientSocket">
<summary>
- The number of bytes taken up by a packet footer.
+ The client handler socket for the client being handled. Is only set if using TCP.
</summary>
</member>
- <member name="F:NetSharp.Packets.NetworkPacketHeader.Size">
+ <member name="M:NetSharp.Deprecated.Server.ClientHandlerArgs.ForTcpClientHandler(System.Net.Sockets.Socket@)">
<summary>
- The number of bytes taken up by a packet header.
+ Constructs a new instance of the <see cref="T:NetSharp.Deprecated.Server.ClientHandlerArgs"/> for a TCP client.
</summary>
+ <returns>A new instance of the <see cref="T:NetSharp.Deprecated.Server.ClientHandlerArgs"/>, setup for a TCP client.</returns>
</member>
- <member name="F:NetSharp.Packets.NetworkPacketHeader.DataLength">
+ <member name="M:NetSharp.Deprecated.Server.ClientHandlerArgs.ForUdpClientHandler(System.Net.EndPoint@)">
<summary>
- The number of bytes of data held in the packet.
+ Constructs a new instance of the <see cref="T:NetSharp.Deprecated.Server.ClientHandlerArgs"/> for a UDP client.
</summary>
+ <returns>A new instance of the <see cref="T:NetSharp.Deprecated.Server.ClientHandlerArgs"/>, setup for a UDP client.</returns>
</member>
- <member name="F:NetSharp.Packets.NetworkPacketHeader.ErrorCode">
+ <member name="E:NetSharp.Deprecated.Server.ClientConnected">
<summary>
- The error code for this packet.
+ Signifies that a connection with a remote endpoint has been made.
</summary>
</member>
- <member name="F:NetSharp.Packets.NetworkPacketHeader.Type">
+ <member name="E:NetSharp.Deprecated.Server.ClientDisconnected">
<summary>
- The packet type.
+ Signifies that a connection with a remote endpoint has been lost.
</summary>
</member>
- <member name="T:NetSharp.Packets.PacketRegistry">
+ <member name="E:NetSharp.Deprecated.Server.ServerStarted">
<summary>
- Provides method of registering request packets and their relevant response packets, as well as mapping their ids.
+ Signifies that the server was started and clients will start being accepted.
</summary>
</member>
- <member name="F:NetSharp.Packets.PacketRegistry.AutomaticPacketTypeIdStartPoint">
+ <member name="E:NetSharp.Deprecated.Server.ServerStopped">
<summary>
- The start id for automatically generated packet type ids. Any custom packet type ids lower than this value
- that come from external assemblies will be incremented by this value, to ensure that there are no clashes.
+ Signifies that the server was stopped and clients will stop being accepted.
</summary>
</member>
- <member name="F:NetSharp.Packets.PacketRegistry.currentAutomaticPacketTypeIdCounterLockObject">
+ <member name="P:NetSharp.Deprecated.Server.NetworkOperationTimeout">
<summary>
- The lock object for synchronising access to the <see cref="F:NetSharp.Packets.PacketRegistry.currentAutomaticPacketTypeIdCounter"/> field.
+ The timeout value for network operations such as sending bytes or receiving bytes over the network.
</summary>
</member>
- <member name="F:NetSharp.Packets.PacketRegistry.idToPacketTypeMap">
+ <member name="P:NetSharp.Deprecated.Server.SocketOptions">
<summary>
- Maps a packet type id to its relevant packet type, and vice-versa.
+ The configured socket options for the underlying connection.
</summary>
</member>
- <member name="F:NetSharp.Packets.PacketRegistry.LibraryAssembly">
+ <member name="M:NetSharp.Deprecated.Server.RunAsync(System.Net.EndPoint)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.Server.Shutdown">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.Server.TryDeregisterComplexPacketHandler``2(NetSharp.Deprecated.ComplexPacketHandler{``0,``1}@)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.Server.TryDeregisterSimplePacketHandler``1(NetSharp.Deprecated.SimplePacketHandler{``0}@)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.Server.TryRegisterComplexPacketHandler``2(NetSharp.Deprecated.ComplexPacketHandler{``0,``1})">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.Server.TryRegisterSimplePacketHandler``1(NetSharp.Deprecated.SimplePacketHandler{``0})">
+ <inheritdoc />
+ </member>
+ <member name="T:NetSharp.Deprecated.ServerClientConnection">
<summary>
- The assembly that represents the library, where all of the builtin packets are defined.
+ Base class for connections, holding methods shared between the <see cref="T:NetSharp.Deprecated.Client"/> and <see cref="T:NetSharp.Deprecated.Server"/> classes.
</summary>
</member>
- <member name="F:NetSharp.Packets.PacketRegistry.requestToResponseMap">
+ <member name="F:NetSharp.Deprecated.ServerClientConnection.logger">
<summary>
- Maps a request packet to its relevant response packet, and vice-versa.
+ The logger to which the server can log messages.
</summary>
</member>
- <member name="F:NetSharp.Packets.PacketRegistry.currentAutomaticPacketTypeIdCounter">
+ <member name="M:NetSharp.Deprecated.ServerClientConnection.#ctor">
<summary>
- The current id for registered packets.
+ Initialises a new instance of the <see cref="T:NetSharp.Deprecated.ServerClientConnection"/> class.
</summary>
</member>
- <member name="M:NetSharp.Packets.PacketRegistry.GetNewPacketTypeId(System.Type)">
+ <member name="M:NetSharp.Deprecated.ServerClientConnection.Dispose(System.Boolean)">
<summary>
- Fetches the packet type id of the given packet type. If the packet type is declared outside of the library
- assembly, then its value is incremented by the <see cref="F:NetSharp.Packets.PacketRegistry.AutomaticPacketTypeIdStartPoint"/> value. This ensure that
- there are no clashes between the packet type ids of packets declared in the library and external packets.
+ Disposes of this <see cref="T:NetSharp.Deprecated.ServerClientConnection"/> instance.
</summary>
- <param name="packetType">The packet type whose id should be fetched.</param>
- <returns>The id of the given packet type.</returns>
+ <param name="disposing">Whether this instance is being disposed.</param>
</member>
- <member name="M:NetSharp.Packets.PacketRegistry.DeregisterPacketType(System.Type,System.Type)">
+ <member name="M:NetSharp.Deprecated.ServerClientConnection.OnBytesReceived(System.Net.EndPoint,System.Int32)">
<summary>
- Deregisters the given packet type from the registry.
+ Invokes the <see cref="E:NetSharp.Deprecated.ServerClientConnection.BytesReceived"/> event.
</summary>
- <param name="requestPacketType">The request packet type to deregister, if it is registered.</param>
- <param name="responsePacketType">The response packet associated with the request packet.</param>
+ <param name="remoteEndPoint">The remote endpoint from which the bytes were received.</param>
+ <param name="bytesReceived">The number of bytes that were received from the remote endpoint.</param>
</member>
- <member name="M:NetSharp.Packets.PacketRegistry.DeregisterPacketTypes(System.Collections.Generic.Dictionary{System.Type,System.Type})">
+ <member name="M:NetSharp.Deprecated.ServerClientConnection.OnBytesSent(System.Net.EndPoint,System.Int32)">
<summary>
- Deregisters the given packet types from the registry.
+ Invokes the <see cref="E:NetSharp.Deprecated.ServerClientConnection.BytesSent"/> event.
</summary>
- <param name="requestToResponsePacketTypeMap">The list of packet types to deregister, if they are registered.</param>
+ <param name="remoteEndPoint">The remote endpoint to which the bytes were sent.</param>
+ <param name="bytesSent">The number of bytes that were sent to the remote endpoint.</param>
</member>
- <member name="M:NetSharp.Packets.PacketRegistry.GetPacketId(System.Type)">
+ <member name="E:NetSharp.Deprecated.ServerClientConnection.BytesReceived">
<summary>
- Returns the packet type id associated with the given packet type.
+ Signifies that some data has been received from the remote endpoint.
</summary>
- <param name="packetType">The packet type whose id to fetch.</param>
- <returns>The id of the packet type given.</returns>
</member>
- <member name="M:NetSharp.Packets.PacketRegistry.GetPacketId``1">
+ <member name="E:NetSharp.Deprecated.ServerClientConnection.BytesSent">
<summary>
- Returns the packet type id associated with the given packet type.
+ Signifies that some data was sent to the remote endpoint.
</summary>
- <typeparam name="TPacket">The packet type whose id to fetch.</typeparam>
- <returns>The id of the packet type given.</returns>
</member>
- <member name="M:NetSharp.Packets.PacketRegistry.GetPacketType(System.UInt32)">
+ <member name="M:NetSharp.Deprecated.ServerClientConnection.ChangeLoggingStream(System.IO.Stream,NetSharp.Deprecated.LogLevel)">
<summary>
- Returns the packet type associated with the given id.
+ Makes the client log to the given stream.
</summary>
- <param name="packetTypeId">The packet id whose mapped type to fetch.</param>
- <returns>The packet type mapped by the given id.</returns>
+ <param name="loggingStream">The stream that new messages should be logged to.</param>
+ <param name="minimumMessageSeverityLevel">
+ The minimum severity level that new messages must have to be logged to the stream.
+ </param>
+ </member>
+ <member name="M:NetSharp.Deprecated.ServerClientConnection.Dispose">
+ <inheritdoc />
</member>
- <member name="M:NetSharp.Packets.PacketRegistry.GetRequestPacketType``1">
+ <member name="T:NetSharp.Deprecated.ServerExtensions">
<summary>
- Returns the type of request packet mapped by the given response packet type.
+ Provides additional methods and functionality to the <see cref="T:NetSharp.Deprecated.Server"/> class.
</summary>
- <typeparam name="TResponse">The response packet type whose request packet type to fetch.</typeparam>
- <returns>The request packet type, <c>null</c> if no type is mapped.</returns>
</member>
- <member name="M:NetSharp.Packets.PacketRegistry.GetRequestPacketType(System.Type)">
+ <member name="M:NetSharp.Deprecated.ServerExtensions.Run(NetSharp.Deprecated.Server,System.Net.IPAddress,System.Int32)">
<summary>
- Returns the type of request packet mapped by the given response packet type.
+ Starts the server synchronously and starts accepting client connections. Blocks.
</summary>
- <param name="responsePacketType">The response packet type whose request packet type to fetch.</param>
- <returns>The request packet type, <c>null</c> if no type is mapped.</returns>
+ <param name="instance">The instance on which this extension method should be called.</param>
+ <param name="localAddress">The local IP address to bind to.</param>
+ <param name="localPort">The local port to bind to.</param>
</member>
- <member name="M:NetSharp.Packets.PacketRegistry.GetResponsePacketType``1">
+ <member name="M:NetSharp.Deprecated.ServerExtensions.Run(NetSharp.Deprecated.Server,System.Net.IPAddress)">
<summary>
- Returns the type of response packet mapped by the given request packet type.
+ Starts the server synchronously and starts accepting client connections. Blocks. Uses the default connection port.
</summary>
- <typeparam name="TRequest">The request packet type whose response packet type to fetch.</typeparam>
- <returns>The response packet type, <c>null</c> if no type is mapped.</returns>
+ <param name="instance">The instance on which this extension method should be called.</param>
+ <param name="localAddress">The local IP address to bind to.</param>
</member>
- <member name="M:NetSharp.Packets.PacketRegistry.GetResponsePacketType(System.Type)">
+ <member name="M:NetSharp.Deprecated.ServerExtensions.RunAsync(NetSharp.Deprecated.Server,System.Net.IPAddress)">
<summary>
- Returns the type of response packet mapped by the given request packet type.
+ Starts the server asynchronously and starts accepting client connections. Does not block. Uses the default
+ connection port.
</summary>
- <param name="requestPacketType">The request packet type whose response packet type to fetch.</param>
- <returns>The response packet type, <c>null</c> if no type is mapped.</returns>
+ <param name="instance">The instance on which this extension method should be called.</param>
+ <param name="localAddress">The local IP address to bind to.</param>
</member>
- <member name="M:NetSharp.Packets.PacketRegistry.RegisterPacketSourceAssemblies(System.Reflection.Assembly[])">
+ <member name="M:NetSharp.Deprecated.ServerExtensions.RunAsync(NetSharp.Deprecated.Server,System.Net.IPAddress,System.Int32)">
<summary>
- Rebuilds the packet registry, by registering every <see cref="T:NetSharp.Deprecated.IPacket"/> inheritor in the given assemblies.
+ Starts the server asynchronously and starts accepting client connections. Does not block.
</summary>
- <param name="packetSourceAssemblies">
- The assemblies from which the packet types to register are sourced.
- </param>
+ <param name="instance">The instance on which this extension method should be called.</param>
+ <param name="localAddress">The local IP address to bind to.</param>
+ <param name="localPort">The local port to bind to.</param>
</member>
- <member name="M:NetSharp.Packets.PacketRegistry.RegisterPacketSourceAssembly(System.Reflection.Assembly)">
+ <member name="T:NetSharp.Deprecated.SocketAcceptor">
<summary>
- Registers all the <see cref="T:NetSharp.Deprecated.IPacket"/> implementors in the given assembly.
+ Helper class providing awaitable wrappers around asynchronous Accept, Connect, and Disconnect operations.
</summary>
- <param name="packetSourceAssembly">The assembly whose packet types to register.</param>
</member>
- <member name="M:NetSharp.Packets.PacketRegistry.RegisterPacketType(System.Type,System.Type)">
+ <member name="M:NetSharp.Deprecated.SocketAcceptor.AcceptAsync(System.Net.Sockets.Socket,System.Threading.CancellationToken)">
<summary>
- Registers the given packet type to the registry.
+ Provides an awaitable wrapper around an asynchronous socket accept operation.
</summary>
- <param name="requestPacketType">The request packet type to register, if it is not registered.</param>
- <param name="responsePacketType">The response packet associated with the request packet.</param>
+ <param name="socket">The socket which should be used to accept an incoming connection attempt.</param>
+ <param name="cancellationToken">The cancellation token to observe for the operation.</param>
+ <returns>The accepted socket.</returns>
</member>
- <member name="M:NetSharp.Packets.PacketRegistry.RegisterPacketTypes(System.Collections.Generic.Dictionary{System.Type,System.Type})">
+ <member name="M:NetSharp.Deprecated.SocketAcceptor.ConnectAsync(System.Net.Sockets.Socket,System.Net.EndPoint,System.Threading.CancellationToken)">
<summary>
- Registers the given packet types to the registry.
+ Provides an awaitable wrapper around an asynchronous socket connect operation.
</summary>
- <param name="requestToResponsePacketTypeMap">
- The dictionary mapping the request packet types to register, to their relevant response packet types.
- The response packet type can be null; then the request packet type is treated as a 'simple' packet.
- </param>
+ <param name="socket">The socket which should asynchronously connect to the remote endpoint.</param>
+ <param name="remoteEndPoint">The remote endpoint to which the socket should connect.</param>
+ <param name="cancellationToken">The cancellation token to observe for the operation.</param>
</member>
- <member name="M:NetSharp.Packets.PacketRegistry.#cctor">
+ <member name="M:NetSharp.Deprecated.SocketAcceptor.DisconnectAsync(System.Net.Sockets.Socket,System.Threading.CancellationToken)">
<summary>
- Initialises a new instance of the <see cref="T:NetSharp.Packets.PacketRegistry"/> class.
+ Provides an awaitable wrapper around an asynchronous socket disconnect operation.
</summary>
+ <param name="socket">The socket which should asynchronously disconnect from its remote endpoint.</param>
+ <param name="cancellationToken">The cancellation token to observe for the operation.</param>
</member>
- <member name="T:NetSharp.Packets.PacketTypeIdAttribute">
+ <member name="M:NetSharp.Deprecated.SocketClient.Finalize">
<summary>
- Allows the placing of a custom packet type on a class or struct. This is used if the class or struct
- inherits from <see cref="T:NetSharp.Deprecated.IRequestPacket"/> or <see cref="T:NetSharp.Deprecated.IResponsePacket`1"/>.
+ Destroys a socket client instance.
</summary>
</member>
- <member name="M:NetSharp.Packets.PacketTypeIdAttribute.#ctor(System.UInt32)">
+ <member name="M:NetSharp.Deprecated.SocketClient.Dispose(System.Boolean)">
<summary>
- Initialises a new instance of the <see cref="T:NetSharp.Packets.PacketTypeIdAttribute"/> attribute.
+ Implementation of dispose pattern.
</summary>
- <param name="type">The custom type id that the decorated packet type should have.</param>
+ <param name="disposing">
+ Whether this method is being called by the object finalizer, or by the <see cref="M:NetSharp.Deprecated.SocketClient.Dispose"/> method.
+ </param>
</member>
- <member name="P:NetSharp.Packets.PacketTypeIdAttribute.Id">
+ <member name="M:NetSharp.Deprecated.SocketClient.Dispose">
+ <inheritdoc />
+ </member>
+ <member name="T:NetSharp.Deprecated.SocketOperations">
<summary>
- The custom type id that the decorated packet type should have. This overrides the automatically generated id.
+ Provides helper awaitable functions for wrapping the <see cref="T:System.Net.Sockets.SocketAsyncEventArgs"/> pattern.
</summary>
</member>
- <member name="T:NetSharp.Pipelines.PacketPipeline`3">
+ <member name="T:NetSharp.Deprecated.SocketOptions">
<summary>
- Represents a pipeline of transformations that packets must undergo.
+ Allows for manipulation of socket options.
</summary>
- <typeparam name="TInput">The type of packet the pipeline receives.</typeparam>
- <typeparam name="TIntermediate">The type of packet the pipeline internally handles.</typeparam>
- <typeparam name="TOutput">The type of packet the pipeline outputs.</typeparam>
</member>
- <member name="M:NetSharp.Pipelines.PacketPipeline`3.ProcessPacket(`0)">
+ <member name="F:NetSharp.Deprecated.SocketOptions.managedSocket">
<summary>
- Passes the given packet through the pipeline.
+ The <see cref="T:System.Net.Sockets.Socket"/> instance whose settings are being managed.
</summary>
- <param name="inputPacket">The incoming packet.</param>
- <returns>The outgoing transformed packet.</returns>
</member>
- <member name="T:NetSharp.Pipelines.PacketPipelineStage`2">
+ <member name="M:NetSharp.Deprecated.SocketOptions.#ctor(System.Net.Sockets.Socket@)">
<summary>
- Represents a single transformation applied to a packet traveling through the pipeline.
+ Initialises a new instance of the <see cref="T:NetSharp.Deprecated.SocketOptions"/> class.
</summary>
- <typeparam name="TInput">The type the transformation takes as input.</typeparam>
- <typeparam name="TOutput">The type the transformation produces as output.</typeparam>
+ <param name="socket">The <see cref="T:System.Net.Sockets.Socket"/> instance whose options should be managed.</param>
</member>
- <member name="T:NetSharp.Pipelines.PacketPipelineBuilder`3">
+ <member name="P:NetSharp.Deprecated.SocketOptions.DualMode">
<summary>
- Allows for configuring and subsequently building a <see cref="T:NetSharp.Pipelines.PacketPipeline`3"/> instance.
+ Whether this <see cref="T:System.Net.Sockets.Socket"/> can operate in dual IPv4 / IPv6 mode.
</summary>
- <typeparam name="TInput">The type of packet that will be submitted to the pipeline.</typeparam>
- <typeparam name="TIntermediate">The type of packet that will be handled internally by the pipeline.</typeparam>
- <typeparam name="TOutput">The type of packet that will be requested from the pipeline.</typeparam>
</member>
- <member name="M:NetSharp.Pipelines.PacketPipelineBuilder`3.Build">
+ <member name="P:NetSharp.Deprecated.SocketOptions.ForceFlush">
<summary>
- Returns the currently configured <see cref="T:NetSharp.Pipelines.PacketPipeline`3"/> instance.
+ Whether sending a packet flushes underlying <see cref="T:System.Net.Sockets.NetworkStream"/>.
</summary>
- <returns>The configured <see cref="T:NetSharp.Pipelines.PacketPipeline`3"/> instance.</returns>
- <exception cref="T:System.ArgumentNullException">
- Thrown when either <see cref="M:NetSharp.Pipelines.PacketPipelineBuilder`3.WithInputStage(System.Func{`0,`1}@)"/> or <see cref="M:NetSharp.Pipelines.PacketPipelineBuilder`3.WithOutputStage(System.Func{`1,`2}@)"/> have not been called.
- </exception>
+ <remarks>
+ This value is only used in a <see cref="T:System.Net.Sockets.TcpClient"/> instance, which uses a <see cref="T:System.Net.Sockets.NetworkStream"/>
+ to send and receive data. A <see cref="T:System.Net.Sockets.UdpClient"/> is unaffected by this value.
+ </remarks>
</member>
- <member name="M:NetSharp.Pipelines.PacketPipelineBuilder`3.WithInputStage(System.Func{`0,`1}@)">
+ <member name="P:NetSharp.Deprecated.SocketOptions.Fragment">
<summary>
- Configures the input stage for the pipeline.
+ Whether this <see cref="T:System.Net.Sockets.Socket"/> is allowed to fragment frames that are too large to send in one go.
</summary>
- <param name="stage">
- The transformation that should be applied to incoming packets, to convert them from the <typeparamref name="TInput"/>
- type to the <typeparamref name="TIntermediate"/> type that the pipeline handles internally.
- </param>
- <returns>The builder instance for further configuration.</returns>
</member>
- <member name="M:NetSharp.Pipelines.PacketPipelineBuilder`3.WithIntermediateStage(System.Func{`1,`1}@)">
+ <member name="P:NetSharp.Deprecated.SocketOptions.HopLimit">
<summary>
- Adds the given intermediate stage to the pipeline.
+ The hop limit for packets sent by this <see cref="T:System.Net.Sockets.Socket"/>. Comparable to IPv4s TTL (Time To Live).
</summary>
- <param name="stage">
- The transformation that should be applied to packets traveling through the pipeline.
- </param>
- <returns>The builder instance for further configuration.</returns>
</member>
- <member name="M:NetSharp.Pipelines.PacketPipelineBuilder`3.WithOutputStage(System.Func{`1,`2}@)">
+ <member name="P:NetSharp.Deprecated.SocketOptions.IsChecksumEnabled">
<summary>
- Configures the output stage for the pipeline.
+ Whether a checksum should be created for each UDP packet sent.
</summary>
- <param name="stage">
- The transformation that should be applied to outgoing packets, to convert them from the
- <typeparamref name="TIntermediate"/> type used internally to the <typeparamref name="TOutput"/> type.
- </param>
- <returns>The builder instance for further configuration.</returns>
</member>
- <member name="T:NetSharp.Sockets.SocketAcceptor">
+ <member name="P:NetSharp.Deprecated.SocketOptions.IsRoutingEnabled">
<summary>
- Helper class providing awaitable wrappers around asynchronous Accept, Connect, and Disconnect operations.
+ Whether the packet should be sent directly to its destination or allowed to be routed through multiple destinations
+ first.
</summary>
</member>
- <member name="M:NetSharp.Sockets.SocketAcceptor.AcceptAsync(System.Net.Sockets.Socket,System.Threading.CancellationToken)">
+ <member name="P:NetSharp.Deprecated.SocketOptions.LocalEndPoint">
<summary>
- Provides an awaitable wrapper around an asynchronous socket accept operation.
+ The local <see cref="T:System.Net.EndPoint"/> for the <see cref="F:NetSharp.Deprecated.SocketOptions.managedSocket"/>.
</summary>
- <param name="socket">The socket which should be used to accept an incoming connection attempt.</param>
- <param name="cancellationToken">The cancellation token to observe for the operation.</param>
- <returns>The accepted socket.</returns>
</member>
- <member name="M:NetSharp.Sockets.SocketAcceptor.ConnectAsync(System.Net.Sockets.Socket,System.Net.EndPoint,System.Threading.CancellationToken)">
+ <member name="P:NetSharp.Deprecated.SocketOptions.LocalIPEndPoint">
<summary>
- Provides an awaitable wrapper around an asynchronous socket connect operation.
+ The local <see cref="T:System.Net.IPEndPoint"/> for this <see cref="T:System.Net.Sockets.Socket"/> instance.
</summary>
- <param name="socket">The socket which should asynchronously connect to the remote endpoint.</param>
- <param name="remoteEndPoint">The remote endpoint to which the socket should connect.</param>
- <param name="cancellationToken">The cancellation token to observe for the operation.</param>
</member>
- <member name="M:NetSharp.Sockets.SocketAcceptor.DisconnectAsync(System.Net.Sockets.Socket,System.Threading.CancellationToken)">
+ <member name="P:NetSharp.Deprecated.SocketOptions.RemoteEndPoint">
<summary>
- Provides an awaitable wrapper around an asynchronous socket disconnect operation.
+ The remote <see cref="T:System.Net.EndPoint"/> for the <see cref="F:NetSharp.Deprecated.SocketOptions.managedSocket"/>.
</summary>
- <param name="socket">The socket which should asynchronously disconnect from its remote endpoint.</param>
- <param name="cancellationToken">The cancellation token to observe for the operation.</param>
</member>
- <member name="M:NetSharp.Sockets.SocketClient.Finalize">
+ <member name="P:NetSharp.Deprecated.SocketOptions.RemoteIPEndPoint">
<summary>
- Destroys a socket client instance.
+ The remote <see cref="T:System.Net.IPEndPoint"/> that this <see cref="T:System.Net.Sockets.Socket"/> instance communicates with.
</summary>
</member>
- <member name="M:NetSharp.Sockets.SocketClient.Dispose(System.Boolean)">
+ <member name="P:NetSharp.Deprecated.SocketOptions.Ttl">
<summary>
- Implementation of dispose pattern.
+ The 'Time To Live' for this <see cref="T:System.Net.Sockets.Socket"/>.
</summary>
- <param name="disposing">
- Whether this method is being called by the object finalizer, or by the <see cref="M:NetSharp.Sockets.SocketClient.Dispose"/> method.
- </param>
- </member>
- <member name="M:NetSharp.Sockets.SocketClient.Dispose">
- <inheritdoc />
</member>
- <member name="T:NetSharp.Sockets.SocketOperations">
+ <member name="P:NetSharp.Deprecated.SocketOptions.UseLoopback">
<summary>
- Provides helper awaitable functions for wrapping the <see cref="T:System.Net.Sockets.SocketAsyncEventArgs"/> pattern.
+ Whether this <see cref="T:System.Net.Sockets.Socket"/> should use a loopback address and bypass hardware.
</summary>
</member>
- <member name="T:NetSharp.Sockets.SocketReader">
+ <member name="T:NetSharp.Deprecated.SocketReader">
<summary>
Helper class providing awaitable wrappers around asynchronous Receive and ReceiveFrom operations.
</summary>
</member>
- <member name="M:NetSharp.Sockets.SocketReader.ReceiveFromAsync(System.Net.Sockets.Socket,System.Net.EndPoint,System.Net.Sockets.SocketFlags,System.Memory{System.Byte},System.Threading.CancellationToken)">
+ <member name="M:NetSharp.Deprecated.SocketReader.ReceiveFromAsync(System.Net.Sockets.Socket,System.Net.EndPoint,System.Net.Sockets.SocketFlags,System.Memory{System.Byte},System.Threading.CancellationToken)">
<summary>
Provides an awaitable wrapper around an asynchronous socket receive operation.
</summary>
@@ -2079,33 +1982,33 @@
<param name="cancellationToken">The cancellation token to observe for the operation.</param>
<returns>The result of the receive operation.</returns>
</member>
- <member name="M:NetSharp.Sockets.SocketServer.Finalize">
+ <member name="M:NetSharp.Deprecated.SocketServer.Finalize">
<summary>
Destroys a socket server instance.
</summary>
</member>
- <member name="F:NetSharp.Sockets.SocketServer.listenerSocket">
+ <member name="F:NetSharp.Deprecated.SocketServer.listenerSocket">
<summary>
The socket which should be used to listen for incoming data and to send outgoing data.
</summary>
</member>
- <member name="M:NetSharp.Sockets.SocketServer.Dispose(System.Boolean)">
+ <member name="M:NetSharp.Deprecated.SocketServer.Dispose(System.Boolean)">
<summary>
Implementation of dispose pattern.
</summary>
<param name="disposing">
- Whether this method is being called by the object finalizer, or by the <see cref="M:NetSharp.Sockets.SocketServer.Dispose"/> method.
+ Whether this method is being called by the object finalizer, or by the <see cref="M:NetSharp.Deprecated.SocketServer.Dispose"/> method.
</param>
</member>
- <member name="M:NetSharp.Sockets.SocketServer.Dispose">
+ <member name="M:NetSharp.Deprecated.SocketServer.Dispose">
<inheritdoc />
</member>
- <member name="T:NetSharp.Sockets.SocketWriter">
+ <member name="T:NetSharp.Deprecated.SocketWriter">
<summary>
Helper class providing awaitable wrappers around asynchronous Send and SendTo operations.
</summary>
</member>
- <member name="M:NetSharp.Sockets.SocketWriter.SendToAsync(System.Net.Sockets.Socket,System.Net.EndPoint,System.Net.Sockets.SocketFlags,System.Memory{System.Byte},System.Threading.CancellationToken)">
+ <member name="M:NetSharp.Deprecated.SocketWriter.SendToAsync(System.Net.Sockets.Socket,System.Net.EndPoint,System.Net.Sockets.SocketFlags,System.Memory{System.Byte},System.Threading.CancellationToken)">
<summary>
Provides an awaitable wrapper around an asynchronous socket send operation.
</summary>
@@ -2116,62 +2019,180 @@
<param name="cancellationToken">The cancellation token to observe for the operation.</param>
<returns>The number of bytes of data which were written to the remote endpoint.</returns>
</member>
- <member name="T:NetSharp.Utils.BiDictionary`2">
+ <member name="T:NetSharp.Deprecated.TcpClient">
+ <summary>
+ Provides methods for TCP communication with a connected <see cref="T:NetSharp.Deprecated.TcpServer"/> instance.
+ </summary>
+ </member>
+ <member name="M:NetSharp.Deprecated.TcpClient.#ctor">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.TcpClient.SendBytesAsync(System.Byte[],System.TimeSpan)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.TcpClient.SendBytesWithResponseAsync(System.Byte[],System.TimeSpan)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.TcpClient.SendComplexAsync``2(``0,System.TimeSpan)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.TcpClient.SendSimpleAsync``1(``0,System.TimeSpan)">
+ <inheritdoc />
+ </member>
+ <member name="T:NetSharp.Deprecated.TcpServer">
+ <summary>
+ Provides methods for TCP communication with connected <see cref="T:NetSharp.Deprecated.TcpClient"/> instances.
+ </summary>
+ </member>
+ <member name="M:NetSharp.Deprecated.TcpServer.HandleClientAsync(NetSharp.Deprecated.Server.ClientHandlerArgs,System.Threading.CancellationToken)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.TcpServer.#ctor(System.TimeSpan)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.TcpServer.#ctor">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.TcpServer.RunAsync(System.Net.EndPoint)">
+ <inheritdoc />
+ </member>
+ <member name="T:NetSharp.Deprecated.TcpSocketOptions">
+ <summary>
+ Allows for manipulation of TCP socket options.
+ </summary>
+ </member>
+ <member name="M:NetSharp.Deprecated.TcpSocketOptions.#ctor(System.Net.Sockets.Socket@)">
+ <inheritdoc />
+ </member>
+ <member name="P:NetSharp.Deprecated.TcpSocketOptions.HopLimit">
+ <inheritdoc />
+ </member>
+ <member name="P:NetSharp.Deprecated.TcpSocketOptions.IsRoutingEnabled">
+ <inheritdoc />
+ </member>
+ <member name="P:NetSharp.Deprecated.TcpSocketOptions.UseLoopback">
+ <inheritdoc />
+ </member>
+ <member name="T:NetSharp.Deprecated.UdpClient">
+ <summary>
+ Provides methods for UDP communication with a connected <see cref="T:NetSharp.Deprecated.UdpServer"/> instance.
+ </summary>
+ </member>
+ <member name="M:NetSharp.Deprecated.UdpClient.#ctor">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.UdpClient.SendBytesAsync(System.Byte[],System.TimeSpan)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.UdpClient.SendBytesWithResponseAsync(System.Byte[],System.TimeSpan)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.UdpClient.SendComplexAsync``2(``0,System.TimeSpan)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.UdpClient.SendSimpleAsync``1(``0,System.TimeSpan)">
+ <inheritdoc />
+ </member>
+ <member name="T:NetSharp.Deprecated.UdpServer">
+ <summary>
+ Provides methods for UDP communication with connected <see cref="T:NetSharp.Deprecated.UdpClient"/> instances.
+ </summary>
+ </member>
+ <member name="F:NetSharp.Deprecated.UdpServer.clientChannelOptions">
+ <summary>
+ The options that should be applied to every channel created to handle a client.
+ </summary>
+ </member>
+ <member name="F:NetSharp.Deprecated.UdpServer.activeClients">
+ <summary>
+ Holds currently connected and active clients, as well as their current received packet queues.
+ </summary>
+ </member>
+ <member name="M:NetSharp.Deprecated.UdpServer.HandleClientAsync(NetSharp.Deprecated.Server.ClientHandlerArgs,System.Threading.CancellationToken)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.UdpServer.#ctor(System.TimeSpan)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.UdpServer.#ctor">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.Deprecated.UdpServer.RunAsync(System.Net.EndPoint)">
+ <inheritdoc />
+ </member>
+ <member name="T:NetSharp.Deprecated.UdpSocketOptions">
+ <summary>
+ Allows for manipulation of UDP socket options.
+ </summary>
+ </member>
+ <member name="M:NetSharp.Deprecated.UdpSocketOptions.#ctor(System.Net.Sockets.Socket@)">
+ <inheritdoc />
+ </member>
+ <member name="P:NetSharp.Deprecated.UdpSocketOptions.HopLimit">
+ <inheritdoc />
+ </member>
+ <member name="P:NetSharp.Deprecated.UdpSocketOptions.IsRoutingEnabled">
+ <inheritdoc />
+ </member>
+ <member name="P:NetSharp.Deprecated.UdpSocketOptions.UseLoopback">
+ <inheritdoc />
+ </member>
+ <member name="T:NetSharp.Deprecated.BiDictionary`2">
<summary>
Represents a concurrent two-way dictionary, that can be indexed by either a key or a value.
</summary>
<typeparam name="K">The type of key that will be stored.</typeparam>
<typeparam name="V">The type of value that will be stored.</typeparam>
</member>
- <member name="F:NetSharp.Utils.BiDictionary`2.keyToValueMap">
+ <member name="F:NetSharp.Deprecated.BiDictionary`2.keyToValueMap">
<summary>
Maps keys to their corresponding values.
</summary>
</member>
- <member name="F:NetSharp.Utils.BiDictionary`2.valueToKeyMap">
+ <member name="F:NetSharp.Deprecated.BiDictionary`2.valueToKeyMap">
<summary>
Maps values to their corresponding keys.
</summary>
</member>
- <member name="M:NetSharp.Utils.BiDictionary`2.#ctor">
+ <member name="M:NetSharp.Deprecated.BiDictionary`2.#ctor">
<summary>
- Initialises a new instance of the <see cref="T:NetSharp.Utils.BiDictionary`2"/> class.
+ Initialises a new instance of the <see cref="T:NetSharp.Deprecated.BiDictionary`2"/> class.
</summary>
</member>
- <member name="P:NetSharp.Utils.BiDictionary`2.Item(`1)">
+ <member name="P:NetSharp.Deprecated.BiDictionary`2.Item(`1)">
<summary>
Indexes this instance with the given value.
</summary>
<param name="index">The value whose key to get or set.</param>
<returns>The fetched key.</returns>
</member>
- <member name="P:NetSharp.Utils.BiDictionary`2.Item(`0)">
+ <member name="P:NetSharp.Deprecated.BiDictionary`2.Item(`0)">
<summary>
Indexes this instance with the given key.
</summary>
<param name="index">The key whose value to get or set.</param>
<returns>The fetched value.</returns>
</member>
- <member name="M:NetSharp.Utils.BiDictionary`2.Clear">
+ <member name="M:NetSharp.Deprecated.BiDictionary`2.Clear">
<summary>
- Clears this instance's <see cref="F:NetSharp.Utils.BiDictionary`2.keyToValueMap"/> and <see cref="F:NetSharp.Utils.BiDictionary`2.valueToKeyMap"/>.
+ Clears this instance's <see cref="F:NetSharp.Deprecated.BiDictionary`2.keyToValueMap"/> and <see cref="F:NetSharp.Deprecated.BiDictionary`2.valueToKeyMap"/>.
</summary>
</member>
- <member name="M:NetSharp.Utils.BiDictionary`2.ContainsKey(`0@)">
+ <member name="M:NetSharp.Deprecated.BiDictionary`2.ContainsKey(`0@)">
<summary>
Whether this instance contains the given key.
</summary>
<param name="key">The key to check.</param>
<returns>Whether the given key was found.</returns>
</member>
- <member name="M:NetSharp.Utils.BiDictionary`2.ContainsValue(`1@)">
+ <member name="M:NetSharp.Deprecated.BiDictionary`2.ContainsValue(`1@)">
<summary>
Whether this instance contains the given value.
</summary>
<param name="value">The value to check.</param>
<returns>Whether the given value was found.</returns>
</member>
- <member name="M:NetSharp.Utils.BiDictionary`2.SetOrUpdateKey(`1,`0)">
+ <member name="M:NetSharp.Deprecated.BiDictionary`2.SetOrUpdateKey(`1,`0)">
<summary>
Attempts to set the key associated with the given value.
</summary>
@@ -2179,7 +2200,7 @@
<param name="key">The new value for the value's associated key.</param>
<returns>Whether the new key was correctly set.</returns>
</member>
- <member name="M:NetSharp.Utils.BiDictionary`2.SetOrUpdateValue(`0,`1)">
+ <member name="M:NetSharp.Deprecated.BiDictionary`2.SetOrUpdateValue(`0,`1)">
<summary>
Attempts to set the value associated with the given key.
</summary>
@@ -2187,7 +2208,7 @@
<param name="value">The new value for the key's associated value.</param>
<returns>Whether the new value was correctly set.</returns>
</member>
- <member name="M:NetSharp.Utils.BiDictionary`2.TryClearKey(`1@,`0@)">
+ <member name="M:NetSharp.Deprecated.BiDictionary`2.TryClearKey(`1@,`0@)">
<summary>
Attempts to remove the key associated with the given value.
</summary>
@@ -2195,7 +2216,7 @@
<param name="key">The old key value.</param>
<returns>Whether the given value had a valid key associated with it.</returns>
</member>
- <member name="M:NetSharp.Utils.BiDictionary`2.TryClearValue(`0@,`1@)">
+ <member name="M:NetSharp.Deprecated.BiDictionary`2.TryClearValue(`0@,`1@)">
<summary>
Attempts to remove the value associated with the given key.
</summary>
@@ -2203,7 +2224,7 @@
<param name="value">The old value.</param>
<returns>Whether the given key had a valid valid associated with it.</returns>
</member>
- <member name="M:NetSharp.Utils.BiDictionary`2.TryGetKey(`1@,`0@)">
+ <member name="M:NetSharp.Deprecated.BiDictionary`2.TryGetKey(`1@,`0@)">
<summary>
Attempts to get the key associated with the given value.
</summary>
@@ -2211,7 +2232,7 @@
<param name="key">The returned key.</param>
<returns>Whether the given value has a valid key associated with it.</returns>
</member>
- <member name="M:NetSharp.Utils.BiDictionary`2.TryGetValue(`0@,`1@)">
+ <member name="M:NetSharp.Deprecated.BiDictionary`2.TryGetValue(`0@,`1@)">
<summary>
Attempts to get the value associated with the given key.
</summary>
@@ -2219,7 +2240,7 @@
<param name="value">The returned value.</param>
<returns>Whether the given key as a valid value associated with it.</returns>
</member>
- <member name="M:NetSharp.Utils.BiDictionary`2.TrySetKey(`1@,`0@)">
+ <member name="M:NetSharp.Deprecated.BiDictionary`2.TrySetKey(`1@,`0@)">
<summary>
Attempts to set the key associated with the given value.
</summary>
@@ -2227,7 +2248,7 @@
<param name="key">The key which should be set for the given value.</param>
<returns>Whether the given value was successfully set.</returns>
</member>
- <member name="M:NetSharp.Utils.BiDictionary`2.TrySetValue(`0@,`1@)">
+ <member name="M:NetSharp.Deprecated.BiDictionary`2.TrySetValue(`0@,`1@)">
<summary>
Attempts to set the value associated with the given key.
</summary>
@@ -2235,86 +2256,94 @@
<param name="value">The value which should be set for the given key.</param>
<returns>Whether the given key was successfully set.</returns>
</member>
- <member name="T:NetSharp.Utils.Constants">
- <summary>
- Holds internal default configurations and constants.
- </summary>
- </member>
- <member name="F:NetSharp.Utils.Constants.DefaultPort">
- <summary>
- The default port over which a connection is made.
- </summary>
- </member>
- <member name="T:NetSharp.Utils.Conversion.EndianAwareBitConverter">
+ <member name="T:NetSharp.Deprecated.Conversion.EndianAwareBitConverter">
<summary>
Wraps the <see cref="T:System.BitConverter"/> class to provide conversion that is endian-aware.
</summary>
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ReverseAsNeeded(System.Span{System.Byte},System.Boolean)">
+ <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.ReverseAsNeeded(System.Span{System.Byte},System.Boolean)">
<summary>
Reverses the given bytes if the endian-nes doesn't match.
</summary>
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.Boolean,System.Boolean)">
+ <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.GetBytes(System.Boolean,System.Boolean)">
<inheritdoc cref="M:System.BitConverter.GetBytes(System.Boolean)"/>
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.Char,System.Boolean)">
+ <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.GetBytes(System.Char,System.Boolean)">
<inheritdoc cref="M:System.BitConverter.GetBytes(System.Char)"/>
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.Double,System.Boolean)">
+ <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.GetBytes(System.Double,System.Boolean)">
<inheritdoc cref="M:System.BitConverter.GetBytes(System.Double)"/>
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.Single,System.Boolean)">
+ <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.GetBytes(System.Single,System.Boolean)">
<inheritdoc cref="M:System.BitConverter.GetBytes(System.Single)"/>
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.Int32,System.Boolean)">
+ <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.GetBytes(System.Int32,System.Boolean)">
<inheritdoc cref="M:System.BitConverter.GetBytes(System.Int32)"/>
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.Int64,System.Boolean)">
+ <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.GetBytes(System.Int64,System.Boolean)">
<inheritdoc cref="M:System.BitConverter.GetBytes(System.Int64)"/>
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.Int16,System.Boolean)">
+ <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.GetBytes(System.Int16,System.Boolean)">
<inheritdoc cref="M:System.BitConverter.GetBytes(System.Int16)"/>
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.UInt32,System.Boolean)">
+ <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.GetBytes(System.UInt32,System.Boolean)">
<inheritdoc cref="M:System.BitConverter.GetBytes(System.UInt32)"/>
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.UInt64,System.Boolean)">
+ <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.GetBytes(System.UInt64,System.Boolean)">
<inheritdoc cref="M:System.BitConverter.GetBytes(System.UInt64)"/>
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.UInt16,System.Boolean)">
+ <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.GetBytes(System.UInt16,System.Boolean)">
<inheritdoc cref="M:System.BitConverter.GetBytes(System.UInt16)"/>
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToBoolean(System.Span{System.Byte},System.Boolean)">
+ <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.ToBoolean(System.Span{System.Byte},System.Boolean)">
<inheritdoc cref="M:System.BitConverter.ToBoolean(System.ReadOnlySpan{System.Byte})"/>
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToChar(System.Span{System.Byte},System.Boolean)">
+ <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.ToChar(System.Span{System.Byte},System.Boolean)">
<inheritdoc cref="M:System.BitConverter.ToChar(System.ReadOnlySpan{System.Byte})"/>
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToDouble(System.Span{System.Byte},System.Boolean)">
+ <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.ToDouble(System.Span{System.Byte},System.Boolean)">
<inheritdoc cref="M:System.BitConverter.ToDouble(System.ReadOnlySpan{System.Byte})"/>
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToInt16(System.Span{System.Byte},System.Boolean)">
+ <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.ToInt16(System.Span{System.Byte},System.Boolean)">
<inheritdoc cref="M:System.BitConverter.ToInt16(System.ReadOnlySpan{System.Byte})"/>
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToInt32(System.Span{System.Byte},System.Boolean)">
+ <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.ToInt32(System.Span{System.Byte},System.Boolean)">
<inheritdoc cref="M:System.BitConverter.ToInt32(System.ReadOnlySpan{System.Byte})"/>
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToInt64(System.Span{System.Byte},System.Boolean)">
+ <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.ToInt64(System.Span{System.Byte},System.Boolean)">
<inheritdoc cref="M:System.BitConverter.ToInt64(System.ReadOnlySpan{System.Byte})"/>
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToSingle(System.Span{System.Byte},System.Boolean)">
+ <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.ToSingle(System.Span{System.Byte},System.Boolean)">
<inheritdoc cref="M:System.BitConverter.ToSingle(System.ReadOnlySpan{System.Byte})"/>
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToUInt16(System.Byte[],System.Boolean)">
+ <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.ToUInt16(System.Byte[],System.Boolean)">
<inheritdoc cref="M:System.BitConverter.ToUInt16(System.ReadOnlySpan{System.Byte})"/>
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToUInt32(System.Span{System.Byte},System.Boolean)">
+ <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.ToUInt32(System.Span{System.Byte},System.Boolean)">
<inheritdoc cref="M:System.BitConverter.ToUInt32(System.ReadOnlySpan{System.Byte})"/>
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToUInt64(System.Span{System.Byte},System.Boolean)">
+ <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.ToUInt64(System.Span{System.Byte},System.Boolean)">
<inheritdoc cref="M:System.BitConverter.ToUInt64(System.ReadOnlySpan{System.Byte})"/>
</member>
+ <member name="M:NetSharp.Packets.NetworkPacket.#ctor(NetSharp.Packets.NetworkPacket.NetworkPacketHeader,System.ReadOnlyMemory{System.Byte},NetSharp.Packets.NetworkPacket.NetworkPacketFooter)">
+ <summary>
+ Constructs a new instance of the <see cref="T:NetSharp.Packets.NetworkPacket"/> struct.
+ </summary>
+ <param name="packetHeader">The header for this packet.</param>
+ <param name="packetDataBuffer">The data that should be stored in the packet.</param>
+ <param name="packetFooter">The footer for this packet.</param>
+ <exception cref="T:System.ArgumentException">
+ Thrown when the given <paramref name="packetDataBuffer"/> exceeds <see cref="F:NetSharp.Packets.NetworkPacket.TotalSize"/> bytes in size.
+ </exception>
+ </member>
+ <member name="M:NetSharp.Sockets.SocketAsyncOperations.HandleIoCompleted(System.Object,System.Net.Sockets.SocketAsyncEventArgs)">
+ <summary>
+ Event handler for the <see cref="E:System.Net.Sockets.SocketAsyncEventArgs.Completed"/> event.
+ </summary>
+ <param name="sender">The object on which the event is raised.</param>
+ <param name="args">The event arguments.</param>
+ </member>
<member name="T:NetSharp.Utils.TransmissionResult">
<summary>
Represents the result of a socket transmission.
diff --git a/NetSharp/NetSharp/Packets/Builtin/ConnectPacket.cs b/NetSharp/NetSharp/Packets/Builtin/ConnectPacket.cs
@@ -1,33 +0,0 @@
-using System;
-using NetSharp.Deprecated;
-
-namespace NetSharp.Packets.Builtin
-{
- /// <summary>
- /// A simple connection request packet for the UDP protocol.
- /// </summary>
- [PacketTypeId(1)]
- internal class ConnectPacket : IRequestPacket
- {
- /// <inheritdoc />
- public void AfterDeserialisation()
- {
- }
-
- /// <inheritdoc />
- public void BeforeSerialisation()
- {
- }
-
- /// <inheritdoc />
- public void Deserialise(ReadOnlyMemory<byte> serialisedObject)
- {
- }
-
- /// <inheritdoc />
- public Memory<byte> Serialise()
- {
- return Memory<byte>.Empty;
- }
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Packets/Builtin/ConnectResponsePacket.cs b/NetSharp/NetSharp/Packets/Builtin/ConnectResponsePacket.cs
@@ -1,36 +0,0 @@
-using System;
-using NetSharp.Deprecated;
-
-namespace NetSharp.Packets.Builtin
-{
- /// <summary>
- /// A response packet for the <see cref="ConnectPacket"/>.
- /// </summary>
- [PacketTypeId(2)]
- internal class ConnectResponsePacket : IResponsePacket<ConnectPacket>
- {
- /// <inheritdoc />
- public ConnectPacket RequestPacket { get; set; } = new ConnectPacket();
-
- /// <inheritdoc />
- public void AfterDeserialisation()
- {
- }
-
- /// <inheritdoc />
- public void BeforeSerialisation()
- {
- }
-
- /// <inheritdoc />
- public void Deserialise(ReadOnlyMemory<byte> serialisedObject)
- {
- }
-
- /// <inheritdoc />
- public Memory<byte> Serialise()
- {
- return Memory<byte>.Empty;
- }
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Packets/Builtin/DataPacket.cs b/NetSharp/NetSharp/Packets/Builtin/DataPacket.cs
@@ -1,56 +0,0 @@
-using System;
-using NetSharp.Deprecated;
-
-namespace NetSharp.Packets.Builtin
-{
- /// <summary>
- /// A simple data transfer packet, that allows for the transmission of an arbitrary number of frames.
- /// </summary>
- [PacketTypeId(5)]
- public class DataPacket : IRequestPacket
- {
- /// <summary>
- /// The data that should be transferred across the network.
- /// </summary>
- public Memory<byte> RequestBuffer;
-
- /// <summary>
- /// Initialises a new instance of the <see cref="DataPacket"/> class.
- /// </summary>
- public DataPacket()
- {
- RequestBuffer = new byte[0];
- }
-
- /// <summary>
- /// Initialises a new instance of the <see cref="DataPacket"/> class.
- /// </summary>
- /// <param name="buffer">The data that this request packet should contain.</param>
- public DataPacket(Memory<byte> buffer)
- {
- RequestBuffer = buffer;
- }
-
- /// <inheritdoc />
- public void AfterDeserialisation()
- {
- }
-
- /// <inheritdoc />
- public void BeforeSerialisation()
- {
- }
-
- /// <inheritdoc />
- public void Deserialise(ReadOnlyMemory<byte> serialisedObject)
- {
- RequestBuffer = serialisedObject.ToArray();
- }
-
- /// <inheritdoc />
- public Memory<byte> Serialise()
- {
- return RequestBuffer;
- }
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Packets/Builtin/DataResponsePacket.cs b/NetSharp/NetSharp/Packets/Builtin/DataResponsePacket.cs
@@ -1,59 +0,0 @@
-using System;
-using NetSharp.Deprecated;
-
-namespace NetSharp.Packets.Builtin
-{
- /// <summary>
- /// A response packet for the <see cref="DataPacket"/>.
- /// </summary>
- [PacketTypeId(6)]
- public class DataResponsePacket : IResponsePacket<DataPacket>
- {
- /// <summary>
- /// The data that should be transferred across the network.
- /// </summary>
- public Memory<byte> ResponseBuffer;
-
- /// <summary>
- /// Initialises a new instance of the <see cref="DataResponsePacket"/> class.
- /// </summary>
- public DataResponsePacket()
- {
- ResponseBuffer = new byte[0];
- }
-
- /// <summary>
- /// Initialises a new instance of the <see cref="DataResponsePacket"/> class.
- /// </summary>
- /// <param name="buffer">The data that this response packet should contain.</param>
- public DataResponsePacket(Memory<byte> buffer)
- {
- ResponseBuffer = buffer;
- }
-
- /// <inheritdoc />
- public DataPacket RequestPacket { get; internal set; } = new DataPacket();
-
- /// <inheritdoc />
- public void AfterDeserialisation()
- {
- }
-
- /// <inheritdoc />
- public void BeforeSerialisation()
- {
- }
-
- /// <inheritdoc />
- public void Deserialise(ReadOnlyMemory<byte> serialisedObject)
- {
- ResponseBuffer = serialisedObject.ToArray();
- }
-
- /// <inheritdoc />
- public Memory<byte> Serialise()
- {
- return ResponseBuffer;
- }
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Packets/Builtin/DisconnectPacket.cs b/NetSharp/NetSharp/Packets/Builtin/DisconnectPacket.cs
@@ -1,33 +0,0 @@
-using System;
-using NetSharp.Deprecated;
-
-namespace NetSharp.Packets.Builtin
-{
- /// <summary>
- /// A simple disconnect packet for the UDP protocol.
- /// </summary>
- [PacketTypeId(0)]
- internal class DisconnectPacket : IRequestPacket
- {
- /// <inheritdoc />
- public void AfterDeserialisation()
- {
- }
-
- /// <inheritdoc />
- public void BeforeSerialisation()
- {
- }
-
- /// <inheritdoc />
- public void Deserialise(ReadOnlyMemory<byte> serialisedObject)
- {
- }
-
- /// <inheritdoc />
- public Memory<byte> Serialise()
- {
- return Memory<byte>.Empty;
- }
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Packets/Builtin/PingPacket.cs b/NetSharp/NetSharp/Packets/Builtin/PingPacket.cs
@@ -1,33 +0,0 @@
-using System;
-using NetSharp.Deprecated;
-
-namespace NetSharp.Packets.Builtin
-{
- /// <summary>
- /// A simple ping request packet for heartbeat monitoring and RTT measurement.
- /// </summary>
- [PacketTypeId(3)]
- public class PingPacket : IRequestPacket
- {
- /// <inheritdoc />
- public void AfterDeserialisation()
- {
- }
-
- /// <inheritdoc />
- public void BeforeSerialisation()
- {
- }
-
- /// <inheritdoc />
- public void Deserialise(ReadOnlyMemory<byte> serialisedObject)
- {
- }
-
- /// <inheritdoc />
- public Memory<byte> Serialise()
- {
- return Memory<byte>.Empty;
- }
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Packets/Builtin/PingResponsePacket.cs b/NetSharp/NetSharp/Packets/Builtin/PingResponsePacket.cs
@@ -1,36 +0,0 @@
-using System;
-using NetSharp.Deprecated;
-
-namespace NetSharp.Packets.Builtin
-{
- /// <summary>
- /// A response packet for the <see cref="PingPacket"/>.
- /// </summary>
- [PacketTypeId(4)]
- public class PingResponsePacket : IResponsePacket<PingPacket>
- {
- /// <inheritdoc />
- public PingPacket RequestPacket { get; internal set; } = new PingPacket();
-
- /// <inheritdoc />
- public void AfterDeserialisation()
- {
- }
-
- /// <inheritdoc />
- public void BeforeSerialisation()
- {
- }
-
- /// <inheritdoc />
- public void Deserialise(ReadOnlyMemory<byte> serialisedObject)
- {
- }
-
- /// <inheritdoc />
- public Memory<byte> Serialise()
- {
- return Memory<byte>.Empty;
- }
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Packets/Builtin/SimpleDataPacket.cs b/NetSharp/NetSharp/Packets/Builtin/SimpleDataPacket.cs
@@ -1,56 +0,0 @@
-using System;
-using NetSharp.Deprecated;
-
-namespace NetSharp.Packets.Builtin
-{
- /// <summary>
- /// A simple one-time-use data transfer packet, that allows for the transmission of an arbitrary number of frames.
- /// </summary>
- [PacketTypeId(7)]
- public class SimpleDataPacket : IRequestPacket
- {
- /// <summary>
- /// The data that should be transferred across the network.
- /// </summary>
- public Memory<byte> RequestBuffer;
-
- /// <summary>
- /// Initialises a new instance of the <see cref="SimpleDataPacket"/> class.
- /// </summary>
- public SimpleDataPacket()
- {
- RequestBuffer = new byte[0];
- }
-
- /// <summary>
- /// Initialises a new instance of the <see cref="SimpleDataPacket"/> class.
- /// </summary>
- /// <param name="buffer">The data that this request packet should contain.</param>
- public SimpleDataPacket(Memory<byte> buffer)
- {
- RequestBuffer = buffer;
- }
-
- /// <inheritdoc />
- public void AfterDeserialisation()
- {
- }
-
- /// <inheritdoc />
- public void BeforeSerialisation()
- {
- }
-
- /// <inheritdoc />
- public void Deserialise(ReadOnlyMemory<byte> serialisedObject)
- {
- RequestBuffer = serialisedObject.ToArray();
- }
-
- /// <inheritdoc />
- public Memory<byte> Serialise()
- {
- return RequestBuffer;
- }
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Packets/NetworkErrorCode.cs b/NetSharp/NetSharp/Packets/NetworkErrorCode.cs
@@ -1,18 +0,0 @@
-namespace NetSharp.Packets
-{
- /// <summary>
- /// Enumerates the possible error codes for network operations, being held in the packet.
- /// </summary>
- public enum NetworkErrorCode : uint
- {
- /// <summary>
- /// Signifies that there was no error during transmission.
- /// </summary>
- Ok = 0,
-
- /// <summary>
- /// A generic error occurred during packet transmission.
- /// </summary>
- Error = 1 << 1,
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Packets/NetworkPacket.cs b/NetSharp/NetSharp/Packets/NetworkPacket.cs
@@ -1,217 +1,95 @@
using System;
-using NetSharp.Utils.Conversion;
namespace NetSharp.Packets
{
- /// <summary>
- /// Represents a low-level packet that is transmitted over the network.
- /// </summary>
public readonly struct NetworkPacket
{
- /// <summary>
- /// Initialises a new instance of the <see cref="NetworkPacket"/> struct.
- /// </summary>
- /// <param name="data">The data that should be transmitted in the packet.</param>
- /// <param name="header">The header for the packet.</param>
- /// <param name="footer">The footer for the packet.</param>
- private NetworkPacket(ReadOnlyMemory<byte> data, NetworkPacketHeader header, NetworkPacketFooter footer)
- {
- Header = header;
+ public const int TotalSize = 4096;
- DataBuffer = data;
+ public const int HeaderSize = NetworkPacketHeader.TotalSize;
- Footer = footer;
- }
+ public const int FooterSize = NetworkPacketFooter.TotalSize;
- /// <summary>
- /// The number of bytes allocated in each packet for user data.
- /// </summary>
- public const int DataSegmentSize = PacketSize - HeaderSize - FooterSize;
+ public const int DataSize = TotalSize - HeaderSize - FooterSize;
- /// <summary>
- /// The number of bytes taken up in each packet by its footer.
- /// </summary>
- public const int FooterSize = NetworkPacketFooter.Size;
+ public readonly ReadOnlyMemory<byte> Data;
- /// <summary>
- /// The number of bytes taken up in each packet by its header.
- /// </summary>
- public const int HeaderSize = NetworkPacketHeader.Size;
-
- /// <summary>
- /// The size of each packet, including its header, footer, and data segment.
- /// </summary>
- public const int PacketSize = 4096;
-
- /// <summary>
- /// The data held in this packet.
- /// </summary>
- public readonly ReadOnlyMemory<byte> DataBuffer;
-
- public readonly NetworkPacketFooter Footer;
public readonly NetworkPacketHeader Header;
- /// <summary>
- /// Initialises a new instance of the <see cref="NetworkPacket"/> struct.
- /// </summary>
- /// <param name="data">The data that should be transmitted in the packet.</param>
- /// <param name="dataLength">The number of bytes that are held in the given data buffer.</param>
- /// <param name="type">The packet type.</param>
- /// <param name="errorCode">The error code associated with this transmission.</param>
- /// <param name="hasSucceedingPacket">Whether this packet has a succeeding packet in the packet chain.</param>
- public NetworkPacket(ReadOnlyMemory<byte> data, int dataLength, uint type, NetworkErrorCode errorCode, bool hasSucceedingPacket)
- {
- Header = new NetworkPacketHeader(type, errorCode, dataLength);
-
- DataBuffer = data;
-
- Footer = new NetworkPacketFooter(hasSucceedingPacket);
- }
-
- /// <summary>
- /// Deserialises the given buffer into a packet instance.
- /// </summary>
- /// <param name="buffer">The byte buffer to serialise.</param>
- /// <returns>The deserialised packet instance.</returns>
- public static NetworkPacket Deserialise(Memory<byte> buffer)
- {
- Span<byte> serialisedPacketHeader = buffer.Slice(0, HeaderSize).Span;
- NetworkPacketHeader header = NetworkPacketHeader.Deserialise(serialisedPacketHeader);
-
- Span<byte> serialisedPacketFooter = buffer.Slice(HeaderSize + DataSegmentSize, FooterSize).Span;
- NetworkPacketFooter footer = NetworkPacketFooter.Deserialise(serialisedPacketFooter);
-
- Memory<byte> serialisedInstanceData = buffer.Slice(HeaderSize, DataSegmentSize);
-
- return new NetworkPacket(serialisedInstanceData, header, footer);
- }
-
- /// <summary>
- /// Serialises the given packet instance to a new byte buffer.
- /// </summary>
- /// <param name="instance">The packet instance to serialise.</param>
- /// <returns>The byte buffer that represents the packet instance.</returns>
- public static Memory<byte> Serialise(NetworkPacket instance)
- {
- byte[] buffer = new byte[PacketSize];
- SerialiseToBuffer(buffer, instance);
- return buffer;
- }
+ public readonly NetworkPacketFooter Footer;
/// <summary>
- /// Serialises the given packet instance into the given byte buffer.
+ /// Constructs a new instance of the <see cref="NetworkPacket"/> struct.
/// </summary>
- /// <param name="buffer">
- /// The buffer to which the instance should be serialised. Must be at least of size <see cref="PacketSize"/>.
- /// </param>
- /// <param name="instance">The packet instance to serialise.</param>
- /// <exception cref="ArgumentException">Thrown if the given buffer is too small.</exception>
- public static void SerialiseToBuffer(Memory<byte> buffer, NetworkPacket instance)
+ /// <param name="packetHeader">The header for this packet.</param>
+ /// <param name="packetDataBuffer">The data that should be stored in the packet.</param>
+ /// <param name="packetFooter">The footer for this packet.</param>
+ /// <exception cref="ArgumentException">
+ /// Thrown when the given <paramref name="packetDataBuffer"/> exceeds <see cref="TotalSize"/> bytes in size.
+ /// </exception>
+ private NetworkPacket(NetworkPacketHeader packetHeader, ReadOnlyMemory<byte> packetDataBuffer, NetworkPacketFooter packetFooter)
{
- if (buffer.Length < PacketSize)
+ if (packetDataBuffer.Length > DataSize)
{
- throw new ArgumentException("Given buffer is too small to serialise the packet instance into.", nameof(buffer));
+ throw new ArgumentException(
+ $"Given buffer exceeds {TotalSize} bytes, and cannot fit into a network packet",
+ nameof(packetDataBuffer));
}
- Span<byte> serialisedPacketHeader = buffer.Slice(0, HeaderSize).Span;
- NetworkPacketHeader.Serialise(serialisedPacketHeader, instance.Header);
-
- Span<byte> serialisedPacketFooter = buffer.Slice(HeaderSize + DataSegmentSize, FooterSize).Span;
- NetworkPacketFooter.Serialise(serialisedPacketFooter, instance.Footer);
-
- Memory<byte> serialisedInstanceData = buffer.Slice(HeaderSize, DataSegmentSize);
- instance.DataBuffer.CopyTo(serialisedInstanceData);
+ Data = packetDataBuffer;
}
- }
- // TODO: Document
- public readonly struct NetworkPacketFooter
- {
- private const int PacketHasNextStart = 0;
+ public static NetworkPacket Deserialise(ReadOnlyMemory<byte> buffer)
+ {
+ ReadOnlyMemory<byte> serialisedPacketHeader = buffer.Slice(0, HeaderSize);
+ NetworkPacketHeader packetHeader = NetworkPacketHeader.Deserialise(serialisedPacketHeader);
- /// <summary>
- /// The number of bytes taken up by a packet footer.
- /// </summary>
- public const int Size = sizeof(bool);
+ ReadOnlyMemory<byte> packetDataBuffer = buffer.Slice(HeaderSize, DataSize);
- public readonly bool HasSucceedingPacket;
+ ReadOnlyMemory<byte> serialisedPacketFooter = buffer.Slice(HeaderSize + DataSize, FooterSize);
+ NetworkPacketFooter packetFooter = NetworkPacketFooter.Deserialise(serialisedPacketFooter);
- public NetworkPacketFooter(bool hasSucceedingPacket)
- {
- HasSucceedingPacket = hasSucceedingPacket;
+ return new NetworkPacket(packetHeader, packetDataBuffer, packetFooter);
}
- public static NetworkPacketFooter Deserialise(Span<byte> buffer)
+ public static void Serialise(NetworkPacket instance, Memory<byte> buffer)
{
- Span<byte> serialisedHasNextFlag = buffer.Slice(PacketHasNextStart, sizeof(bool));
+ Memory<byte> packetHeader = buffer.Slice(0, HeaderSize);
+ NetworkPacketHeader.Serialise(instance.Header, packetHeader);
- return new NetworkPacketFooter(
- EndianAwareBitConverter.ToBoolean(serialisedHasNextFlag));
- }
+ Memory<byte> packetDataBuffer = buffer.Slice(HeaderSize, DataSize);
+ instance.Data.CopyTo(packetDataBuffer);
- public static void Serialise(Span<byte> buffer, NetworkPacketFooter instance)
- {
- Span<byte> serialisedHasNextFlag = buffer.Slice(PacketHasNextStart, sizeof(bool));
-
- EndianAwareBitConverter.GetBytes(instance.HasSucceedingPacket).CopyTo(serialisedHasNextFlag);
+ Memory<byte> packetFooter = buffer.Slice(HeaderSize + DataSize, FooterSize);
+ NetworkPacketFooter.Serialise(instance.Footer, packetFooter);
}
- }
-
- // TODO: Document
- public readonly struct NetworkPacketHeader
- {
- private const int PacketDataLengthStart = 2 * sizeof(uint);
- private const int PacketErrorCodeStart = sizeof(uint);
- private const int PacketTypeStart = 0;
- /// <summary>
- /// The number of bytes taken up by a packet header.
- /// </summary>
- public const int Size = sizeof(uint) + sizeof(uint) + sizeof(int);
-
- /// <summary>
- /// The number of bytes of data held in the packet.
- /// </summary>
- public readonly int DataLength;
-
- /// <summary>
- /// The error code for this packet.
- /// </summary>
- public readonly NetworkErrorCode ErrorCode;
+ public readonly struct NetworkPacketHeader
+ {
+ public const int TotalSize = 0;
- /// <summary>
- /// The packet type.
- /// </summary>
- public readonly uint Type;
+ public static NetworkPacketHeader Deserialise(ReadOnlyMemory<byte> buffer)
+ {
+ return new NetworkPacketHeader();
+ }
- public NetworkPacketHeader(uint packetType, NetworkErrorCode packetErrorCode, int packetDataLength)
- {
- Type = packetType;
- ErrorCode = packetErrorCode;
- DataLength = packetDataLength;
+ public static void Serialise(NetworkPacketHeader instance, Memory<byte> buffer)
+ {
+ }
}
- public static NetworkPacketHeader Deserialise(Span<byte> buffer)
+ public readonly struct NetworkPacketFooter
{
- Span<byte> serialisedType = buffer.Slice(PacketTypeStart, sizeof(uint));
- Span<byte> serialisedErrorCode = buffer.Slice(PacketErrorCodeStart, sizeof(uint));
- Span<byte> serialisedDataLength = buffer.Slice(PacketDataLengthStart, sizeof(int));
-
- return new NetworkPacketHeader(
- EndianAwareBitConverter.ToUInt32(serialisedType),
- (NetworkErrorCode)EndianAwareBitConverter.ToUInt32(serialisedErrorCode),
- EndianAwareBitConverter.ToInt32(serialisedDataLength));
- }
+ public const int TotalSize = 0;
- public static void Serialise(Span<byte> buffer, NetworkPacketHeader instance)
- {
- Span<byte> serialisedType = buffer.Slice(PacketTypeStart, sizeof(uint));
- Span<byte> serialisedErrorCode = buffer.Slice(PacketErrorCodeStart, sizeof(uint));
- Span<byte> serialisedDataLength = buffer.Slice(PacketDataLengthStart, sizeof(int));
+ public static NetworkPacketFooter Deserialise(ReadOnlyMemory<byte> buffer)
+ {
+ return new NetworkPacketFooter();
+ }
- EndianAwareBitConverter.GetBytes(instance.Type).CopyTo(serialisedType);
- EndianAwareBitConverter.GetBytes((uint)instance.ErrorCode).CopyTo(serialisedErrorCode);
- EndianAwareBitConverter.GetBytes(instance.DataLength).CopyTo(serialisedDataLength);
+ public static void Serialise(NetworkPacketFooter instance, Memory<byte> buffer)
+ {
+ }
}
}
}
\ No newline at end of file
diff --git a/NetSharp/NetSharp/Packets/PacketRegistry.cs b/NetSharp/NetSharp/Packets/PacketRegistry.cs
@@ -1,287 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using NetSharp.Deprecated;
-using NetSharp.Utils;
-
-namespace NetSharp.Packets
-{
- /// <summary>
- /// Provides method of registering request packets and their relevant response packets, as well as mapping their ids.
- /// </summary>
- internal static class PacketRegistry
- {
- /// <summary>
- /// The start id for automatically generated packet type ids. Any custom packet type ids lower than this value
- /// that come from external assemblies will be incremented by this value, to ensure that there are no clashes.
- /// </summary>
- private const uint AutomaticPacketTypeIdStartPoint = 100;
-
- /// <summary>
- /// The lock object for synchronising access to the <see cref="currentAutomaticPacketTypeIdCounter"/> field.
- /// </summary>
- private static readonly object currentAutomaticPacketTypeIdCounterLockObject = new object();
-
- /// <summary>
- /// Maps a packet type id to its relevant packet type, and vice-versa.
- /// </summary>
- private static readonly BiDictionary<uint, Type> idToPacketTypeMap;
-
- /// <summary>
- /// The assembly that represents the library, where all of the builtin packets are defined.
- /// </summary>
- private static readonly Assembly LibraryAssembly = Assembly.GetAssembly(typeof(PacketRegistry));
-
- /// <summary>
- /// Maps a request packet to its relevant response packet, and vice-versa.
- /// </summary>
- private static readonly BiDictionary<Type, Type> requestToResponseMap;
-
- /// <summary>
- /// The current id for registered packets.
- /// </summary>
- private static uint currentAutomaticPacketTypeIdCounter = AutomaticPacketTypeIdStartPoint;
-
- /// <summary>
- /// Fetches the packet type id of the given packet type. If the packet type is declared outside of the library
- /// assembly, then its value is incremented by the <see cref="AutomaticPacketTypeIdStartPoint"/> value. This ensure that
- /// there are no clashes between the packet type ids of packets declared in the library and external packets.
- /// </summary>
- /// <param name="packetType">The packet type whose id should be fetched.</param>
- /// <returns>The id of the given packet type.</returns>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static uint GetNewPacketTypeId(Type packetType)
- {
- uint packetTypeId;
-
- if (packetType.Assembly != LibraryAssembly)
- {
- lock (currentAutomaticPacketTypeIdCounterLockObject)
- {
- packetTypeId = currentAutomaticPacketTypeIdCounter++;
- }
- }
- else
- {
- PacketTypeIdAttribute customPacketTypeIdAttribute =
- (PacketTypeIdAttribute)packetType.GetCustomAttributes(typeof(PacketTypeIdAttribute)).First();
-
- packetTypeId = customPacketTypeIdAttribute.Id;
- }
-
- return packetTypeId;
- }
-
- /// <summary>
- /// Deregisters the given packet type from the registry.
- /// </summary>
- /// <param name="requestPacketType">The request packet type to deregister, if it is registered.</param>
- /// <param name="responsePacketType">The response packet associated with the request packet.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static void DeregisterPacketType(Type requestPacketType, Type? responsePacketType)
- {
- if (idToPacketTypeMap.ContainsValue(requestPacketType))
- {
- idToPacketTypeMap.TryClearKey(requestPacketType, out _);
- }
-
- // if the given response packet is null, then skip deregistering a response packet type
- if (responsePacketType == default) return;
-
- if (!idToPacketTypeMap.ContainsValue(responsePacketType))
- {
- idToPacketTypeMap.TryClearKey(responsePacketType, out _);
- }
-
- if (!requestToResponseMap.ContainsValue(requestPacketType))
- {
- requestToResponseMap.TryClearKey(requestPacketType, out _);
- }
- }
-
- /// <summary>
- /// Deregisters the given packet types from the registry.
- /// </summary>
- /// <param name="requestToResponsePacketTypeMap">The list of packet types to deregister, if they are registered.</param>
- internal static void DeregisterPacketTypes(Dictionary<Type, Type?> requestToResponsePacketTypeMap)
- {
- foreach ((Type requestPacketType, Type? responsePacketType) in requestToResponsePacketTypeMap)
- {
- DeregisterPacketType(requestPacketType, responsePacketType);
- }
- }
-
- /// <summary>
- /// Returns the packet type id associated with the given packet type.
- /// </summary>
- /// <param name="packetType">The packet type whose id to fetch.</param>
- /// <returns>The id of the packet type given.</returns>
- internal static uint GetPacketId(Type packetType) => idToPacketTypeMap[packetType];
-
- /// <summary>
- /// Returns the packet type id associated with the given packet type.
- /// </summary>
- /// <typeparam name="TPacket">The packet type whose id to fetch.</typeparam>
- /// <returns>The id of the packet type given.</returns>
- internal static uint GetPacketId<TPacket>() where TPacket : IPacket => idToPacketTypeMap[typeof(TPacket)];
-
- /// <summary>
- /// Returns the packet type associated with the given id.
- /// </summary>
- /// <param name="packetTypeId">The packet id whose mapped type to fetch.</param>
- /// <returns>The packet type mapped by the given id.</returns>
- internal static Type GetPacketType(uint packetTypeId) => idToPacketTypeMap[packetTypeId];
-
- /// <summary>
- /// Returns the type of request packet mapped by the given response packet type.
- /// </summary>
- /// <typeparam name="TResponse">The response packet type whose request packet type to fetch.</typeparam>
- /// <returns>The request packet type, <c>null</c> if no type is mapped.</returns>
- internal static Type GetRequestPacketType<TResponse>() where TResponse : IResponsePacket<IRequestPacket>
- {
- requestToResponseMap.TryGetKey(typeof(TResponse), out Type requestPacketType);
-
- return requestPacketType;
- }
-
- /// <summary>
- /// Returns the type of request packet mapped by the given response packet type.
- /// </summary>
- /// <param name="responsePacketType">The response packet type whose request packet type to fetch.</param>
- /// <returns>The request packet type, <c>null</c> if no type is mapped.</returns>
- internal static Type GetRequestPacketType(Type responsePacketType)
- {
- requestToResponseMap.TryGetKey(responsePacketType, out Type requestPacketType);
-
- return requestPacketType;
- }
-
- /// <summary>
- /// Returns the type of response packet mapped by the given request packet type.
- /// </summary>
- /// <typeparam name="TRequest">The request packet type whose response packet type to fetch.</typeparam>
- /// <returns>The response packet type, <c>null</c> if no type is mapped.</returns>
- internal static Type? GetResponsePacketType<TRequest>() where TRequest : IRequestPacket
- {
- return requestToResponseMap.TryGetValue(typeof(TRequest), out Type responsePacketType) ? responsePacketType : default;
- }
-
- /// <summary>
- /// Returns the type of response packet mapped by the given request packet type.
- /// </summary>
- /// <param name="requestPacketType">The request packet type whose response packet type to fetch.</param>
- /// <returns>The response packet type, <c>null</c> if no type is mapped.</returns>
- internal static Type? GetResponsePacketType(Type requestPacketType)
- {
- return requestToResponseMap.TryGetValue(requestPacketType, out Type responsePacketType) ? responsePacketType : default;
- }
-
- /// <summary>
- /// Rebuilds the packet registry, by registering every <see cref="IPacket"/> inheritor in the given assemblies.
- /// </summary>
- /// <param name="packetSourceAssemblies">
- /// The assemblies from which the packet types to register are sourced.
- /// </param>
- internal static void RegisterPacketSourceAssemblies(params Assembly[] packetSourceAssemblies)
- {
- foreach (Assembly assembly in packetSourceAssemblies)
- {
- RegisterPacketSourceAssembly(assembly);
- }
- }
-
- /// <summary>
- /// Registers all the <see cref="IPacket"/> implementors in the given assembly.
- /// </summary>
- /// <param name="packetSourceAssembly">The assembly whose packet types to register.</param>
- //[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static void RegisterPacketSourceAssembly(Assembly packetSourceAssembly)
- {
- Dictionary<Type, Type?> requestToResponseTypeMap = new Dictionary<Type, Type?>();
-
- foreach (Type type in packetSourceAssembly.DefinedTypes)
- {
- foreach (Type interfaceType in type.GetInterfaces())
- {
- if (!typeof(IPacket).IsAssignableFrom(interfaceType) || interfaceType == typeof(IPacket))
- {
- continue;
- }
-
- if (interfaceType == typeof(IRequestPacket))
- {
- requestToResponseTypeMap[type] = default;
- }
- else //if (interfaceType == typeof(IResponsePacket<>))
- {
- Type handledRequestType = interfaceType.GetGenericArguments()[0];
-
- requestToResponseTypeMap[handledRequestType] = type;
- }
- }
- }
-
- RegisterPacketTypes(requestToResponseTypeMap);
- }
-
- /// <summary>
- /// Registers the given packet type to the registry.
- /// </summary>
- /// <param name="requestPacketType">The request packet type to register, if it is not registered.</param>
- /// <param name="responsePacketType">The response packet associated with the request packet.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static void RegisterPacketType(Type requestPacketType, Type? responsePacketType)
- {
- if (!idToPacketTypeMap.ContainsValue(requestPacketType))
- {
- uint requestPacketTypeId = GetNewPacketTypeId(requestPacketType);
-
- idToPacketTypeMap.TrySetValue(requestPacketTypeId, requestPacketType);
- }
-
- // if the given response packet is null, then skip registering a response packet type
- if (responsePacketType == default) return;
-
- if (!idToPacketTypeMap.ContainsValue(responsePacketType))
- {
- uint responsePacketTypeId = GetNewPacketTypeId(responsePacketType);
-
- idToPacketTypeMap.TrySetValue(responsePacketTypeId, responsePacketType);
- }
-
- if (!requestToResponseMap.ContainsValue(requestPacketType))
- {
- requestToResponseMap.TrySetValue(requestPacketType, responsePacketType);
- }
- }
-
- /// <summary>
- /// Registers the given packet types to the registry.
- /// </summary>
- /// <param name="requestToResponsePacketTypeMap">
- /// The dictionary mapping the request packet types to register, to their relevant response packet types.
- /// The response packet type can be null; then the request packet type is treated as a 'simple' packet.
- /// </param>
- internal static void RegisterPacketTypes(Dictionary<Type, Type?> requestToResponsePacketTypeMap)
- {
- foreach ((Type requestPacketType, Type? responsePacketType) in requestToResponsePacketTypeMap)
- {
- RegisterPacketType(requestPacketType, responsePacketType);
- }
- }
-
- /// <summary>
- /// Initialises a new instance of the <see cref="PacketRegistry"/> class.
- /// </summary>
- static PacketRegistry()
- {
- idToPacketTypeMap = new BiDictionary<uint, Type>();
-
- requestToResponseMap = new BiDictionary<Type, Type>();
-
- RegisterPacketSourceAssembly(LibraryAssembly);
- }
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Packets/PacketTypeIdAttribute.cs b/NetSharp/NetSharp/Packets/PacketTypeIdAttribute.cs
@@ -1,27 +0,0 @@
-using System;
-using NetSharp.Deprecated;
-
-namespace NetSharp.Packets
-{
- /// <summary>
- /// Allows the placing of a custom packet type on a class or struct. This is used if the class or struct
- /// inherits from <see cref="IRequestPacket"/> or <see cref="IResponsePacket{TReq}"/>.
- /// </summary>
- [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
- internal sealed class PacketTypeIdAttribute : Attribute
- {
- /// <summary>
- /// Initialises a new instance of the <see cref="PacketTypeIdAttribute"/> attribute.
- /// </summary>
- /// <param name="type">The custom type id that the decorated packet type should have.</param>
- internal PacketTypeIdAttribute(uint type)
- {
- Id = type;
- }
-
- /// <summary>
- /// The custom type id that the decorated packet type should have. This overrides the automatically generated id.
- /// </summary>
- internal uint Id { get; }
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Pipelines/PacketPipeline.cs b/NetSharp/NetSharp/Pipelines/PacketPipeline.cs
@@ -1,65 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace NetSharp.Pipelines
-{
- /// <summary>
- /// Represents a pipeline of transformations that packets must undergo.
- /// </summary>
- /// <typeparam name="TInput">The type of packet the pipeline receives.</typeparam>
- /// <typeparam name="TIntermediate">The type of packet the pipeline internally handles.</typeparam>
- /// <typeparam name="TOutput">The type of packet the pipeline outputs.</typeparam>
- // TODO: Implement a packet pipeline, with multiple transform stages to allow encryption, compression, and various other bytewise manipulation stages.
- internal readonly struct PacketPipeline<TInput, TIntermediate, TOutput>
- {
- private readonly PacketPipelineStage<TInput, TIntermediate> pipelineInputStage;
- private readonly IReadOnlyCollection<PacketPipelineStage<TIntermediate, TIntermediate>> pipelineIntermediateStages;
- private readonly PacketPipelineStage<TIntermediate, TOutput> pipelineOutputStage;
-
- internal PacketPipeline(
- PacketPipelineStage<TInput, TIntermediate> firstStage,
- PacketPipelineStage<TIntermediate, TOutput> lastStage,
- IReadOnlyCollection<PacketPipelineStage<TIntermediate, TIntermediate>> intermediateStages)
- {
- pipelineInputStage = firstStage;
- pipelineOutputStage = lastStage;
-
- pipelineIntermediateStages = intermediateStages;
- }
-
- /// <summary>
- /// Passes the given packet through the pipeline.
- /// </summary>
- /// <param name="inputPacket">The incoming packet.</param>
- /// <returns>The outgoing transformed packet.</returns>
- internal TOutput ProcessPacket(TInput inputPacket)
- {
- TIntermediate intermediatePacket = pipelineInputStage.Process(inputPacket);
-
- intermediatePacket = pipelineIntermediateStages.Aggregate(intermediatePacket, (current, stage) => stage.Process(current));
-
- return pipelineOutputStage.Process(intermediatePacket);
- }
- }
-
- /// <summary>
- /// Represents a single transformation applied to a packet traveling through the pipeline.
- /// </summary>
- /// <typeparam name="TInput">The type the transformation takes as input.</typeparam>
- /// <typeparam name="TOutput">The type the transformation produces as output.</typeparam>
- internal readonly struct PacketPipelineStage<TInput, TOutput>
- {
- private readonly Func<TInput, TOutput> stageDelegate;
-
- internal PacketPipelineStage(in Func<TInput, TOutput> stageProcessingDelegate)
- {
- stageDelegate = stageProcessingDelegate;
- }
-
- internal TOutput Process(TInput input)
- {
- return stageDelegate(input);
- }
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Pipelines/PacketPipelineBuilder.cs b/NetSharp/NetSharp/Pipelines/PacketPipelineBuilder.cs
@@ -1,87 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace NetSharp.Pipelines
-{
- /// <summary>
- /// Allows for configuring and subsequently building a <see cref="PacketPipeline{TInput,TIntermediate,TOutput}"/> instance.
- /// </summary>
- /// <typeparam name="TInput">The type of packet that will be submitted to the pipeline.</typeparam>
- /// <typeparam name="TIntermediate">The type of packet that will be handled internally by the pipeline.</typeparam>
- /// <typeparam name="TOutput">The type of packet that will be requested from the pipeline.</typeparam>
- internal sealed class PacketPipelineBuilder<TInput, TIntermediate, TOutput>
- {
- private readonly List<PacketPipelineStage<TIntermediate, TIntermediate>> intermediateStages;
-
- private PacketPipelineStage<TInput, TIntermediate>? inputStage;
- private PacketPipelineStage<TIntermediate, TOutput>? outputStage;
-
- internal PacketPipelineBuilder()
- {
- intermediateStages = new List<PacketPipelineStage<TIntermediate, TIntermediate>>();
- }
-
- /// <summary>
- /// Returns the currently configured <see cref="PacketPipeline{TInput,TIntermediate,TOutput}"/> instance.
- /// </summary>
- /// <returns>The configured <see cref="PacketPipeline{TInput,TIntermediate,TOutput}"/> instance.</returns>
- /// <exception cref="ArgumentNullException">
- /// Thrown when either <see cref="WithInputStage"/> or <see cref="WithOutputStage"/> have not been called.
- /// </exception>
- internal PacketPipeline<TInput, TIntermediate, TOutput> Build()
- {
- if (inputStage == null)
- {
- throw new ArgumentNullException(nameof(inputStage), $"{nameof(WithInputStage)} has not been called.");
- }
-
- if (outputStage == null)
- {
- throw new ArgumentNullException(nameof(outputStage), $"{nameof(WithOutputStage)} has not been called.");
- }
-
- return new PacketPipeline<TInput, TIntermediate, TOutput>(inputStage.Value, outputStage.Value, intermediateStages);
- }
-
- /// <summary>
- /// Configures the input stage for the pipeline.
- /// </summary>
- /// <param name="stage">
- /// The transformation that should be applied to incoming packets, to convert them from the <typeparamref name="TInput"/>
- /// type to the <typeparamref name="TIntermediate"/> type that the pipeline handles internally.
- /// </param>
- /// <returns>The builder instance for further configuration.</returns>
- internal PacketPipelineBuilder<TInput, TIntermediate, TOutput> WithInputStage(in Func<TInput, TIntermediate> stage)
- {
- inputStage = new PacketPipelineStage<TInput, TIntermediate>(in stage);
- return this;
- }
-
- /// <summary>
- /// Adds the given intermediate stage to the pipeline.
- /// </summary>
- /// <param name="stage">
- /// The transformation that should be applied to packets traveling through the pipeline.
- /// </param>
- /// <returns>The builder instance for further configuration.</returns>
- internal PacketPipelineBuilder<TInput, TIntermediate, TOutput> WithIntermediateStage(in Func<TIntermediate, TIntermediate> stage)
- {
- intermediateStages.Add(new PacketPipelineStage<TIntermediate, TIntermediate>(in stage));
- return this;
- }
-
- /// <summary>
- /// Configures the output stage for the pipeline.
- /// </summary>
- /// <param name="stage">
- /// The transformation that should be applied to outgoing packets, to convert them from the
- /// <typeparamref name="TIntermediate"/> type used internally to the <typeparamref name="TOutput"/> type.
- /// </param>
- /// <returns>The builder instance for further configuration.</returns>
- internal PacketPipelineBuilder<TInput, TIntermediate, TOutput> WithOutputStage(in Func<TIntermediate, TOutput> stage)
- {
- outputStage = new PacketPipelineStage<TIntermediate, TOutput>(in stage);
- return this;
- }
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Sockets/Datagram/DatagramSocketClient.cs b/NetSharp/NetSharp/Sockets/Datagram/DatagramSocketClient.cs
@@ -0,0 +1,12 @@
+using System.Net.Sockets;
+
+namespace NetSharp.Sockets.Datagram
+{
+ public class DatagramSocketClient : SocketClient
+ {
+ public DatagramSocketClient(in AddressFamily connectionAddressFamily, in ProtocolType connectionProtocolType)
+ : base(in connectionAddressFamily, SocketType.Dgram, in connectionProtocolType)
+ {
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Sockets/Datagram/DatagramSocketServer.cs b/NetSharp/NetSharp/Sockets/Datagram/DatagramSocketServer.cs
@@ -0,0 +1,169 @@
+using NetSharp.Packets;
+using NetSharp.Utils;
+
+using System;
+using System.Collections.Concurrent;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading;
+using System.Threading.Channels;
+using System.Threading.Tasks;
+
+namespace NetSharp.Sockets.Datagram
+{
+ public class DatagramSocketServer : SocketServer
+ {
+ private readonly ConcurrentDictionary<EndPoint, RemoteDatagramClientToken> connectedClientTokens;
+
+ private readonly struct RemoteDatagramClientToken
+ {
+ private readonly Channel<NetworkPacket> PacketChannel;
+
+ public readonly ChannelReader<NetworkPacket> PacketReader;
+
+ public readonly ChannelWriter<NetworkPacket> PacketWriter;
+
+ public RemoteDatagramClientToken(in Channel<NetworkPacket> packetChannel)
+ {
+ PacketChannel = packetChannel;
+ PacketReader = packetChannel.Reader;
+ PacketWriter = packetChannel.Writer;
+ }
+ }
+
+ public DatagramSocketServer(in AddressFamily connectionAddressFamily, in ProtocolType connectionProtocolType)
+ : base(in connectionAddressFamily, SocketType.Dgram, in connectionProtocolType)
+ {
+ connectedClientTokens = new ConcurrentDictionary<EndPoint, RemoteDatagramClientToken>();
+ }
+
+ protected override SocketAsyncEventArgs GenerateConnectionArgs(EndPoint remoteEndPoint)
+ {
+ SocketAsyncEventArgs connectionArgs = new SocketAsyncEventArgs { RemoteEndPoint = remoteEndPoint };
+
+ connectionArgs.Completed += SocketAsyncOperations.HandleIoCompleted;
+
+ return connectionArgs;
+ }
+
+ protected override void DestroyConnectionArgs(SocketAsyncEventArgs remoteConnectionArgs)
+ {
+ remoteConnectionArgs.Completed -= SocketAsyncOperations.HandleIoCompleted;
+
+ remoteConnectionArgs.Dispose();
+ }
+
+ protected override async Task HandleClient(SocketAsyncEventArgs clientArgs, CancellationToken cancellationToken = default)
+ {
+ EndPoint clientEndPoint = clientArgs.RemoteEndPoint;
+ RemoteDatagramClientToken clientToken = connectedClientTokens[clientEndPoint];
+
+ byte[] responseBuffer = new byte[NetworkPacket.TotalSize];
+ Memory<byte> responseBufferMemory = new Memory<byte>(responseBuffer);
+
+ try
+ {
+ while (!cancellationToken.IsCancellationRequested)
+ {
+ NetworkPacket request = await clientToken.PacketReader.ReadAsync(cancellationToken);
+
+ // TODO implement actual request handling, besides just an echo
+ NetworkPacket response = request;
+
+ NetworkPacket.Serialise(response, responseBufferMemory);
+
+ TransmissionResult sendResult =
+ await SocketAsyncOperations
+ .SendToAsync(clientArgs, connection, clientEndPoint, SocketFlags.None, responseBufferMemory, cancellationToken);
+
+#if DEBUG
+ lock (typeof(Console))
+ {
+ Console.WriteLine($"[Server] Sent {sendResult.Count} bytes to {sendResult.RemoteEndPoint}");
+ Console.WriteLine($"[Server] >>>> {Encoding.UTF8.GetString(sendResult.Buffer.Span)}");
+ }
+#endif
+ }
+ }
+ catch (OperationCanceledException) { }
+ finally
+ {
+ DestroyConnectionArgs(clientArgs);
+ }
+ }
+
+ public override async Task RunAsync(CancellationToken cancellationToken = default)
+ {
+ byte[] requestBuffer = new byte[NetworkPacket.TotalSize];
+ Memory<byte> requestBufferMemory = new Memory<byte>(requestBuffer);
+
+ EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
+ using SocketAsyncEventArgs remoteArgs = GenerateConnectionArgs(remoteEndPoint);
+
+ while (!cancellationToken.IsCancellationRequested)
+ {
+ remoteArgs.RemoteEndPoint = remoteEndPoint;
+
+ TransmissionResult receiveResult =
+ await SocketAsyncOperations
+ .ReceiveFromAsync(remoteArgs, connection, remoteEndPoint, SocketFlags.None, requestBufferMemory, cancellationToken)
+ .ConfigureAwait(false);
+
+ EndPoint clientEndPoint = receiveResult.RemoteEndPoint;
+
+#if DEBUG
+ lock (typeof(Console))
+ {
+ Console.WriteLine($"[Server] Received {receiveResult.Count} bytes from {receiveResult.RemoteEndPoint}");
+ Console.WriteLine($"[Server] <<<< {Encoding.UTF8.GetString(receiveResult.Buffer.Span)}");
+ }
+#endif
+
+ if (!ConnectedClientHandlerTasks.ContainsKey(clientEndPoint))
+ {
+ SocketAsyncEventArgs clientArgs = GenerateConnectionArgs(receiveResult.RemoteEndPoint);
+
+ BoundedChannelOptions clientChannelOptions = new BoundedChannelOptions(60)
+ { FullMode = BoundedChannelFullMode.DropOldest, SingleReader = true, SingleWriter = true };
+ Channel<NetworkPacket> clientChannel = Channel.CreateBounded<NetworkPacket>(clientChannelOptions);
+
+ connectedClientTokens[clientEndPoint] = new RemoteDatagramClientToken(in clientChannel);
+
+ ConnectedClientHandlerTasks[clientEndPoint] = HandleClient(clientArgs, cancellationToken);
+ }
+
+ NetworkPacket requestPacket = NetworkPacket.Deserialise(requestBufferMemory);
+
+ await connectedClientTokens[clientEndPoint].PacketWriter.WriteAsync(requestPacket, cancellationToken);
+ }
+
+ /*
+ while (true)
+ {
+ TransmissionResult receiveResult =
+ await SocketAsyncEventArgs.ReceiveAsync(remoteEndPoint, SocketFlags.None, requestBufferMemory);
+
+#if DEBUG
+ lock (typeof(Console))
+ {
+ Console.WriteLine($"[Server] Received {receiveResult.Count} bytes from {receiveResult.RemoteEndPoint}");
+ Console.WriteLine($"[Server] <<<< {Encoding.UTF8.GetString(receiveResult.Buffer.Span)}");
+ }
+#endif
+
+ TransmissionResult sendResult =
+ await SocketAsyncOperations.SendAsync(receiveResult.RemoteEndPoint, SocketFlags.None, requestBuffer);
+
+#if DEBUG
+ lock (typeof(Console))
+ {
+ Console.WriteLine($"[Server] Sent {sendResult.Count} bytes to {sendResult.RemoteEndPoint}");
+ Console.WriteLine($"[Server] >>>> {Encoding.UTF8.GetString(sendResult.Buffer.Span)}");
+ }
+#endif
+ }
+ */
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Sockets/SocketAcceptor.cs b/NetSharp/NetSharp/Sockets/SocketAcceptor.cs
@@ -1,280 +0,0 @@
-using System;
-using System.Net;
-using System.Net.Sockets;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.Extensions.ObjectPool;
-
-namespace NetSharp.Sockets
-{
- /// <summary>
- /// Helper class providing awaitable wrappers around asynchronous Accept, Connect, and Disconnect operations.
- /// </summary>
- public sealed class SocketAcceptor
- {
- private readonly ObjectPool<SocketAsyncEventArgs> acceptAsyncEventArgsPool;
- private readonly ObjectPool<SocketAsyncEventArgs> connectAsyncEventArgsPool;
- private readonly ObjectPool<SocketAsyncEventArgs> disconnectAsyncEventArgsPool;
-
- private void HandleIOCompleted(object? sender, SocketAsyncEventArgs args)
- {
- switch (args.LastOperation)
- {
- case SocketAsyncOperation.Accept:
- AsyncAcceptToken asyncAcceptToken = (AsyncAcceptToken)args.UserToken;
-
- if (asyncAcceptToken.CancellationToken.IsCancellationRequested)
- {
- asyncAcceptToken.CompletionSource.SetCanceled();
- }
- else
- {
- if (args.SocketError != SocketError.Success)
- {
- asyncAcceptToken.CompletionSource.SetException(
- new SocketException((int)args.SocketError));
- }
- else
- {
- asyncAcceptToken.CompletionSource.SetResult(args.AcceptSocket);
- }
- }
-
- acceptAsyncEventArgsPool.Return(args);
-
- break;
-
- case SocketAsyncOperation.Connect:
- AsyncConnectToken asyncConnectToken = (AsyncConnectToken)args.UserToken;
-
- if (asyncConnectToken.CancellationToken.IsCancellationRequested)
- {
- asyncConnectToken.CompletionSource.SetCanceled();
- }
- else
- {
- if (args.SocketError != SocketError.Success)
- {
- asyncConnectToken.CompletionSource.SetException(
- new SocketException((int)args.SocketError));
- }
- else
- {
- asyncConnectToken.CompletionSource.SetResult(true);
- }
- }
-
- connectAsyncEventArgsPool.Return(args);
-
- break;
-
- case SocketAsyncOperation.Disconnect:
- AsyncDisconnectToken asyncDisconnectToken = (AsyncDisconnectToken)args.UserToken;
-
- if (asyncDisconnectToken.CancellationToken.IsCancellationRequested)
- {
- asyncDisconnectToken.CompletionSource.SetCanceled();
- }
- else
- {
- if (args.SocketError != SocketError.Success)
- {
- asyncDisconnectToken.CompletionSource.SetException(
- new SocketException((int)args.SocketError));
- }
- else
- {
- asyncDisconnectToken.CompletionSource.SetResult(true);
- }
- }
-
- disconnectAsyncEventArgsPool.Return(args);
-
- break;
-
- default:
- throw new InvalidOperationException(
- $"The {nameof(SocketAcceptor)} class doesn't support the {args.LastOperation} operation.");
- }
- }
-
- private readonly struct AsyncAcceptToken
- {
- public readonly CancellationToken CancellationToken;
- public readonly TaskCompletionSource<Socket> CompletionSource;
-
- public AsyncAcceptToken(TaskCompletionSource<Socket> tcs, CancellationToken cancellationToken = default)
- {
- CompletionSource = tcs;
- CancellationToken = cancellationToken;
- }
- }
-
- private readonly struct AsyncConnectToken
- {
- public readonly CancellationToken CancellationToken;
- public readonly TaskCompletionSource<bool> CompletionSource;
-
- public AsyncConnectToken(TaskCompletionSource<bool> tcs, CancellationToken cancellationToken = default)
- {
- CompletionSource = tcs;
- CancellationToken = cancellationToken;
- }
- }
-
- private readonly struct AsyncDisconnectToken
- {
- public readonly CancellationToken CancellationToken;
- public readonly TaskCompletionSource<bool> CompletionSource;
-
- public AsyncDisconnectToken(TaskCompletionSource<bool> tcs, CancellationToken cancellationToken = default)
- {
- CompletionSource = tcs;
- CancellationToken = cancellationToken;
- }
- }
-
- internal SocketAcceptor(int maxPooledObjects = 10)
- {
- acceptAsyncEventArgsPool =
- new DefaultObjectPool<SocketAsyncEventArgs>(new DefaultPooledObjectPolicy<SocketAsyncEventArgs>(),
- maxPooledObjects);
-
- connectAsyncEventArgsPool =
- new DefaultObjectPool<SocketAsyncEventArgs>(new DefaultPooledObjectPolicy<SocketAsyncEventArgs>(),
- maxPooledObjects);
-
- disconnectAsyncEventArgsPool =
- new DefaultObjectPool<SocketAsyncEventArgs>(new DefaultPooledObjectPolicy<SocketAsyncEventArgs>(),
- maxPooledObjects);
-
- for (int i = 0; i < maxPooledObjects; i++)
- {
- SocketAsyncEventArgs acceptArgs = new SocketAsyncEventArgs();
- acceptArgs.Completed += HandleIOCompleted;
- acceptAsyncEventArgsPool.Return(acceptArgs);
-
- SocketAsyncEventArgs connectArgs = new SocketAsyncEventArgs();
- connectArgs.Completed += HandleIOCompleted;
- connectAsyncEventArgsPool.Return(connectArgs);
-
- SocketAsyncEventArgs disconnectArgs = new SocketAsyncEventArgs();
- disconnectArgs.Completed += HandleIOCompleted;
- connectAsyncEventArgsPool.Return(disconnectArgs);
- }
- }
-
- /// <summary>
- /// Provides an awaitable wrapper around an asynchronous socket accept operation.
- /// </summary>
- /// <param name="socket">The socket which should be used to accept an incoming connection attempt.</param>
- /// <param name="cancellationToken">The cancellation token to observe for the operation.</param>
- /// <returns>The accepted socket.</returns>
- public Task<Socket> AcceptAsync(Socket socket, CancellationToken cancellationToken = default)
- {
- TaskCompletionSource<Socket> tcs = new TaskCompletionSource<Socket>();
-
- SocketAsyncEventArgs args = acceptAsyncEventArgsPool.Get();
- args.UserToken = new AsyncAcceptToken(tcs, cancellationToken);
-
- /*
- // register cleanup action for when the cancellation token is thrown
- cancellationToken.Register(() =>
- {
- tcs.SetCanceled();
-
- //TODO this is probably a hideous solution. find a better one
- args.Completed -= HandleIOCompleted;
- args.Dispose();
-
- SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
- newArgs.Completed += HandleIOCompleted;
- acceptAsyncEventArgsPool.Return(newArgs);
- });
- */
-
- // if the accept operation doesn't complete synchronously, return the awaitable task
- if (socket.AcceptAsync(args)) return tcs.Task;
-
- Socket result = args.AcceptSocket;
-
- acceptAsyncEventArgsPool.Return(args);
-
- return Task.FromResult(result);
- }
-
- /// <summary>
- /// Provides an awaitable wrapper around an asynchronous socket connect operation.
- /// </summary>
- /// <param name="socket">The socket which should asynchronously connect to the remote endpoint.</param>
- /// <param name="remoteEndPoint">The remote endpoint to which the socket should connect.</param>
- /// <param name="cancellationToken">The cancellation token to observe for the operation.</param>
- public Task ConnectAsync(Socket socket, EndPoint remoteEndPoint, CancellationToken cancellationToken = default)
- {
- TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
-
- SocketAsyncEventArgs args = connectAsyncEventArgsPool.Get();
- args.RemoteEndPoint = remoteEndPoint;
- args.UserToken = new AsyncConnectToken(tcs, cancellationToken);
-
- /*
- // register cleanup action for when the cancellation token is thrown
- cancellationToken.Register(() =>
- {
- tcs.SetCanceled();
-
- //TODO this is probably a hideous solution. find a better one
- args.Completed -= HandleIOCompleted;
- args.Dispose();
-
- SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
- newArgs.Completed += HandleIOCompleted;
- connectAsyncEventArgsPool.Return(newArgs);
- });
- */
-
- // if the connect operation doesn't complete synchronously, return the awaitable task
- if (socket.ConnectAsync(args)) return tcs.Task;
-
- connectAsyncEventArgsPool.Return(args);
-
- return Task.CompletedTask;
- }
-
- /// <summary>
- /// Provides an awaitable wrapper around an asynchronous socket disconnect operation.
- /// </summary>
- /// <param name="socket">The socket which should asynchronously disconnect from its remote endpoint.</param>
- /// <param name="cancellationToken">The cancellation token to observe for the operation.</param>
- public Task DisconnectAsync(Socket socket, CancellationToken cancellationToken = default)
- {
- TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
-
- SocketAsyncEventArgs args = connectAsyncEventArgsPool.Get();
- args.UserToken = new AsyncDisconnectToken(tcs, cancellationToken);
-
- /*
- // register cleanup action for when the cancellation token is thrown
- cancellationToken.Register(() =>
- {
- tcs.SetCanceled();
-
- //TODO this is probably a hideous solution. find a better one
- args.Completed -= HandleIOCompleted;
- args.Dispose();
-
- SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
- newArgs.Completed += HandleIOCompleted;
- disconnectAsyncEventArgsPool.Return(newArgs);
- });
- */
-
- // if the disconnect operation doesn't complete synchronously, return the awaitable task
- if (socket.DisconnectAsync(args)) return tcs.Task;
-
- connectAsyncEventArgsPool.Return(args);
-
- return Task.CompletedTask;
- }
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Sockets/SocketAsyncOperationTokens.cs b/NetSharp/NetSharp/Sockets/SocketAsyncOperationTokens.cs
@@ -0,0 +1,91 @@
+using NetSharp.Utils;
+
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace NetSharp.Sockets
+{
+ internal readonly struct AsyncAcceptToken
+ {
+ public readonly CancellationToken CancellationToken;
+ public readonly TaskCompletionSource<bool> CompletionSource;
+
+ public AsyncAcceptToken(in TaskCompletionSource<bool> tcs, in CancellationToken cancellationToken = default)
+ {
+ CompletionSource = tcs;
+ CancellationToken = cancellationToken;
+ }
+ }
+
+ internal readonly struct AsyncConnectToken
+ {
+ public readonly CancellationToken CancellationToken;
+ public readonly TaskCompletionSource<bool> CompletionSource;
+
+ public AsyncConnectToken(in TaskCompletionSource<bool> tcs, in CancellationToken cancellationToken = default)
+ {
+ CompletionSource = tcs;
+ CancellationToken = cancellationToken;
+ }
+ }
+
+ internal readonly struct AsyncDisconnectToken
+ {
+ public readonly CancellationToken CancellationToken;
+ public readonly TaskCompletionSource<bool> CompletionSource;
+
+ public AsyncDisconnectToken(in TaskCompletionSource<bool> tcs, in CancellationToken cancellationToken = default)
+ {
+ CompletionSource = tcs;
+ CancellationToken = cancellationToken;
+ }
+ }
+
+ internal readonly struct AsyncReadToken
+ {
+ public readonly CancellationToken CancellationToken;
+ public readonly TaskCompletionSource<TransmissionResult> CompletionSource;
+
+ public AsyncReadToken(in TaskCompletionSource<TransmissionResult> tcs, in CancellationToken cancellationToken = default)
+ {
+ CompletionSource = tcs;
+ CancellationToken = cancellationToken;
+ }
+ }
+
+ internal readonly struct AsyncWriteToken
+ {
+ public readonly CancellationToken CancellationToken;
+ public readonly TaskCompletionSource<TransmissionResult> CompletionSource;
+
+ public AsyncWriteToken(in TaskCompletionSource<TransmissionResult> tcs, in CancellationToken cancellationToken = default)
+ {
+ CompletionSource = tcs;
+ CancellationToken = cancellationToken;
+ }
+ }
+
+ internal readonly struct AsyncReadFromToken
+ {
+ public readonly CancellationToken CancellationToken;
+ public readonly TaskCompletionSource<TransmissionResult> CompletionSource;
+
+ public AsyncReadFromToken(in TaskCompletionSource<TransmissionResult> tcs, in CancellationToken cancellationToken = default)
+ {
+ CompletionSource = tcs;
+ CancellationToken = cancellationToken;
+ }
+ }
+
+ internal readonly struct AsyncWriteToToken
+ {
+ public readonly CancellationToken CancellationToken;
+ public readonly TaskCompletionSource<TransmissionResult> CompletionSource;
+
+ public AsyncWriteToToken(in TaskCompletionSource<TransmissionResult> tcs, in CancellationToken cancellationToken = default)
+ {
+ CompletionSource = tcs;
+ CancellationToken = cancellationToken;
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Sockets/SocketAsyncOperations.cs b/NetSharp/NetSharp/Sockets/SocketAsyncOperations.cs
@@ -0,0 +1,307 @@
+using NetSharp.Utils;
+
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace NetSharp.Sockets
+{
+ public static class SocketAsyncOperations
+ {
+ /// <summary>
+ /// Event handler for the <see cref="SocketAsyncEventArgs.Completed"/> event.
+ /// </summary>
+ /// <param name="sender">The object on which the event is raised.</param>
+ /// <param name="args">The event arguments.</param>
+ public static void HandleIoCompleted(object sender, SocketAsyncEventArgs args)
+ {
+ switch (args.LastOperation)
+ {
+ case SocketAsyncOperation.Accept:
+ AsyncAcceptToken asyncAcceptToken = (AsyncAcceptToken)args.UserToken;
+
+ if (asyncAcceptToken.CancellationToken.IsCancellationRequested)
+ {
+ asyncAcceptToken.CompletionSource.SetCanceled();
+ }
+ else
+ {
+ if (args.SocketError != SocketError.Success)
+ {
+ asyncAcceptToken.CompletionSource.SetException(
+ new SocketException((int)args.SocketError));
+ }
+ else
+ {
+ asyncAcceptToken.CompletionSource.SetResult(true);
+ }
+ }
+
+ break;
+
+ case SocketAsyncOperation.Connect:
+ AsyncConnectToken asyncConnectToken = (AsyncConnectToken)args.UserToken;
+
+ if (asyncConnectToken.CancellationToken.IsCancellationRequested)
+ {
+ asyncConnectToken.CompletionSource.SetCanceled();
+ }
+ else
+ {
+ if (args.SocketError != SocketError.Success)
+ {
+ asyncConnectToken.CompletionSource.SetException(
+ new SocketException((int)args.SocketError));
+ }
+ else
+ {
+ asyncConnectToken.CompletionSource.SetResult(true);
+ }
+ }
+
+ break;
+
+ case SocketAsyncOperation.Disconnect:
+ AsyncDisconnectToken asyncDisconnectToken = (AsyncDisconnectToken)args.UserToken;
+
+ if (asyncDisconnectToken.CancellationToken.IsCancellationRequested)
+ {
+ asyncDisconnectToken.CompletionSource.SetCanceled();
+ }
+ else
+ {
+ if (args.SocketError != SocketError.Success)
+ {
+ asyncDisconnectToken.CompletionSource.SetException(
+ new SocketException((int)args.SocketError));
+ }
+ else
+ {
+ asyncDisconnectToken.CompletionSource.SetResult(true);
+ }
+ }
+
+ break;
+
+ case SocketAsyncOperation.Receive:
+ AsyncReadToken asyncReceiveToken = (AsyncReadToken)args.UserToken;
+
+ if (asyncReceiveToken.CancellationToken.IsCancellationRequested)
+ {
+ asyncReceiveToken.CompletionSource.SetCanceled();
+ }
+ else
+ {
+ if (args.SocketError != SocketError.Success)
+ {
+ asyncReceiveToken.CompletionSource.SetException(
+ new SocketException((int)args.SocketError));
+ }
+ else if (args.BytesTransferred > 0)
+ {
+ TransmissionResult result = new TransmissionResult(args);
+
+ asyncReceiveToken.CompletionSource.SetResult(result);
+ }
+ else
+ {
+ asyncReceiveToken.CompletionSource.SetException(
+ new Exception($"Receive method received 0 bytes from remote endpoint!"));
+ }
+ }
+
+ break;
+
+ case SocketAsyncOperation.ReceiveFrom:
+ AsyncReadFromToken asyncReceiveFromToken = (AsyncReadFromToken)args.UserToken;
+
+ if (asyncReceiveFromToken.CancellationToken.IsCancellationRequested)
+ {
+ asyncReceiveFromToken.CompletionSource.SetCanceled();
+ }
+ else
+ {
+ if (args.SocketError != SocketError.Success)
+ {
+ asyncReceiveFromToken.CompletionSource.SetException(
+ new SocketException((int)args.SocketError));
+ }
+ else
+ {
+ TransmissionResult result = new TransmissionResult(args);
+
+ asyncReceiveFromToken.CompletionSource.SetResult(result);
+ }
+ }
+
+ break;
+
+ case SocketAsyncOperation.Send:
+ AsyncWriteToken asyncSendToken = (AsyncWriteToken)args.UserToken;
+
+ if (asyncSendToken.CancellationToken.IsCancellationRequested)
+ {
+ asyncSendToken.CompletionSource.SetCanceled();
+ }
+ else
+ {
+ if (args.SocketError != SocketError.Success)
+ {
+ asyncSendToken.CompletionSource.SetException(
+ new SocketException((int)args.SocketError));
+ }
+ else
+ {
+ TransmissionResult result = new TransmissionResult(args);
+
+ asyncSendToken.CompletionSource.SetResult(result);
+ }
+ }
+
+ break;
+
+ case SocketAsyncOperation.SendTo:
+ AsyncWriteToToken asyncSendToToken = (AsyncWriteToToken)args.UserToken;
+
+ if (asyncSendToToken.CancellationToken.IsCancellationRequested)
+ {
+ asyncSendToToken.CompletionSource.SetCanceled();
+ }
+ else
+ {
+ if (args.SocketError != SocketError.Success)
+ {
+ asyncSendToToken.CompletionSource.SetException(
+ new SocketException((int)args.SocketError));
+ }
+ else
+ {
+ TransmissionResult result = new TransmissionResult(args);
+
+ asyncSendToToken.CompletionSource.SetResult(result);
+ }
+ }
+
+ break;
+
+ case SocketAsyncOperation.None:
+ case SocketAsyncOperation.ReceiveMessageFrom:
+ case SocketAsyncOperation.SendPackets:
+ throw new InvalidOperationException(
+ $"{nameof(args.LastOperation)} is not supported by {nameof(SocketAsyncOperations)}");
+
+ default:
+ throw new ArgumentOutOfRangeException(nameof(args.LastOperation),
+ $"Invalid value in the {nameof(args.LastOperation)} enum.");
+ }
+ }
+
+ public static ValueTask AcceptAsync(SocketAsyncEventArgs clientAcceptArgs, Socket socket,
+ CancellationToken cancellationToken = default)
+ {
+ TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
+
+ clientAcceptArgs.UserToken = new AsyncAcceptToken(tcs, cancellationToken);
+
+ // if the accept operation doesn't complete synchronously, return the awaitable task
+ return socket.AcceptAsync(clientAcceptArgs) ? new ValueTask(tcs.Task) : new ValueTask();
+ }
+
+ public static ValueTask ConnectAsync(SocketAsyncEventArgs clientConnectArgs, Socket socket, EndPoint remoteEndPoint,
+ CancellationToken cancellationToken = default)
+ {
+ TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
+
+ clientConnectArgs.RemoteEndPoint = remoteEndPoint;
+ clientConnectArgs.UserToken = new AsyncConnectToken(tcs, cancellationToken);
+
+ // if the connect operation doesn't complete synchronously, return the awaitable task
+ return socket.ConnectAsync(clientConnectArgs) ? new ValueTask(tcs.Task) : new ValueTask();
+ }
+
+ public static ValueTask DisconnectAsync(SocketAsyncEventArgs clientDisconnectArgs, Socket socket,
+ CancellationToken cancellationToken = default)
+ {
+ TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
+
+ clientDisconnectArgs.UserToken = new AsyncDisconnectToken(tcs, cancellationToken);
+
+ // if the disconnect operation doesn't complete synchronously, return the awaitable task
+ return socket.DisconnectAsync(clientDisconnectArgs) ? new ValueTask(tcs.Task) : new ValueTask();
+ }
+
+ public static ValueTask<TransmissionResult> ReceiveAsync(SocketAsyncEventArgs socketArgs, Socket socket, EndPoint remoteEndPoint,
+ SocketFlags socketFlags, Memory<byte> inputBuffer, CancellationToken cancellationToken = default)
+ {
+ TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>();
+
+ socketArgs.SetBuffer(inputBuffer);
+ socketArgs.SocketFlags = socketFlags;
+ socketArgs.RemoteEndPoint = remoteEndPoint;
+ socketArgs.UserToken = new AsyncReadToken(tcs, cancellationToken);
+
+ // if the receive operation doesn't complete synchronously, returns the awaitable task
+ if (socket.ReceiveAsync(socketArgs)) return new ValueTask<TransmissionResult>(tcs.Task);
+
+ TransmissionResult result = new TransmissionResult(socketArgs);
+
+ return new ValueTask<TransmissionResult>(result);
+ }
+
+ public static ValueTask<TransmissionResult> ReceiveFromAsync(SocketAsyncEventArgs socketArgs, Socket socket, EndPoint remoteEndPoint,
+ SocketFlags socketFlags, Memory<byte> inputBuffer, CancellationToken cancellationToken = default)
+ {
+ TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>();
+
+ socketArgs.SetBuffer(inputBuffer);
+ socketArgs.SocketFlags = socketFlags;
+ socketArgs.RemoteEndPoint = remoteEndPoint;
+ socketArgs.UserToken = new AsyncReadFromToken(tcs, cancellationToken);
+
+ // if the receive operation doesn't complete synchronously, returns the awaitable task
+ if (socket.ReceiveFromAsync(socketArgs)) return new ValueTask<TransmissionResult>(tcs.Task);
+
+ TransmissionResult result = new TransmissionResult(socketArgs);
+
+ return new ValueTask<TransmissionResult>(result);
+ }
+
+ public static ValueTask<TransmissionResult> SendAsync(SocketAsyncEventArgs socketArgs, Socket socket, EndPoint remoteEndPoint,
+ SocketFlags socketFlags, Memory<byte> outputBuffer, CancellationToken cancellationToken = default)
+ {
+ TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>();
+
+ socketArgs.SetBuffer(outputBuffer);
+ socketArgs.SocketFlags = socketFlags;
+ socketArgs.RemoteEndPoint = remoteEndPoint;
+ socketArgs.UserToken = new AsyncWriteToken(tcs, cancellationToken);
+
+ // if the send operation doesn't complete synchronously, return the awaitable task
+ if (socket.SendAsync(socketArgs)) return new ValueTask<TransmissionResult>(tcs.Task);
+
+ TransmissionResult result = new TransmissionResult(socketArgs);
+
+ return new ValueTask<TransmissionResult>(result);
+ }
+
+ public static ValueTask<TransmissionResult> SendToAsync(SocketAsyncEventArgs socketArgs, Socket socket, EndPoint remoteEndPoint,
+ SocketFlags socketFlags, Memory<byte> outputBuffer, CancellationToken cancellationToken = default)
+ {
+ TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>();
+
+ socketArgs.SetBuffer(outputBuffer);
+ socketArgs.SocketFlags = socketFlags;
+ socketArgs.RemoteEndPoint = remoteEndPoint;
+ socketArgs.UserToken = new AsyncWriteToToken(tcs, cancellationToken);
+
+ // if the send operation doesn't complete synchronously, return the awaitable task
+ if (socket.SendToAsync(socketArgs)) return new ValueTask<TransmissionResult>(tcs.Task);
+
+ TransmissionResult result = new TransmissionResult(socketArgs);
+
+ return new ValueTask<TransmissionResult>(result);
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Sockets/SocketClient.cs b/NetSharp/NetSharp/Sockets/SocketClient.cs
@@ -1,92 +1,48 @@
-using System;
+using NetSharp.Packets;
+
+using System;
+using System.Buffers;
using System.Net;
using System.Net.Sockets;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.Extensions.ObjectPool;
-using NetSharp.Utils;
namespace NetSharp.Sockets
{
- public class SocketClient : IDisposable
+ public abstract class SocketClient : SocketConnection
{
- private readonly ObjectPool<SocketAsyncEventArgs> transmissionArgsPool;
+ protected readonly ArrayPool<byte> BufferPool;
- /// <summary>
- /// Destroys a socket client instance.
- /// </summary>
- ~SocketClient()
+ protected SocketClient(in AddressFamily connectionAddressFamily, in SocketType connectionSocketType, in ProtocolType connectionProtocolType)
+ : base(in connectionAddressFamily, in connectionSocketType, in connectionProtocolType)
{
- Dispose(false);
+ BufferPool = ArrayPool<byte>.Create(NetworkPacket.TotalSize, 10);
}
- protected readonly Socket transmitterSocket;
-
- /// <summary>
- /// Implementation of dispose pattern.
- /// </summary>
- /// <param name="disposing">
- /// Whether this method is being called by the object finalizer, or by the <see cref="Dispose()"/> method.
- /// </param>
- protected virtual void Dispose(bool disposing)
+ public int SendBytes(Memory<byte> outgoingDataBuffer)
{
- if (disposing)
- {
- transmitterSocket.Dispose();
- }
+ return connection.Send(outgoingDataBuffer.Span);
}
- public SocketClient(AddressFamily transmitterAddressFamily, SocketType transmitterSocketType,
- ProtocolType transmitterProtocolType)
+ public int SendBytesTo(Memory<byte> outgoingDataBuffer, EndPoint remoteEndPoint)
{
- transmitterSocket = new Socket(transmitterAddressFamily, transmitterSocketType, transmitterProtocolType);
-
- transmissionArgsPool = new DefaultObjectPool<SocketAsyncEventArgs>(new DefaultPooledObjectPolicy<SocketAsyncEventArgs>());
+ return connection.SendTo(outgoingDataBuffer.ToArray(), remoteEndPoint);
}
- /// <inheritdoc />
- public void Dispose()
+ public int ReceiveBytes(Memory<byte> incomingDataBuffer)
{
- Dispose(true);
- GC.SuppressFinalize(this);
- }
+ byte[] temporaryBuffer = new byte[NetworkPacket.TotalSize];
+ int receivedBytes = connection.Receive(temporaryBuffer);
+ temporaryBuffer.CopyTo(incomingDataBuffer);
- public ValueTask<TransmissionResult> ReceiveAsync(EndPoint remoteEndPoint, SocketFlags receiveFlags, Memory<byte> receiveBuffer,
- CancellationToken cancellationToken = default)
- {
- return SocketOperations.ReceiveFromAsync(transmissionArgsPool, transmitterSocket, remoteEndPoint,
- receiveFlags, receiveBuffer, cancellationToken);
+ return receivedBytes;
}
- public ValueTask<TransmissionResult> SendAsync(EndPoint remoteEndPoint, SocketFlags sendFlags, Memory<byte> sendBuffer,
- CancellationToken cancellationToken = default)
+ public int ReceiveBytesFrom(Memory<byte> incomingDataBuffer, ref EndPoint remoteEndPoint)
{
- return SocketOperations.SendToAsync(transmissionArgsPool, transmitterSocket, remoteEndPoint, sendFlags,
- sendBuffer, cancellationToken);
- }
-
- public Task<bool> TryBindAsync(EndPoint localEndPoint, TimeSpan timeout)
- {
- using CancellationTokenSource cts = new CancellationTokenSource(timeout);
-
- try
- {
- return Task.Run(() =>
- {
- transmitterSocket.Bind(localEndPoint);
+ byte[] temporaryBuffer = new byte[NetworkPacket.TotalSize];
+ int receivedBytes = connection.ReceiveFrom(temporaryBuffer, ref remoteEndPoint);
+ temporaryBuffer.CopyTo(incomingDataBuffer);
- return true;
- }, cts.Token);
- }
- catch (TaskCanceledException)
- {
- return Task.FromResult(false);
- }
- catch (SocketException ex)
- {
- Console.WriteLine($"Socket exception on binding socket to {localEndPoint}: {ex}");
- return Task.FromResult(false);
- }
+ return receivedBytes;
}
}
}
\ No newline at end of file
diff --git a/NetSharp/NetSharp/Sockets/SocketConnection.cs b/NetSharp/NetSharp/Sockets/SocketConnection.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Net;
+using System.Net.Sockets;
+
+namespace NetSharp.Sockets
+{
+ public abstract class SocketConnection : IDisposable
+ {
+ protected readonly Socket connection;
+
+ protected SocketConnection(in AddressFamily connectionAddressFamily, in SocketType connectionSocketType, in ProtocolType connectionProtocolType)
+ {
+ connection = new Socket(connectionAddressFamily, connectionSocketType, connectionProtocolType);
+ }
+
+ public void Bind(in EndPoint localEndPoint)
+ {
+ connection.Bind(localEndPoint);
+ }
+
+ public void Shutdown(SocketShutdown how)
+ {
+ try
+ {
+ connection.Shutdown(how);
+ }
+ catch (SocketException) { }
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!disposing) return;
+
+ connection.Close();
+ connection.Dispose();
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Sockets/SocketOperations.cs b/NetSharp/NetSharp/Sockets/SocketOperations.cs
@@ -1,427 +0,0 @@
-using System;
-using System.Buffers;
-using System.Net;
-using System.Net.Sockets;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.Extensions.ObjectPool;
-using NetSharp.Utils;
-
-namespace NetSharp.Sockets
-{
- /// <summary>
- /// Provides helper awaitable functions for wrapping the <see cref="SocketAsyncEventArgs"/> pattern.
- /// </summary>
- public static class SocketOperations
- {
- private static void HandleIOCompleted(object? sender, SocketAsyncEventArgs args)
- {
- args.Completed -= HandleIOCompleted;
-
- switch (args.LastOperation)
- {
- case SocketAsyncOperation.ReceiveFrom:
- AsyncReadToken asyncReceiveFromToken = (AsyncReadToken)args.UserToken;
-
- if (asyncReceiveFromToken.CancellationToken.IsCancellationRequested)
- {
- asyncReceiveFromToken.CompletionSource.SetCanceled();
- }
- else
- {
- if (args.SocketError != SocketError.Success)
- {
- asyncReceiveFromToken.CompletionSource.SetException(
- new SocketException((int)args.SocketError));
- }
- else
- {
- TransmissionResult result = new TransmissionResult(args);
-
- asyncReceiveFromToken.CompletionSource.SetResult(result);
- }
- }
-
- asyncReceiveFromToken.ReadArgsPool.Return(args);
-
- break;
-
- case SocketAsyncOperation.SendTo:
- AsyncWriteToken asyncSendToToken = (AsyncWriteToken)args.UserToken;
-
- if (asyncSendToToken.CancellationToken.IsCancellationRequested)
- {
- asyncSendToToken.CompletionSource.SetCanceled();
- }
- else
- {
- if (args.SocketError != SocketError.Success)
- {
- asyncSendToToken.CompletionSource.SetException(
- new SocketException((int)args.SocketError));
- }
- else
- {
- TransmissionResult result = new TransmissionResult(args);
-
- asyncSendToToken.CompletionSource.SetResult(result);
- }
- }
-
- asyncSendToToken.WriteArgsPool.Return(args);
- break;
-
- case SocketAsyncOperation.Accept:
- AsyncAcceptToken asyncAcceptToken = (AsyncAcceptToken)args.UserToken;
-
- if (asyncAcceptToken.CancellationToken.IsCancellationRequested)
- {
- asyncAcceptToken.CompletionSource.SetCanceled();
- }
- else
- {
- if (args.SocketError != SocketError.Success)
- {
- asyncAcceptToken.CompletionSource.SetException(
- new SocketException((int)args.SocketError));
- }
- else
- {
- asyncAcceptToken.CompletionSource.SetResult(args.AcceptSocket);
- }
- }
-
- asyncAcceptToken.AcceptArgsPool.Return(args);
-
- break;
-
- case SocketAsyncOperation.Connect:
- AsyncConnectToken asyncConnectToken = (AsyncConnectToken)args.UserToken;
-
- if (asyncConnectToken.CancellationToken.IsCancellationRequested)
- {
- asyncConnectToken.CompletionSource.SetCanceled();
- }
- else
- {
- if (args.SocketError != SocketError.Success)
- {
- asyncConnectToken.CompletionSource.SetException(
- new SocketException((int)args.SocketError));
- }
- else
- {
- asyncConnectToken.CompletionSource.SetResult(args.ConnectSocket);
- }
- }
-
- asyncConnectToken.ConnectArgsPool.Return(args);
-
- break;
-
- case SocketAsyncOperation.Disconnect:
- AsyncOperationToken asyncDisconnectToken = (AsyncOperationToken)args.UserToken;
-
- if (asyncDisconnectToken.CancellationToken.IsCancellationRequested)
- {
- asyncDisconnectToken.CompletionSource.SetCanceled();
- }
- else
- {
- if (args.SocketError != SocketError.Success)
- {
- asyncDisconnectToken.CompletionSource.SetException(
- new SocketException((int)args.SocketError));
- }
- else
- {
- asyncDisconnectToken.CompletionSource.SetResult(true);
- }
- }
-
- asyncDisconnectToken.OperationArgsPool.Return(args);
-
- break;
-
- default:
- throw new InvalidOperationException(
- $"The {nameof(SocketReader)} class doesn't support the {args.LastOperation} operation.");
- }
- }
-
- private readonly struct AsyncAcceptToken
- {
- public readonly ObjectPool<SocketAsyncEventArgs> AcceptArgsPool;
- public readonly CancellationToken CancellationToken;
- public readonly TaskCompletionSource<Socket> CompletionSource;
-
- public AsyncAcceptToken(in ObjectPool<SocketAsyncEventArgs> argsPool, in TaskCompletionSource<Socket> tcs,
- in CancellationToken cancellationToken = default)
- {
- AcceptArgsPool = argsPool;
-
- CompletionSource = tcs;
- CancellationToken = cancellationToken;
- }
- }
-
- private readonly struct AsyncConnectToken
- {
- public readonly CancellationToken CancellationToken;
- public readonly TaskCompletionSource<Socket> CompletionSource;
- public readonly ObjectPool<SocketAsyncEventArgs> ConnectArgsPool;
-
- public AsyncConnectToken(in ObjectPool<SocketAsyncEventArgs> argsPool, in TaskCompletionSource<Socket> tcs,
- in CancellationToken cancellationToken = default)
- {
- ConnectArgsPool = argsPool;
-
- CompletionSource = tcs;
- CancellationToken = cancellationToken;
- }
- }
-
- private readonly struct AsyncOperationToken
- {
- public readonly CancellationToken CancellationToken;
- public readonly TaskCompletionSource<bool> CompletionSource;
- public readonly ObjectPool<SocketAsyncEventArgs> OperationArgsPool;
-
- public AsyncOperationToken(in ObjectPool<SocketAsyncEventArgs> argsPool, in TaskCompletionSource<bool> tcs,
- in CancellationToken cancellationToken = default)
- {
- OperationArgsPool = argsPool;
-
- CompletionSource = tcs;
- CancellationToken = cancellationToken;
- }
- }
-
- private readonly struct AsyncReadToken
- {
- public readonly CancellationToken CancellationToken;
- public readonly TaskCompletionSource<TransmissionResult> CompletionSource;
- public readonly ObjectPool<SocketAsyncEventArgs> ReadArgsPool;
- public readonly Memory<byte> UserBuffer;
-
- public AsyncReadToken(in ObjectPool<SocketAsyncEventArgs> argsPool, in Memory<byte> userBuffer,
- in TaskCompletionSource<TransmissionResult> tcs, in CancellationToken cancellationToken = default)
- {
- ReadArgsPool = argsPool;
- UserBuffer = userBuffer;
-
- CompletionSource = tcs;
- CancellationToken = cancellationToken;
- }
- }
-
- private readonly struct AsyncWriteToken
- {
- public readonly CancellationToken CancellationToken;
- public readonly TaskCompletionSource<TransmissionResult> CompletionSource;
- public readonly ObjectPool<SocketAsyncEventArgs> WriteArgsPool;
-
- public AsyncWriteToken(in ObjectPool<SocketAsyncEventArgs> argsPool,
- in TaskCompletionSource<TransmissionResult> tcs, in CancellationToken cancellationToken = default)
- {
- WriteArgsPool = argsPool;
-
- CompletionSource = tcs;
- CancellationToken = cancellationToken;
- }
- }
-
- public static Task<Socket> AcceptAsync(ObjectPool<SocketAsyncEventArgs> acceptArgsPool,
- Socket socket, CancellationToken cancellationToken = default)
- {
- TaskCompletionSource<Socket> tcs = new TaskCompletionSource<Socket>();
-
- SocketAsyncEventArgs args = acceptArgsPool.Get();
- args.UserToken = new AsyncAcceptToken(acceptArgsPool, tcs, cancellationToken);
-
- /*
- // register cleanup action for when the cancellation token is thrown
- cancellationToken.Register(() =>
- {
- tcs.SetCanceled();
-
- //TODO this is probably a hideous solution. find a better one
- args.Completed -= HandleIOCompleted;
- args.Dispose();
-
- SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
- newArgs.Completed += HandleIOCompleted;
- acceptAsyncEventArgsPool.Return(newArgs);
- });
- */
-
- // if the accept operation doesn't complete synchronously, return the awaitable task
- if (socket.AcceptAsync(args)) return tcs.Task;
-
- Socket result = args.AcceptSocket;
- args.Completed -= HandleIOCompleted;
-
- acceptArgsPool.Return(args);
-
- return Task.FromResult(result);
- }
-
- public static Task<Socket> ConnectAsync(ObjectPool<SocketAsyncEventArgs> connectArgsPool,
- Socket socket, EndPoint remoteEndPoint, CancellationToken cancellationToken = default)
- {
- TaskCompletionSource<Socket> tcs = new TaskCompletionSource<Socket>();
-
- SocketAsyncEventArgs args = connectArgsPool.Get();
- args.RemoteEndPoint = remoteEndPoint;
- args.UserToken = new AsyncConnectToken(connectArgsPool, tcs, cancellationToken);
-
- /*
- // register cleanup action for when the cancellation token is thrown
- cancellationToken.Register(() =>
- {
- tcs.SetCanceled();
-
- //TODO this is probably a hideous solution. find a better one
- args.Completed -= HandleIOCompleted;
- args.Dispose();
-
- SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
- newArgs.Completed += HandleIOCompleted;
- connectAsyncEventArgsPool.Return(newArgs);
- });
- */
-
- // if the connect operation doesn't complete synchronously, return the awaitable task
- if (socket.ConnectAsync(args)) return tcs.Task;
-
- Socket result = args.ConnectSocket;
- args.Completed -= HandleIOCompleted;
-
- connectArgsPool.Return(args);
-
- return Task.FromResult(result);
- }
-
- public static Task DisconnectAsync(ObjectPool<SocketAsyncEventArgs> disconnectArgsPool,
- Socket socket, CancellationToken cancellationToken = default)
- {
- TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
-
- SocketAsyncEventArgs args = disconnectArgsPool.Get();
- args.UserToken = new AsyncOperationToken(disconnectArgsPool, tcs, cancellationToken);
-
- /*
- // register cleanup action for when the cancellation token is thrown
- cancellationToken.Register(() =>
- {
- tcs.SetCanceled();
-
- //TODO this is probably a hideous solution. find a better one
- args.Completed -= HandleIOCompleted;
- args.Dispose();
-
- SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
- newArgs.Completed += HandleIOCompleted;
- disconnectAsyncEventArgsPool.Return(newArgs);
- });
- */
-
- // if the disconnect operation doesn't complete synchronously, return the awaitable task
- if (socket.DisconnectAsync(args)) return tcs.Task;
-
- args.Completed -= HandleIOCompleted;
-
- disconnectArgsPool.Return(args);
-
- return Task.CompletedTask;
- }
-
- public static ValueTask<TransmissionResult> ReceiveFromAsync(ObjectPool<SocketAsyncEventArgs> receiveArgsPool,
- Socket socket, EndPoint remoteEndPoint, SocketFlags socketFlags, Memory<byte> inputBuffer,
- CancellationToken cancellationToken = default)
- {
- TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>();
-
- SocketAsyncEventArgs args = receiveArgsPool.Get();
- args.SetBuffer(inputBuffer);
- args.SocketFlags = socketFlags;
- args.RemoteEndPoint = remoteEndPoint;
- args.UserToken = new AsyncReadToken(receiveArgsPool, inputBuffer, tcs, cancellationToken);
-
- args.Completed += HandleIOCompleted;
-
- /*
- // register cleanup action for when the cancellation token is thrown
- cancellationToken.Register(() =>
- {
- tcs.SetCanceled();
-
- receiveBufferPool.Return(rentedReceiveFromBuffer, true);
-
- //TODO this is probably a hideous solution. find a better one
- args.Completed -= HandleIOCompleted;
- args.Dispose();
-
- SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
- newArgs.Completed += HandleIOCompleted;
- receiveAsyncEventArgsPool.Return(newArgs);
- });
- */
-
- // if the receive operation doesn't complete synchronously, returns the awaitable task
- if (socket.ReceiveFromAsync(args)) return new ValueTask<TransmissionResult>(tcs.Task);
-
- args.Completed -= HandleIOCompleted;
-
- TransmissionResult result = new TransmissionResult(args);
-
- receiveArgsPool.Return(args);
-
- return new ValueTask<TransmissionResult>(result);
- }
-
- public static ValueTask<TransmissionResult> SendToAsync(ObjectPool<SocketAsyncEventArgs> sendArgsPool,
- Socket socket, EndPoint remoteEndPoint, SocketFlags socketFlags, Memory<byte> outputBuffer,
- CancellationToken cancellationToken = default)
- {
- TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>();
-
- SocketAsyncEventArgs args = sendArgsPool.Get();
- args.SetBuffer(outputBuffer);
- args.SocketFlags = socketFlags;
- args.RemoteEndPoint = remoteEndPoint;
- args.UserToken = new AsyncWriteToken(sendArgsPool, tcs, cancellationToken);
-
- args.Completed += HandleIOCompleted;
-
- /*
- // register cleanup action for when the cancellation token is thrown
- cancellationToken.Register(() =>
- {
- tcs.SetCanceled();
-
- sendBufferPool.Return(rentedSendToBuffer, true);
-
- //TODO this is probably a hideous solution. find a better one
- args.Completed -= HandleIOCompleted;
- args.Dispose();
-
- SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
- newArgs.Completed += HandleIOCompleted;
- sendAsyncEventArgsPool.Return(newArgs);
- });
- */
-
- // if the send operation doesn't complete synchronously, return the awaitable task
- if (socket.SendToAsync(args)) return new ValueTask<TransmissionResult>(tcs.Task);
-
- args.Completed -= HandleIOCompleted;
-
- TransmissionResult result = new TransmissionResult(args);
-
- sendArgsPool.Return(args);
-
- return new ValueTask<TransmissionResult>(result);
- }
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Sockets/SocketReader.cs b/NetSharp/NetSharp/Sockets/SocketReader.cs
@@ -1,152 +0,0 @@
-using System;
-using System.Buffers;
-using System.Net;
-using System.Net.Sockets;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.Extensions.ObjectPool;
-using NetSharp.Packets;
-using NetSharp.Utils;
-
-namespace NetSharp.Sockets
-{
- /// <summary>
- /// Helper class providing awaitable wrappers around asynchronous Receive and ReceiveFrom operations.
- /// </summary>
- public sealed class SocketReader
- {
- private readonly int PacketBufferLength;
- private readonly ObjectPool<SocketAsyncEventArgs> receiveFromAsyncEventArgsPool;
- private readonly ArrayPool<byte> receiveFromBufferPool;
-
- private void HandleIOCompleted(object? sender, SocketAsyncEventArgs args)
- {
- switch (args.LastOperation)
- {
- case SocketAsyncOperation.ReceiveFrom:
- AsyncReadToken asyncReceiveFromToken = (AsyncReadToken)args.UserToken;
-
- if (asyncReceiveFromToken.CancellationToken.IsCancellationRequested)
- {
- asyncReceiveFromToken.CompletionSource.SetCanceled();
- }
- else
- {
- if (args.SocketError != SocketError.Success)
- {
- asyncReceiveFromToken.CompletionSource.SetException(
- new SocketException((int)args.SocketError));
- }
- else
- {
- args.MemoryBuffer.CopyTo(asyncReceiveFromToken.UserBuffer);
-
- TransmissionResult result = new TransmissionResult(args);
-
- asyncReceiveFromToken.CompletionSource.SetResult(result);
- }
- }
-
- receiveFromBufferPool.Return(asyncReceiveFromToken.RentedBuffer, true);
- receiveFromAsyncEventArgsPool.Return(args);
-
- break;
-
- default:
- throw new InvalidOperationException(
- $"The {nameof(SocketReader)} class doesn't support the {args.LastOperation} operation.");
- }
- }
-
- private readonly struct AsyncReadToken
- {
- public readonly CancellationToken CancellationToken;
- public readonly TaskCompletionSource<TransmissionResult> CompletionSource;
- public readonly byte[] RentedBuffer;
- public readonly Memory<byte> UserBuffer;
-
- public AsyncReadToken(byte[] rentedBuffer, Memory<byte> userBuffer, TaskCompletionSource<TransmissionResult> tcs,
- CancellationToken cancellationToken = default)
- {
- RentedBuffer = rentedBuffer;
- UserBuffer = userBuffer;
-
- CompletionSource = tcs;
- CancellationToken = cancellationToken;
- }
- }
-
- internal SocketReader(int packetBufferLength = NetworkPacket.PacketSize, int maxPooledObjects = 10,
- bool preallocateBuffers = false)
- {
- PacketBufferLength = packetBufferLength;
-
- receiveFromBufferPool = ArrayPool<byte>.Create(packetBufferLength, maxPooledObjects);
-
- receiveFromAsyncEventArgsPool =
- new DefaultObjectPool<SocketAsyncEventArgs>(new DefaultPooledObjectPolicy<SocketAsyncEventArgs>(),
- maxPooledObjects);
-
- for (int i = 0; i < maxPooledObjects; i++)
- {
- SocketAsyncEventArgs receiveFromArgs = new SocketAsyncEventArgs();
- receiveFromArgs.Completed += HandleIOCompleted;
- receiveFromAsyncEventArgsPool.Return(receiveFromArgs);
- }
- }
-
- /// <summary>
- /// Provides an awaitable wrapper around an asynchronous socket receive operation.
- /// </summary>
- /// <param name="socket">The socket which should receive data from the remote endpoint.</param>
- /// <param name="remoteEndPoint">The remove endpoint from which data should be received.</param>
- /// <param name="socketFlags">The socket flags associated with the receive operation.</param>
- /// <param name="inputBuffer">The memory buffer into which received data will be stored.</param>
- /// <param name="cancellationToken">The cancellation token to observe for the operation.</param>
- /// <returns>The result of the receive operation.</returns>
- public Task<TransmissionResult> ReceiveFromAsync(Socket socket, EndPoint remoteEndPoint, SocketFlags socketFlags,
- Memory<byte> inputBuffer, CancellationToken cancellationToken = default)
- {
- TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>();
-
- byte[] rentedReceiveFromBuffer = receiveFromBufferPool.Rent(PacketBufferLength);
- Memory<byte> rentedReceiveFromBufferMemory = new Memory<byte>(rentedReceiveFromBuffer);
-
- SocketAsyncEventArgs args = receiveFromAsyncEventArgsPool.Get();
- args.SetBuffer(rentedReceiveFromBufferMemory);
- args.SocketFlags = socketFlags;
- args.RemoteEndPoint = remoteEndPoint;
- args.UserToken = new AsyncReadToken(rentedReceiveFromBuffer, inputBuffer, tcs, cancellationToken);
-
- /*
- // register cleanup action for when the cancellation token is thrown
- cancellationToken.Register(() =>
- {
- tcs.SetCanceled();
-
- receiveBufferPool.Return(rentedReceiveFromBuffer, true);
-
- //TODO this is probably a hideous solution. find a better one
- args.Completed -= HandleIOCompleted;
- args.Dispose();
-
- SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
- newArgs.Completed += HandleIOCompleted;
- receiveAsyncEventArgsPool.Return(newArgs);
- });
- */
-
- // if the receive operation doesn't complete synchronously, returns the awaitable task
- if (socket.ReceiveFromAsync(args)) return tcs.Task;
-
- args.MemoryBuffer.CopyTo(inputBuffer);
-
- TransmissionResult result = new TransmissionResult(args);
-
- receiveFromBufferPool.Return(rentedReceiveFromBuffer, true);
- receiveFromAsyncEventArgsPool.Return(args);
-
- return Task.FromResult(result);
- }
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Sockets/SocketServer.cs b/NetSharp/NetSharp/Sockets/SocketServer.cs
@@ -1,95 +1,35 @@
-using System;
+using NetSharp.Packets;
+
+using System.Buffers;
+using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
-using Microsoft.Extensions.ObjectPool;
-using NetSharp.Utils;
namespace NetSharp.Sockets
{
- public class SocketServer : IDisposable
+ public abstract class SocketServer : SocketConnection
{
- private readonly ObjectPool<SocketAsyncEventArgs> transmissionArgsPool;
+ protected readonly ConcurrentDictionary<EndPoint, Task> ConnectedClientHandlerTasks;
- /// <summary>
- /// Destroys a socket server instance.
- /// </summary>
- ~SocketServer()
- {
- Dispose(false);
- }
+ protected readonly ArrayPool<byte> BufferPool;
- /// <summary>
- /// The socket which should be used to listen for incoming data and to send outgoing data.
- /// </summary>
- protected readonly Socket listenerSocket;
-
- /// <summary>
- /// Implementation of dispose pattern.
- /// </summary>
- /// <param name="disposing">
- /// Whether this method is being called by the object finalizer, or by the <see cref="Dispose()"/> method.
- /// </param>
- protected virtual void Dispose(bool disposing)
+ protected SocketServer(in AddressFamily connectionAddressFamily, in SocketType connectionSocketType, in ProtocolType connectionProtocolType)
+ : base(in connectionAddressFamily, in connectionSocketType, in connectionProtocolType)
{
- if (disposing)
- {
- listenerSocket.Dispose();
- }
- }
+ BufferPool = ArrayPool<byte>.Create(NetworkPacket.TotalSize, 10);
- public SocketServer(AddressFamily listenerAddressFamily, SocketType listenerSocketType,
- ProtocolType listenerProtocolType)
- {
- listenerSocket = new Socket(listenerAddressFamily, listenerSocketType, listenerProtocolType);
-
- transmissionArgsPool = new DefaultObjectPool<SocketAsyncEventArgs>(new DefaultPooledObjectPolicy<SocketAsyncEventArgs>());
+ ConnectedClientHandlerTasks = new ConcurrentDictionary<EndPoint, Task>();
}
- /// <inheritdoc />
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
+ protected abstract SocketAsyncEventArgs GenerateConnectionArgs(EndPoint remoteEndPoint);
- public ValueTask<TransmissionResult> ReceiveAsync(EndPoint remoteEndPoint, SocketFlags receiveFlags, Memory<byte> receiveBuffer,
- CancellationToken cancellationToken = default)
- {
- return SocketOperations.ReceiveFromAsync(transmissionArgsPool, listenerSocket,
- remoteEndPoint, receiveFlags, receiveBuffer, cancellationToken);
- }
-
- public ValueTask<TransmissionResult> SendAsync(EndPoint remoteEndPoint, SocketFlags sendFlags, Memory<byte> sendBuffer,
- CancellationToken cancellationToken = default)
- {
- return SocketOperations.SendToAsync(transmissionArgsPool, listenerSocket,
- remoteEndPoint, sendFlags, sendBuffer, cancellationToken);
- }
-
- public Task<bool> TryBindAsync(EndPoint localEndPoint, TimeSpan timeout)
- {
- using CancellationTokenSource cts = new CancellationTokenSource(timeout);
+ protected abstract void DestroyConnectionArgs(SocketAsyncEventArgs remoteConnectionArgs);
- try
- {
- return Task.Run(() =>
- {
- listenerSocket.Bind(localEndPoint);
+ protected abstract Task HandleClient(SocketAsyncEventArgs clientArgs,
+ CancellationToken cancellationToken = default);
- return true;
- }, cts.Token);
- }
- catch (TaskCanceledException)
- {
- return Task.FromResult(false);
- }
- catch (SocketException ex)
- {
- Console.WriteLine($"Socket exception on binding socket to {localEndPoint}: {ex}");
- return Task.FromResult(false);
- }
- }
+ public abstract Task RunAsync(CancellationToken cancellationToken = default);
}
}
\ No newline at end of file
diff --git a/NetSharp/NetSharp/Sockets/SocketWriter.cs b/NetSharp/NetSharp/Sockets/SocketWriter.cs
@@ -1,144 +0,0 @@
-using System;
-using System.Buffers;
-using System.Net;
-using System.Net.Sockets;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.Extensions.ObjectPool;
-using NetSharp.Packets;
-
-namespace NetSharp.Sockets
-{
- /// <summary>
- /// Helper class providing awaitable wrappers around asynchronous Send and SendTo operations.
- /// </summary>
- public sealed class SocketWriter
- {
- private readonly int PacketBufferLength;
- private readonly ObjectPool<SocketAsyncEventArgs> sendToAsyncEventArgsPool;
- private readonly ArrayPool<byte> sendToBufferPool;
-
- private void HandleIOCompleted(object? sender, SocketAsyncEventArgs args)
- {
- switch (args.LastOperation)
- {
- case SocketAsyncOperation.SendTo:
- AsyncWriteToken asyncSendToToken = (AsyncWriteToken)args.UserToken;
-
- if (asyncSendToToken.CancellationToken.IsCancellationRequested)
- {
- asyncSendToToken.CompletionSource.SetCanceled();
- }
- else
- {
- if (args.SocketError != SocketError.Success)
- {
- asyncSendToToken.CompletionSource.SetException(
- new SocketException((int)args.SocketError));
- }
- else
- {
- asyncSendToToken.CompletionSource.SetResult(args.BytesTransferred);
- }
- }
-
- sendToBufferPool.Return(asyncSendToToken.RentedBuffer, true);
- sendToAsyncEventArgsPool.Return(args);
- break;
-
- default:
- throw new InvalidOperationException(
- $"The {nameof(SocketWriter)} class doesn't support the {args.LastOperation} operation.");
- }
- }
-
- private readonly struct AsyncWriteToken
- {
- public readonly CancellationToken CancellationToken;
- public readonly TaskCompletionSource<int> CompletionSource;
- public readonly byte[] RentedBuffer;
-
- public AsyncWriteToken(byte[] rentedBuffer, TaskCompletionSource<int> tcs,
- CancellationToken cancellationToken = default)
- {
- RentedBuffer = rentedBuffer;
-
- CompletionSource = tcs;
- CancellationToken = cancellationToken;
- }
- }
-
- internal SocketWriter(int packetBufferLength = NetworkPacket.PacketSize, int maxPooledObjects = 10,
- bool preallocateBuffers = false)
- {
- PacketBufferLength = packetBufferLength;
-
- sendToBufferPool = ArrayPool<byte>.Create(packetBufferLength, maxPooledObjects);
-
- sendToAsyncEventArgsPool =
- new DefaultObjectPool<SocketAsyncEventArgs>(new DefaultPooledObjectPolicy<SocketAsyncEventArgs>(),
- maxPooledObjects);
-
- for (int i = 0; i < maxPooledObjects; i++)
- {
- SocketAsyncEventArgs sendToArgs = new SocketAsyncEventArgs();
- sendToArgs.Completed += HandleIOCompleted;
- sendToAsyncEventArgsPool.Return(sendToArgs);
- }
- }
-
- /// <summary>
- /// Provides an awaitable wrapper around an asynchronous socket send operation.
- /// </summary>
- /// <param name="socket">The socket which should send the data to the remote endpoint.</param>
- /// <param name="remoteEndPoint">The remote endpoint to which data should be written.</param>
- /// <param name="socketFlags">The socket flags associated with the send operation.</param>
- /// <param name="outputBuffer">The data buffer which should be sent.</param>
- /// <param name="cancellationToken">The cancellation token to observe for the operation.</param>
- /// <returns>The number of bytes of data which were written to the remote endpoint.</returns>
- public ValueTask<int> SendToAsync(Socket socket, EndPoint remoteEndPoint, SocketFlags socketFlags,
- Memory<byte> outputBuffer, CancellationToken cancellationToken = default)
- {
- TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
-
- byte[] rentedSendToBuffer = sendToBufferPool.Rent(PacketBufferLength);
- Memory<byte> rentedSendToBufferMemory = new Memory<byte>(rentedSendToBuffer);
-
- outputBuffer.CopyTo(rentedSendToBufferMemory);
-
- SocketAsyncEventArgs args = sendToAsyncEventArgsPool.Get();
- args.SetBuffer(rentedSendToBufferMemory);
- args.SocketFlags = socketFlags;
- args.RemoteEndPoint = remoteEndPoint;
- args.UserToken = new AsyncWriteToken(rentedSendToBuffer, tcs, cancellationToken);
-
- /*
- // register cleanup action for when the cancellation token is thrown
- cancellationToken.Register(() =>
- {
- tcs.SetCanceled();
-
- sendBufferPool.Return(rentedSendToBuffer, true);
-
- //TODO this is probably a hideous solution. find a better one
- args.Completed -= HandleIOCompleted;
- args.Dispose();
-
- SocketAsyncEventArgs newArgs = new SocketAsyncEventArgs();
- newArgs.Completed += HandleIOCompleted;
- sendAsyncEventArgsPool.Return(newArgs);
- });
- */
-
- // if the send operation doesn't complete synchronously, return the awaitable task
- if (socket.SendToAsync(args)) return new ValueTask<int>(tcs.Task);
-
- int result = args.BytesTransferred;
-
- sendToBufferPool.Return(rentedSendToBuffer, true);
- sendToAsyncEventArgsPool.Return(args);
-
- return new ValueTask<int>(result);
- }
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Sockets/Stream/StreamSocketClient.cs b/NetSharp/NetSharp/Sockets/Stream/StreamSocketClient.cs
@@ -0,0 +1,23 @@
+using System.Net;
+using System.Net.Sockets;
+
+namespace NetSharp.Sockets.Stream
+{
+ public class StreamSocketClient : SocketClient
+ {
+ public StreamSocketClient(in AddressFamily connectionAddressFamily, in ProtocolType connectionProtocolType)
+ : base(in connectionAddressFamily, SocketType.Stream, in connectionProtocolType)
+ {
+ }
+
+ public void Connect(in EndPoint remoteEndPoint)
+ {
+ connection.Connect(remoteEndPoint);
+ }
+
+ public void Disconnect()
+ {
+ connection.Disconnect(true);
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Sockets/Stream/StreamSocketServer.cs b/NetSharp/NetSharp/Sockets/Stream/StreamSocketServer.cs
@@ -0,0 +1,145 @@
+using System;
+using System.Collections.Concurrent;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading;
+using System.Threading.Channels;
+using System.Threading.Tasks;
+using NetSharp.Packets;
+using NetSharp.Utils;
+
+namespace NetSharp.Sockets.Stream
+{
+ public class StreamSocketServer : SocketServer
+ {
+ private readonly ConcurrentDictionary<EndPoint, RemoteStreamClientToken> connectedClientTokens;
+
+ private readonly struct RemoteStreamClientToken
+ {
+ private readonly Channel<NetworkPacket> PacketChannel;
+
+ public readonly ChannelReader<NetworkPacket> PacketReader;
+
+ public readonly ChannelWriter<NetworkPacket> PacketWriter;
+
+ public RemoteStreamClientToken(in Channel<NetworkPacket> packetChannel)
+ {
+ PacketChannel = packetChannel;
+ PacketReader = packetChannel.Reader;
+ PacketWriter = packetChannel.Writer;
+ }
+ }
+
+ public StreamSocketServer(in AddressFamily connectionAddressFamily, in ProtocolType connectionProtocolType)
+ : base(in connectionAddressFamily, SocketType.Stream, in connectionProtocolType)
+ {
+ connectedClientTokens = new ConcurrentDictionary<EndPoint, RemoteStreamClientToken>();
+ }
+
+ protected override SocketAsyncEventArgs GenerateConnectionArgs(EndPoint remoteEndPoint)
+ {
+ SocketAsyncEventArgs connectionArgs = new SocketAsyncEventArgs { RemoteEndPoint = remoteEndPoint };
+
+ connectionArgs.Completed += SocketAsyncOperations.HandleIoCompleted;
+
+ return connectionArgs;
+ }
+
+ protected override void DestroyConnectionArgs(SocketAsyncEventArgs remoteConnectionArgs)
+ {
+ remoteConnectionArgs.AcceptSocket.Shutdown(SocketShutdown.Both);
+ remoteConnectionArgs.AcceptSocket.Close();
+
+ remoteConnectionArgs.Completed -= SocketAsyncOperations.HandleIoCompleted;
+
+ remoteConnectionArgs.Dispose();
+ }
+
+ protected override async Task HandleClient(SocketAsyncEventArgs clientArgs, CancellationToken cancellationToken = default)
+ {
+ EndPoint clientEndPoint = clientArgs.AcceptSocket.RemoteEndPoint;
+ RemoteStreamClientToken clientToken = connectedClientTokens[clientEndPoint];
+
+ Socket clientSocket = clientArgs.AcceptSocket;
+
+ byte[] requestBuffer = new byte[NetworkPacket.TotalSize];
+ Memory<byte> requestBufferMemory = new Memory<byte>(requestBuffer);
+
+ byte[] responseBuffer = new byte[NetworkPacket.TotalSize];
+ Memory<byte> responseBufferMemory = new Memory<byte>(responseBuffer);
+
+ try
+ {
+ while (!cancellationToken.IsCancellationRequested)
+ {
+ TransmissionResult receiveResult =
+ await SocketAsyncOperations
+ .ReceiveAsync(clientArgs, clientSocket, clientEndPoint, SocketFlags.None, requestBufferMemory, cancellationToken)
+ .ConfigureAwait(false);
+
+ if (receiveResult.Count == 0)
+ {
+ break;
+ }
+#if DEBUG
+ lock (typeof(Console))
+ {
+ Console.WriteLine($"[Server] Received {receiveResult.Count} bytes from {receiveResult.RemoteEndPoint}");
+ Console.WriteLine($"[Server] <<<< {Encoding.UTF8.GetString(receiveResult.Buffer.Span)}");
+ }
+#endif
+
+ NetworkPacket request = NetworkPacket.Deserialise(requestBufferMemory);
+
+ // TODO implement actual request handling, besides just an echo
+ NetworkPacket response = request;
+
+ NetworkPacket.Serialise(response, responseBufferMemory);
+
+ TransmissionResult sendResult =
+ await SocketAsyncOperations
+ .SendAsync(clientArgs, clientSocket, clientEndPoint, SocketFlags.None, responseBufferMemory, cancellationToken)
+ .ConfigureAwait(false);
+
+#if DEBUG
+ lock (typeof(Console))
+ {
+ Console.WriteLine($"[Server] Sent {sendResult.Count} bytes to {sendResult.RemoteEndPoint}");
+ Console.WriteLine($"[Server] >>>> {Encoding.UTF8.GetString(sendResult.Buffer.Span)}");
+ }
+#endif
+ }
+ }
+ catch (OperationCanceledException) { }
+ finally
+ {
+ DestroyConnectionArgs(clientArgs);
+ }
+ }
+
+ public override async Task RunAsync(CancellationToken cancellationToken = default)
+ {
+ connection.Listen(100);
+
+ EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
+
+ while (!cancellationToken.IsCancellationRequested)
+ {
+ SocketAsyncEventArgs clientArgs = GenerateConnectionArgs(remoteEndPoint);
+
+ await SocketAsyncOperations.AcceptAsync(clientArgs, connection, cancellationToken);
+
+ EndPoint clientEndPoint = clientArgs.AcceptSocket.RemoteEndPoint;
+
+ BoundedChannelOptions clientChannelOptions = new BoundedChannelOptions(60)
+ { FullMode = BoundedChannelFullMode.DropOldest, SingleReader = true, SingleWriter = true };
+ Channel<NetworkPacket> clientChannel = Channel.CreateBounded<NetworkPacket>(clientChannelOptions);
+
+ connectedClientTokens[clientEndPoint] = new RemoteStreamClientToken(in clientChannel);
+
+ ConnectedClientHandlerTasks[clientEndPoint] = HandleClient(clientArgs, cancellationToken);
+ }
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Utils/BiDictionary.cs b/NetSharp/NetSharp/Utils/BiDictionary.cs
@@ -1,6 +1,6 @@
using System.Collections.Concurrent;
-namespace NetSharp.Utils
+namespace NetSharp.Deprecated
{
/// <summary>
/// Represents a concurrent two-way dictionary, that can be indexed by either a key or a value.
diff --git a/NetSharp/NetSharp/Utils/Constants.cs b/NetSharp/NetSharp/Utils/Constants.cs
@@ -1,15 +0,0 @@
-namespace NetSharp.Utils
-{
- /// <summary>
- /// Holds internal default configurations and constants.
- /// </summary>
- internal static class Constants
- {
- /// <summary>
- /// The default port over which a connection is made.
- /// </summary>
- internal const int DefaultPort = 12374;
-
- internal const int MaximumUdpPacketBytes = 65507;
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Utils/Conversion/EndianAwareBitConverter.cs b/NetSharp/NetSharp/Utils/Conversion/EndianAwareBitConverter.cs
@@ -1,7 +1,7 @@
using System;
using System.Runtime.CompilerServices;
-namespace NetSharp.Utils.Conversion
+namespace NetSharp.Deprecated.Conversion
{
/// <summary>
/// Wraps the <see cref="BitConverter"/> class to provide conversion that is endian-aware.
diff --git a/NetSharp/NetSharp/Utils/CryptographyHelpers.cs b/NetSharp/NetSharp/Utils/CryptographyHelpers.cs
@@ -1,96 +0,0 @@
-using System;
-using System.IO;
-using System.Security.Cryptography;
-using System.Text;
-
-namespace NetSharp.Utils
-{
- internal static class CryptographyHelpers
- {
- #region Settings
-
- private static string _hash = "SHA1";
- private static int _iterations = 2;
- private static int _keySize = 256;
- private static string _salt = "aselrias38490a32"; // Random
- private static string _vector = "8947az34awl34kjq"; // Random
-
- #endregion Settings
-
- public static string Decrypt(byte[] value, string password)
- {
- return Decrypt<AesManaged>(value, password);
- }
-
- public static string Decrypt<T>(byte[] value, string password) where T : SymmetricAlgorithm, new()
- {
- byte[] vectorBytes = Encoding.ASCII.GetBytes(_vector); // GetBytes<ASCIIEncoding>(_vector);
- byte[] saltBytes = Encoding.ASCII.GetBytes(_salt); // GetBytes<ASCIIEncoding>(_salt);
- byte[] valueBytes = value;
-
- byte[] decrypted;
- int decryptedByteCount = 0;
-
- using (T cipher = new T())
- {
- PasswordDeriveBytes _passwordBytes = new PasswordDeriveBytes(password, saltBytes, _hash, _iterations);
- byte[] keyBytes = _passwordBytes.GetBytes(_keySize / 8);
-
- cipher.Mode = CipherMode.CBC;
-
- try
- {
- using (ICryptoTransform decryptor = cipher.CreateDecryptor(keyBytes, vectorBytes))
- {
- using MemoryStream from = new MemoryStream(valueBytes);
- using CryptoStream reader = new CryptoStream(@from, decryptor, CryptoStreamMode.Read);
-
- decrypted = new byte[valueBytes.Length];
- decryptedByteCount = reader.Read(decrypted, 0, decrypted.Length);
- }
- }
- catch (Exception ex)
- {
- return String.Empty;
- }
-
- cipher.Clear();
- }
- return Encoding.UTF8.GetString(decrypted, 0, decryptedByteCount);
- }
-
- public static byte[] Encrypt(string value, string password)
- {
- return Encrypt<AesManaged>(value, password);
- }
-
- public static byte[] Encrypt<T>(string value, string password) where T : SymmetricAlgorithm, new()
- {
- byte[] vectorBytes = Encoding.ASCII.GetBytes(_vector); // GetBytes<ASCIIEncoding>(_vector);
- byte[] saltBytes = Encoding.ASCII.GetBytes(_salt); // GetBytes<ASCIIEncoding>(_salt);
- byte[] valueBytes = Encoding.UTF8.GetBytes(value); // GetBytes<UTF8Encoding>(value);
-
- byte[] encrypted;
- using (T cipher = new T())
- {
- PasswordDeriveBytes _passwordBytes =
- new PasswordDeriveBytes(password, saltBytes, _hash, _iterations);
- byte[] keyBytes = _passwordBytes.GetBytes(_keySize / 8);
-
- cipher.Mode = CipherMode.CBC;
-
- using (ICryptoTransform encryptor = cipher.CreateEncryptor(keyBytes, vectorBytes))
- {
- using MemoryStream to = new MemoryStream();
- using CryptoStream writer = new CryptoStream(to, encryptor, CryptoStreamMode.Write);
-
- writer.Write(valueBytes, 0, valueBytes.Length);
- writer.FlushFinalBlock();
- encrypted = to.ToArray();
- }
- cipher.Clear();
- }
- return encrypted;
- }
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Utils/RingBuffer.cs b/NetSharp/NetSharp/Utils/RingBuffer.cs
@@ -1,50 +0,0 @@
-using System.Threading;
-
-namespace NetSharp.Utils
-{
- public class RingBuffer<T>
- {
- private readonly T[] buffer;
-
- private int currentIndex;
-
- public RingBuffer(int capacity)
- {
- buffer = new T[capacity];
-
- Capacity = capacity;
- Count = 0;
- }
-
- public int Capacity { get; }
-
- public int Count { get; }
-
- public T Pop()
- {
- T removedItem = buffer[currentIndex--];
-
- currentIndex = currentIndex < 0 ? currentIndex + Capacity : currentIndex;
-
- return removedItem;
- }
-
- public bool Push(T newItem, out T removedItem)
- {
- bool overwroteItem = false;
- removedItem = default;
-
- if (buffer[currentIndex] != null)
- {
- removedItem = buffer[currentIndex];
- overwroteItem = true;
- }
-
- buffer[currentIndex] = newItem;
-
- currentIndex = (currentIndex + 1) % Capacity;
-
- return overwroteItem;
- }
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharpExamples/Program.cs b/NetSharp/NetSharpExamples/Program.cs
@@ -1,19 +1,21 @@
-using System;
+#define TCP
+//#undef TCP
+
+using NetSharp.Sockets.Datagram;
+using NetSharp.Sockets.Stream;
+
+using System;
using System.Collections.Generic;
using System.Diagnostics;
-using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using NetSharp;
-using NetSharp.Extensions;
-using NetSharp.Logging;
-using NetSharp.Packets;
-using NetSharp.Sockets;
-using NetSharp.Utils;
+
+using NetworkPacket = NetSharp.Packets.NetworkPacket;
+using SocketServer = NetSharp.Sockets.SocketServer;
namespace NetSharpExamples
{
@@ -21,7 +23,7 @@ namespace NetSharpExamples
{
private const int NetworkTimeout = 1_000_000;
private const int ServerPort = 12374;
- private static readonly IPAddress ServerAddress = IPAddress.Parse("10.4.3.167"); // IPAddress.Parse("192.168.0.31");
+ private static readonly IPAddress ServerAddress = IPAddress.Parse("192.168.0.15");
private static readonly EndPoint ServerEndPoint = new IPEndPoint(ServerAddress, ServerPort);
private static async Task Main()
@@ -32,117 +34,13 @@ namespace NetSharpExamples
await Task.Factory.StartNew(TestSocketClient).Result;
Console.ReadLine();
-
- //await Task.Factory.StartNew(TestServer);
- //await Task.Factory.StartNew(TestClient).Result;
- }
-
- #region Connection Tests
-
- private static async Task TestClient()
- {
- TimeSpan socketTimeout = TimeSpan.FromSeconds(NetworkTimeout);
-
- const int clientCount = 10;
- const long sentPacketCount = 10_000;
-
- ConnectionBuilder clientBuilder = new ConnectionBuilder();
-
- Console.WriteLine($"Testing client connections...");
-
- for (int i = 0; i < clientCount; i++)
- {
- await Task.Factory.StartNew(async clientId =>
- {
- Console.WriteLine($"Starting client {clientId}");
-
- using Connection client = clientBuilder.Build();
- await client.TryBindAsync(new IPEndPoint(IPAddress.Any, 0));
- await client.TryConnectAsync(ServerEndPoint);
- //client.SetLoggingStream(Console.OpenStandardOutput());
- //TimeSpan timeout = TimeSpan.FromMilliseconds(100);
- Stopwatch stopwatch = new Stopwatch();
-
- byte[] message = Encoding.UTF8.GetBytes("Hello World!");
- Memory<byte> messageBuffer = new Memory<byte>(message);
-
- NetworkPacket requestPacket = new NetworkPacket(messageBuffer, message.Length, 1, NetworkErrorCode.Ok, false);
- byte[] requestPacketBuffer = new byte[NetworkPacket.PacketSize];
- NetworkPacket.SerialiseToBuffer(requestPacketBuffer, requestPacket);
-
- byte[] response = new byte[NetworkPacket.PacketSize];
- Memory<byte> responseBuffer = new Memory<byte>(response);
-
- long sentPackets = 0, receivedPackets = 0;
- for (int j = 0; j < sentPacketCount; j++)
- {
- try
- {
- stopwatch.Start();
- //int sentBytes = await client.SendToAsync(serverEndPoint, requestPacketBuffer, SocketFlags.None);
- int sentBytes = await client.SendAsync(ServerEndPoint, requestPacketBuffer, SocketFlags.None);
- stopwatch.Stop();
- Interlocked.Increment(ref sentPackets);
-
- //Console.WriteLine($"[Client {clientId}] Sent {sentBytes} bytes to {serverEndPoint}");
-
- stopwatch.Start();
- //TransmissionResult result = await client.ReceiveFromAsync(serverEndPoint, responseBuffer, SocketFlags.None);
- TransmissionResult result = await client.ReceiveAsync(ServerEndPoint, responseBuffer, SocketFlags.None);
- stopwatch.Stop();
- Interlocked.Increment(ref receivedPackets);
-
- //Console.WriteLine($"[Client {clientId}] Received {result.Count} bytes from {result.RemoteEndPoint}");
- }
- catch (Exception ex)
- {
- Console.WriteLine($"[Client {clientId}] Exception: {ex}");
- }
- }
-
- long millis = stopwatch.ElapsedMilliseconds;
- double megabytes = sentPackets * NetworkPacket.DataSegmentSize / 1_000_000.0;
-
- Console.WriteLine($"[Client {clientId}] Sent {sentPacketCount} packets to {ServerEndPoint} in {millis} milliseconds");
- Console.WriteLine($"[Client {clientId}] Approximate bandwidth: {megabytes / (millis / 1000.0):F3} MBps");
-
- await client.TryDisconnectAsync();
- Console.WriteLine($"[Client {clientId}] Closed client.");
- }, i, TaskCreationOptions.LongRunning);
- }
-
- Console.ReadLine();
}
- private static async Task TestServer()
- {
- const string serverLogFile = @"./serverLog.txt";
- File.Delete(serverLogFile);
- await using Stream serverOutputStream = File.OpenWrite(serverLogFile);
-
- ConnectionBuilder serverBuilder = new ConnectionBuilder();
-
- using Connection server = serverBuilder.WithLogging(Console.OpenStandardOutput(), LogLevel.Info).Build();
- await server.TryBindAsync(ServerEndPoint);
- //server.SetLoggingStream(Console.OpenStandardOutput());
- //server.ChangeLoggingStream(serverOutputStream, LogLevel.Error);
-
- Console.WriteLine("Starting server...");
-
- await server.RunServerAsync();
-
- Console.WriteLine("Server stopped");
-
- Console.ReadLine();
- }
-
- #endregion Connection Tests
-
#region Socket Tests
private static async Task TestSocketClient()
{
- const int clientCount = 100;
+ const int clientCount = 16;
const long packetsToSend = 100_000;
Thread[] clientThreads = new Thread[clientCount];
@@ -158,9 +56,17 @@ namespace NetSharpExamples
Console.WriteLine($"[Client {id}] Starting client...");
}
- using SocketClient client = new SocketClient(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
+#if TCP
+ using StreamSocketClient client = new StreamSocketClient(AddressFamily.InterNetwork, ProtocolType.Tcp);
+#else
+ using DatagramSocketClient client = new DatagramSocketClient(AddressFamily.InterNetwork, ProtocolType.Udp);
+#endif
- if (!await client.TryBindAsync(new IPEndPoint(IPAddress.Any, 0), TimeSpan.FromMilliseconds(1_000)))
+ try
+ {
+ client.Bind(new IPEndPoint(IPAddress.Any, 0));
+ }
+ catch (SocketException)
{
lock (typeof(Console))
{
@@ -168,45 +74,63 @@ namespace NetSharpExamples
return;
}
}
+#if TCP
+ client.Connect(in ServerEndPoint);
+#endif
- byte[] requestBuffer = new byte[NetworkPacket.PacketSize];
+ byte[] requestBuffer = new byte[NetworkPacket.TotalSize];
Memory<byte> requestBufferMemory = new Memory<byte>(requestBuffer);
- byte[] responseBuffer = new byte[NetworkPacket.PacketSize];
+ byte[] responseBuffer = new byte[NetworkPacket.TotalSize];
Memory<byte> responseBufferMemory = new Memory<byte>(responseBuffer);
Stopwatch rttStopwatch = new Stopwatch();
Stopwatch bandwidthStopwatch = new Stopwatch();
+ long minRttTicks = int.MaxValue, maxRttTicks = int.MinValue;
+ long minRttMs = int.MaxValue, maxRttMs = int.MinValue;
+
for (int i = 0; i < packetsToSend; i++)
{
Encoding.UTF8.GetBytes($"Hello World! (Packet {i})").CopyTo(requestBufferMemory);
rttStopwatch.Start();
bandwidthStopwatch.Start();
- TransmissionResult sendResult = await client.SendAsync(ServerEndPoint, SocketFlags.None, requestBufferMemory);
+#if TCP
+ int sendResult = client.SendBytes(requestBufferMemory);
+#else
+ int sendResult = client.SendBytesTo(requestBufferMemory, ServerEndPoint);
+#endif
+
bandwidthStopwatch.Stop();
rttStopwatch.Stop();
#if DEBUG
lock (typeof(Console))
{
- //Console.WriteLine($"[Client {id}, Packet {i}] Sent {sendResult.Count} bytes to {sendResult.RemoteEndPoint}");
- //Console.WriteLine($"[Client {id}, Packet {i}] >>>> {Encoding.UTF8.GetString(sendResult.Buffer.Span)}");
+ Console.WriteLine($"[Client {id}, Packet {i}] Sent {sendResult} bytes to {ServerEndPoint}");
+ Console.WriteLine($"[Client {id}, Packet {i}] >>>> {Encoding.UTF8.GetString(requestBufferMemory.Span)}");
}
#endif
rttStopwatch.Start();
bandwidthStopwatch.Start();
- TransmissionResult receiveResult = await client.ReceiveAsync(ServerEndPoint, SocketFlags.None, responseBufferMemory);
+ EndPoint serverEndPoint = ServerEndPoint;
+
+#if TCP
+ int receiveResult = client.ReceiveBytes(responseBufferMemory);
+#else
+ int receiveResult = client.ReceiveBytesFrom(responseBufferMemory, ref serverEndPoint);
+#endif
+
bandwidthStopwatch.Stop();
rttStopwatch.Stop();
#if DEBUG
lock (typeof(Console))
{
- //Console.WriteLine($"[Client {id}, Packet {i}] Received {receiveResult.Count} bytes from {receiveResult.RemoteEndPoint}");
- //Console.WriteLine($"[Client {id}, Packet {i}] <<<< {Encoding.UTF8.GetString(receiveResult.Buffer.Span)}");
+ Console.WriteLine($"[Client {id}, Packet {i}] Received {receiveResult} bytes from {serverEndPoint}");
+ Console.WriteLine($"[Client {id}, Packet {i}] <<<< {Encoding.UTF8.GetString(responseBufferMemory.Span)}");
}
#endif
@@ -217,13 +141,36 @@ namespace NetSharpExamples
activeThreads.Add((int)id);
}
- //Console.WriteLine($"[Client {id}] Client Round Trip Time: {rttStopwatch.ElapsedMilliseconds} ms");
+#if DEBUG
+ Console.WriteLine($"[Client {id}] Client Round Trip Time: {rttStopwatch.ElapsedTicks} ticks ({rttStopwatch.ElapsedMilliseconds} ms)");
+#endif
+ minRttTicks = rttStopwatch.ElapsedTicks < minRttTicks
+ ? rttStopwatch.ElapsedTicks
+ : minRttTicks;
+
+ minRttMs = rttStopwatch.ElapsedMilliseconds < minRttMs
+ ? rttStopwatch.ElapsedMilliseconds
+ : minRttMs;
+
+ maxRttTicks = rttStopwatch.ElapsedTicks > maxRttTicks
+ ? rttStopwatch.ElapsedTicks
+ : maxRttTicks;
+
+ maxRttMs = rttStopwatch.ElapsedMilliseconds > maxRttMs
+ ? rttStopwatch.ElapsedMilliseconds
+ : maxRttMs;
+
rttStopwatch.Reset();
}
}
+#if TCP
+ client.Disconnect();
+ client.Shutdown(SocketShutdown.Both);
+#endif
+
long millis = bandwidthStopwatch.ElapsedMilliseconds;
- double megabytes = packetsToSend * NetworkPacket.DataSegmentSize / 1_000_000.0;
+ double megabytes = packetsToSend * NetworkPacket.DataSize / 1_000_000.0;
double bandwidth = megabytes / (millis / 1000.0);
clientBandwidths[(int)id] = bandwidth;
@@ -232,6 +179,9 @@ namespace NetSharpExamples
{
Console.WriteLine($"[Client {id}] Sent {packetsToSend} packets to {ServerEndPoint} in {millis} milliseconds");
Console.WriteLine($"[Client {id}] Approximate bandwidth: {bandwidth:F3} MBps");
+
+ Console.WriteLine($"[Client {id}] Min RTT: {minRttTicks} ticks, {minRttMs} ms");
+ Console.WriteLine($"[Client {id}] Max RTT: {maxRttTicks} ticks, {maxRttMs} ms");
Console.WriteLine($"[Client {id}] Stopping client...");
}
@@ -270,25 +220,17 @@ namespace NetSharpExamples
private static async Task TestSocketServer()
{
- using SocketServer server =
- new SocketServer(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
- await server.TryBindAsync(ServerEndPoint, TimeSpan.FromMilliseconds(1_000));
-
- byte[] requestBuffer = new byte[NetworkPacket.PacketSize];
- Memory<byte> requestBufferMemory = new Memory<byte>(requestBuffer);
-
- while (true)
- {
- EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
+#if TCP
+ using SocketServer server = new StreamSocketServer(AddressFamily.InterNetwork, ProtocolType.Tcp);
+#else
+ using SocketServer server = new DatagramSocketServer(AddressFamily.InterNetwork, ProtocolType.Udp);
+#endif
- TransmissionResult receiveResult =
- await server.ReceiveAsync(remoteEndPoint, SocketFlags.None, requestBufferMemory);
+ server.Bind(in ServerEndPoint);
- TransmissionResult sendResult =
- await server.SendAsync(receiveResult.RemoteEndPoint, SocketFlags.None, requestBuffer);
- }
+ await server.RunAsync();
}
- #endregion Socket Tests
+#endregion Socket Tests
}
}
\ No newline at end of file