aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Net.Transport.SimpleTCP/README.md66
-rw-r--r--lib/Net.Transport.SimpleTCP/src/ISockAsyncArgsHandler.cs41
-rw-r--r--lib/Net.Transport.SimpleTCP/src/SocketPipeLineWorker.cs34
-rw-r--r--lib/Net.Transport.SimpleTCP/src/TCPConfig.cs9
-rw-r--r--lib/Net.Transport.SimpleTCP/src/TcpServer.cs81
-rw-r--r--lib/Net.Transport.SimpleTCP/src/TcpServerExtensions.cs104
-rw-r--r--lib/Net.Transport.SimpleTCP/src/TransportEventContext.cs41
-rw-r--r--lib/Net.Transport.SimpleTCP/src/VnSocketAsyncArgs.cs35
8 files changed, 242 insertions, 169 deletions
diff --git a/lib/Net.Transport.SimpleTCP/README.md b/lib/Net.Transport.SimpleTCP/README.md
index 3ced963..0012499 100644
--- a/lib/Net.Transport.SimpleTCP/README.md
+++ b/lib/Net.Transport.SimpleTCP/README.md
@@ -1,64 +1,14 @@
# VNLib.Net.Transport.SimpleTCP
-_A managed .NET simple, high performance - single process, low/no allocation, fully asynchronous, tcp socket server._
+*A managed .NET simple, high performance - single process, low/no allocation, fully asynchronous, TCP socket server.*
-This library was created for use with the VNLib.Net.Http library and subsequent stacked framework libraries, however it was designed to be useful as a standalone high-performance .NET tcp listener. This library relies on the managed .NET [System.IO.Pipelines](https://github.com/dotnet/docs/blob/main/docs/standard/io/pipelines.md) library, and the **VNLib.Utils** library.
+This library was created for use with the VNLib.Net.Http library and subsequent stacked framework libraries, however it was designed to be useful as a standalone high-performance .NET TCP listener. This library relies on the managed .NET [System.IO.Pipelines](https://github.com/dotnet/docs/blob/main/docs/standard/io/pipelines.md) library, and the [VNLib.Utils](../Utils) library.
-### Builds
-Debug build w/ symbols & xml docs, release builds, NuGet packages, and individually packaged source code are available on my [website](https://www.vaughnnugent.com/resources/software). All tar-gzip (.tgz) files will have an associated .sha384 appended checksum of the desired download file.
+## Docs
+Documentation, including overview/architecture and usage is available [here](https://www.vaughnnugent.com/resources/software/articles?tags=docs,_VNLib.Net.Transport.SimpleTCP).
-#### SSL Support
-The TcpServer manages ssl/tls using the SslStream class to make tls as transparent to the application as possible. The server manages authentication and negotiation based on the configured `SslServerAuthenticationOptions`
+## Builds
+Debug build w/ symbols & xml docs, release builds, NuGet packages, and individually packaged source code are available on my [website](https://www.vaughnnugent.com/resources/software/modules/VNLib.Core). All tar-gzip (.tgz) files will have an associated .sha384 appended checksum of the desired download file.
-## Usage
-
-```programming language C#
- //Init config
- TCPConfig config = new()
- {
- //... configure
- }
-
- //Create the new server
- TcpServer server = new(config);
-
- //Open the socket and begin listening for connections until the token is cancelled
- server.Start(<cancellationToken>);
-
- //Listen for connections
- while(true)
- {
- TransportEventContext ctx = await server.AcceptAsync(<cancellationToken>);
-
- try
- {
- //...Do stuff with context, such as read data from stream
- byte[] buffer = new byte [1024];
- int count = await ctx.ConnectionStream.ReadAsync(buffer)
- }
- finally
- {
- await ctx.CloseConnectionAsync();
- }
- }
-```
-
-
-### Tuning information
-
-##### Internal buffers
-Internal buffers are allocated for reading and writing to the internal socket. Receive buffers sizes are set to the `Socket.ReceiveBufferSize`,
-so if you wish to reduce socket memory consumption, you may use the `TCPConfig.OnSocketCreated` callback method to configure your socket accordingly.
-
-##### Threading
-This library uses the SocketAsyncEventArgs WinSock socket programming paradigm, so the `TCPConfig.AcceptThreads` configuration property is the number of outstanding SocketAsyncEvents that will be pending. This value should be tuned to your use case, lower numbers relative to processor count may yield less accepts/second, higher numbers may see no increase or even reduced performance.
-
-##### Internal object cache
-TcpServer maintains a complete object cache (VNLib.Utils.Memory.Caching.ObjectCache) which may grow quite large for your application depending on load, tuning the cache quota config property may be useful for your application. Lower numbers will increase GC load, higher values (or disabled) will likely yield a larger working set. Because of this the TcpServer class implements the ICacheHolder interface. **Note:** because TcpServer caches store disposable objects, the `CacheClear()` method does nothing. To programatically clear these caches, call the `CacheHardClear()` method.
-
-##### Memory pools
-Since this library implements the System.IO.Pipelines, it uses the `MemoryPool<byte>` memory manager interface, you may consider using the VNLib.Utils `IUnmanagedHeap.ToPool<T>()` extension method to convert your `IUnmanagedHeap` to a `MemoryPool<byte>`
-
-## Lisence
-The software in this repository is licensed under the GNU Affero General Public License (or any later version).
-See the LICENSE files for more information. \ No newline at end of file
+## License
+The software in this repository is licensed under the GNU Affero General Public License (or any later version). See the LICENSE files for more information. \ No newline at end of file
diff --git a/lib/Net.Transport.SimpleTCP/src/ISockAsyncArgsHandler.cs b/lib/Net.Transport.SimpleTCP/src/ISockAsyncArgsHandler.cs
new file mode 100644
index 0000000..76fb0ae
--- /dev/null
+++ b/lib/Net.Transport.SimpleTCP/src/ISockAsyncArgsHandler.cs
@@ -0,0 +1,41 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Net.Transport.SimpleTCP
+* File: ISockAsyncArgsHandler.cs
+*
+* ISockAsyncArgsHandler.cs is part of VNLib.Net.Transport.SimpleTCP which
+* is part of the larger VNLib collection of libraries and utilities.
+*
+* VNLib.Net.Transport.SimpleTCP is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License as
+* published by the Free Software Foundation, either version 2 of the
+* License, or (at your option) any later version.
+*
+* VNLib.Net.Transport.SimpleTCP is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+
+namespace VNLib.Net.Transport.Tcp
+{
+ internal interface ISockAsyncArgsHandler
+ {
+ /// <summary>
+ /// Called when an asynchronous accept operation has completed
+ /// </summary>
+ /// <param name="args">The arguments that completed the accept operation</param>
+ void OnSocketAccepted(VnSocketAsyncArgs args);
+
+ /// <summary>
+ /// Called when an asynchronous disconnect operation has completed
+ /// </summary>
+ /// <param name="args">The args that are disconnecting</param>
+ void OnSocketDisconnected(VnSocketAsyncArgs args);
+ }
+}
diff --git a/lib/Net.Transport.SimpleTCP/src/SocketPipeLineWorker.cs b/lib/Net.Transport.SimpleTCP/src/SocketPipeLineWorker.cs
index e08ee76..dda859c 100644
--- a/lib/Net.Transport.SimpleTCP/src/SocketPipeLineWorker.cs
+++ b/lib/Net.Transport.SimpleTCP/src/SocketPipeLineWorker.cs
@@ -56,8 +56,7 @@ namespace VNLib.Net.Transport.Tcp
* may be safely reset for reuse
*/
if (_recvTask != null)
- {
- //Since the
+ {
SendPipe.Reset();
RecvPipe.Reset();
}
@@ -100,8 +99,10 @@ namespace VNLib.Net.Transport.Tcp
private readonly Timer SendTimer;
private readonly Stream RecvStream;
+ ///<inheritdoc/>
public int SendTimeoutMs { get; set; }
+ ///<inheritdoc/>
public int RecvTimeoutMs { get; set; }
@@ -180,6 +181,8 @@ namespace VNLib.Net.Transport.Tcp
* the pipes and the socket
*/
+ private ReadResult _sendReadRes;
+
private async Task SendDoWorkAsync(Socket sock)
{
Exception? cause = null;
@@ -189,18 +192,21 @@ namespace VNLib.Net.Transport.Tcp
while (true)
{
//wait for data from the write pipe and write it to the socket
- ReadResult result = await SendPipe.Reader.ReadAsync(CancellationToken.None);
+ _sendReadRes = await SendPipe.Reader.ReadAsync(CancellationToken.None);
//Catch error/cancel conditions and break the loop
- if (result.IsCanceled || !sock.Connected || result.Buffer.IsEmpty)
+ if (_sendReadRes.IsCanceled || !sock.Connected || _sendReadRes.Buffer.IsEmpty)
{
break;
}
- //get sequence
- ReadOnlySequence<byte> buffer = result.Buffer;
+
+ /*
+ * Even if the pipe was completed, and if the buffer is not empty, then
+ * there is still data to be written to the socket, so we must continue
+ */
//Get enumerator to write memory segments
- ReadOnlySequence<byte>.Enumerator enumerator = buffer.GetEnumerator();
+ ReadOnlySequence<byte>.Enumerator enumerator = _sendReadRes.Buffer.GetEnumerator();
//Begin enumerator
while (enumerator.MoveNext())
@@ -233,10 +239,10 @@ namespace VNLib.Net.Transport.Tcp
}
//Advance pipe
- SendPipe.Reader.AdvanceTo(buffer.End);
+ SendPipe.Reader.AdvanceTo(_sendReadRes.Buffer.End);
//Pipe has been completed and all data was written
- if (result.IsCompleted)
+ if (_sendReadRes.IsCompleted)
{
break;
}
@@ -248,6 +254,8 @@ namespace VNLib.Net.Transport.Tcp
}
finally
{
+ _sendReadRes = default;
+
//Complete the send pipe writer
await SendPipe.Reader.CompleteAsync(cause);
@@ -256,6 +264,8 @@ namespace VNLib.Net.Transport.Tcp
}
}
+ private FlushResult _recvFlushRes;
+
private async Task RecvDoWorkAsync(Socket sock, bool initialData)
{
//init new cts
@@ -299,10 +309,10 @@ namespace VNLib.Net.Transport.Tcp
RecvPipe.Writer.Advance(count);
//Publish read data
- FlushResult res = await RecvPipe.Writer.FlushAsync(CancellationToken.None);
+ _recvFlushRes = await RecvPipe.Writer.FlushAsync(CancellationToken.None);
//Writing has completed, time to exit
- if (res.IsCompleted || res.IsCanceled)
+ if (_recvFlushRes.IsCompleted || _recvFlushRes.IsCanceled)
{
break;
}
@@ -323,6 +333,8 @@ namespace VNLib.Net.Transport.Tcp
}
finally
{
+ _recvFlushRes = default;
+
//Stop timer incase exception
RecvTimer.Stop();
diff --git a/lib/Net.Transport.SimpleTCP/src/TCPConfig.cs b/lib/Net.Transport.SimpleTCP/src/TCPConfig.cs
index 6955e63..a6a416c 100644
--- a/lib/Net.Transport.SimpleTCP/src/TCPConfig.cs
+++ b/lib/Net.Transport.SimpleTCP/src/TCPConfig.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022 Vaughn Nugent
+* Copyright (c) 2023 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Net.Transport.SimpleTCP
@@ -26,7 +26,6 @@ using System;
using System.Net;
using System.Buffers;
using System.Net.Sockets;
-using System.Net.Security;
using VNLib.Utils.Logging;
@@ -35,7 +34,7 @@ namespace VNLib.Net.Transport.Tcp
/// <summary>
/// Represents the required configuration variables for the transport
/// </summary>
- public readonly struct TCPConfig
+ public readonly record struct TCPConfig
{
/// <summary>
/// The <see cref="IPEndPoint"/> the listening socket will bind to
@@ -58,10 +57,6 @@ namespace VNLib.Net.Transport.Tcp
/// </summary>
public readonly bool TcpKeepalive { get; init; }
/// <summary>
- /// The authentication options to use for processing TLS connections. This value must be set when a certificate has been specified
- /// </summary>
- public readonly SslServerAuthenticationOptions? AuthenticationOptions { get; init; }
- /// <summary>
/// The maximum number of waiting WSA asynchronous socket accept operations
/// </summary>
public readonly uint AcceptThreads { get; init; }
diff --git a/lib/Net.Transport.SimpleTCP/src/TcpServer.cs b/lib/Net.Transport.SimpleTCP/src/TcpServer.cs
index 0782158..6deeb56 100644
--- a/lib/Net.Transport.SimpleTCP/src/TcpServer.cs
+++ b/lib/Net.Transport.SimpleTCP/src/TcpServer.cs
@@ -26,10 +26,8 @@ using System;
using System.Security;
using System.Threading;
using System.Net.Sockets;
-using System.Net.Security;
using System.IO.Pipelines;
using System.Threading.Tasks;
-using System.Security.Authentication;
using System.Runtime.CompilerServices;
using VNLib.Utils.Async;
@@ -48,7 +46,7 @@ namespace VNLib.Net.Transport.Tcp
/// connections is expected. This class cannot be inherited
/// </para>
/// </summary>
- public sealed class TcpServer : ICacheHolder
+ public sealed class TcpServer : ICacheHolder, ISockAsyncArgsHandler
{
/// <summary>
/// The current <see cref="TcpServer"/> configuration
@@ -57,7 +55,6 @@ namespace VNLib.Net.Transport.Tcp
private readonly ObjectRental<VnSocketAsyncArgs> SockAsyncArgPool;
private readonly PipeOptions PipeOptions;
- private readonly bool _usingTls;
/// <summary>
/// Initializes a new <see cref="TcpServer"/> with the specified <see cref="TCPConfig"/>
@@ -94,14 +91,13 @@ namespace VNLib.Net.Transport.Tcp
minimumSegmentSize: 8192,
useSynchronizationContext:false
);
- //store tls value
- _usingTls = Config.AuthenticationOptions != null;
SockAsyncArgPool = ObjectRental.CreateReusable(ArgsConstructor, Config.CacheQuota);
}
///<inheritdoc/>
public void CacheClear() => SockAsyncArgPool.CacheClear();
+
///<inheritdoc/>
public void CacheHardClear() => SockAsyncArgPool.CacheHardClear();
@@ -151,7 +147,7 @@ namespace VNLib.Net.Transport.Tcp
Config.OnSocketCreated?.Invoke(ServerSock);
//Init waiting socket queue
- WaitingSockets = new(false, true);
+ WaitingSockets = new(false, false);
//Clear canceled flag
_canceledFlag = false;
@@ -186,11 +182,23 @@ namespace VNLib.Net.Transport.Tcp
//Register cleanup
_ = token.Register(cleanup, this, false);
}
+
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private VnSocketAsyncArgs ArgsConstructor()
+ {
+ //Socket args accept callback functions for this
+ VnSocketAsyncArgs args = new(this, PipeOptions);
+ return args;
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void ReturnCb(VnSocketAsyncArgs args)
+ void ISockAsyncArgsHandler.OnSocketAccepted(VnSocketAsyncArgs args) => AcceptCompleted(args);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ void ISockAsyncArgsHandler.OnSocketDisconnected(VnSocketAsyncArgs args)
{
- //If the server has exited, dispose the args and dont return to pool
+ //If the is closed, dispose the args and exit
if (_canceledFlag)
{
args.Dispose();
@@ -202,14 +210,6 @@ namespace VNLib.Net.Transport.Tcp
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private VnSocketAsyncArgs ArgsConstructor()
- {
- //Socket args accept callback functions for this
- VnSocketAsyncArgs args = new(AcceptCompleted, ReturnCb, PipeOptions);
- return args;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void AcceptConnection()
{
//Make sure cancellation isnt pending
@@ -249,42 +249,45 @@ namespace VNLib.Net.Transport.Tcp
//Accept a new connection
AcceptConnection();
}
-
/// <summary>
/// Retreives a connected socket from the waiting queue
/// </summary>
/// <returns>The context of the connect</returns>
/// <exception cref="InvalidOperationException"></exception>
- public async ValueTask<TransportEventContext> AcceptAsync(CancellationToken cancellation)
+ public ValueTask<TransportEventContext> AcceptAsync(CancellationToken cancellation)
{
_ = WaitingSockets ?? throw new InvalidOperationException("Server is not listening");
- //Args is ready to use
- VnSocketAsyncArgs args = await WaitingSockets.DequeueAsync(cancellation);
- //See if tls is enabled, if so, start tls handshake
- if (_usingTls)
+
+ //Try get args from queue
+ if(WaitingSockets.TryDequeue(out VnSocketAsyncArgs? args))
{
- //Begin authenication and make sure the socket stream is closed as its required to cleanup
- SslStream stream = new(args.Stream, false);
- try
- {
- //auth the new connection
- await stream.AuthenticateAsServerAsync(Config.AuthenticationOptions!, cancellation);
- return new(args, stream);
- }
- catch(Exception ex)
- {
- await stream.DisposeAsync();
+ return ValueTask.FromResult<TransportEventContext>(new(args, args.Stream));
+ }
- //Disconnect socket
- args.Disconnect();
+ return AcceptAsyncCore(cancellation);
+ }
- throw new AuthenticationException("Failed client/server TLS authentication", ex);
- }
+ private async ValueTask<TransportEventContext> AcceptAsyncCore(CancellationToken cancellation)
+ {
+ //Await async
+ VnSocketAsyncArgs args = await WaitingSockets.DequeueAsync(cancellation);
+
+ return new(args, args.Stream);
+ }
+
+ internal ValueTask<VnSocketAsyncArgs> AcceptArgsAsync(CancellationToken cancellation)
+ {
+ _ = WaitingSockets ?? throw new InvalidOperationException("Server is not listening");
+
+ //Try get args from queue
+ if (WaitingSockets.TryDequeue(out VnSocketAsyncArgs? args))
+ {
+ return ValueTask.FromResult(args);
}
else
{
- return new(args, args.Stream);
+ return WaitingSockets.DequeueAsync(cancellation);
}
}
}
diff --git a/lib/Net.Transport.SimpleTCP/src/TcpServerExtensions.cs b/lib/Net.Transport.SimpleTCP/src/TcpServerExtensions.cs
new file mode 100644
index 0000000..a6a4327
--- /dev/null
+++ b/lib/Net.Transport.SimpleTCP/src/TcpServerExtensions.cs
@@ -0,0 +1,104 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Net.Transport.SimpleTCP
+* File: TcpServerExtensions.cs
+*
+* TcpServerExtensions.cs is part of VNLib.Net.Transport.SimpleTCP which is
+* part of the larger VNLib collection of libraries and utilities.
+*
+* VNLib.Net.Transport.SimpleTCP is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License as
+* published by the Free Software Foundation, either version 2 of the
+* License, or (at your option) any later version.
+*
+* VNLib.Net.Transport.SimpleTCP is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+
+using System;
+using System.Threading;
+using System.Net.Security;
+using System.Threading.Tasks;
+using System.Security.Authentication;
+using System.Runtime.CompilerServices;
+
+namespace VNLib.Net.Transport.Tcp
+{
+ /// <summary>
+ /// Exposes extension methods for <see cref="TcpServer"/>
+ /// </summary>
+ public static class TcpServerExtensions
+ {
+
+ /// <summary>
+ /// Accepts a new ssl connection and attemts to authenticate it as a server
+ /// </summary>
+ /// <param name="server"></param>
+ /// <param name="options">The ssl server authentication options used to initalize the connection</param>
+ /// <param name="cancellation">A token to cancel the async accept operation</param>
+ /// <returns>A <see cref="ValueTask"/> that resolve the <see cref="TransportEventContext"/> around the connection</returns>
+ /// <exception cref="AuthenticationException"></exception>
+ public static async Task<TransportEventContext> AcceptSslAsync(this TcpServer server, SslServerAuthenticationOptions options, CancellationToken cancellation = default)
+ {
+ //accept internal args
+ VnSocketAsyncArgs args = await server.AcceptArgsAsync(cancellation);
+
+ //Begin authenication and make sure the socket stream is closed as its required to cleanup
+ SslStream stream = new(args.Stream, false);
+ try
+ {
+ //auth the new connection
+ await stream.AuthenticateAsServerAsync(options, cancellation);
+ return new(args, stream);
+ }
+ catch (Exception ex)
+ {
+ //Cleanup the socket when auth fails
+ await stream.DisposeAsync();
+
+ //Disconnect socket
+ args.Disconnect();
+
+ throw new AuthenticationException("Failed client/server TLS authentication", ex);
+ }
+ }
+
+ /// <summary>
+ /// Safley closes an ssl connection
+ /// </summary>
+ /// <param name="ctx">The context to close the connection on</param>
+ /// <returns>A value task that completes when the connection is closed</returns>
+ public static async ValueTask CloseSslConnectionAsync(this TransportEventContext ctx)
+ {
+ try
+ {
+ //Close the ssl stream
+ await (ctx.ConnectionStream as SslStream)!.ShutdownAsync();
+ }
+ finally
+ {
+ //Always close the connection
+ await ctx.CloseConnectionAsync();
+ }
+ }
+
+ /// <summary>
+ /// Gets the SslProtocol for an ssl connection
+ /// </summary>
+ /// <param name="ctx">The <see cref="TransportEventContext"/> that contains the ssl connection stream</param>
+ /// <returns>The current <see cref="SslProtocols"/> of the connection</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static SslProtocols GetSslProtocol(this in TransportEventContext ctx)
+ {
+ return (ctx.ConnectionStream as SslStream)!.SslProtocol;
+ }
+
+ }
+} \ No newline at end of file
diff --git a/lib/Net.Transport.SimpleTCP/src/TransportEventContext.cs b/lib/Net.Transport.SimpleTCP/src/TransportEventContext.cs
index fc04d0c..994b2ba 100644
--- a/lib/Net.Transport.SimpleTCP/src/TransportEventContext.cs
+++ b/lib/Net.Transport.SimpleTCP/src/TransportEventContext.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022 Vaughn Nugent
+* Copyright (c) 2023 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Net.Transport.SimpleTCP
@@ -38,20 +38,16 @@ namespace VNLib.Net.Transport.Tcp
/// Represents the context of a transport connection. It includes the active socket
/// and a stream representing the active transport.
/// </summary>
- public readonly struct TransportEventContext
+ public readonly record struct TransportEventContext
{
/// <summary>
/// The socket referrence to the incoming connection
/// </summary>
private readonly Socket Socket;
- internal readonly VnSocketAsyncArgs _socketArgs;
+ private readonly VnSocketAsyncArgs _socketArgs;
/// <summary>
- /// The transport security layer security protocol
- /// </summary>
- public readonly SslProtocols SslVersion { get; } = SslProtocols.None;
- /// <summary>
/// A copy of the local endpoint of the listening socket
/// </summary>
public readonly IPEndPoint LocalEndPoint
@@ -59,6 +55,7 @@ namespace VNLib.Net.Transport.Tcp
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => (Socket.LocalEndPoint as IPEndPoint)!;
}
+
/// <summary>
/// The <see cref="IPEndPoint"/> representing the client's connection information
/// </summary>
@@ -67,6 +64,7 @@ namespace VNLib.Net.Transport.Tcp
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => (Socket.RemoteEndPoint as IPEndPoint)!;
}
+
/// <summary>
/// The transport stream to be actively read
/// </summary>
@@ -76,48 +74,21 @@ namespace VNLib.Net.Transport.Tcp
internal TransportEventContext(VnSocketAsyncArgs args, Stream @stream)
{
_socketArgs = args;
- Socket = args.Socket!;
+ Socket = args.AcceptSocket!;
ConnectionStream = stream;
}
- internal TransportEventContext(VnSocketAsyncArgs args, SslStream @stream):this(args, (Stream)stream)
- {
- SslVersion = stream.SslProtocol;
- }
/// <summary>
/// Closes a connection and cleans up any resources
/// </summary>
- /// <param name="ctx"></param>
/// <returns></returns>
public async ValueTask CloseConnectionAsync()
{
- //Var to capture ssl shudown exception
- Exception? closeExp = null;
-
- //Verify ssl is being used and the socket is still 'connected'
- if (SslVersion > SslProtocols.None && _socketArgs.Socket!.Connected)
- {
- try
- {
- await (ConnectionStream as SslStream)!.ShutdownAsync();
- }
- catch (Exception ex)
- {
- closeExp = ex;
- }
- }
-
//dispose the stream and wait for buffered data to be sent
await ConnectionStream.DisposeAsync();
//Disconnect
_socketArgs.Disconnect();
-
- //if excp occured, re-throw
- if (closeExp != null)
- {
- throw closeExp;
- }
}
}
} \ No newline at end of file
diff --git a/lib/Net.Transport.SimpleTCP/src/VnSocketAsyncArgs.cs b/lib/Net.Transport.SimpleTCP/src/VnSocketAsyncArgs.cs
index 9f37762..766a866 100644
--- a/lib/Net.Transport.SimpleTCP/src/VnSocketAsyncArgs.cs
+++ b/lib/Net.Transport.SimpleTCP/src/VnSocketAsyncArgs.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022 Vaughn Nugent
+* Copyright (c) 2023 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Net.Transport.SimpleTCP
@@ -29,10 +29,8 @@ using System.IO.Pipelines;
using VNLib.Utils.Memory.Caching;
-
namespace VNLib.Net.Transport.Tcp
{
- internal delegate void SocketCallback(VnSocketAsyncArgs args);
/// <summary>
/// Reusable <see cref="SocketAsyncEventArgs"/> that manages a pipeline for sending and recieving data.
@@ -40,24 +38,20 @@ namespace VNLib.Net.Transport.Tcp
/// </summary>
internal sealed class VnSocketAsyncArgs : SocketAsyncEventArgs, IReusable
{
- private readonly SocketCallback SocketAccepted;
- private readonly SocketCallback SocketDisconnected;
+ private readonly ISockAsyncArgsHandler _handler;
public readonly SocketPipeLineWorker SocketWorker;
- public Socket? Socket => AcceptSocket;
+ public Stream Stream => SocketWorker.NetworkStream;
- public VnSocketAsyncArgs(SocketCallback accepted, SocketCallback disconnected, PipeOptions options) : base()
+ public VnSocketAsyncArgs(ISockAsyncArgsHandler handler, PipeOptions options) : base()
{
SocketWorker = new(options);
- SocketAccepted = accepted;
+ _handler = handler;
//Only reuse socketes if windows
DisconnectReuseSocket = OperatingSystem.IsWindows();
- SocketDisconnected = disconnected;
}
- public Stream Stream => SocketWorker.NetworkStream;
-
/// <summary>
/// Begins an asynchronous accept operation on the current (bound) socket
/// </summary>
@@ -69,7 +63,7 @@ namespace VNLib.Net.Transport.Tcp
SocketError = SocketError.Success;
SocketFlags = SocketFlags.None;
- //Recv during accept is not supported on linux, this flag is set to false on linux
+ //Recv during accept is only supported on windows, this flag is true when on windows
if (DisconnectReuseSocket)
{
//get buffer from the pipe to write initial accept data to
@@ -93,7 +87,7 @@ namespace VNLib.Net.Transport.Tcp
//remove ref to buffer
SetBuffer(null);
//start the socket worker
- SocketWorker.Start(Socket!, BytesTransferred);
+ SocketWorker.Start(AcceptSocket!, BytesTransferred);
return true;
}
return false;
@@ -108,12 +102,12 @@ namespace VNLib.Net.Transport.Tcp
//Clear flags
SocketError = SocketError.Success;
//accept async
- if (!Socket!.DisconnectAsync(this))
+ if (!AcceptSocket!.DisconnectAsync(this))
{
//Invoke disconnected callback since op completed sync
EndDisconnect();
//Invoke disconnected callback since op completed sync
- SocketDisconnected(this);
+ _handler.OnSocketDisconnected(this);
}
}
@@ -123,7 +117,7 @@ namespace VNLib.Net.Transport.Tcp
if (SocketError != SocketError.Success)
{
//Dispose the socket before clearing the socket
- Socket?.Dispose();
+ AcceptSocket?.Dispose();
AcceptSocket = null;
}
}
@@ -134,12 +128,12 @@ namespace VNLib.Net.Transport.Tcp
{
case SocketAsyncOperation.Accept:
//Invoke the accepted callback
- SocketAccepted(this);
+ _handler.OnSocketAccepted(this);
break;
case SocketAsyncOperation.Disconnect:
EndDisconnect();
//Invoke disconnected callback since op completed sync
- SocketDisconnected(this);
+ _handler.OnSocketDisconnected(this);
break;
default:
throw new InvalidOperationException("Invalid socket operation");
@@ -158,6 +152,7 @@ namespace VNLib.Net.Transport.Tcp
{
UserToken = null;
SocketWorker.Release();
+
//if the sockeet is connected (or not windows), dispose it and clear the accept socket
if (AcceptSocket?.Connected == true || !DisconnectReuseSocket)
{
@@ -171,10 +166,12 @@ namespace VNLib.Net.Transport.Tcp
{
//Dispose the base class
base.Dispose();
+
//Dispose the socket if its set
AcceptSocket?.Dispose();
AcceptSocket = null;
- //Dispose the overlapped stream
+
+ //Cleanup socket worker
SocketWorker.DisposeInternal();
}
}