commit 5d92816a0aa1097d0a28e8b9cfdf83bb2fd0032d parent e5a4d11735c7f2eedfa866760c787f5092adcb90 Author: Mikolaj Lenczewski <mikolaj.lenczewski308@gmail.com> Date: Sat, 9 May 2020 11:53:39 +0100 Reverted Connection. Split RawNetworkReader more. Diffstat:
17 files changed, 182 insertions(+), 826 deletions(-)
diff --git a/NetSharp/NetSharp/Connection.cs b/NetSharp/NetSharp/Connection.cs @@ -1,151 +0,0 @@ -using NetSharp.Raw; - -using System; -using System.Net; -using System.Net.Sockets; -using System.Threading.Tasks; - -namespace NetSharp -{ - // TODO complete class - public sealed class Connection : ConnectionBase - { - /// <inheritdoc /> - internal Connection(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, - IRawNetworkTransportProvider transportProvider, EndPoint defaultEndPoint, int packetBufferSize, - int pooledBuffersPerBucket, uint preallocatedStateObjects) : base(addressFamily, socketType, protocolType, - transportProvider, defaultEndPoint, packetBufferSize, pooledBuffersPerBucket, preallocatedStateObjects) - { - } - - /// <inheritdoc /> - /// TODO convert to use registered packet handlers - protected override bool HandleRawPacketReceived(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> requestBuffer, int receivedRequestBytes, - Memory<byte> responseBuffer) - { - requestBuffer.CopyTo(responseBuffer); - - return true; - } - - /// <inheritdoc /> - public override void Connect(EndPoint remoteEndPoint) - { - Writer.Connect(remoteEndPoint); - } - - /// <inheritdoc /> - public override ValueTask ConnectAsync(EndPoint remoteEndPoint) - { - return Writer.ConnectAsync(remoteEndPoint); - } - - /// <inheritdoc /> - public override int Read(ref EndPoint remoteEndPoint, Memory<byte> readBuffer, SocketFlags flags = SocketFlags.None) - { - return Writer.Read(ref remoteEndPoint, readBuffer, flags); - } - - /// <inheritdoc /> - public override ValueTask<int> ReadAsync(EndPoint remoteEndPoint, Memory<byte> readBuffer, SocketFlags flags = SocketFlags.None) - { - return Writer.ReadAsync(remoteEndPoint, readBuffer, flags); - } - - /// <inheritdoc /> - public override void Start(ushort concurrentReadTasks) - { - Reader.Start(concurrentReadTasks); - } - - /// <inheritdoc /> - public override void Stop() - { - Reader.Stop(); - } - - /// <inheritdoc /> - public override int Write(EndPoint remoteEndPoint, ReadOnlyMemory<byte> writeBuffer, SocketFlags flags = SocketFlags.None) - { - return Writer.Write(remoteEndPoint, writeBuffer, flags); - } - - /// <inheritdoc /> - public override ValueTask<int> WriteAsync(EndPoint remoteEndPoint, ReadOnlyMemory<byte> writeBuffer, SocketFlags flags = SocketFlags.None) - { - return Writer.ReadAsync(remoteEndPoint, Memory<byte>.Empty, flags); - } - } - - // TODO complete class - public abstract class ConnectionBase : IDisposable, INetworkReader, INetworkWriter - { - private readonly Socket connection; - - protected readonly RawNetworkReaderBase Reader; - - protected readonly RawNetworkWriterBase Writer; - - private protected ConnectionBase(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, - IRawNetworkTransportProvider transportProvider, EndPoint defaultEndPoint, int packetBufferSize, - int pooledBuffersPerBucket, uint preallocatedStateObjects) - { - connection = new Socket(addressFamily, socketType, protocolType); - - Reader = transportProvider.GetReader(ref connection, defaultEndPoint, HandleRawPacketReceived, - packetBufferSize, pooledBuffersPerBucket, preallocatedStateObjects); - - Writer = transportProvider.GetWriter(ref connection, defaultEndPoint, packetBufferSize, - pooledBuffersPerBucket, preallocatedStateObjects); - } - - protected virtual void Dispose(bool disposing) - { - if (!disposing) return; - - Writer.Dispose(); - - Reader.Stop(); - Reader.Dispose(); - - connection.Dispose(); - } - - protected abstract bool HandleRawPacketReceived(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> requestBuffer, int receivedRequestBytes, - Memory<byte> responseBuffer); - - /// <inheritdoc /> - public abstract void Connect(EndPoint remoteEndPoint); - - /// <inheritdoc /> - public abstract ValueTask ConnectAsync(EndPoint remoteEndPoint); - - /// <inheritdoc /> - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// <inheritdoc /> - public abstract int Read(ref EndPoint remoteEndPoint, Memory<byte> readBuffer, SocketFlags flags = SocketFlags.None); - - /// <inheritdoc /> - public abstract ValueTask<int> ReadAsync(EndPoint remoteEndPoint, Memory<byte> readBuffer, - SocketFlags flags = SocketFlags.None); - - /// <inheritdoc /> - public abstract void Start(ushort concurrentReceiveTasks); - - /// <inheritdoc /> - public abstract void Stop(); - - /// <inheritdoc /> - public abstract int Write(EndPoint remoteEndPoint, ReadOnlyMemory<byte> writeBuffer, - SocketFlags flags = SocketFlags.None); - - /// <inheritdoc /> - public abstract ValueTask<int> WriteAsync(EndPoint remoteEndPoint, ReadOnlyMemory<byte> writeBuffer, - SocketFlags flags = SocketFlags.None); - } -} -\ No newline at end of file diff --git a/NetSharp/NetSharp/ConnectionBuilder.cs b/NetSharp/NetSharp/ConnectionBuilder.cs @@ -1,104 +0,0 @@ -using System.Net; -using System.Net.Sockets; -using NetSharp.Raw; - -namespace NetSharp -{ - public static class ConnectionBuilder - { - public static ConfiguredConnectionBuilder WithCustomTransport( - IRawNetworkTransportProvider transportProvider, ProtocolType transportProtocol) => - new ConfiguredConnectionBuilder(transportProvider, transportProtocol); - - public static ConfiguredConnectionBuilder WithDatagramTransport(ushort datagramSize = 8192, ProtocolType transportProtocol = ProtocolType.Udp) => - WithCustomTransport(new DatagramRawNetworkTransportProvider(datagramSize), transportProtocol); - - public static ConfiguredConnectionBuilder WithStreamTransport(ProtocolType transportProtocol = ProtocolType.Tcp) => - WithCustomTransport(new StreamRawNetworkTransportProvider(), transportProtocol); - - public sealed class ConfiguredConnectionBuilder - { - private readonly IRawNetworkTransportProvider transportProvider; - - internal ConfiguredConnectionBuilder(IRawNetworkTransportProvider transportProvider, ProtocolType transportProtocol) - { - this.transportProvider = transportProvider; - - SocketType = transportProvider.TransportProtocolType; - - ProtocolType = transportProtocol; - } - - public AddressFamily AddressFamily { get; private set; } = AddressFamily.InterNetwork; - public EndPoint DefaultEndPoint { get; private set; } = new IPEndPoint(IPAddress.Any, 0); - public ProtocolType ProtocolType { get; } - public SocketType SocketType { get; } - - public ConfiguredConnectionBuilder WithAddressFamily(AddressFamily addressFamily, EndPoint defaultEndPoint) - { - AddressFamily = addressFamily; - - DefaultEndPoint = defaultEndPoint; - - return this; - } - - public CompletedConnectionBuilder WithDefaultSettings(int packetBufferSize) => - WithSettings(packetBufferSize, 1000, 0); - - public ConfiguredConnectionBuilder WithInterNetwork(EndPoint defaultEndPoint) => - WithAddressFamily(AddressFamily.InterNetwork, defaultEndPoint); - - public ConfiguredConnectionBuilder WithInterNetworkV6(EndPoint defaultEndPoint) => - WithAddressFamily(AddressFamily.InterNetworkV6, defaultEndPoint); - - public CompletedConnectionBuilder WithSettings(int packetBufferSize, int pooledBuffersPerBucket, - uint preallocatedStateObjects) - { - return new CompletedConnectionBuilder(transportProvider, AddressFamily, DefaultEndPoint, SocketType, - ProtocolType, packetBufferSize, pooledBuffersPerBucket, preallocatedStateObjects); - } - - public sealed class CompletedConnectionBuilder - { - private readonly IRawNetworkTransportProvider transportProvider; - - internal CompletedConnectionBuilder( - IRawNetworkTransportProvider transportProvider, AddressFamily addressFamily, EndPoint defaultEndPoint, - SocketType transportProtocolType, ProtocolType transportProtocol, int maxBufferSize, int pooledBuffersPerBucket, - uint preallocatedStateObjects) - { - this.transportProvider = transportProvider; - - AddressFamily = addressFamily; - - DefaultEndPoint = defaultEndPoint; - - SocketType = transportProtocolType; - - ProtocolType = transportProtocol; - - BufferSize = maxBufferSize; - - PooledBuffersPerBucket = pooledBuffersPerBucket; - - PreallocatedStateObjects = preallocatedStateObjects; - } - - public AddressFamily AddressFamily { get; } - public int BufferSize { get; } - public EndPoint DefaultEndPoint { get; } - public int PooledBuffersPerBucket { get; } - public uint PreallocatedStateObjects { get; } - public ProtocolType ProtocolType { get; } - public SocketType SocketType { get; } - - public Connection BuildDefault() - { - return new Connection(AddressFamily, SocketType, ProtocolType, transportProvider, DefaultEndPoint, - BufferSize, PooledBuffersPerBucket, PreallocatedStateObjects); - } - } - } - } -} -\ No newline at end of file diff --git a/NetSharp/NetSharp/NetSharp.csproj b/NetSharp/NetSharp/NetSharp.csproj @@ -20,4 +20,8 @@ <PackageReference Include="Microsoft.CSharp" Version="4.7.0" /> <PackageReference Include="Microsoft.Extensions.ObjectPool" Version="3.1.3" /> </ItemGroup> + + <ItemGroup> + <Folder Include="Packets\" /> + </ItemGroup> </Project> \ No newline at end of file diff --git a/NetSharp/NetSharp/NetSharp.xml b/NetSharp/NetSharp/NetSharp.xml @@ -4,217 +4,7 @@ <name>NetSharp</name> </assembly> <members> - <member name="M:NetSharp.Connection.#ctor(System.Net.Sockets.AddressFamily,System.Net.Sockets.SocketType,System.Net.Sockets.ProtocolType,NetSharp.Raw.IRawNetworkTransportProvider,System.Net.EndPoint,System.Int32,System.Int32,System.UInt32)"> - <inheritdoc /> - </member> - <member name="M:NetSharp.Connection.HandleRawPacketReceived(System.Net.EndPoint@,System.ReadOnlyMemory{System.Byte},System.Int32,System.Memory{System.Byte})"> - <inheritdoc /> - TODO convert to use registered packet handlers - </member> - <member name="M:NetSharp.Connection.Connect(System.Net.EndPoint)"> - <inheritdoc /> - </member> - <member name="M:NetSharp.Connection.ConnectAsync(System.Net.EndPoint)"> - <inheritdoc /> - </member> - <member name="M:NetSharp.Connection.Read(System.Net.EndPoint@,System.Memory{System.Byte},System.Net.Sockets.SocketFlags)"> - <inheritdoc /> - </member> - <member name="M:NetSharp.Connection.ReadAsync(System.Net.EndPoint,System.Memory{System.Byte},System.Net.Sockets.SocketFlags)"> - <inheritdoc /> - </member> - <member name="M:NetSharp.Connection.Start(System.UInt16)"> - <inheritdoc /> - </member> - <member name="M:NetSharp.Connection.Stop"> - <inheritdoc /> - </member> - <member name="M:NetSharp.Connection.Write(System.Net.EndPoint,System.ReadOnlyMemory{System.Byte},System.Net.Sockets.SocketFlags)"> - <inheritdoc /> - </member> - <member name="M:NetSharp.Connection.WriteAsync(System.Net.EndPoint,System.ReadOnlyMemory{System.Byte},System.Net.Sockets.SocketFlags)"> - <inheritdoc /> - </member> - <member name="M:NetSharp.ConnectionBase.Connect(System.Net.EndPoint)"> - <inheritdoc /> - </member> - <member name="M:NetSharp.ConnectionBase.ConnectAsync(System.Net.EndPoint)"> - <inheritdoc /> - </member> - <member name="M:NetSharp.ConnectionBase.Dispose"> - <inheritdoc /> - </member> - <member name="M:NetSharp.ConnectionBase.Read(System.Net.EndPoint@,System.Memory{System.Byte},System.Net.Sockets.SocketFlags)"> - <inheritdoc /> - </member> - <member name="M:NetSharp.ConnectionBase.ReadAsync(System.Net.EndPoint,System.Memory{System.Byte},System.Net.Sockets.SocketFlags)"> - <inheritdoc /> - </member> - <member name="M:NetSharp.ConnectionBase.Start(System.UInt16)"> - <inheritdoc /> - </member> - <member name="M:NetSharp.ConnectionBase.Stop"> - <inheritdoc /> - </member> - <member name="M:NetSharp.ConnectionBase.Write(System.Net.EndPoint,System.ReadOnlyMemory{System.Byte},System.Net.Sockets.SocketFlags)"> - <inheritdoc /> - </member> - <member name="M:NetSharp.ConnectionBase.WriteAsync(System.Net.EndPoint,System.ReadOnlyMemory{System.Byte},System.Net.Sockets.SocketFlags)"> - <inheritdoc /> - </member> - <member name="T:NetSharp.Packets.NetworkPacket"> - <summary> - Represents a raw packet sent across the network. - </summary> - </member> - <member name="F:NetSharp.Packets.NetworkPacket.DataSize"> - <summary> - The size in bytes of the packet data segment. - </summary> - </member> - <member name="F:NetSharp.Packets.NetworkPacket.FooterSize"> - <summary> - The size in bytes of the packet footer segment. - </summary> - </member> - <member name="F:NetSharp.Packets.NetworkPacket.HeaderSize"> - <summary> - The size in bytes of the packet header segment. - </summary> - </member> - <member name="F:NetSharp.Packets.NetworkPacket.TotalSize"> - <summary> - The total size of the packet in bytes. - </summary> - </member> - <member name="F:NetSharp.Packets.NetworkPacket.NullPacket"> - <summary> - Represents an empty packet. - </summary> - </member> - <member name="F:NetSharp.Packets.NetworkPacket.Data"> - <summary> - The data held by this packet instance. - </summary> - </member> - <member name="F:NetSharp.Packets.NetworkPacket.Footer"> - <summary> - The footer for this packet instance, holding additional metadata. - </summary> - </member> - <member name="F:NetSharp.Packets.NetworkPacket.Header"> - <summary> - The header for this packet instance, holding additional metadata. - </summary> - </member> - <member name="M:NetSharp.Packets.NetworkPacket.#ctor(NetSharp.Packets.NetworkPacketHeader,System.ReadOnlyMemory{System.Byte},NetSharp.Packets.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> - </member> - <member name="M:NetSharp.Packets.NetworkPacket.Deserialise(System.ReadOnlyMemory{System.Byte},NetSharp.Packets.NetworkPacket@)"> - <summary> - Deserialises the serialised packet in the given memory buffer into a new <see cref="T:NetSharp.Packets.NetworkPacket" /> instance. - </summary> - <param name="buffer"> - The memory buffer to read the serialised packet instance from. - </param> - <param name="instance"> - The deserialised instance. - </param> - <returns> - Whether the deserialisation attempt was successful. The <paramref name="instance" /> will be equal to <see cref="F:NetSharp.Packets.NetworkPacket.NullPacket" /> if the - attempt fails. - </returns> - </member> - <member name="M:NetSharp.Packets.NetworkPacket.Serialise(NetSharp.Packets.NetworkPacket,System.Memory{System.Byte})"> - <summary> - Serialises the given <see cref="T:NetSharp.Packets.NetworkPacket" /> instance into the given memory buffer. - </summary> - <param name="instance"> - The packet instance which should be serialised. - </param> - <param name="buffer"> - The memory buffer to write the serialised packet instance to. <see cref="F:NetSharp.Packets.NetworkPacket.TotalSize" /> bytes will be written into this buffer on success. - </param> - <returns> - Whether the serialisation attempt was successful. No bytes are written to the <paramref name="buffer" /> if the attempt fails. - </returns> - </member> - <member name="T:NetSharp.Packets.NetworkPacketFooter"> - <summary> - Represents the footer of a <see cref="T:NetSharp.Packets.NetworkPacket" />, holding additional metadata. - </summary> - </member> - <member name="F:NetSharp.Packets.NetworkPacketFooter.TotalSize"> - <summary> - The total size of the packet footer, in bytes. - </summary> - </member> - <member name="M:NetSharp.Packets.NetworkPacketFooter.Deserialise(System.ReadOnlyMemory{System.Byte})"> - <summary> - Deserialises the serialised packet footer in the given memory buffer into a new <see cref="T:NetSharp.Packets.NetworkPacketFooter" /> instance. - </summary> - <param name="buffer"> - The memory buffer to read the serialised packet footer instance from. - </param> - <returns> - The deserialised instance. - </returns> - </member> - <member name="M:NetSharp.Packets.NetworkPacketFooter.Serialise(NetSharp.Packets.NetworkPacketFooter,System.Memory{System.Byte})"> - <summary> - Serialises the given <see cref="T:NetSharp.Packets.NetworkPacketFooter" /> instance into the given memory buffer. - </summary> - <param name="instance"> - The packet footer instance which should be serialised. - </param> - <param name="buffer"> - The memory buffer to write the serialised packet footer instance to. - </param> - </member> - <member name="T:NetSharp.Packets.NetworkPacketHeader"> - <summary> - Represents the header of a <see cref="T:NetSharp.Packets.NetworkPacket" />, holding additional metadata. - </summary> - </member> - <member name="F:NetSharp.Packets.NetworkPacketHeader.TotalSize"> - <summary> - The total size of the packet header, in bytes. - </summary> - </member> - <member name="M:NetSharp.Packets.NetworkPacketHeader.Deserialise(System.ReadOnlyMemory{System.Byte})"> - <summary> - Deserialises the serialised packet header in the given memory buffer into a new <see cref="T:NetSharp.Packets.NetworkPacketHeader" /> instance. - </summary> - <param name="buffer"> - The memory buffer to read the serialised packet header instance from. - </param> - <returns> - The deserialised instance. - </returns> - </member> - <member name="M:NetSharp.Packets.NetworkPacketHeader.Serialise(NetSharp.Packets.NetworkPacketHeader,System.Memory{System.Byte})"> - <summary> - Serialises the given <see cref="T:NetSharp.Packets.NetworkPacketHeader" /> instance into the given memory buffer. - </summary> - <param name="instance"> - The packet header instance which should be serialised. - </param> - <param name="buffer"> - The memory buffer to write the serialised packet header instance to. - </param> - </member> - <member name="M:NetSharp.Raw.Datagram.RawDatagramNetworkReader.#ctor(System.Net.Sockets.Socket@,NetSharp.Raw.NetworkRequestHandler,System.Net.EndPoint,System.Int32,System.Int32,System.UInt32)"> + <member name="M:NetSharp.Raw.Datagram.RawDatagramNetworkReader.#ctor(System.Net.Sockets.Socket@,NetSharp.Raw.Datagram.RawDatagramRequestHandler,System.Net.EndPoint,System.Int32,System.Int32,System.UInt32)"> <inheritdoc /> </member> <member name="M:NetSharp.Raw.Datagram.RawDatagramNetworkReader.CanReuseStateObject(System.Net.Sockets.SocketAsyncEventArgs@)"> @@ -268,7 +58,7 @@ <member name="P:NetSharp.Raw.DatagramRawNetworkTransportProvider.TransportProtocolType"> <inheritdoc /> </member> - <member name="M:NetSharp.Raw.DatagramRawNetworkTransportProvider.GetReader(System.Net.Sockets.Socket@,System.Net.EndPoint,NetSharp.Raw.NetworkRequestHandler,System.Int32,System.Int32,System.UInt32)"> + <member name="M:NetSharp.Raw.DatagramRawNetworkTransportProvider.GetReader(System.Net.Sockets.Socket@,System.Net.EndPoint,NetSharp.Raw.Datagram.RawDatagramRequestHandler,System.Int32,System.Int32,System.UInt32)"> <inheritdoc /> </member> <member name="M:NetSharp.Raw.DatagramRawNetworkTransportProvider.GetWriter(System.Net.Sockets.Socket@,System.Net.EndPoint,System.Int32,System.Int32,System.UInt32)"> @@ -277,7 +67,7 @@ <member name="P:NetSharp.Raw.StreamRawNetworkTransportProvider.TransportProtocolType"> <inheritdoc /> </member> - <member name="M:NetSharp.Raw.StreamRawNetworkTransportProvider.GetReader(System.Net.Sockets.Socket@,System.Net.EndPoint,NetSharp.Raw.NetworkRequestHandler,System.Int32,System.Int32,System.UInt32)"> + <member name="M:NetSharp.Raw.StreamRawNetworkTransportProvider.GetReader(System.Net.Sockets.Socket@,System.Net.EndPoint,NetSharp.Raw.Stream.RawStreamRequestHandler,System.Int32,System.Int32,System.UInt32)"> <inheritdoc /> </member> <member name="M:NetSharp.Raw.StreamRawNetworkTransportProvider.GetWriter(System.Net.Sockets.Socket@,System.Net.EndPoint,System.Int32,System.Int32,System.UInt32)"> @@ -291,7 +81,7 @@ <member name="M:NetSharp.Raw.RawNetworkConnectionBase.Dispose"> <inheritdoc /> </member> - <member name="M:NetSharp.Raw.RawNetworkReaderBase.#ctor(System.Net.Sockets.Socket@,System.Net.EndPoint,NetSharp.Raw.NetworkRequestHandler,System.Int32,System.Int32,System.UInt32)"> + <member name="M:NetSharp.Raw.RawNetworkReaderBase.#ctor(System.Net.Sockets.Socket@,System.Net.EndPoint,System.Int32,System.Int32,System.UInt32)"> <inheritdoc /> </member> <member name="M:NetSharp.Raw.RawNetworkReaderBase.Dispose(System.Boolean)"> @@ -324,7 +114,7 @@ <member name="M:NetSharp.Raw.RawNetworkWriterBase.WriteAsync(System.Net.EndPoint,System.ReadOnlyMemory{System.Byte},System.Net.Sockets.SocketFlags)"> <inheritdoc /> </member> - <member name="M:NetSharp.Raw.Stream.RawStreamNetworkReader.#ctor(System.Net.Sockets.Socket@,NetSharp.Raw.NetworkRequestHandler,System.Net.EndPoint,System.Int32,System.Int32,System.UInt32)"> + <member name="M:NetSharp.Raw.Stream.RawStreamNetworkReader.#ctor(System.Net.Sockets.Socket@,NetSharp.Raw.Stream.RawStreamRequestHandler,System.Net.EndPoint,System.Int32,System.Int32,System.UInt32)"> <inheritdoc /> </member> <member name="M:NetSharp.Raw.Stream.RawStreamNetworkReader.CanReuseStateObject(System.Net.Sockets.SocketAsyncEventArgs@)"> diff --git a/NetSharp/NetSharp/Packets/NetworkPacket.cs b/NetSharp/NetSharp/Packets/NetworkPacket.cs @@ -1,218 +0,0 @@ -using System; -using System.Runtime.CompilerServices; - -namespace NetSharp.Packets -{ - /// <summary> - /// Represents a raw packet sent across the network. - /// </summary> - public readonly struct NetworkPacket - { - /// <summary> - /// The size in bytes of the packet data segment. - /// </summary> - public const int DataSize = 8192; - - /// <summary> - /// The size in bytes of the packet footer segment. - /// </summary> - public const int FooterSize = NetworkPacketFooter.TotalSize; - - /// <summary> - /// The size in bytes of the packet header segment. - /// </summary> - public const int HeaderSize = NetworkPacketHeader.TotalSize; - - /// <summary> - /// The total size of the packet in bytes. - /// </summary> - public const int TotalSize = HeaderSize + DataSize + FooterSize; - - /// <summary> - /// Represents an empty packet. - /// </summary> - public static NetworkPacket NullPacket = new NetworkPacket(); - - /// <summary> - /// The data held by this packet instance. - /// </summary> - public readonly ReadOnlyMemory<byte> Data; - - /// <summary> - /// The footer for this packet instance, holding additional metadata. - /// </summary> - public readonly NetworkPacketFooter Footer; - - /// <summary> - /// The header for this packet instance, holding additional metadata. - /// </summary> - public readonly NetworkPacketHeader Header; - - /// <summary> - /// Constructs a new instance of the <see cref="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> - private NetworkPacket(NetworkPacketHeader packetHeader, ReadOnlyMemory<byte> packetDataBuffer, NetworkPacketFooter packetFooter) - { - Header = packetHeader; - - Data = packetDataBuffer; - - Footer = packetFooter; - } - - /// <summary> - /// Deserialises the serialised packet in the given memory buffer into a new <see cref="NetworkPacket" /> instance. - /// </summary> - /// <param name="buffer"> - /// The memory buffer to read the serialised packet instance from. - /// </param> - /// <param name="instance"> - /// The deserialised instance. - /// </param> - /// <returns> - /// Whether the deserialisation attempt was successful. The <paramref name="instance" /> will be equal to <see cref="NullPacket" /> if the - /// attempt fails. - /// </returns> - public static bool Deserialise(ReadOnlyMemory<byte> buffer, out NetworkPacket instance) - { - if (buffer.Length != TotalSize) - { - instance = NullPacket; - - return false; - } - - ReadOnlyMemory<byte> serialisedPacketHeader = buffer.Slice(0, HeaderSize); - NetworkPacketHeader packetHeader = NetworkPacketHeader.Deserialise(serialisedPacketHeader); - - ReadOnlyMemory<byte> packetDataBuffer = buffer.Slice(HeaderSize, DataSize); - - ReadOnlyMemory<byte> serialisedPacketFooter = buffer.Slice(HeaderSize + DataSize, FooterSize); - NetworkPacketFooter packetFooter = NetworkPacketFooter.Deserialise(serialisedPacketFooter); - - instance = new NetworkPacket(packetHeader, packetDataBuffer, packetFooter); - - return true; - } - - /// <summary> - /// Serialises the given <see cref="NetworkPacket" /> instance into the given memory buffer. - /// </summary> - /// <param name="instance"> - /// The packet instance which should be serialised. - /// </param> - /// <param name="buffer"> - /// The memory buffer to write the serialised packet instance to. <see cref="TotalSize" /> bytes will be written into this buffer on success. - /// </param> - /// <returns> - /// Whether the serialisation attempt was successful. No bytes are written to the <paramref name="buffer" /> if the attempt fails. - /// </returns> - public static bool Serialise(NetworkPacket instance, Memory<byte> buffer) - { - if (buffer.Length < TotalSize) - { - return false; - } - - Memory<byte> packetHeader = buffer.Slice(0, HeaderSize); - NetworkPacketHeader.Serialise(instance.Header, packetHeader); - - Memory<byte> packetDataBuffer = buffer.Slice(HeaderSize, DataSize); - instance.Data.CopyTo(packetDataBuffer); - - Memory<byte> packetFooter = buffer.Slice(HeaderSize + DataSize, FooterSize); - NetworkPacketFooter.Serialise(instance.Footer, packetFooter); - - return true; - } - } - - /// <summary> - /// Represents the footer of a <see cref="NetworkPacket" />, holding additional metadata. - /// </summary> - public readonly struct NetworkPacketFooter - { - /// <summary> - /// The total size of the packet footer, in bytes. - /// </summary> - public const int TotalSize = 0; - - /// <summary> - /// Deserialises the serialised packet footer in the given memory buffer into a new <see cref="NetworkPacketFooter" /> instance. - /// </summary> - /// <param name="buffer"> - /// The memory buffer to read the serialised packet footer instance from. - /// </param> - /// <returns> - /// The deserialised instance. - /// </returns> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static NetworkPacketFooter Deserialise(ReadOnlyMemory<byte> buffer) - { - return new NetworkPacketFooter(); - } - - /// <summary> - /// Serialises the given <see cref="NetworkPacketFooter" /> instance into the given memory buffer. - /// </summary> - /// <param name="instance"> - /// The packet footer instance which should be serialised. - /// </param> - /// <param name="buffer"> - /// The memory buffer to write the serialised packet footer instance to. - /// </param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void Serialise(NetworkPacketFooter instance, Memory<byte> buffer) - { - } - } - - /// <summary> - /// Represents the header of a <see cref="NetworkPacket" />, holding additional metadata. - /// </summary> - public readonly struct NetworkPacketHeader - { - /// <summary> - /// The total size of the packet header, in bytes. - /// </summary> - public const int TotalSize = 0; - - /// <summary> - /// Deserialises the serialised packet header in the given memory buffer into a new <see cref="NetworkPacketHeader" /> instance. - /// </summary> - /// <param name="buffer"> - /// The memory buffer to read the serialised packet header instance from. - /// </param> - /// <returns> - /// The deserialised instance. - /// </returns> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static NetworkPacketHeader Deserialise(ReadOnlyMemory<byte> buffer) - { - return new NetworkPacketHeader(); - } - - /// <summary> - /// Serialises the given <see cref="NetworkPacketHeader" /> instance into the given memory buffer. - /// </summary> - /// <param name="instance"> - /// The packet header instance which should be serialised. - /// </param> - /// <param name="buffer"> - /// The memory buffer to write the serialised packet header instance to. - /// </param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void Serialise(NetworkPacketHeader instance, Memory<byte> buffer) - { - } - } -} -\ No newline at end of file diff --git a/NetSharp/NetSharp/Raw/Datagram/RawDatagramNetworkReader.cs b/NetSharp/NetSharp/Raw/Datagram/RawDatagramNetworkReader.cs @@ -1,15 +1,34 @@ -using System.Net; +using System; +using System.Net; using System.Net.Sockets; namespace NetSharp.Raw.Datagram { + public delegate bool RawDatagramRequestHandler(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> requestBuffer, int receivedRequestBytes, + Memory<byte> responseBuffer); + public sealed class RawDatagramNetworkReader : RawNetworkReaderBase { + private const int MaxDatagramSize = ushort.MaxValue - 28; + + private readonly int datagramSize; + + private readonly RawDatagramRequestHandler requestHandler; + /// <inheritdoc /> - public RawDatagramNetworkReader(ref Socket rawConnection, NetworkRequestHandler? requestHandler, EndPoint defaultEndPoint, int pooledPacketBufferSize, - int pooledBuffersPerBucket = 1000, uint preallocatedStateObjects = 0) : base(ref rawConnection, defaultEndPoint, requestHandler, pooledPacketBufferSize, + public RawDatagramNetworkReader(ref Socket rawConnection, RawDatagramRequestHandler? requestHandler, EndPoint defaultEndPoint, int datagramSize, + int pooledBuffersPerBucket = 50, uint preallocatedStateObjects = 0) : base(ref rawConnection, defaultEndPoint, datagramSize, pooledBuffersPerBucket, preallocatedStateObjects) { + if (datagramSize <= 0 || MaxDatagramSize < datagramSize) + { + throw new ArgumentOutOfRangeException(nameof(datagramSize), datagramSize, + $"The datagram size must be greater than 0 and less than {MaxDatagramSize}"); + } + + this.datagramSize = datagramSize; + + this.requestHandler = requestHandler ?? DefaultRequestHandler; } private void CompleteReceiveFrom(SocketAsyncEventArgs args) @@ -19,22 +38,15 @@ namespace NetSharp.Raw.Datagram switch (args.SocketError) { case SocketError.Success: - byte[] responseBuffer = BufferPool.Rent(PacketBufferSize); + byte[] responseBuffer = BufferPool.Rent(datagramSize); bool responseExists = - RequestHandler(args.RemoteEndPoint, receiveBuffer, args.BytesTransferred, responseBuffer); - BufferPool.Return(receiveBuffer, true); - - if (responseExists) - { - args.SetBuffer(responseBuffer, 0, PacketBufferSize); - - StartSendTo(args); - - return; - } + requestHandler(args.RemoteEndPoint, receiveBuffer, args.BytesTransferred, responseBuffer); + Buffer.BlockCopy(responseBuffer, 0, receiveBuffer, 0, datagramSize); BufferPool.Return(responseBuffer, true); + + if (responseExists) StartSendTo(args); break; default: @@ -47,8 +59,8 @@ namespace NetSharp.Raw.Datagram private void CompleteSendTo(SocketAsyncEventArgs args) { byte[] sendBuffer = args.Buffer; - BufferPool.Return(sendBuffer, true); + ArgsPool.Return(args); } @@ -81,17 +93,14 @@ namespace NetSharp.Raw.Datagram private void StartReceiveFrom(SocketAsyncEventArgs args) { - byte[] receiveBuffer = BufferPool.Rent(PacketBufferSize); - if (ShutdownToken.IsCancellationRequested) { - BufferPool.Return(receiveBuffer, true); ArgsPool.Return(args); - return; } - args.SetBuffer(receiveBuffer, 0, PacketBufferSize); + byte[] receiveBuffer = BufferPool.Rent(datagramSize); + args.SetBuffer(receiveBuffer, 0, datagramSize); if (Connection.ReceiveFromAsync(args)) return; @@ -101,11 +110,11 @@ namespace NetSharp.Raw.Datagram private void StartSendTo(SocketAsyncEventArgs args) { - byte[] sendBuffer = args.Buffer; - if (ShutdownToken.IsCancellationRequested) { + byte[] sendBuffer = args.Buffer; BufferPool.Return(sendBuffer, true); + ArgsPool.Return(args); return; @@ -144,6 +153,12 @@ namespace NetSharp.Raw.Datagram instance.RemoteEndPoint = DefaultEndPoint; } + public static bool DefaultRequestHandler(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> requestBuffer, int receivedRequestBytes, + Memory<byte> responseBuffer) + { + return requestBuffer.TryCopyTo(responseBuffer); + } + /// <inheritdoc /> public override void Start(ushort concurrentReadTasks) { diff --git a/NetSharp/NetSharp/Raw/Datagram/RawDatagramNetworkWriter.cs b/NetSharp/NetSharp/Raw/Datagram/RawDatagramNetworkWriter.cs @@ -7,10 +7,21 @@ namespace NetSharp.Raw.Datagram { public sealed class RawDatagramNetworkWriter : RawNetworkWriterBase { + private const int MaxDatagramSize = ushort.MaxValue - 28; + + private readonly int datagramSize; + /// <inheritdoc /> - public RawDatagramNetworkWriter(ref Socket rawConnection, EndPoint defaultEndPoint, int pooledPacketBufferSize, int pooledBuffersPerBucket = 1000, - uint preallocatedStateObjects = 0) : base(ref rawConnection, defaultEndPoint, pooledPacketBufferSize, pooledBuffersPerBucket, preallocatedStateObjects) + public RawDatagramNetworkWriter(ref Socket rawConnection, EndPoint defaultEndPoint, int datagramSize, int pooledBuffersPerBucket = 50, + uint preallocatedStateObjects = 0) : base(ref rawConnection, defaultEndPoint, datagramSize, pooledBuffersPerBucket, preallocatedStateObjects) { + if (datagramSize <= 0 || MaxDatagramSize < datagramSize) + { + throw new ArgumentOutOfRangeException(nameof(datagramSize), datagramSize, + $"The datagram size must be greater than 0 and less than {MaxDatagramSize}"); + } + + this.datagramSize = datagramSize; } private void CompleteConnect(SocketAsyncEventArgs args) @@ -162,15 +173,15 @@ namespace NetSharp.Raw.Datagram public override int Read(ref EndPoint remoteEndPoint, Memory<byte> readBuffer, SocketFlags flags = SocketFlags.None) { int totalBytes = readBuffer.Length; - if (totalBytes > PacketBufferSize) + if (totalBytes > datagramSize) { throw new ArgumentException( - $"Cannot rent a temporary buffer of size: {totalBytes} bytes; maximum temporary buffer size: {PacketBufferSize} bytes", + $"Cannot rent a temporary buffer of size: {totalBytes} bytes; maximum temporary buffer size: {datagramSize} bytes", nameof(readBuffer.Length) ); } - byte[] transmissionBuffer = BufferPool.Rent(PacketBufferSize); + byte[] transmissionBuffer = BufferPool.Rent(datagramSize); int readBytes = Connection.ReceiveFrom(transmissionBuffer, flags, ref remoteEndPoint); @@ -184,10 +195,10 @@ namespace NetSharp.Raw.Datagram public override ValueTask<int> ReadAsync(EndPoint remoteEndPoint, Memory<byte> readBuffer, SocketFlags flags = SocketFlags.None) { int totalBytes = readBuffer.Length; - if (totalBytes > PacketBufferSize) + if (totalBytes > datagramSize) { throw new ArgumentException( - $"Cannot rent a temporary buffer of size: {totalBytes} bytes; maximum temporary buffer size: {PacketBufferSize} bytes", + $"Cannot rent a temporary buffer of size: {totalBytes} bytes; maximum temporary buffer size: {datagramSize} bytes", nameof(readBuffer.Length) ); } @@ -195,9 +206,9 @@ namespace NetSharp.Raw.Datagram TaskCompletionSource<int> tcs = new TaskCompletionSource<int>(); SocketAsyncEventArgs args = ArgsPool.Rent(); - byte[] transmissionBuffer = BufferPool.Rent(PacketBufferSize); + byte[] transmissionBuffer = BufferPool.Rent(datagramSize); - args.SetBuffer(transmissionBuffer, 0, PacketBufferSize); + args.SetBuffer(transmissionBuffer, 0, datagramSize); args.RemoteEndPoint = remoteEndPoint; args.SocketFlags = flags; @@ -223,15 +234,15 @@ namespace NetSharp.Raw.Datagram SocketFlags flags = SocketFlags.None) { int totalBytes = writeBuffer.Length; - if (totalBytes > PacketBufferSize) + if (totalBytes > datagramSize) { throw new ArgumentException( - $"Cannot rent a temporary buffer of size: {totalBytes} bytes; maximum temporary buffer size: {PacketBufferSize} bytes", + $"Cannot rent a temporary buffer of size: {totalBytes} bytes; maximum temporary buffer size: {datagramSize} bytes", nameof(writeBuffer.Length) ); } - byte[] transmissionBuffer = BufferPool.Rent(PacketBufferSize); + byte[] transmissionBuffer = BufferPool.Rent(datagramSize); writeBuffer.CopyTo(transmissionBuffer); int writtenBytes = Connection.SendTo(transmissionBuffer, flags, remoteEndPoint); @@ -245,10 +256,10 @@ namespace NetSharp.Raw.Datagram public override ValueTask<int> WriteAsync(EndPoint remoteEndPoint, ReadOnlyMemory<byte> writeBuffer, SocketFlags flags = SocketFlags.None) { int totalBytes = writeBuffer.Length; - if (totalBytes > PacketBufferSize) + if (totalBytes > datagramSize) { throw new ArgumentException( - $"Cannot rent a temporary buffer of size: {totalBytes} bytes; maximum temporary buffer size: {PacketBufferSize} bytes", + $"Cannot rent a temporary buffer of size: {totalBytes} bytes; maximum temporary buffer size: {datagramSize} bytes", nameof(writeBuffer.Length) ); } @@ -256,10 +267,10 @@ namespace NetSharp.Raw.Datagram TaskCompletionSource<int> tcs = new TaskCompletionSource<int>(); SocketAsyncEventArgs args = ArgsPool.Rent(); - byte[] transmissionBuffer = BufferPool.Rent(PacketBufferSize); + byte[] transmissionBuffer = BufferPool.Rent(datagramSize); writeBuffer.CopyTo(transmissionBuffer); - args.SetBuffer(transmissionBuffer, 0, PacketBufferSize); + args.SetBuffer(transmissionBuffer, 0, datagramSize); args.RemoteEndPoint = remoteEndPoint; args.SocketFlags = flags; diff --git a/NetSharp/NetSharp/Raw/IRawNetworkTransportProvider.cs b/NetSharp/NetSharp/Raw/IRawNetworkTransportProvider.cs @@ -1,4 +1,5 @@ -using NetSharp.Raw.Datagram; +using System; +using NetSharp.Raw.Datagram; using NetSharp.Raw.Stream; using System.Net; @@ -6,18 +7,18 @@ using System.Net.Sockets; namespace NetSharp.Raw { - public interface IRawNetworkTransportProvider + public interface IRawNetworkTransportProvider<in TReqHandler> where TReqHandler : Delegate { SocketType TransportProtocolType { get; } - RawNetworkReaderBase GetReader(ref Socket rawConnection, EndPoint defaultEndPoint, NetworkRequestHandler? requestHandler, int maxPooledBufferSize, + RawNetworkReaderBase GetReader(ref Socket rawConnection, EndPoint defaultEndPoint, TReqHandler requestHandler, int maxPooledBufferSize, int maxPooledBuffersPerBucket = 1000, uint preallocatedStateObjects = 0); RawNetworkWriterBase GetWriter(ref Socket rawConnection, EndPoint defaultEndPoint, int maxPooledBufferSize, int maxPooledBuffersPerBucket = 1000, uint preallocatedStateObjects = 0); } - public sealed class DatagramRawNetworkTransportProvider : IRawNetworkTransportProvider + public sealed class DatagramRawNetworkTransportProvider : IRawNetworkTransportProvider<RawDatagramRequestHandler> { private readonly ushort datagramSize; @@ -30,9 +31,8 @@ namespace NetSharp.Raw public SocketType TransportProtocolType { get; } = SocketType.Dgram; /// <inheritdoc /> - public RawNetworkReaderBase GetReader(ref Socket rawConnection, EndPoint defaultEndPoint, - NetworkRequestHandler? requestHandler, int maxPooledBufferSize, int maxPooledBuffersPerBucket = 1000, - uint preallocatedStateObjects = 0) + public RawNetworkReaderBase GetReader(ref Socket rawConnection, EndPoint defaultEndPoint, RawDatagramRequestHandler? requestHandler, + int maxPooledBufferSize, int maxPooledBuffersPerBucket = 1000, uint preallocatedStateObjects = 0) { return new RawDatagramNetworkReader(ref rawConnection, requestHandler, defaultEndPoint, maxPooledBufferSize, maxPooledBuffersPerBucket, preallocatedStateObjects); @@ -47,13 +47,13 @@ namespace NetSharp.Raw } } - public sealed class StreamRawNetworkTransportProvider : IRawNetworkTransportProvider + public sealed class StreamRawNetworkTransportProvider : IRawNetworkTransportProvider<RawStreamRequestHandler> { /// <inheritdoc /> public SocketType TransportProtocolType { get; } = SocketType.Stream; /// <inheritdoc /> - public RawNetworkReaderBase GetReader(ref Socket rawConnection, EndPoint defaultEndPoint, NetworkRequestHandler? requestHandler, + public RawNetworkReaderBase GetReader(ref Socket rawConnection, EndPoint defaultEndPoint, RawStreamRequestHandler? requestHandler, int maxPooledBufferSize, int maxPooledBuffersPerBucket = 1000, uint preallocatedStateObjects = 0) { return new RawStreamNetworkReader(ref rawConnection, requestHandler, defaultEndPoint, maxPooledBufferSize, diff --git a/NetSharp/NetSharp/Raw/RawNetworkConnectionBase.cs b/NetSharp/NetSharp/Raw/RawNetworkConnectionBase.cs @@ -9,19 +9,22 @@ namespace NetSharp.Raw { public abstract class RawNetworkConnectionBase : IDisposable { + // https://github.com/dotnet/coreclr/blob/master/src/System.Private.CoreLib/shared/System/Buffers/ConfigurableArrayPool.cs + private const int DefaultMaxPooledBufferSize = 1024 * 1024, DefaultMaxPooledBuffersPerBucket = 50; + protected readonly SlimObjectPool<SocketAsyncEventArgs> ArgsPool; protected readonly ArrayPool<byte> BufferPool; protected readonly Socket Connection; protected readonly EndPoint DefaultEndPoint; - protected readonly int PacketBufferSize; protected RawNetworkConnectionBase(ref Socket rawConnection, EndPoint defaultEndPoint, int pooledPacketBufferSize, - int pooledBuffersPerBucket = 1000, uint preallocatedStateObjects = 0) + int pooledBuffersPerBucket = 50, uint preallocatedStateObjects = 0) { Connection = rawConnection; - PacketBufferSize = pooledPacketBufferSize; - BufferPool = ArrayPool<byte>.Create(pooledPacketBufferSize, pooledBuffersPerBucket); + BufferPool = pooledPacketBufferSize <= DefaultMaxPooledBufferSize && pooledBuffersPerBucket <= DefaultMaxPooledBuffersPerBucket + ? ArrayPool<byte>.Shared + : BufferPool = ArrayPool<byte>.Create(pooledPacketBufferSize, pooledBuffersPerBucket); DefaultEndPoint = defaultEndPoint; diff --git a/NetSharp/NetSharp/Raw/RawNetworkReaderBase.cs b/NetSharp/NetSharp/Raw/RawNetworkReaderBase.cs @@ -5,25 +5,18 @@ using System.Threading; namespace NetSharp.Raw { - public delegate bool NetworkRequestHandler(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> requestBuffer, int receivedRequestBytes, - Memory<byte> responseBuffer); - public abstract class RawNetworkReaderBase : RawNetworkConnectionBase, INetworkReader { private readonly CancellationTokenSource shutdownTokenSource; - protected readonly NetworkRequestHandler RequestHandler; protected readonly CancellationToken ShutdownToken; /// <inheritdoc /> - protected RawNetworkReaderBase(ref Socket rawConnection, EndPoint defaultEndPoint, NetworkRequestHandler? requestHandler, int pooledPacketBufferSize, - int pooledBuffersPerBucket = 1000, uint preallocatedStateObjects = 0) : base(ref rawConnection, defaultEndPoint, pooledPacketBufferSize, - pooledBuffersPerBucket, preallocatedStateObjects) + private protected RawNetworkReaderBase(ref Socket rawConnection, EndPoint defaultEndPoint, int pooledPacketBufferSize, int pooledBuffersPerBucket = 50, + uint preallocatedStateObjects = 0) : base(ref rawConnection, defaultEndPoint, pooledPacketBufferSize, pooledBuffersPerBucket, preallocatedStateObjects) { shutdownTokenSource = new CancellationTokenSource(); ShutdownToken = shutdownTokenSource.Token; - - RequestHandler = requestHandler ?? DefaultRequestHandler; } /// <inheritdoc /> @@ -37,12 +30,6 @@ namespace NetSharp.Raw base.Dispose(disposing); } - public static bool DefaultRequestHandler(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> requestBuffer, int receivedRequestBytes, - Memory<byte> responseBuffer) - { - return requestBuffer.TryCopyTo(responseBuffer); - } - /// <inheritdoc /> public abstract void Start(ushort concurrentReadTasks); diff --git a/NetSharp/NetSharp/Raw/RawNetworkWriterBase.cs b/NetSharp/NetSharp/Raw/RawNetworkWriterBase.cs @@ -8,7 +8,7 @@ namespace NetSharp.Raw public abstract class RawNetworkWriterBase : RawNetworkConnectionBase, INetworkWriter { /// <inheritdoc /> - protected RawNetworkWriterBase(ref Socket rawConnection, EndPoint defaultEndPoint, int pooledPacketBufferSize, int pooledBuffersPerBucket = 1000, + protected RawNetworkWriterBase(ref Socket rawConnection, EndPoint defaultEndPoint, int pooledPacketBufferSize, int pooledBuffersPerBucket = 50, uint preallocatedStateObjects = 0) : base(ref rawConnection, defaultEndPoint, pooledPacketBufferSize, pooledBuffersPerBucket, preallocatedStateObjects) { } diff --git a/NetSharp/NetSharp/Raw/Stream/RawStreamNetworkReader.cs b/NetSharp/NetSharp/Raw/Stream/RawStreamNetworkReader.cs @@ -1,16 +1,28 @@ -using System.Net; +using System; +using System.Net; using System.Net.Sockets; using System.Runtime.CompilerServices; namespace NetSharp.Raw.Stream { + public delegate bool RawStreamRequestHandler(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> requestBuffer, int receivedRequestBytes, + Memory<byte> responseBuffer); + public sealed class RawStreamNetworkReader : RawNetworkReaderBase { + // TODO remove and replace with proper packet size + private readonly int datagramSize; + + private readonly RawStreamRequestHandler requestHandler; + /// <inheritdoc /> - public RawStreamNetworkReader(ref Socket rawConnection, NetworkRequestHandler? requestHandler, EndPoint defaultEndPoint, int pooledPacketBufferSize, - int pooledBuffersPerBucket = 1000, uint preallocatedStateObjects = 0) : base(ref rawConnection, defaultEndPoint, requestHandler, pooledPacketBufferSize, + public RawStreamNetworkReader(ref Socket rawConnection, RawStreamRequestHandler? requestHandler, EndPoint defaultEndPoint, int pooledPacketBufferSize, + int pooledBuffersPerBucket = 50, uint preallocatedStateObjects = 0) : base(ref rawConnection, defaultEndPoint, pooledPacketBufferSize, pooledBuffersPerBucket, preallocatedStateObjects) { + datagramSize = pooledPacketBufferSize; + + this.requestHandler = requestHandler ?? DefaultRequestHandler; } private void CloseClientConnection(SocketAsyncEventArgs args) @@ -66,16 +78,16 @@ namespace NetSharp.Raw.Stream if (totalReceivedBytes + receivedBytes == expectedBytes) // transmission complete { - byte[] responseBufferHandle = BufferPool.Rent(expectedBytes); + byte[] responseBuffer = BufferPool.Rent(expectedBytes); bool responseExists = - RequestHandler(args.AcceptSocket.RemoteEndPoint, receiveBuffer, totalReceivedBytes + receivedBytes, responseBufferHandle); - BufferPool.Return(receiveBuffer, true); + requestHandler(args.AcceptSocket.RemoteEndPoint, receiveBuffer, totalReceivedBytes + receivedBytes, responseBuffer); + + Buffer.BlockCopy(responseBuffer, 0, receiveBuffer, 0, datagramSize); + BufferPool.Return(responseBuffer, true); if (responseExists) { - args.SetBuffer(responseBufferHandle, 0, PacketBufferSize); - TransmissionToken sendToken = new TransmissionToken(0); args.UserToken = sendToken; @@ -83,8 +95,6 @@ namespace NetSharp.Raw.Stream return; } - BufferPool.Return(responseBufferHandle, true); - StartReceive(args); } else if (0 < totalReceivedBytes + receivedBytes && totalReceivedBytes + receivedBytes < expectedBytes) // transmission not complete @@ -232,9 +242,9 @@ namespace NetSharp.Raw.Stream Socket clientSocket = args.AcceptSocket; - byte[] receiveBuffer = BufferPool.Rent(PacketBufferSize); + byte[] receiveBuffer = BufferPool.Rent(datagramSize); - args.SetBuffer(receiveBuffer, 0, PacketBufferSize); + args.SetBuffer(receiveBuffer, 0, datagramSize); TransmissionToken token = new TransmissionToken(0); args.UserToken = token; @@ -287,6 +297,12 @@ namespace NetSharp.Raw.Stream instance.AcceptSocket = null; } + public static bool DefaultRequestHandler(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> requestBuffer, int receivedRequestBytes, + Memory<byte> responseBuffer) + { + return requestBuffer.TryCopyTo(responseBuffer); + } + /// <inheritdoc /> public override void Start(ushort concurrentReadTasks) { diff --git a/NetSharp/NetSharp/Raw/Stream/RawStreamNetworkWriter.cs b/NetSharp/NetSharp/Raw/Stream/RawStreamNetworkWriter.cs @@ -8,10 +8,14 @@ namespace NetSharp.Raw.Stream { public sealed class RawStreamNetworkWriter : RawNetworkWriterBase { + // TODO replace with proper packet size + private readonly int datagramSize; + /// <inheritdoc /> - public RawStreamNetworkWriter(ref Socket rawConnection, EndPoint defaultEndPoint, int pooledPacketBufferSize, int pooledBuffersPerBucket = 1000, + public RawStreamNetworkWriter(ref Socket rawConnection, EndPoint defaultEndPoint, int pooledPacketBufferSize, int pooledBuffersPerBucket = 50, uint preallocatedStateObjects = 0) : base(ref rawConnection, defaultEndPoint, pooledPacketBufferSize, pooledBuffersPerBucket, preallocatedStateObjects) { + datagramSize = pooledPacketBufferSize; } private void CompleteConnect(SocketAsyncEventArgs args) @@ -270,10 +274,10 @@ namespace NetSharp.Raw.Stream public override int Read(ref EndPoint remoteEndPoint, Memory<byte> readBuffer, SocketFlags flags = SocketFlags.None) { int totalBytes = readBuffer.Length; - if (totalBytes > PacketBufferSize) + if (totalBytes > datagramSize) { throw new ArgumentException( - $"Cannot rent a temporary buffer of size: {totalBytes} bytes; maximum temporary buffer size: {PacketBufferSize} bytes", + $"Cannot rent a temporary buffer of size: {totalBytes} bytes; maximum temporary buffer size: {datagramSize} bytes", nameof(readBuffer.Length) ); } @@ -297,10 +301,10 @@ namespace NetSharp.Raw.Stream public override ValueTask<int> ReadAsync(EndPoint remoteEndPoint, Memory<byte> readBuffer, SocketFlags flags = SocketFlags.None) { int totalBytes = readBuffer.Length; - if (totalBytes > PacketBufferSize) + if (totalBytes > datagramSize) { throw new ArgumentException( - $"Cannot rent a temporary buffer of size: {totalBytes} bytes; maximum temporary buffer size: {PacketBufferSize} bytes", + $"Cannot rent a temporary buffer of size: {totalBytes} bytes; maximum temporary buffer size: {datagramSize} bytes", nameof(readBuffer.Length) ); } @@ -310,7 +314,7 @@ namespace NetSharp.Raw.Stream byte[] transmissionBuffer = BufferPool.Rent(totalBytes); - args.SetBuffer(transmissionBuffer, 0, PacketBufferSize); + args.SetBuffer(transmissionBuffer, 0, datagramSize); args.RemoteEndPoint = remoteEndPoint; args.SocketFlags = flags; @@ -323,7 +327,7 @@ namespace NetSharp.Raw.Stream // inlining CompleteReceive(SocketAsyncEventArgs) for performance int receivedBytes = args.BytesTransferred, totalReceivedBytes = token.TotalReadBytes; - if (totalReceivedBytes + receivedBytes == PacketBufferSize) // transmission complete + if (totalReceivedBytes + receivedBytes == datagramSize) // transmission complete { transmissionBuffer.CopyTo(readBuffer); @@ -332,13 +336,13 @@ namespace NetSharp.Raw.Stream return new ValueTask<int>(totalReceivedBytes + receivedBytes); } - else if (0 < totalReceivedBytes + receivedBytes && totalReceivedBytes + receivedBytes < PacketBufferSize) // transmission not complete + else if (0 < totalReceivedBytes + receivedBytes && totalReceivedBytes + receivedBytes < datagramSize) // transmission not complete { // update user token to take account of newly read bytes token = new AsyncStreamReadToken(in token, receivedBytes); args.UserToken = token; - args.SetBuffer(totalReceivedBytes, PacketBufferSize - receivedBytes); + args.SetBuffer(totalReceivedBytes, datagramSize - receivedBytes); ContinueReceive(args); } @@ -354,10 +358,10 @@ namespace NetSharp.Raw.Stream public override int Write(EndPoint remoteEndPoint, ReadOnlyMemory<byte> writeBuffer, SocketFlags flags = SocketFlags.None) { int totalBytes = writeBuffer.Length; - if (totalBytes > PacketBufferSize) + if (totalBytes > datagramSize) { throw new ArgumentException( - $"Cannot rent a temporary buffer of size: {totalBytes} bytes; maximum temporary buffer size: {PacketBufferSize} bytes", + $"Cannot rent a temporary buffer of size: {totalBytes} bytes; maximum temporary buffer size: {datagramSize} bytes", nameof(writeBuffer.Length) ); } @@ -381,10 +385,10 @@ namespace NetSharp.Raw.Stream public override ValueTask<int> WriteAsync(EndPoint remoteEndPoint, ReadOnlyMemory<byte> writeBuffer, SocketFlags flags = SocketFlags.None) { int totalBytes = writeBuffer.Length; - if (totalBytes > PacketBufferSize) + if (totalBytes > datagramSize) { throw new ArgumentException( - $"Cannot rent a temporary buffer of size: {totalBytes} bytes; maximum temporary buffer size: {PacketBufferSize} bytes", + $"Cannot rent a temporary buffer of size: {totalBytes} bytes; maximum temporary buffer size: {datagramSize} bytes", nameof(writeBuffer.Length) ); } @@ -395,7 +399,7 @@ namespace NetSharp.Raw.Stream byte[] transmissionBuffer = BufferPool.Rent(totalBytes); writeBuffer.CopyTo(transmissionBuffer); - args.SetBuffer(transmissionBuffer, 0, PacketBufferSize); + args.SetBuffer(transmissionBuffer, 0, datagramSize); args.RemoteEndPoint = remoteEndPoint; args.SocketFlags = flags; @@ -408,20 +412,20 @@ namespace NetSharp.Raw.Stream // inlining CompleteSend(SocketAsyncEventArgs) for performance int sentBytes = args.BytesTransferred, totalSentBytes = token.TotalWrittenBytes; - if (totalSentBytes + sentBytes == PacketBufferSize) // transmission complete + if (totalSentBytes + sentBytes == datagramSize) // transmission complete { BufferPool.Return(transmissionBuffer, true); ArgsPool.Return(args); return new ValueTask<int>(totalSentBytes + sentBytes); } - else if (0 < totalSentBytes + sentBytes && totalSentBytes + sentBytes < PacketBufferSize) // transmission not complete + else if (0 < totalSentBytes + sentBytes && totalSentBytes + sentBytes < datagramSize) // transmission not complete { // update user token to take account of newly written bytes token = new AsyncStreamWriteToken(in token, sentBytes); args.UserToken = token; - args.SetBuffer(totalSentBytes, PacketBufferSize - sentBytes); + args.SetBuffer(totalSentBytes, datagramSize - sentBytes); ContinueSend(args); } diff --git a/NetSharp/NetSharp/Raw/Stream/RawStreamPacket.cs b/NetSharp/NetSharp/Raw/Stream/RawStreamPacket.cs @@ -0,0 +1,35 @@ +using System; +using NetSharp.Utils.Conversion; + +namespace NetSharp.Raw.Stream +{ + public readonly struct RawStreamPacket + { + } + + public readonly struct RawStreamPacketHeader + { + public const int HeaderSize = sizeof(int); + public readonly int PacketSize; + + private RawStreamPacketHeader(int packetSize) + { + PacketSize = packetSize; + } + + public static RawStreamPacketHeader Deserialise(Memory<byte> buffer) + { + Span<byte> packetSizeSpan = buffer.Slice(0, sizeof(int)).Span; + + int packetSize = EndianAwareBitConverter.ToInt32(packetSizeSpan); + + return new RawStreamPacketHeader(packetSize); + } + + public static void Serialise(RawStreamPacketHeader instance, Memory<byte> buffer) + { + Span<byte> packetSizeSpan = buffer.Slice(0, sizeof(int)).Span; + EndianAwareBitConverter.GetBytes(instance.PacketSize).CopyTo(packetSizeSpan); + } + } +} +\ No newline at end of file diff --git a/NetSharp/NetSharpExamples/Examples/Connection Examples/DefaultConnectionExample.cs b/NetSharp/NetSharpExamples/Examples/Connection Examples/DefaultConnectionExample.cs @@ -1,31 +0,0 @@ -using System.Net; -using System.Threading; -using System.Threading.Tasks; -using NetSharp; -using NetSharp.Packets; - -namespace NetSharpExamples.Examples.Connection_Examples -{ - public class DefaultConnectionExample : INetSharpExample - { - /// <inheritdoc /> - public string Name { get; } = "Connection Instantiation Code Example"; - - /// <inheritdoc /> - public Task RunAsync() - { - using Connection streamConnection = ConnectionBuilder - .WithStreamTransport() - .WithInterNetwork(new IPEndPoint(IPAddress.Any, 0)) - .WithSettings(NetworkPacket.TotalSize, 1000, 0) - .BuildDefault(); - - using Connection datagramConnection = ConnectionBuilder - .WithDatagramTransport() - .WithDefaultSettings(1024) - .BuildDefault(); - - return Task.CompletedTask; - } - } -} -\ No newline at end of file diff --git a/NetSharp/NetSharpExamples/NetSharpExamples.csproj b/NetSharp/NetSharpExamples/NetSharpExamples.csproj @@ -16,4 +16,8 @@ <ItemGroup> <ProjectReference Include="..\NetSharp\NetSharp.csproj" /> </ItemGroup> + + <ItemGroup> + <Folder Include="Examples\Connection Examples\" /> + </ItemGroup> </Project> \ No newline at end of file diff --git a/NetSharp/NetSharpExamples/NetSharpExamples.xml b/NetSharp/NetSharpExamples/NetSharpExamples.xml @@ -40,12 +40,6 @@ <member name="M:NetSharpExamples.Benchmarks.Stream_Network_Connection_Benchmarks.StreamNetworkWriterSyncBenchmark.RunAsync"> <inheritdoc /> </member> - <member name="P:NetSharpExamples.Examples.Connection_Examples.DefaultConnectionExample.Name"> - <inheritdoc /> - </member> - <member name="M:NetSharpExamples.Examples.Connection_Examples.DefaultConnectionExample.RunAsync"> - <inheritdoc /> - </member> <member name="P:NetSharpExamples.Examples.Datagram_Network_Connection_Examples.DatagramNetworkReaderExample.Name"> <inheritdoc /> </member>