NetSharp

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

commit a099d521e14ee630e5d9f736075f12944d38538c
parent 3773021f29a41d125b91fe8c20f892547450d1f4
Author: Mikolaj Lenczewski <mikolaj.lenczewski308@gmail.com>
Date:   Sun, 12 Apr 2020 12:18:35 +0100

Fixed memory leak (i think) for servers and clients

Diffstat:
MNetSharp/NetSharp/NetSharp.xml | 89++++++++++++++++++++++++++++++++++++-------------------------------------------
MNetSharp/NetSharp/Sockets/Datagram/DatagramSocketClient.cs | 11++++++-----
MNetSharp/NetSharp/Sockets/Datagram/DatagramSocketServer.cs | 5++---
DNetSharp/NetSharp/Sockets/SocketAsyncOperationTokens.cs | 92-------------------------------------------------------------------------------
DNetSharp/NetSharp/Sockets/SocketAsyncOperations.cs | 308-------------------------------------------------------------------------------
MNetSharp/NetSharp/Sockets/SocketClient.cs | 27+++++++++++++++++++++++++--
MNetSharp/NetSharp/Sockets/SocketConnection.cs | 7++++---
MNetSharp/NetSharp/Sockets/Stream/StreamSocketClient.cs | 16+++++++++-------
MNetSharp/NetSharp/Sockets/Stream/StreamSocketServer.cs | 50++++++++++++++++----------------------------------
MNetSharp/NetSharp/Utils/BiDictionary.cs | 2+-
MNetSharp/NetSharp/Utils/Conversion/EndianAwareBitConverter.cs | 2+-
MNetSharp/NetSharp/Utils/SlimObjectPool.cs | 4+++-
MNetSharp/NetSharpExamples/Program.cs | 13+++++++------
13 files changed, 115 insertions(+), 511 deletions(-)

