NetSharp

NetSharp.git
git clone git://git.lenczewski.org/NetSharp.git
Log | Files | Refs | README | LICENSE

commit d6c8b600ef67aa55e97011a2dbab601df9826607
parent a4d3c32780db721b39a7758631263c71634b7a6e
Author: Mikolaj Lenczewski <mikolaj.lenczewski308@gmail.com>
Date:   Sat, 19 Dec 2020 18:16:16 +0000

Split state token into 3 separate classes

Diffstat:
MNetSharp/NetSharp/Raw/Stream/RawStreamConnection.cs | 251++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
1 file changed, 178 insertions(+), 73 deletions(-)

diff --git a/NetSharp/NetSharp/Raw/Stream/RawStreamConnection.cs b/NetSharp/NetSharp/Raw/Stream/RawStreamConnection.cs @@ -37,8 +37,10 @@ namespace NetSharp.Raw.Stream /// </summary> public sealed class RawStreamConnection : RawConnectionBase, IRawStreamWriter { + private readonly SlimObjectPool<OperationStateToken> operationStatePool; + private readonly SlimObjectPool<ReaderStateToken> readerStatePool; private readonly ConcurrentDictionary<int, RawStreamPacketHandler> registeredHandlers; - private readonly SlimObjectPool<StateToken> stateTokenPool; + private readonly SlimObjectPool<WriterStateToken> writerStatePool; /// <summary> /// Initialises a new instance of the <see cref="RawStreamConnection" /> class. @@ -54,13 +56,65 @@ namespace NetSharp.Raw.Stream { registeredHandlers = new ConcurrentDictionary<int, RawStreamPacketHandler>(); - static StateToken CreateStateToken() => new StateToken(); + static OperationStateToken CreateOperationToken() + { + return new OperationStateToken(); + } - static void ResetStateToken(ref StateToken instance) => instance.Reset(); + static void ResetOperationToken(ref OperationStateToken instance) + { + instance.Reset(); + } - static void DestroyStateToken(StateToken instance) => instance.Dispose(); + static void DestroyOperationToken(OperationStateToken instance) + { + instance.Dispose(); + } - stateTokenPool = new SlimObjectPool<StateToken>(CreateStateToken, ResetStateToken, DestroyStateToken); + operationStatePool = new SlimObjectPool<OperationStateToken>( + CreateOperationToken, + ResetOperationToken, + DestroyOperationToken); + + static ReaderStateToken CreateReaderToken() + { + return new ReaderStateToken(); + } + + static void ResetReaderToken(ref ReaderStateToken instance) + { + instance.Reset(); + } + + static void DestroyReaderToken(ReaderStateToken instance) + { + instance.Dispose(); + } + + readerStatePool = new SlimObjectPool<ReaderStateToken>( + CreateReaderToken, + ResetReaderToken, + DestroyReaderToken); + + static WriterStateToken CreateWriterToken() + { + return new WriterStateToken(); + } + + static void ResetWriterToken(ref WriterStateToken instance) + { + instance.Reset(); + } + + static void DestroyWriterToken(WriterStateToken instance) + { + instance.Dispose(); + } + + writerStatePool = new SlimObjectPool<WriterStateToken>( + CreateWriterToken, + ResetWriterToken, + DestroyWriterToken); } /// <summary> @@ -77,10 +131,10 @@ namespace NetSharp.Raw.Stream TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>(); SocketAsyncEventArgs socketArgs = RentSocketArgs(); - StateToken state = stateTokenPool.Rent(); - state.OperationCompletionSource = tcs; + OperationStateToken operationState = operationStatePool.Rent(); + operationState.OperationCompletionSource = tcs; - socketArgs.UserToken = state; + socketArgs.UserToken = operationState; socketArgs.RemoteEndPoint = remoteEndPoint; @@ -123,10 +177,10 @@ namespace NetSharp.Raw.Stream TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>(); SocketAsyncEventArgs socketArgs = RentSocketArgs(); - StateToken state = stateTokenPool.Rent(); - state.OperationCompletionSource = tcs; + OperationStateToken operationState = operationStatePool.Rent(); + operationState.OperationCompletionSource = tcs; - socketArgs.UserToken = state; + socketArgs.UserToken = operationState; socketArgs.DisconnectReuseSocket = leaveConnectionReusable; @@ -155,9 +209,9 @@ namespace NetSharp.Raw.Stream RawPacketHeader header = new RawPacketHeader(type, buffer.Length); byte[] ownedBuffer = RentBuffer(RawPacket.TotalSize(in header)); - StateToken state = stateTokenPool.Rent(); + WriterStateToken writerState = writerStatePool.Rent(); - ConfigureSendRequestAsync(socketArgs, ref ownedBuffer, in header, in buffer, state, tcs); + ConfigureSendRequestAsync(socketArgs, ref ownedBuffer, in header, in buffer, writerState, tcs); socketArgs.SocketFlags = flags; @@ -200,12 +254,14 @@ namespace NetSharp.Raw.Stream return; } + base.Dispose(disposing); + if (disposing) { - stateTokenPool.Dispose(); + operationStatePool.Dispose(); + readerStatePool.Dispose(); + writerStatePool.Dispose(); } - - base.Dispose(disposing); } /// <inheritdoc /> @@ -255,7 +311,7 @@ namespace NetSharp.Raw.Stream ref byte[] ownedBuffer, in RawPacketHeader pendingHeader, in ReadOnlyMemory<byte> pendingData, - StateToken state, + WriterStateToken writerState, TaskCompletionSource<int> tcs) { Memory<byte> ownedBufferMemory = new Memory<byte>(ownedBuffer); @@ -264,10 +320,10 @@ namespace NetSharp.Raw.Stream int totalTransferredBytes = RawPacket.TotalSize(in pendingHeader); args.SetBuffer(ownedBuffer, 0, totalTransferredBytes); - state.BytesToTransfer = totalTransferredBytes; - state.RequestCompletionSource = tcs; + writerState.BytesToTransfer = totalTransferredBytes; + writerState.RequestCompletionSource = tcs; - args.UserToken = state; + args.UserToken = writerState; } /// <summary> @@ -277,7 +333,20 @@ namespace NetSharp.Raw.Stream { if (cleanupUserToken) { - stateTokenPool.Return((StateToken)args.UserToken); + switch (args.UserToken) + { + case OperationStateToken operationState: + operationStatePool.Return(operationState); + break; + + case ReaderStateToken readerState: + readerStatePool.Return(readerState); + break; + + case WriterStateToken writerState: + writerStatePool.Return(writerState); + break; + } } ReturnSocketArgs(args); @@ -301,7 +370,7 @@ namespace NetSharp.Raw.Stream /// <summary> /// Prepares the given socket args for receiving a packet's data from the network. /// </summary> - private void ConfigureReceiveDataAsync(SocketAsyncEventArgs args, StateToken state, in RawPacketHeader header) + private void ConfigureReceiveDataAsync(SocketAsyncEventArgs args, ReaderStateToken readerState, in RawPacketHeader header) { ReturnBuffer(args.Buffer); // return and clear the previously parsed request header buffer @@ -309,16 +378,16 @@ namespace NetSharp.Raw.Stream args.SetBuffer(pendingDataBuffer, 0, header.DataLength); - state.BytesToTransfer = header.DataLength; - state.RequestHeader = header; + readerState.BytesToTransfer = header.DataLength; + readerState.RequestHeader = header; - args.UserToken = state; + args.UserToken = readerState; } /// <summary> /// Prepares the given socket args for receiving a packet's header from the network. /// </summary> - private void ConfigureReceiveHeaderAsync(SocketAsyncEventArgs args, StateToken state) + private void ConfigureReceiveHeaderAsync(SocketAsyncEventArgs args, ReaderStateToken readerState) { ReturnBuffer(args.Buffer); // return and clear the previously sent response packet buffer @@ -326,9 +395,9 @@ namespace NetSharp.Raw.Stream args.SetBuffer(pendingHeaderBuffer, 0, RawPacketHeader.Length); - state.BytesToTransfer = RawPacketHeader.Length; + readerState.BytesToTransfer = RawPacketHeader.Length; - args.UserToken = state; + args.UserToken = readerState; } /// <summary> @@ -345,9 +414,10 @@ namespace NetSharp.Raw.Stream // the ResponseDataBuffer). args.SetBuffer(Array.Empty<byte>(), 0, 0); - StateToken state = stateTokenPool.Rent(); - ConfigureReceiveHeaderAsync(args, state); + ReaderStateToken readerState = readerStatePool.Rent(); + // TODO convert into iteration instead of recursion + ConfigureReceiveHeaderAsync(args, readerState); StartOrContinueReceiving(args); break; @@ -362,8 +432,8 @@ namespace NetSharp.Raw.Stream /// </summary> private void HandleConnected(SocketAsyncEventArgs args) { - StateToken state = (StateToken)args.UserToken; - TaskCompletionSource<bool>? tcs = state.OperationCompletionSource; + OperationStateToken readerState = (OperationStateToken)args.UserToken; + TaskCompletionSource<bool>? tcs = readerState.OperationCompletionSource; Debug.Assert( tcs != default, @@ -392,8 +462,8 @@ namespace NetSharp.Raw.Stream /// </summary> private void HandleDisconnected(SocketAsyncEventArgs args) { - StateToken state = (StateToken)args.UserToken; - TaskCompletionSource<bool>? tcs = state.OperationCompletionSource; + OperationStateToken readerState = (OperationStateToken)args.UserToken; + TaskCompletionSource<bool>? tcs = readerState.OperationCompletionSource; Debug.Assert( tcs != default, @@ -456,25 +526,26 @@ namespace NetSharp.Raw.Stream /// </summary> private void HandleReceived(SocketAsyncEventArgs args) { - StateToken state = (StateToken)args.UserToken; + ReaderStateToken readerState = (ReaderStateToken)args.UserToken; switch (args.SocketError) { case SocketError.Success: - switch (state.BytesToTransfer) + switch (readerState.BytesToTransfer) { case RawPacketHeader.Length: - HandleReceivedHeader(args, state); + HandleReceivedHeader(args, readerState); break; default: - HandleReceivedData(args, state); + HandleReceivedData(args, readerState); break; } break; default: + // TODO break out of iteration in HandleAccepted CloseClientConnection(args); break; } @@ -483,26 +554,27 @@ namespace NetSharp.Raw.Stream /// <summary> /// Handles the completion of a <see cref="Socket.ReceiveAsync" /> call, when receiving a packet's data from the network. /// </summary> - private void HandleReceivedData(SocketAsyncEventArgs args, StateToken state) + private void HandleReceivedData(SocketAsyncEventArgs args, ReaderStateToken readerState) { int received = args.BytesTransferred; int previouslyReceived = args.Offset; int totalReceived = previouslyReceived + received; - int expected = state.BytesToTransfer; + int expected = readerState.BytesToTransfer; - RawPacketHeader header = state.RequestHeader!.Value; + RawPacketHeader header = readerState.RequestHeader!.Value; byte[] dataBuffer = args.Buffer; ReadOnlyMemory<byte> dataBufferMemory = new ReadOnlyMemory<byte>(dataBuffer, 0, header.DataLength); if (totalReceived == expected) { + // TODO switch out recursion for iteration in HandleAccepted if (registeredHandlers.TryGetValue(header.Type, out RawStreamPacketHandler handler)) { handler.Invoke(args.AcceptSocket.RemoteEndPoint, in header, in dataBufferMemory, this); } - ConfigureReceiveHeaderAsync(args, state); + ConfigureReceiveHeaderAsync(args, readerState); StartOrContinueReceiving(args); } else if (totalReceived > 0 && totalReceived < expected) @@ -512,6 +584,7 @@ namespace NetSharp.Raw.Stream } else if (received == 0) { + // TODO break out of iteration in HandleAccepted CloseClientConnection(args); } } @@ -520,12 +593,12 @@ namespace NetSharp.Raw.Stream /// Handles the completion of a <see cref="Socket.ReceiveAsync" /> call, when receiving a packet's header from /// the network. /// </summary> - private void HandleReceivedHeader(SocketAsyncEventArgs args, StateToken state) + private void HandleReceivedHeader(SocketAsyncEventArgs args, ReaderStateToken readerState) { int received = args.BytesTransferred; int previouslyReceived = args.Offset; int totalReceived = previouslyReceived + received; - int expected = state.BytesToTransfer; + int expected = readerState.BytesToTransfer; byte[] headerBuffer = args.Buffer; ReadOnlySpan<byte> headerBufferMemory = new ReadOnlySpan<byte>(headerBuffer); @@ -534,7 +607,7 @@ namespace NetSharp.Raw.Stream { RawPacketHeader header = RawPacketHeader.Deserialise(in headerBufferMemory); - ConfigureReceiveDataAsync(args, state, in header); + ConfigureReceiveDataAsync(args, readerState, in header); StartOrContinueReceiving(args); } else if (totalReceived > 0 && totalReceived < expected) @@ -544,6 +617,7 @@ namespace NetSharp.Raw.Stream } else if (received == 0) { + // TODO break out of iteration in HandleAccepted CloseClientConnection(args); } } @@ -553,39 +627,38 @@ namespace NetSharp.Raw.Stream /// </summary> private void HandleSent(SocketAsyncEventArgs args) { - StateToken state = (StateToken)args.UserToken; - TaskCompletionSource<int>? tcs = state.RequestCompletionSource; - - switch (tcs) + switch (args.UserToken) { - case null: + case ReaderStateToken readerState: switch (args.SocketError) { case SocketError.Success: - HandleSentResponse(args, state); + HandleSentResponse(args, readerState); break; default: + // TODO break out of iteration in HandleAccepted CloseClientConnection(args); break; } break; - default: + case WriterStateToken writerState: switch (args.SocketError) { case SocketError.Success: - HandleSentRequest(args, state); + HandleSentRequest(args, writerState); break; case SocketError.OperationAborted: - tcs.SetCanceled(); + writerState.RequestCompletionSource!.SetCanceled(); CleanupArgs(args); break; default: - tcs.SetException(new SocketException((int)args.SocketError)); + writerState.RequestCompletionSource!.SetException( + new SocketException((int)args.SocketError)); CleanupArgs(args); break; } @@ -598,14 +671,14 @@ namespace NetSharp.Raw.Stream /// Handles the completion of a <see cref="Socket.SendAsync" /> call, when sending a request packet to the /// network. In this case, the <see cref="SocketAsyncEventArgs.ConnectSocket" /> will be used to perform the transmission. /// </summary> - private void HandleSentRequest(SocketAsyncEventArgs args, StateToken state) + private void HandleSentRequest(SocketAsyncEventArgs args, WriterStateToken writerState) { - TaskCompletionSource<int> tcs = state.RequestCompletionSource!; + TaskCompletionSource<int> tcs = writerState.RequestCompletionSource!; int sent = args.BytesTransferred; int previouslySent = args.Offset; int totalSent = previouslySent + sent; - int expected = state.BytesToTransfer; + int expected = writerState.BytesToTransfer; if (totalSent == expected) { @@ -629,16 +702,17 @@ namespace NetSharp.Raw.Stream /// Handles the completion of a <see cref="Socket.SendAsync" /> call, when sending a response packet to the /// network. In this case, the <see cref="SocketAsyncEventArgs.AcceptSocket" /> will be used to perform the transmission. /// </summary> - private void HandleSentResponse(SocketAsyncEventArgs args, StateToken state) + private void HandleSentResponse(SocketAsyncEventArgs args, ReaderStateToken readerState) { int sent = args.BytesTransferred; int previouslySent = args.Offset; int totalSent = previouslySent + sent; - int expected = state.BytesToTransfer; + int expected = readerState.BytesToTransfer; if (totalSent == expected) { - ConfigureReceiveHeaderAsync(args, state); + // TODO switch out recursion for iteration in HandleAccepted + ConfigureReceiveHeaderAsync(args, readerState); StartOrContinueReceiving(args); } else if (totalSent > 0 && totalSent < expected) @@ -648,6 +722,7 @@ namespace NetSharp.Raw.Stream } else if (sent == 0) { + // TODO break out of iteration in HandleAccepted CloseClientConnection(args); } } @@ -680,10 +755,26 @@ namespace NetSharp.Raw.Stream HandleSent(args); } - /// <summary> - /// State token for the stream network connection. - /// </summary> - private sealed class StateToken : IDisposable + private sealed class OperationStateToken : IDisposable + { + /// <summary> + /// The <see cref="TaskCompletionSource{TResult}" /> for asynchronous network operations. + /// </summary> + internal TaskCompletionSource<bool>? OperationCompletionSource { get; set; } + + /// <inheritdoc /> + public void Dispose() + { + Reset(); + } + + internal void Reset() + { + OperationCompletionSource = null; + } + } + + private sealed class ReaderStateToken : IDisposable { /// <summary> /// The number of bytes that we need to transfer over the network. @@ -691,20 +782,36 @@ namespace NetSharp.Raw.Stream internal int BytesToTransfer { get; set; } /// <summary> - /// The <see cref="TaskCompletionSource{TResult}" /> for asynchronous network operations. + /// The deserialised request packet header. /// </summary> - internal TaskCompletionSource<bool>? OperationCompletionSource { get; set; } + internal RawPacketHeader? RequestHeader { get; set; } + /// <inheritdoc /> + public void Dispose() + { + Reset(); + } + + internal void Reset() + { + BytesToTransfer = 0; + RequestHeader = null; + } + } + + private sealed class WriterStateToken : IDisposable + { /// <summary> - /// The <see cref="TaskCompletionSource{TResult}" /> for asynchronous packet writes. + /// The number of bytes that we need to transfer over the network. /// </summary> - internal TaskCompletionSource<int>? RequestCompletionSource { get; set; } + internal int BytesToTransfer { get; set; } /// <summary> - /// The deserialised request packet header. + /// The <see cref="TaskCompletionSource{TResult}" /> for asynchronous packet writes. /// </summary> - internal RawPacketHeader? RequestHeader { get; set; } + internal TaskCompletionSource<int>? RequestCompletionSource { get; set; } + /// <inheritdoc /> public void Dispose() { Reset(); @@ -713,9 +820,7 @@ namespace NetSharp.Raw.Stream internal void Reset() { BytesToTransfer = 0; - OperationCompletionSource = null; RequestCompletionSource = null; - RequestHeader = null; } } }