diff --git a/NetSharp/NetSharp/NetSharp.xml b/NetSharp/NetSharp/NetSharp.xml @@ -15,69 +15,62 @@ 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.Deprecated.BiDictionary`2"> + <member name="T:NetSharp.Utils.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.Deprecated.BiDictionary`2.keyToValueMap"> + <member name="F:NetSharp.Utils.BiDictionary`2.keyToValueMap"> <summary> Maps keys to their corresponding values. </summary> </member> - <member name="F:NetSharp.Deprecated.BiDictionary`2.valueToKeyMap"> + <member name="F:NetSharp.Utils.BiDictionary`2.valueToKeyMap"> <summary> Maps values to their corresponding keys. </summary> </member> - <member name="M:NetSharp.Deprecated.BiDictionary`2.#ctor"> + <member name="M:NetSharp.Utils.BiDictionary`2.#ctor"> <summary> - Initialises a new instance of the <see cref="T:NetSharp.Deprecated.BiDictionary`2"/> class. + Initialises a new instance of the <see cref="T:NetSharp.Utils.BiDictionary`2"/> class. </summary> </member> - <member name="P:NetSharp.Deprecated.BiDictionary`2.Item(`1)"> + <member name="P:NetSharp.Utils.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.Deprecated.BiDictionary`2.Item(`0)"> + <member name="P:NetSharp.Utils.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.Deprecated.BiDictionary`2.Clear"> + <member name="M:NetSharp.Utils.BiDictionary`2.Clear"> <summary> - Clears this instance's <see cref="F:NetSharp.Deprecated.BiDictionary`2.keyToValueMap"/> and <see cref="F:NetSharp.Deprecated.BiDictionary`2.valueToKeyMap"/>. + Clears this instance's <see cref="F:NetSharp.Utils.BiDictionary`2.keyToValueMap"/> and <see cref="F:NetSharp.Utils.BiDictionary`2.valueToKeyMap"/>. </summary> </member> - <member name="M:NetSharp.Deprecated.BiDictionary`2.ContainsKey(`0@)"> + <member name="M:NetSharp.Utils.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.Deprecated.BiDictionary`2.ContainsValue(`1@)"> + <member name="M:NetSharp.Utils.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.Deprecated.BiDictionary`2.SetOrUpdateKey(`1,`0)"> + <member name="M:NetSharp.Utils.BiDictionary`2.SetOrUpdateKey(`1,`0)"> <summary> Attempts to set the key associated with the given value. </summary> @@ -85,7 +78,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.Deprecated.BiDictionary`2.SetOrUpdateValue(`0,`1)"> + <member name="M:NetSharp.Utils.BiDictionary`2.SetOrUpdateValue(`0,`1)"> <summary> Attempts to set the value associated with the given key. </summary> @@ -93,7 +86,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.Deprecated.BiDictionary`2.TryClearKey(`1@,`0@)"> + <member name="M:NetSharp.Utils.BiDictionary`2.TryClearKey(`1@,`0@)"> <summary> Attempts to remove the key associated with the given value. </summary> @@ -101,7 +94,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.Deprecated.BiDictionary`2.TryClearValue(`0@,`1@)"> + <member name="M:NetSharp.Utils.BiDictionary`2.TryClearValue(`0@,`1@)"> <summary> Attempts to remove the value associated with the given key. </summary> @@ -109,7 +102,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.Deprecated.BiDictionary`2.TryGetKey(`1@,`0@)"> + <member name="M:NetSharp.Utils.BiDictionary`2.TryGetKey(`1@,`0@)"> <summary> Attempts to get the key associated with the given value. </summary> @@ -117,7 +110,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.Deprecated.BiDictionary`2.TryGetValue(`0@,`1@)"> + <member name="M:NetSharp.Utils.BiDictionary`2.TryGetValue(`0@,`1@)"> <summary> Attempts to get the value associated with the given key. </summary> @@ -125,7 +118,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.Deprecated.BiDictionary`2.TrySetKey(`1@,`0@)"> + <member name="M:NetSharp.Utils.BiDictionary`2.TrySetKey(`1@,`0@)"> <summary> Attempts to set the key associated with the given value. </summary> @@ -133,7 +126,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.Deprecated.BiDictionary`2.TrySetValue(`0@,`1@)"> + <member name="M:NetSharp.Utils.BiDictionary`2.TrySetValue(`0@,`1@)"> <summary> Attempts to set the value associated with the given key. </summary> @@ -141,74 +134,74 @@ <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.Deprecated.Conversion.EndianAwareBitConverter"> + <member name="T:NetSharp.Utils.Conversion.EndianAwareBitConverter"> <summary> Wraps the <see cref="T:System.BitConverter"/> class to provide conversion that is endian-aware. </summary> </member> - <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.ReverseAsNeeded(System.Span{System.Byte},System.Boolean)"> + <member name="M:NetSharp.Utils.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.Deprecated.Conversion.EndianAwareBitConverter.GetBytes(System.Boolean,System.Boolean)"> + <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.Boolean,System.Boolean)"> <inheritdoc cref="M:System.BitConverter.GetBytes(System.Boolean)"/> </member> - <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.GetBytes(System.Char,System.Boolean)"> + <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.Char,System.Boolean)"> <inheritdoc cref="M:System.BitConverter.GetBytes(System.Char)"/> </member> - <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.GetBytes(System.Double,System.Boolean)"> + <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.Double,System.Boolean)"> <inheritdoc cref="M:System.BitConverter.GetBytes(System.Double)"/> </member> - <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.GetBytes(System.Single,System.Boolean)"> + <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.Single,System.Boolean)"> <inheritdoc cref="M:System.BitConverter.GetBytes(System.Single)"/> </member> - <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.GetBytes(System.Int32,System.Boolean)"> + <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.Int32,System.Boolean)"> <inheritdoc cref="M:System.BitConverter.GetBytes(System.Int32)"/> </member> - <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.GetBytes(System.Int64,System.Boolean)"> + <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.Int64,System.Boolean)"> <inheritdoc cref="M:System.BitConverter.GetBytes(System.Int64)"/> </member> - <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.GetBytes(System.Int16,System.Boolean)"> + <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.Int16,System.Boolean)"> <inheritdoc cref="M:System.BitConverter.GetBytes(System.Int16)"/> </member> - <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.GetBytes(System.UInt32,System.Boolean)"> + <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.UInt32,System.Boolean)"> <inheritdoc cref="M:System.BitConverter.GetBytes(System.UInt32)"/> </member> - <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.GetBytes(System.UInt64,System.Boolean)"> + <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.UInt64,System.Boolean)"> <inheritdoc cref="M:System.BitConverter.GetBytes(System.UInt64)"/> </member> - <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.GetBytes(System.UInt16,System.Boolean)"> + <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.UInt16,System.Boolean)"> <inheritdoc cref="M:System.BitConverter.GetBytes(System.UInt16)"/> </member> - <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.ToBoolean(System.Span{System.Byte},System.Boolean)"> + <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToBoolean(System.Span{System.Byte},System.Boolean)"> <inheritdoc cref="M:System.BitConverter.ToBoolean(System.ReadOnlySpan{System.Byte})"/> </member> - <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.ToChar(System.Span{System.Byte},System.Boolean)"> + <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToChar(System.Span{System.Byte},System.Boolean)"> <inheritdoc cref="M:System.BitConverter.ToChar(System.ReadOnlySpan{System.Byte})"/> </member> - <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.ToDouble(System.Span{System.Byte},System.Boolean)"> + <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToDouble(System.Span{System.Byte},System.Boolean)"> <inheritdoc cref="M:System.BitConverter.ToDouble(System.ReadOnlySpan{System.Byte})"/> </member> - <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.ToInt16(System.Span{System.Byte},System.Boolean)"> + <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToInt16(System.Span{System.Byte},System.Boolean)"> <inheritdoc cref="M:System.BitConverter.ToInt16(System.ReadOnlySpan{System.Byte})"/> </member> - <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.ToInt32(System.Span{System.Byte},System.Boolean)"> + <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToInt32(System.Span{System.Byte},System.Boolean)"> <inheritdoc cref="M:System.BitConverter.ToInt32(System.ReadOnlySpan{System.Byte})"/> </member> - <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.ToInt64(System.Span{System.Byte},System.Boolean)"> + <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToInt64(System.Span{System.Byte},System.Boolean)"> <inheritdoc cref="M:System.BitConverter.ToInt64(System.ReadOnlySpan{System.Byte})"/> </member> - <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.ToSingle(System.Span{System.Byte},System.Boolean)"> + <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToSingle(System.Span{System.Byte},System.Boolean)"> <inheritdoc cref="M:System.BitConverter.ToSingle(System.ReadOnlySpan{System.Byte})"/> </member> - <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.ToUInt16(System.Byte[],System.Boolean)"> + <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToUInt16(System.Byte[],System.Boolean)"> <inheritdoc cref="M:System.BitConverter.ToUInt16(System.ReadOnlySpan{System.Byte})"/> </member> - <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.ToUInt32(System.Span{System.Byte},System.Boolean)"> + <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToUInt32(System.Span{System.Byte},System.Boolean)"> <inheritdoc cref="M:System.BitConverter.ToUInt32(System.ReadOnlySpan{System.Byte})"/> </member> - <member name="M:NetSharp.Deprecated.Conversion.EndianAwareBitConverter.ToUInt64(System.Span{System.Byte},System.Boolean)"> + <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToUInt64(System.Span{System.Byte},System.Boolean)"> <inheritdoc cref="M:System.BitConverter.ToUInt64(System.ReadOnlySpan{System.Byte})"/> </member> <member name="T:NetSharp.Utils.TransmissionResult"> diff --git a/NetSharp/NetSharp/Sockets/Datagram/DatagramSocketClient.cs b/NetSharp/NetSharp/Sockets/Datagram/DatagramSocketClient.cs @@ -1,9 +1,10 @@ -using System; +using NetSharp.Utils; + +using System; using System.Net; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; -using NetSharp.Utils; namespace NetSharp.Sockets.Datagram { @@ -89,8 +90,8 @@ namespace NetSharp.Sockets.Datagram break; case SocketAsyncOperation.SendTo: - AsyncTransmissionToken sendToken = (AsyncTransmissionToken) args.UserToken; - + AsyncTransmissionToken sendToken = (AsyncTransmissionToken)args.UserToken; + if (sendToken.CancellationToken.IsCancellationRequested) { sendToken.CompletionSource.SetCanceled(); @@ -167,7 +168,7 @@ namespace NetSharp.Sockets.Datagram if (connection.SendToAsync(args)) return new ValueTask<TransmissionResult>(tcs.Task); TransmissionResult result = new TransmissionResult(in args); - + TransmissionArgsPool.Return(args); return new ValueTask<TransmissionResult>(result); diff --git a/NetSharp/NetSharp/Sockets/Datagram/DatagramSocketServer.cs b/NetSharp/NetSharp/Sockets/Datagram/DatagramSocketServer.cs @@ -3,7 +3,6 @@ using System; using System.Net; using System.Net.Sockets; -using System.Text; using System.Threading; using System.Threading.Tasks; @@ -168,7 +167,7 @@ namespace NetSharp.Sockets.Datagram private void CompleteSendTo(SocketAsyncEventArgs sendArgs) { - SocketOperationToken sendToken = (SocketOperationToken) sendArgs.UserToken; + SocketOperationToken sendToken = (SocketOperationToken)sendArgs.UserToken; TransmissionResult sendResult = new TransmissionResult(in sendArgs); @@ -195,7 +194,7 @@ namespace NetSharp.Sockets.Datagram ReceiveFrom(newReceiveArgs); } - return cancellationToken.WaitHandle.WaitOneAsync(); + return cancellationToken.WaitHandle.WaitOneAsync(CancellationToken.None); } } } \ No newline at end of file diff --git a/NetSharp/NetSharp/Sockets/SocketAsyncOperationTokens.cs b/NetSharp/NetSharp/Sockets/SocketAsyncOperationTokens.cs @@ -1,91 +0,0 @@ -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 @@ -1,307 +0,0 @@ -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(in 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(in 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(in 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(in 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(in 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(in 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(in 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(in 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,8 +1,9 @@ -using System.Net; +using NetSharp.Utils; + +using System.Net; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; -using NetSharp.Utils; namespace NetSharp.Sockets { @@ -39,6 +40,21 @@ namespace NetSharp.Sockets } } + //TODO document + protected readonly struct AsyncCancellationToken + { + public readonly Socket Socket; + + public readonly SocketAsyncEventArgs TransmissionArgs; + + public AsyncCancellationToken(in Socket socket, in SocketAsyncEventArgs args) + { + Socket = socket; + + TransmissionArgs = args; + } + } + protected SocketClient(in AddressFamily connectionAddressFamily, in SocketType connectionSocketType, in ProtocolType connectionProtocolType) : base(in connectionAddressFamily, in connectionSocketType, in connectionProtocolType) { @@ -58,6 +74,13 @@ namespace NetSharp.Sockets args.RemoteEndPoint = remoteEndPoint; args.UserToken = new AsyncOperationToken(in tcs, in cancellationToken); + cancellationToken.Register(token => + { + AsyncCancellationToken cancellationArgs = (AsyncCancellationToken)token; + + Socket.CancelConnectAsync(cancellationArgs.TransmissionArgs); + }, new AsyncCancellationToken(in connection, in args)); + if (connection.ConnectAsync(args)) return new ValueTask(tcs.Task); TransmissionArgsPool.Return(args); diff --git a/NetSharp/NetSharp/Sockets/SocketConnection.cs b/NetSharp/NetSharp/Sockets/SocketConnection.cs @@ -1,9 +1,10 @@ -using System; +using NetSharp.Packets; +using NetSharp.Utils; + +using System; using System.Buffers; using System.Net; using System.Net.Sockets; -using NetSharp.Packets; -using NetSharp.Utils; namespace NetSharp.Sockets { diff --git a/NetSharp/NetSharp/Sockets/Stream/StreamSocketClient.cs b/NetSharp/NetSharp/Sockets/Stream/StreamSocketClient.cs @@ -1,9 +1,9 @@ -using System; -using System.Net; +using NetSharp.Utils; + +using System; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; -using NetSharp.Utils; namespace NetSharp.Sockets.Stream { @@ -47,10 +47,12 @@ namespace NetSharp.Sockets.Stream switch (args.LastOperation) { case SocketAsyncOperation.Connect: - AsyncOperationToken connectToken = (AsyncOperationToken) args.UserToken; + AsyncOperationToken connectToken = (AsyncOperationToken)args.UserToken; if (connectToken.CancellationToken.IsCancellationRequested) { + connection.Disconnect(true); + connectToken.CompletionSource.SetCanceled(); } else if (args.SocketError == SocketError.Success) @@ -67,7 +69,7 @@ namespace NetSharp.Sockets.Stream break; case SocketAsyncOperation.Disconnect: - AsyncOperationToken disconnectToken = (AsyncOperationToken) args.UserToken; + AsyncOperationToken disconnectToken = (AsyncOperationToken)args.UserToken; if (disconnectToken.CancellationToken.IsCancellationRequested) { @@ -87,7 +89,7 @@ namespace NetSharp.Sockets.Stream break; case SocketAsyncOperation.Receive: - AsyncTransmissionToken receiveToken = (AsyncTransmissionToken) args.UserToken; + AsyncTransmissionToken receiveToken = (AsyncTransmissionToken)args.UserToken; if (receiveToken.CancellationToken.IsCancellationRequested) { @@ -139,7 +141,7 @@ namespace NetSharp.Sockets.Stream break; case SocketAsyncOperation.Send: - AsyncTransmissionToken sendToken = (AsyncTransmissionToken) args.UserToken; + AsyncTransmissionToken sendToken = (AsyncTransmissionToken)args.UserToken; if (sendToken.CancellationToken.IsCancellationRequested) { diff --git a/NetSharp/NetSharp/Sockets/Stream/StreamSocketServer.cs b/NetSharp/NetSharp/Sockets/Stream/StreamSocketServer.cs @@ -1,13 +1,10 @@ -using System; -using System.Collections.Concurrent; -using System.Net; +using NetSharp.Packets; +using NetSharp.Utils; + +using System; 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 { @@ -48,6 +45,8 @@ namespace NetSharp.Sockets.Stream public void Dispose() { + ClientSocket.Shutdown(SocketShutdown.Both); + ClientSocket.Close(); ClientSocket.Dispose(); } } @@ -72,7 +71,6 @@ namespace NetSharp.Sockets.Stream protected override void ResetTransmissionArgs(SocketAsyncEventArgs args) { - } protected override bool CanTransmissionArgsBeReused(in SocketAsyncEventArgs args) @@ -82,10 +80,7 @@ namespace NetSharp.Sockets.Stream protected override void DestroyTransmissionArgs(SocketAsyncEventArgs remoteConnectionArgs) { - remoteConnectionArgs.AcceptSocket.Shutdown(SocketShutdown.Both); - remoteConnectionArgs.AcceptSocket.Close(); - - remoteConnectionArgs.Completed -= SocketAsyncOperations.HandleIoCompleted; + remoteConnectionArgs.Completed -= HandleIoCompleted; remoteConnectionArgs.Dispose(); } @@ -132,7 +127,7 @@ namespace NetSharp.Sockets.Stream private void CompleteAccept(SocketAsyncEventArgs connectedClientArgs) { Socket clientSocket = connectedClientArgs.AcceptSocket; - + RemoteStreamClientToken clientToken = new RemoteStreamClientToken(in clientSocket); connectedClientArgs.UserToken = clientToken; @@ -142,7 +137,7 @@ namespace NetSharp.Sockets.Stream private void Receive(SocketAsyncEventArgs clientArgs) { - RemoteStreamClientToken clientToken = (RemoteStreamClientToken) clientArgs.UserToken; + RemoteStreamClientToken clientToken = (RemoteStreamClientToken)clientArgs.UserToken; byte[] requestBuffer = BufferPool.Rent(ServerOptions.PacketSize); Memory<byte> requestBufferMemory = new Memory<byte>(requestBuffer); @@ -160,7 +155,7 @@ namespace NetSharp.Sockets.Stream private void CompleteReceive(SocketAsyncEventArgs clientArgs) { - RemoteStreamClientToken receiveToken = (RemoteStreamClientToken) clientArgs.UserToken; + RemoteStreamClientToken receiveToken = (RemoteStreamClientToken)clientArgs.UserToken; if (clientArgs.SocketError == SocketError.Success) { @@ -184,7 +179,6 @@ namespace NetSharp.Sockets.Stream clientArgs.SetBuffer(responseBuffer, 0, ServerOptions.PacketSize); Send(clientArgs); - } else if (ServerOptions.PacketSize > clientArgs.BytesTransferred && clientArgs.BytesTransferred > 0) { @@ -211,7 +205,7 @@ namespace NetSharp.Sockets.Stream private void Send(SocketAsyncEventArgs clientArgs) { - RemoteStreamClientToken clientToken = (RemoteStreamClientToken) clientArgs.UserToken; + RemoteStreamClientToken clientToken = (RemoteStreamClientToken)clientArgs.UserToken; bool operationPending = clientToken.ClientSocket.SendAsync(clientArgs); @@ -223,7 +217,7 @@ namespace NetSharp.Sockets.Stream private void CompleteSend(SocketAsyncEventArgs clientArgs) { - RemoteStreamClientToken sendToken = (RemoteStreamClientToken) clientArgs.UserToken; + RemoteStreamClientToken sendToken = (RemoteStreamClientToken)clientArgs.UserToken; if (clientArgs.SocketError == SocketError.Success) { @@ -262,22 +256,10 @@ namespace NetSharp.Sockets.Stream private void CloseClientSocket(SocketAsyncEventArgs clientArgs) { - RemoteStreamClientToken clientToken = (RemoteStreamClientToken) clientArgs.UserToken; - - try - { - clientToken.ClientSocket.Shutdown(SocketShutdown.Both); - } - catch (SocketException ex) - { - Console.WriteLine(ex); - } - - clientToken.ClientSocket.Close(); + RemoteStreamClientToken clientToken = (RemoteStreamClientToken)clientArgs.UserToken; + clientToken.Dispose(); TransmissionArgsPool.Return(clientArgs); - - clientToken.Dispose(); } public override async Task RunAsync(CancellationToken cancellationToken = default) @@ -287,11 +269,11 @@ namespace NetSharp.Sockets.Stream for (int i = 0; i < ServerOptions.ConcurrentAcceptCalls; i++) { SocketAsyncEventArgs acceptArgs = TransmissionArgsPool.Rent(); - + Accept(acceptArgs); } - await cancellationToken.WaitHandle.WaitOneAsync(); + await cancellationToken.WaitHandle.WaitOneAsync(CancellationToken.None); } } } \ 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.Deprecated +namespace NetSharp.Utils { /// <summary> /// Represents a concurrent two-way dictionary, that can be indexed by either a key or a value. 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.Deprecated.Conversion +namespace NetSharp.Utils.Conversion { /// <summary> /// Wraps the <see cref="BitConverter"/> class to provide conversion that is endian-aware. diff --git a/NetSharp/NetSharp/Utils/SlimObjectPool.cs b/NetSharp/NetSharp/Utils/SlimObjectPool.cs @@ -2,6 +2,7 @@ namespace NetSharp.Utils { + //TODO document public class SlimObjectPool<T> where T : class { public delegate T CreateObjectDelegate(); @@ -19,7 +20,8 @@ namespace NetSharp.Utils private readonly ConcurrentQueue<T> objectBuffer; - public SlimObjectPool(in CreateObjectDelegate createDelegate, in ResetObjectDelegate resetDelegate, in DestroyObjectDelegate destroyDelegate, in CanRebufferObjectPredicate rebufferPredicate) + public SlimObjectPool(in CreateObjectDelegate createDelegate, in ResetObjectDelegate resetDelegate, + in DestroyObjectDelegate destroyDelegate, in CanRebufferObjectPredicate rebufferPredicate) { createObjectDelegate = createDelegate; diff --git a/NetSharp/NetSharpExamples/Program.cs b/NetSharp/NetSharpExamples/Program.cs @@ -1,8 +1,9 @@ #define TCP -#undef TCP +//#undef TCP using NetSharp.Sockets.Datagram; using NetSharp.Sockets.Stream; +using NetSharp.Utils; using System; using System.Collections.Generic; @@ -11,9 +12,8 @@ using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; -using System.Threading; using System.Threading.Tasks; -using NetSharp.Utils; + using NetworkPacket = NetSharp.Packets.NetworkPacket; using SocketServer = NetSharp.Sockets.SocketServer; @@ -30,6 +30,7 @@ namespace NetSharpExamples { Console.WriteLine("Hello World!"); + Console.WriteLine("Starting socket server test..."); Task serverTest = TestSocketServer(); @@ -44,7 +45,7 @@ namespace NetSharpExamples private static async Task TestSocketClient() { - const int clientCount = 16; + const int clientCount = 4; const long packetsToSend = 100_000; Task[] clientTasks = new Task[clientCount]; @@ -185,7 +186,7 @@ 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"); @@ -244,6 +245,6 @@ namespace NetSharpExamples } } -#endregion Socket Tests + #endregion Socket Tests } } \ No newline at end of file