From a55994526d8e3dc3a04ce3813c1e3f14a8db5085 Mon Sep 17 00:00:00 2001
From: mockingjay <8400684@qq.com>
Date: Thu, 2 May 2024 12:58:22 +0800
Subject: [PATCH 01/18] add quic
---
SuperSocket.sln | 30 ++++
.../QuicPipeConnection.cs | 24 +++
.../SuperSocket.Quic.Connection.csproj | 12 ++
src/SuperSocket.Quic/QuicConnectionFactory.cs | 35 ++++
.../QuicConnectionFactoryBuilder.cs | 14 ++
.../QuicConnectionListener.cs | 156 ++++++++++++++++++
.../QuicConnectionListenerFactory.cs | 27 +++
.../QuicServerHostBuilderExtensions.cs | 32 ++++
test/SuperSocket.Tests/ClientTest.cs | 1 +
.../SuperSocket.Tests/QuicHostConfigurator.cs | 148 +++++++++++++++++
.../SuperSocket.Tests.csproj | 1 +
test/SuperSocket.Tests/UdpHostConfigurator.cs | 16 +-
12 files changed, 491 insertions(+), 5 deletions(-)
create mode 100644 src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
create mode 100644 src/SuperSocket.Quic.Connection/SuperSocket.Quic.Connection.csproj
create mode 100644 src/SuperSocket.Quic/QuicConnectionFactory.cs
create mode 100644 src/SuperSocket.Quic/QuicConnectionFactoryBuilder.cs
create mode 100644 src/SuperSocket.Quic/QuicConnectionListener.cs
create mode 100644 src/SuperSocket.Quic/QuicConnectionListenerFactory.cs
create mode 100644 src/SuperSocket.Quic/QuicServerHostBuilderExtensions.cs
create mode 100644 test/SuperSocket.Tests/QuicHostConfigurator.cs
diff --git a/SuperSocket.sln b/SuperSocket.sln
index 834eed086..728f9f3d0 100644
--- a/SuperSocket.sln
+++ b/SuperSocket.sln
@@ -39,6 +39,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperSocket.Connection", "s
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperSocket.Kestrel", "src\SuperSocket.Kestrel\SuperSocket.Kestrel.csproj", "{8C8507D6-903F-4786-8F18-ACA54257454B}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperSocket.Quic.Connection", "src\SuperSocket.Quic.Connection\SuperSocket.Quic.Connection.csproj", "{8F14B3E1-C9D8-4E9E-ACDA-D424BA44CA97}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperSocket.Quic", "src\SuperSocket.Quic\SuperSocket.Quic.csproj", "{AEE8630B-3A2E-48BB-A55C-35C9D2D205DF}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -241,6 +245,30 @@ Global
{8C8507D6-903F-4786-8F18-ACA54257454B}.Release|x64.Build.0 = Release|Any CPU
{8C8507D6-903F-4786-8F18-ACA54257454B}.Release|x86.ActiveCfg = Release|Any CPU
{8C8507D6-903F-4786-8F18-ACA54257454B}.Release|x86.Build.0 = Release|Any CPU
+ {8F14B3E1-C9D8-4E9E-ACDA-D424BA44CA97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8F14B3E1-C9D8-4E9E-ACDA-D424BA44CA97}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8F14B3E1-C9D8-4E9E-ACDA-D424BA44CA97}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {8F14B3E1-C9D8-4E9E-ACDA-D424BA44CA97}.Debug|x64.Build.0 = Debug|Any CPU
+ {8F14B3E1-C9D8-4E9E-ACDA-D424BA44CA97}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {8F14B3E1-C9D8-4E9E-ACDA-D424BA44CA97}.Debug|x86.Build.0 = Debug|Any CPU
+ {8F14B3E1-C9D8-4E9E-ACDA-D424BA44CA97}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8F14B3E1-C9D8-4E9E-ACDA-D424BA44CA97}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8F14B3E1-C9D8-4E9E-ACDA-D424BA44CA97}.Release|x64.ActiveCfg = Release|Any CPU
+ {8F14B3E1-C9D8-4E9E-ACDA-D424BA44CA97}.Release|x64.Build.0 = Release|Any CPU
+ {8F14B3E1-C9D8-4E9E-ACDA-D424BA44CA97}.Release|x86.ActiveCfg = Release|Any CPU
+ {8F14B3E1-C9D8-4E9E-ACDA-D424BA44CA97}.Release|x86.Build.0 = Release|Any CPU
+ {AEE8630B-3A2E-48BB-A55C-35C9D2D205DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AEE8630B-3A2E-48BB-A55C-35C9D2D205DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AEE8630B-3A2E-48BB-A55C-35C9D2D205DF}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {AEE8630B-3A2E-48BB-A55C-35C9D2D205DF}.Debug|x64.Build.0 = Debug|Any CPU
+ {AEE8630B-3A2E-48BB-A55C-35C9D2D205DF}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {AEE8630B-3A2E-48BB-A55C-35C9D2D205DF}.Debug|x86.Build.0 = Debug|Any CPU
+ {AEE8630B-3A2E-48BB-A55C-35C9D2D205DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AEE8630B-3A2E-48BB-A55C-35C9D2D205DF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AEE8630B-3A2E-48BB-A55C-35C9D2D205DF}.Release|x64.ActiveCfg = Release|Any CPU
+ {AEE8630B-3A2E-48BB-A55C-35C9D2D205DF}.Release|x64.Build.0 = Release|Any CPU
+ {AEE8630B-3A2E-48BB-A55C-35C9D2D205DF}.Release|x86.ActiveCfg = Release|Any CPU
+ {AEE8630B-3A2E-48BB-A55C-35C9D2D205DF}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -262,6 +290,8 @@ Global
{8454E8D5-777D-46CB-B050-76C5119B624B} = {DDA4741E-097F-40C3-A252-2E1E3476C1A7}
{FC2B529F-4AF4-4C39-BC4F-A3836CC7B37C} = {DDA4741E-097F-40C3-A252-2E1E3476C1A7}
{8C8507D6-903F-4786-8F18-ACA54257454B} = {DDA4741E-097F-40C3-A252-2E1E3476C1A7}
+ {8F14B3E1-C9D8-4E9E-ACDA-D424BA44CA97} = {DDA4741E-097F-40C3-A252-2E1E3476C1A7}
+ {AEE8630B-3A2E-48BB-A55C-35C9D2D205DF} = {DDA4741E-097F-40C3-A252-2E1E3476C1A7}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {ADB30AA2-A848-4CB3-8A20-488C80F1BA9E}
diff --git a/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs b/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
new file mode 100644
index 000000000..85ea0e2e8
--- /dev/null
+++ b/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
@@ -0,0 +1,24 @@
+using System;
+using System.IO;
+using System.Net;
+using SuperSocket.Connection;
+
+namespace SuperSocket.Quic.Connection;
+
+public class QuicPipeConnection : StreamPipeConnection
+{
+ public QuicPipeConnection(Stream stream, EndPoint remoteEndPoint, ConnectionOptions options)
+ : base(stream, remoteEndPoint, options)
+ {
+ }
+
+ public QuicPipeConnection(Stream stream, EndPoint remoteEndPoint, EndPoint localEndPoint, ConnectionOptions options)
+ : base(stream, remoteEndPoint, localEndPoint, options)
+ {
+ }
+
+ protected override bool IsIgnorableException(Exception e)
+ {
+ return base.IsIgnorableException(e);
+ }
+}
\ No newline at end of file
diff --git a/src/SuperSocket.Quic.Connection/SuperSocket.Quic.Connection.csproj b/src/SuperSocket.Quic.Connection/SuperSocket.Quic.Connection.csproj
new file mode 100644
index 000000000..59a8daf1b
--- /dev/null
+++ b/src/SuperSocket.Quic.Connection/SuperSocket.Quic.Connection.csproj
@@ -0,0 +1,12 @@
+
+
+
+ SuperSocket quic connection library.
+ net7.0
+
+
+
+
+
+
+
diff --git a/src/SuperSocket.Quic/QuicConnectionFactory.cs b/src/SuperSocket.Quic/QuicConnectionFactory.cs
new file mode 100644
index 000000000..08a3c563a
--- /dev/null
+++ b/src/SuperSocket.Quic/QuicConnectionFactory.cs
@@ -0,0 +1,35 @@
+using System.Net.Quic;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+using SuperSocket.Connection;
+using SuperSocket.Server.Abstractions;
+#pragma warning disable CA2252
+namespace SuperSocket.Quic
+{
+ internal class QuicConnectionFactory : IConnectionFactory
+ {
+ private readonly ILogger _logger ;
+ private readonly ListenOptions _listenOptions;
+ private readonly ConnectionOptions _connectionOptions;
+
+ public QuicConnectionFactory(
+ ListenOptions listenOptions,
+ ConnectionOptions connectionOptions)
+ {
+ _listenOptions = listenOptions;
+ _connectionOptions = connectionOptions;
+ _logger = connectionOptions.Logger;
+ }
+
+ public async Task CreateConnection(object connection, CancellationToken cancellationToken)
+ {
+ var quicConnection = connection as QuicConnection;
+
+ var stream = await quicConnection.AcceptInboundStreamAsync(cancellationToken);
+
+ return new StreamPipeConnection(stream, quicConnection.RemoteEndPoint, quicConnection.LocalEndPoint, _connectionOptions);
+ }
+ }
+}
+#pragma warning restore CA2252
\ No newline at end of file
diff --git a/src/SuperSocket.Quic/QuicConnectionFactoryBuilder.cs b/src/SuperSocket.Quic/QuicConnectionFactoryBuilder.cs
new file mode 100644
index 000000000..ee4df7c9f
--- /dev/null
+++ b/src/SuperSocket.Quic/QuicConnectionFactoryBuilder.cs
@@ -0,0 +1,14 @@
+using SuperSocket.Connection;
+using SuperSocket.Server.Abstractions;
+using SuperSocket.Server.Abstractions.Connections;
+
+namespace SuperSocket.Quic
+{
+ internal class QuicConnectionFactoryBuilder : IConnectionFactoryBuilder
+ {
+ public IConnectionFactory Build(ListenOptions listenOptions, ConnectionOptions connectionOptions)
+ {
+ return new QuicConnectionFactory(listenOptions, connectionOptions);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/SuperSocket.Quic/QuicConnectionListener.cs b/src/SuperSocket.Quic/QuicConnectionListener.cs
new file mode 100644
index 000000000..7037cedcb
--- /dev/null
+++ b/src/SuperSocket.Quic/QuicConnectionListener.cs
@@ -0,0 +1,156 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+using SuperSocket.Connection;
+using SuperSocket.Server.Abstractions;
+using SuperSocket.Server.Abstractions.Connections;
+using System.Net.Quic;
+using System.Net.Security;
+
+#pragma warning disable CA2252
+namespace SuperSocket.Quic
+{
+ internal sealed class QuicConnectionListener : IConnectionListener
+ {
+ private readonly ILogger _logger;
+
+ private QuicListener _listenSocket;
+ private CancellationTokenSource _cancellationTokenSource;
+ private TaskCompletionSource _stopTaskCompletionSource;
+ public IConnectionFactory ConnectionFactory { get; }
+ public ListenOptions Options { get; }
+ public bool IsRunning { get; private set; }
+
+ public QuicConnectionListener(ListenOptions options, IConnectionFactory connectionFactory, ILogger logger)
+ {
+ Options = options;
+ ConnectionFactory = connectionFactory;
+ _logger = logger;
+ }
+
+ public bool Start()
+ {
+ var options = Options;
+
+ try
+ {
+ var listenEndpoint = options.ToEndPoint();
+
+ var quicListenerOptions = new QuicListenerOptions
+ {
+ ListenBacklog = options.BackLog,
+ ListenEndPoint = listenEndpoint,
+ ApplicationProtocols = new List { SslApplicationProtocol.Http3 },
+ ConnectionOptionsCallback = (connection, ssl, token) => ValueTask.FromResult(
+ new QuicServerConnectionOptions()
+ {
+ DefaultStreamErrorCode = 0,
+ DefaultCloseErrorCode = 0,
+ //IdleTimeout = 0,
+ //MaxInboundBidirectionalStreams = 0,
+ //MaxInboundUnidirectionalStreams = 0,
+ ServerAuthenticationOptions = new SslServerAuthenticationOptions()
+ {
+ ApplicationProtocols =
+ new List { SslApplicationProtocol.Http3 },
+ ServerCertificate = options.CertificateOptions.Certificate,
+ RemoteCertificateValidationCallback =
+ options.CertificateOptions.RemoteCertificateValidationCallback,
+ }
+ })
+ };
+
+ var result = QuicListener.ListenAsync(quicListenerOptions);
+
+ if (result.IsCompleted)
+ _listenSocket = result.Result;
+ else
+ _listenSocket = result.GetAwaiter().GetResult();
+
+ var listenSocket = _listenSocket;
+
+ IsRunning = true;
+
+ _cancellationTokenSource = new CancellationTokenSource();
+
+ KeepAcceptAsync(listenSocket, _cancellationTokenSource.Token).DoNotAwait();
+ return true;
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, $"The listener[{this.ToString()}] failed to start.");
+ return false;
+ }
+ }
+
+
+ private async Task KeepAcceptAsync(QuicListener listenSocket, CancellationToken cancellationToken)
+
+ {
+ while (!cancellationToken.IsCancellationRequested)
+ {
+ try
+ {
+ var quicConnection =
+ await listenSocket.AcceptConnectionAsync(cancellationToken).ConfigureAwait(false);
+ OnNewClientAccept(quicConnection, cancellationToken);
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, $"Listener[{this.ToString()}] failed to do AcceptAsync");
+ continue;
+ }
+ }
+
+ _stopTaskCompletionSource.TrySetResult(true);
+ }
+
+ public event NewConnectionAcceptHandler NewConnectionAccept;
+
+ private async void OnNewClientAccept(QuicConnection quicConnection, CancellationToken cancellationToken)
+ {
+ var handler = NewConnectionAccept;
+
+ if (handler == null)
+ return;
+
+ IConnection connection = null;
+
+ try
+ {
+ using var cts = CancellationTokenSourcePool.Shared.Rent(Options.ConnectionAcceptTimeOut);
+ connection = await ConnectionFactory.CreateConnection(quicConnection, cts.Token);
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, $"Failed to create quicConnection for {quicConnection.RemoteEndPoint}.");
+ return;
+ }
+
+ await handler.Invoke(this.Options, connection);
+ }
+
+ public async Task StopAsync()
+ {
+ var listenSocket = _listenSocket;
+
+ if (listenSocket == null)
+ return;
+
+ _stopTaskCompletionSource = new TaskCompletionSource();
+
+ _cancellationTokenSource.Cancel();
+ await _listenSocket.DisposeAsync();
+
+ await _stopTaskCompletionSource.Task;
+ }
+
+ public override string ToString()
+ {
+ return Options?.ToString();
+ }
+ }
+}
+#pragma warning restore CA2252
\ No newline at end of file
diff --git a/src/SuperSocket.Quic/QuicConnectionListenerFactory.cs b/src/SuperSocket.Quic/QuicConnectionListenerFactory.cs
new file mode 100644
index 000000000..2f3326098
--- /dev/null
+++ b/src/SuperSocket.Quic/QuicConnectionListenerFactory.cs
@@ -0,0 +1,27 @@
+using Microsoft.Extensions.Logging;
+using SuperSocket.Connection;
+using SuperSocket.Server.Abstractions;
+using SuperSocket.Server.Abstractions.Connections;
+
+namespace SuperSocket.Quic
+{
+ internal class QuicConnectionListenerFactory : IConnectionListenerFactory
+ {
+ private readonly IConnectionFactoryBuilder _connectionFactoryBuilder;
+
+ public QuicConnectionListenerFactory(IConnectionFactoryBuilder connectionFactoryBuilder)
+ {
+ _connectionFactoryBuilder = connectionFactoryBuilder;
+ }
+
+ public IConnectionListener CreateConnectionListener(ListenOptions options, ConnectionOptions connectionOptions, ILoggerFactory loggerFactory)
+ {
+ connectionOptions.Logger = loggerFactory.CreateLogger(nameof(IConnection));
+ var connectionFactoryLogger = loggerFactory.CreateLogger(nameof(QuicConnectionListener));
+
+ var connectionFactory = _connectionFactoryBuilder.Build(options, connectionOptions);
+
+ return new QuicConnectionListener(options, connectionFactory, connectionFactoryLogger);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/SuperSocket.Quic/QuicServerHostBuilderExtensions.cs b/src/SuperSocket.Quic/QuicServerHostBuilderExtensions.cs
new file mode 100644
index 000000000..8d13e0d93
--- /dev/null
+++ b/src/SuperSocket.Quic/QuicServerHostBuilderExtensions.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Linq;
+using System.Net.Quic;
+using Microsoft.Extensions.DependencyInjection;
+using SuperSocket.Server.Abstractions.Connections;
+using SuperSocket.Server.Abstractions.Host;
+using SuperSocket.Quic;
+#pragma warning disable CA2252
+
+namespace SuperSocket.Server
+{
+ public static class QuicServerHostBuilderExtensions
+ {
+ public static ISuperSocketHostBuilder UseQuic(this ISuperSocketHostBuilder hostBuilder)
+ {
+ if (!QuicListener.IsSupported)
+ throw new PlatformNotSupportedException("System.Net.Quic is not supported on this platform.");
+
+ return hostBuilder.ConfigureServices((_, services) =>
+ {
+ services.AddSingleton();
+ services.AddSingleton();
+ }) as ISuperSocketHostBuilder;
+ }
+
+ public static ISuperSocketHostBuilder UseQuic(this ISuperSocketHostBuilder hostBuilder)
+ {
+ return (hostBuilder as ISuperSocketHostBuilder).UseQuic() as ISuperSocketHostBuilder;
+ }
+ }
+}
+#pragma warning disable CA2252
\ No newline at end of file
diff --git a/test/SuperSocket.Tests/ClientTest.cs b/test/SuperSocket.Tests/ClientTest.cs
index b36cff6e2..7b34cccb3 100644
--- a/test/SuperSocket.Tests/ClientTest.cs
+++ b/test/SuperSocket.Tests/ClientTest.cs
@@ -37,6 +37,7 @@ public ClientTest(ITestOutputHelper outputHelper)
[InlineData(typeof(GzipHostConfigurator), false)]
[InlineData(typeof(GzipSecureHostConfigurator), false)]
[InlineData(typeof(RegularHostConfigurator), true)]
+ [InlineData(typeof(QuicHostConfigurator), false)]
public async Task TestEcho(Type hostConfiguratorType, bool clientReadAsDemand)
{
var serverSessionEvent = new AutoResetEvent(false);
diff --git a/test/SuperSocket.Tests/QuicHostConfigurator.cs b/test/SuperSocket.Tests/QuicHostConfigurator.cs
new file mode 100644
index 000000000..813566122
--- /dev/null
+++ b/test/SuperSocket.Tests/QuicHostConfigurator.cs
@@ -0,0 +1,148 @@
+using System;
+using System.Buffers;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Net.Quic;
+using System.Net.Security;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using SuperSocket.Connection;
+using SuperSocket.Server;
+using SuperSocket.Server.Abstractions;
+using SuperSocket.Server.Abstractions.Host;
+using SuperSocket.Client;
+using SuperSocket.ProtoBase;
+
+namespace SuperSocket.Tests
+{
+#if NET7_0_OR_GREATER
+
+ public class QuicHostConfigurator : IHostConfigurator
+ {
+ private static readonly ArrayPool _bufferPool = ArrayPool.Shared;
+
+ public string WebSocketSchema => "ws";
+
+ public bool IsSecure => false;
+
+ public ListenOptions Listener { get; private set; }
+
+ public IEasyClient ConfigureEasyClient(IPipelineFilter pipelineFilter,
+ ConnectionOptions options) where TPackageInfo : class
+ {
+ return new QuicClient(pipelineFilter, options);
+ }
+
+ private static Random _rd = new Random();
+
+ public void Configure(ISuperSocketHostBuilder hostBuilder)
+ {
+ hostBuilder
+ .UseQuic()
+ .ConfigureServices((ctx, services) =>
+ {
+ services.Configure((options) =>
+ {
+ var listener = options.Listeners[0];
+ listener.CertificateOptions = new CertificateOptions
+ {
+ FilePath = "supersocket.pfx",
+ Password = "supersocket"
+ };
+ Listener = listener;
+ });
+ }
+ );
+ }
+
+ public TextReader GetStreamReader(Stream stream, Encoding encoding)
+ {
+ throw new NotImplementedException();
+ }
+
+ public ValueTask GetClientStream(Socket socket)
+ {
+ throw new NotImplementedException();
+ }
+
+ private IPipelineFilter GetPipelineFilter()
+ {
+ return new TerminatorPipelineFilter(new[] { (byte)'\r', (byte)'\n' })
+ {
+ Decoder = new UdpPackageDecoder()
+ };
+ }
+
+ class UdpPackageDecoder : IPackageDecoder
+ {
+ public TextPackageInfo Decode(ref ReadOnlySequence buffer, object context)
+ {
+ return new TextPackageInfo { Text = buffer.GetString(Encoding.UTF8) };
+ }
+ }
+
+ class QuicClient : EasyClient
+ where TReceivePackage : class
+ {
+ public QuicClient(IPipelineFilter pipelineFilter, ConnectionOptions options)
+ : base(pipelineFilter, options)
+ {
+ }
+
+ protected override IConnector GetConnector()
+ {
+ return new QuicConnector();
+ }
+ }
+
+ class QuicConnector : ConnectorBase
+ {
+ protected override async ValueTask ConnectAsync(EndPoint remoteEndPoint, ConnectState state,
+ CancellationToken cancellationToken)
+ {
+#pragma warning disable CA2252
+
+ var quicConnection = await QuicConnection.ConnectAsync(new QuicClientConnectionOptions
+ {
+ DefaultCloseErrorCode = 0,
+ DefaultStreamErrorCode = 0,
+ RemoteEndPoint = remoteEndPoint,
+ ClientAuthenticationOptions = new SslClientAuthenticationOptions
+ {
+ ApplicationProtocols = new List { SslApplicationProtocol.Http3 },
+ RemoteCertificateValidationCallback = (sender, certificate, chain, errors) => { return true; }
+ }
+ });
+
+ var stream =
+ await quicConnection.OpenOutboundStreamAsync(QuicStreamType.Bidirectional, cancellationToken);
+
+ return new ConnectState
+ {
+ Stream = stream,
+ Result = true,
+ };
+
+#pragma warning restore CA2252
+ }
+ }
+
+ public async ValueTask KeepSequence()
+ {
+ await Task.Delay(200);
+ }
+
+ public Socket CreateClient()
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+#endif
+}
\ No newline at end of file
diff --git a/test/SuperSocket.Tests/SuperSocket.Tests.csproj b/test/SuperSocket.Tests/SuperSocket.Tests.csproj
index 2f292b952..084867a20 100755
--- a/test/SuperSocket.Tests/SuperSocket.Tests.csproj
+++ b/test/SuperSocket.Tests/SuperSocket.Tests.csproj
@@ -13,6 +13,7 @@
+
diff --git a/test/SuperSocket.Tests/UdpHostConfigurator.cs b/test/SuperSocket.Tests/UdpHostConfigurator.cs
index 2ce971122..651e4dd50 100644
--- a/test/SuperSocket.Tests/UdpHostConfigurator.cs
+++ b/test/SuperSocket.Tests/UdpHostConfigurator.cs
@@ -1,7 +1,10 @@
using System;
using System.Buffers;
+using System.Collections.Generic;
using System.IO;
using System.Net;
+using System.Net.Quic;
+using System.Net.Security;
using System.Net.Sockets;
using System.Text;
using System.Threading;
@@ -19,7 +22,7 @@ namespace SuperSocket.Tests
public class UdpHostConfigurator : IHostConfigurator
{
private static readonly ArrayPool _bufferPool = ArrayPool.Shared;
-
+
public string WebSocketSchema => "ws";
public bool IsSecure => false;
@@ -43,7 +46,8 @@ public void Configure(ISuperSocketHostBuilder hostBuilder)
);
}
- public IEasyClient ConfigureEasyClient(IPipelineFilter pipelineFilter, ConnectionOptions options)
+ public IEasyClient ConfigureEasyClient(IPipelineFilter pipelineFilter,
+ ConnectionOptions options)
where TPackageInfo : class
{
return new EasyClient(pipelineFilter, options);
@@ -83,10 +87,12 @@ private async Task UdpReceive(Socket socket, IVirtualConnection connection)
try
{
var result = await socket
- .ReceiveFromAsync(new ArraySegment(buffer, 0, buffer.Length), SocketFlags.None, remoteEndPoint)
+ .ReceiveFromAsync(new ArraySegment(buffer, 0, buffer.Length), SocketFlags.None,
+ remoteEndPoint)
.ConfigureAwait(false);
- await connection.WritePipeDataAsync((new ArraySegment(buffer, 0, result.ReceivedBytes)).AsMemory(), CancellationToken.None);
+ await connection.WritePipeDataAsync(
+ (new ArraySegment(buffer, 0, result.ReceivedBytes)).AsMemory(), CancellationToken.None);
}
catch (NullReferenceException)
{
@@ -139,10 +145,10 @@ public TextPackageInfo Decode(ref ReadOnlySequence buffer, object context)
}
}
+
public async ValueTask KeepSequence()
{
await Task.Delay(200);
}
-
}
}
\ No newline at end of file
From f1ff6de1230a3df40a8e8392a1e4d0c9b98bb641 Mon Sep 17 00:00:00 2001
From: mockingjay <8400684@qq.com>
Date: Thu, 2 May 2024 12:58:38 +0800
Subject: [PATCH 02/18] add quic
---
src/SuperSocket.Quic/SuperSocket.Quic.csproj | 13 +++++++++++++
1 file changed, 13 insertions(+)
create mode 100644 src/SuperSocket.Quic/SuperSocket.Quic.csproj
diff --git a/src/SuperSocket.Quic/SuperSocket.Quic.csproj b/src/SuperSocket.Quic/SuperSocket.Quic.csproj
new file mode 100644
index 000000000..be86866bd
--- /dev/null
+++ b/src/SuperSocket.Quic/SuperSocket.Quic.csproj
@@ -0,0 +1,13 @@
+
+
+
+ SuperSocket quic library.
+ net7.0
+ True
+
+
+
+
+
+
+
From 6918d91e06bf40c09536cbd913f11068602fab04 Mon Sep 17 00:00:00 2001
From: mockingjay <8400684@qq.com>
Date: Thu, 2 May 2024 12:59:14 +0800
Subject: [PATCH 03/18] add quic
---
.../SuperSocket.Quic.Connection.csproj | 2 +-
src/SuperSocket.Quic/SuperSocket.Quic.csproj | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/SuperSocket.Quic.Connection/SuperSocket.Quic.Connection.csproj b/src/SuperSocket.Quic.Connection/SuperSocket.Quic.Connection.csproj
index 59a8daf1b..52434414a 100644
--- a/src/SuperSocket.Quic.Connection/SuperSocket.Quic.Connection.csproj
+++ b/src/SuperSocket.Quic.Connection/SuperSocket.Quic.Connection.csproj
@@ -2,7 +2,7 @@
SuperSocket quic connection library.
- net7.0
+ net7.0;net8.0
diff --git a/src/SuperSocket.Quic/SuperSocket.Quic.csproj b/src/SuperSocket.Quic/SuperSocket.Quic.csproj
index be86866bd..ce7765350 100644
--- a/src/SuperSocket.Quic/SuperSocket.Quic.csproj
+++ b/src/SuperSocket.Quic/SuperSocket.Quic.csproj
@@ -2,7 +2,7 @@
SuperSocket quic library.
- net7.0
+ net7.0;net8.0
True
From a425b5790310d85d00a4797c4ff0b16cd04429c3 Mon Sep 17 00:00:00 2001
From: mockingjay <8400684@qq.com>
Date: Thu, 2 May 2024 17:55:20 +0800
Subject: [PATCH 04/18] add quic
---
.../QuicPipeConnection.cs | 96 ++++++++++++++++---
src/SuperSocket.Quic/QuicConnectionFactory.cs | 10 +-
.../QuicConnectionListener.cs | 1 -
.../SuperSocket.Tests/QuicHostConfigurator.cs | 58 +++++------
4 files changed, 119 insertions(+), 46 deletions(-)
diff --git a/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs b/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
index 85ea0e2e8..c60c02657 100644
--- a/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
+++ b/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
@@ -1,24 +1,92 @@
using System;
+using System.Buffers;
using System.IO;
-using System.Net;
+using System.Net.Quic;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
using SuperSocket.Connection;
-namespace SuperSocket.Quic.Connection;
+#pragma warning disable CA2252
-public class QuicPipeConnection : StreamPipeConnection
+namespace SuperSocket.Quic.Connection
{
- public QuicPipeConnection(Stream stream, EndPoint remoteEndPoint, ConnectionOptions options)
- : base(stream, remoteEndPoint, options)
+ public class QuicPipeConnection : PipeConnection
{
- }
+ private QuicStream _stream;
+ private ValueTask _task;
+ private readonly QuicConnection _quicConnection;
- public QuicPipeConnection(Stream stream, EndPoint remoteEndPoint, EndPoint localEndPoint, ConnectionOptions options)
- : base(stream, remoteEndPoint, localEndPoint, options)
- {
- }
+ public QuicPipeConnection(QuicConnection quicConnection, ConnectionOptions options) : base(options)
+ {
+ _quicConnection = quicConnection;
+ RemoteEndPoint = quicConnection.RemoteEndPoint;
+ LocalEndPoint = quicConnection.LocalEndPoint;
+ }
- protected override bool IsIgnorableException(Exception e)
- {
- return base.IsIgnorableException(e);
+ protected override async Task StartInputPipeTask(IObjectPipe packagePipe,
+ CancellationToken cancellationToken)
+ {
+ _stream = await _task;
+ await base.StartInputPipeTask(packagePipe, cancellationToken);
+ }
+
+ public void OpenOutboundStream(CancellationToken cancellationToken)
+ {
+ _task = _quicConnection.OpenOutboundStreamAsync(QuicStreamType.Bidirectional, cancellationToken);
+ }
+
+ public void AcceptInboundStream(CancellationToken cancellationToken)
+ {
+ _task = _quicConnection.AcceptInboundStreamAsync(cancellationToken);
+ }
+
+ protected override void Close()
+ {
+ _stream.Close();
+ }
+
+ protected override void OnClosed()
+ {
+ _stream = null;
+ base.OnClosed();
+ }
+
+ protected override async ValueTask FillPipeWithDataAsync(Memory memory,
+ CancellationToken cancellationToken)
+ {
+ return await _stream.ReadAsync(memory, cancellationToken).ConfigureAwait(false);
+ }
+
+ protected override async ValueTask SendOverIOAsync(ReadOnlySequence buffer,
+ CancellationToken cancellationToken)
+ {
+ var total = 0;
+
+ foreach (var data in buffer)
+ {
+ await _stream.WriteAsync(data, cancellationToken).ConfigureAwait(false);
+ total += data.Length;
+ }
+
+ await _stream.FlushAsync(cancellationToken).ConfigureAwait(false);
+ return total;
+ }
+
+ protected override bool IsIgnorableException(Exception e)
+ {
+ if (base.IsIgnorableException(e))
+ return true;
+
+ if (e is SocketException se)
+ {
+ if (se.IsIgnorableSocketException())
+ return true;
+ }
+
+ return false;
+ }
}
-}
\ No newline at end of file
+}
+
+#pragma warning disable CA2252
\ No newline at end of file
diff --git a/src/SuperSocket.Quic/QuicConnectionFactory.cs b/src/SuperSocket.Quic/QuicConnectionFactory.cs
index 08a3c563a..9ac8e0b50 100644
--- a/src/SuperSocket.Quic/QuicConnectionFactory.cs
+++ b/src/SuperSocket.Quic/QuicConnectionFactory.cs
@@ -3,13 +3,15 @@
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using SuperSocket.Connection;
+using SuperSocket.Quic.Connection;
using SuperSocket.Server.Abstractions;
+
#pragma warning disable CA2252
namespace SuperSocket.Quic
{
internal class QuicConnectionFactory : IConnectionFactory
{
- private readonly ILogger _logger ;
+ private readonly ILogger _logger;
private readonly ListenOptions _listenOptions;
private readonly ConnectionOptions _connectionOptions;
@@ -26,9 +28,11 @@ public async Task CreateConnection(object connection, CancellationT
{
var quicConnection = connection as QuicConnection;
- var stream = await quicConnection.AcceptInboundStreamAsync(cancellationToken);
+ var pipcPipeConnection = new QuicPipeConnection(quicConnection, _connectionOptions);
+
+ pipcPipeConnection.AcceptInboundStream(cancellationToken);
- return new StreamPipeConnection(stream, quicConnection.RemoteEndPoint, quicConnection.LocalEndPoint, _connectionOptions);
+ return pipcPipeConnection;
}
}
}
diff --git a/src/SuperSocket.Quic/QuicConnectionListener.cs b/src/SuperSocket.Quic/QuicConnectionListener.cs
index 7037cedcb..28a7237f9 100644
--- a/src/SuperSocket.Quic/QuicConnectionListener.cs
+++ b/src/SuperSocket.Quic/QuicConnectionListener.cs
@@ -100,7 +100,6 @@ private async Task KeepAcceptAsync(QuicListener listenSocket, CancellationToken
catch (Exception e)
{
_logger.LogError(e, $"Listener[{this.ToString()}] failed to do AcceptAsync");
- continue;
}
}
diff --git a/test/SuperSocket.Tests/QuicHostConfigurator.cs b/test/SuperSocket.Tests/QuicHostConfigurator.cs
index 813566122..f42b01de0 100644
--- a/test/SuperSocket.Tests/QuicHostConfigurator.cs
+++ b/test/SuperSocket.Tests/QuicHostConfigurator.cs
@@ -18,6 +18,7 @@
using SuperSocket.Server.Abstractions.Host;
using SuperSocket.Client;
using SuperSocket.ProtoBase;
+using SuperSocket.Quic.Connection;
namespace SuperSocket.Tests
{
@@ -95,40 +96,41 @@ public QuicClient(IPipelineFilter pipelineFilter, ConnectionOpt
{
}
- protected override IConnector GetConnector()
- {
- return new QuicConnector();
- }
- }
-
- class QuicConnector : ConnectorBase
- {
- protected override async ValueTask ConnectAsync(EndPoint remoteEndPoint, ConnectState state,
+ protected override async ValueTask ConnectAsync(EndPoint remoteEndPoint,
CancellationToken cancellationToken)
{
#pragma warning disable CA2252
-
- var quicConnection = await QuicConnection.ConnectAsync(new QuicClientConnectionOptions
- {
- DefaultCloseErrorCode = 0,
- DefaultStreamErrorCode = 0,
- RemoteEndPoint = remoteEndPoint,
- ClientAuthenticationOptions = new SslClientAuthenticationOptions
+ var quicConnection = await QuicConnection.ConnectAsync(
+ cancellationToken: cancellationToken,
+ options: new QuicClientConnectionOptions
{
- ApplicationProtocols = new List { SslApplicationProtocol.Http3 },
- RemoteCertificateValidationCallback = (sender, certificate, chain, errors) => { return true; }
- }
- });
-
- var stream =
- await quicConnection.OpenOutboundStreamAsync(QuicStreamType.Bidirectional, cancellationToken);
+ DefaultCloseErrorCode = 0,
+ DefaultStreamErrorCode = 0,
+ RemoteEndPoint = remoteEndPoint,
+ ClientAuthenticationOptions = new SslClientAuthenticationOptions
+ {
+ ApplicationProtocols = new List { SslApplicationProtocol.Http3 },
+ RemoteCertificateValidationCallback = (sender, certificate, chain, errors) =>
+ {
+ return true;
+ }
+ }
+ });
- return new ConnectState
+ if (cancellationToken.IsCancellationRequested)
{
- Stream = stream,
- Result = true,
- };
-
+ OnError($"The connection to {remoteEndPoint} was cancelled.");
+ return false;
+ }
+
+ var connection = new QuicPipeConnection(quicConnection, Options);
+
+ connection.OpenOutboundStream(cancellationToken);
+
+ SetupConnection(connection);
+
+ return true;
+
#pragma warning restore CA2252
}
}
From ef1529cba095c6b153fe3d0f4c825c66aedeaf3e Mon Sep 17 00:00:00 2001
From: mockingjay <8400684@qq.com>
Date: Thu, 2 May 2024 18:00:04 +0800
Subject: [PATCH 05/18] ini
---
src/SuperSocket.Quic/QuicConnectionListener.cs | 4 ++++
test/SuperSocket.Tests/ClientTest.cs | 10 +++++-----
2 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/src/SuperSocket.Quic/QuicConnectionListener.cs b/src/SuperSocket.Quic/QuicConnectionListener.cs
index 28a7237f9..62f3f9327 100644
--- a/src/SuperSocket.Quic/QuicConnectionListener.cs
+++ b/src/SuperSocket.Quic/QuicConnectionListener.cs
@@ -38,6 +38,10 @@ public bool Start()
{
var listenEndpoint = options.ToEndPoint();
+ ArgumentNullException.ThrowIfNull(options.CertificateOptions);
+
+ options.CertificateOptions.EnsureCertificate();
+
var quicListenerOptions = new QuicListenerOptions
{
ListenBacklog = options.BackLog,
diff --git a/test/SuperSocket.Tests/ClientTest.cs b/test/SuperSocket.Tests/ClientTest.cs
index 7b34cccb3..3b2fda78c 100644
--- a/test/SuperSocket.Tests/ClientTest.cs
+++ b/test/SuperSocket.Tests/ClientTest.cs
@@ -32,11 +32,11 @@ public ClientTest(ITestOutputHelper outputHelper)
[Theory]
[Trait("Category", "Client.TestEcho")]
- [InlineData(typeof(RegularHostConfigurator), false)]
- [InlineData(typeof(SecureHostConfigurator), false)]
- [InlineData(typeof(GzipHostConfigurator), false)]
- [InlineData(typeof(GzipSecureHostConfigurator), false)]
- [InlineData(typeof(RegularHostConfigurator), true)]
+ // [InlineData(typeof(RegularHostConfigurator), false)]
+ // [InlineData(typeof(SecureHostConfigurator), false)]
+ // [InlineData(typeof(GzipHostConfigurator), false)]
+ // [InlineData(typeof(GzipSecureHostConfigurator), false)]
+ // [InlineData(typeof(RegularHostConfigurator), true)]
[InlineData(typeof(QuicHostConfigurator), false)]
public async Task TestEcho(Type hostConfiguratorType, bool clientReadAsDemand)
{
From 1670a4de4bdf5999448c33ac41b36b32b3ef0ea8 Mon Sep 17 00:00:00 2001
From: wujun <8400684@qq.com>
Date: Thu, 2 May 2024 18:04:09 +0800
Subject: [PATCH 06/18] add quic
---
src/SuperSocket.Quic/QuicConnectionFactory.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/SuperSocket.Quic/QuicConnectionFactory.cs b/src/SuperSocket.Quic/QuicConnectionFactory.cs
index 9ac8e0b50..795808556 100644
--- a/src/SuperSocket.Quic/QuicConnectionFactory.cs
+++ b/src/SuperSocket.Quic/QuicConnectionFactory.cs
@@ -24,7 +24,7 @@ public QuicConnectionFactory(
_logger = connectionOptions.Logger;
}
- public async Task CreateConnection(object connection, CancellationToken cancellationToken)
+ public Task CreateConnection(object connection, CancellationToken cancellationToken)
{
var quicConnection = connection as QuicConnection;
@@ -32,7 +32,7 @@ public async Task CreateConnection(object connection, CancellationT
pipcPipeConnection.AcceptInboundStream(cancellationToken);
- return pipcPipeConnection;
+ return Task.FromResult(pipcPipeConnection);
}
}
}
From 007bcfeb62c73c92d34bb4a7a841612ade5f4fd3 Mon Sep 17 00:00:00 2001
From: mockingjay <8400684@qq.com>
Date: Thu, 2 May 2024 18:17:04 +0800
Subject: [PATCH 07/18] ini
---
src/SuperSocket.Quic/QuicConnectionListener.cs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/SuperSocket.Quic/QuicConnectionListener.cs b/src/SuperSocket.Quic/QuicConnectionListener.cs
index 62f3f9327..43dcc9fca 100644
--- a/src/SuperSocket.Quic/QuicConnectionListener.cs
+++ b/src/SuperSocket.Quic/QuicConnectionListener.cs
@@ -40,7 +40,8 @@ public bool Start()
ArgumentNullException.ThrowIfNull(options.CertificateOptions);
- options.CertificateOptions.EnsureCertificate();
+ if (options.CertificateOptions.Certificate == null)
+ options.CertificateOptions.EnsureCertificate();
var quicListenerOptions = new QuicListenerOptions
{
From 8b6a690296a965295d85e722aefc2425c46111cf Mon Sep 17 00:00:00 2001
From: mockingjay <8400684@qq.com>
Date: Thu, 2 May 2024 18:24:48 +0800
Subject: [PATCH 08/18] ini
---
.../QuicPipeConnection.cs | 27 ++++++++++++++-----
.../SuperSocket.Tests/QuicHostConfigurator.cs | 2 +-
2 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs b/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
index c60c02657..2fde2b614 100644
--- a/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
+++ b/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
@@ -1,6 +1,5 @@
using System;
using System.Buffers;
-using System.IO;
using System.Net.Quic;
using System.Net.Sockets;
using System.Threading;
@@ -14,7 +13,7 @@ namespace SuperSocket.Quic.Connection
public class QuicPipeConnection : PipeConnection
{
private QuicStream _stream;
- private ValueTask _task;
+ private ValueTask _readStreamTask;
private readonly QuicConnection _quicConnection;
public QuicPipeConnection(QuicConnection quicConnection, ConnectionOptions options) : base(options)
@@ -27,22 +26,27 @@ public QuicPipeConnection(QuicConnection quicConnection, ConnectionOptions optio
protected override async Task StartInputPipeTask(IObjectPipe packagePipe,
CancellationToken cancellationToken)
{
- _stream = await _task;
- await base.StartInputPipeTask(packagePipe, cancellationToken);
+ ArgumentNullException.ThrowIfNull(_readStreamTask);
+
+ _stream = await _readStreamTask.ConfigureAwait(false);
+
+ await base.StartInputPipeTask(packagePipe, cancellationToken).ConfigureAwait(false);
}
- public void OpenOutboundStream(CancellationToken cancellationToken)
+ public void OpenOutboundStream(QuicStreamType quicStreamType, CancellationToken cancellationToken)
{
- _task = _quicConnection.OpenOutboundStreamAsync(QuicStreamType.Bidirectional, cancellationToken);
+ _readStreamTask = _quicConnection.OpenOutboundStreamAsync(quicStreamType, cancellationToken);
}
public void AcceptInboundStream(CancellationToken cancellationToken)
{
- _task = _quicConnection.AcceptInboundStreamAsync(cancellationToken);
+ _readStreamTask = _quicConnection.AcceptInboundStreamAsync(cancellationToken);
}
protected override void Close()
{
+ ThrowIfStreamNull();
+
_stream.Close();
}
@@ -55,12 +59,16 @@ protected override void OnClosed()
protected override async ValueTask FillPipeWithDataAsync(Memory memory,
CancellationToken cancellationToken)
{
+ ThrowIfStreamNull();
+
return await _stream.ReadAsync(memory, cancellationToken).ConfigureAwait(false);
}
protected override async ValueTask SendOverIOAsync(ReadOnlySequence buffer,
CancellationToken cancellationToken)
{
+ ThrowIfStreamNull();
+
var total = 0;
foreach (var data in buffer)
@@ -86,6 +94,11 @@ protected override bool IsIgnorableException(Exception e)
return false;
}
+
+ private void ThrowIfStreamNull()
+ {
+ ArgumentNullException.ThrowIfNull(_stream);
+ }
}
}
diff --git a/test/SuperSocket.Tests/QuicHostConfigurator.cs b/test/SuperSocket.Tests/QuicHostConfigurator.cs
index f42b01de0..fcdb837fb 100644
--- a/test/SuperSocket.Tests/QuicHostConfigurator.cs
+++ b/test/SuperSocket.Tests/QuicHostConfigurator.cs
@@ -125,7 +125,7 @@ protected override async ValueTask ConnectAsync(EndPoint remoteEndPoint,
var connection = new QuicPipeConnection(quicConnection, Options);
- connection.OpenOutboundStream(cancellationToken);
+ connection.OpenOutboundStream(QuicStreamType.Bidirectional, cancellationToken);
SetupConnection(connection);
From 42b837eee6bce9e65a688f81bd3a1c361f6f8b7f Mon Sep 17 00:00:00 2001
From: wujun <8400684@qq.com>
Date: Thu, 2 May 2024 18:30:01 +0800
Subject: [PATCH 09/18] add quic
---
test/SuperSocket.Tests/ClientTest.cs | 1 +
1 file changed, 1 insertion(+)
diff --git a/test/SuperSocket.Tests/ClientTest.cs b/test/SuperSocket.Tests/ClientTest.cs
index 3b2fda78c..38260c883 100644
--- a/test/SuperSocket.Tests/ClientTest.cs
+++ b/test/SuperSocket.Tests/ClientTest.cs
@@ -198,6 +198,7 @@ public void TestCancellationTokenIsBeingUsedWhenConnecting()
[InlineData(typeof(SecureHostConfigurator))]
[InlineData(typeof(GzipSecureHostConfigurator))]
[InlineData(typeof(GzipHostConfigurator))]
+ [InlineData(typeof(QuicHostConfigurator))]
public async Task TestCommandLine(Type hostConfiguratorType)
{
var packageEvent = new AutoResetEvent(false);
From c1fcd79c78432c9348499ace97cd835b8a5fefe9 Mon Sep 17 00:00:00 2001
From: mockingjay <8400684@qq.com>
Date: Thu, 2 May 2024 19:21:51 +0800
Subject: [PATCH 10/18] add quic testBindLocalEndPoint
---
test/SuperSocket.Tests/ClientTest.cs | 15 ++++++++-------
test/SuperSocket.Tests/QuicHostConfigurator.cs | 1 +
2 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/test/SuperSocket.Tests/ClientTest.cs b/test/SuperSocket.Tests/ClientTest.cs
index 38260c883..e902680b0 100644
--- a/test/SuperSocket.Tests/ClientTest.cs
+++ b/test/SuperSocket.Tests/ClientTest.cs
@@ -32,11 +32,11 @@ public ClientTest(ITestOutputHelper outputHelper)
[Theory]
[Trait("Category", "Client.TestEcho")]
- // [InlineData(typeof(RegularHostConfigurator), false)]
- // [InlineData(typeof(SecureHostConfigurator), false)]
- // [InlineData(typeof(GzipHostConfigurator), false)]
- // [InlineData(typeof(GzipSecureHostConfigurator), false)]
- // [InlineData(typeof(RegularHostConfigurator), true)]
+ [InlineData(typeof(RegularHostConfigurator), false)]
+ [InlineData(typeof(SecureHostConfigurator), false)]
+ [InlineData(typeof(GzipHostConfigurator), false)]
+ [InlineData(typeof(GzipSecureHostConfigurator), false)]
+ [InlineData(typeof(RegularHostConfigurator), true)]
[InlineData(typeof(QuicHostConfigurator), false)]
public async Task TestEcho(Type hostConfiguratorType, bool clientReadAsDemand)
{
@@ -98,8 +98,9 @@ public async Task TestEcho(Type hostConfiguratorType, bool clientReadAsDemand)
}
[Theory]
- [InlineData(typeof(RegularHostConfigurator))]
- [InlineData(typeof(GzipHostConfigurator))]
+ // [InlineData(typeof(RegularHostConfigurator))]
+ // [InlineData(typeof(GzipHostConfigurator))]
+ [InlineData(typeof(QuicHostConfigurator))]
[Trait("Category", "Client.TestBindLocalEndPoint")]
public async Task TestBindLocalEndPoint(Type hostConfiguratorType)
{
diff --git a/test/SuperSocket.Tests/QuicHostConfigurator.cs b/test/SuperSocket.Tests/QuicHostConfigurator.cs
index fcdb837fb..4210bf45c 100644
--- a/test/SuperSocket.Tests/QuicHostConfigurator.cs
+++ b/test/SuperSocket.Tests/QuicHostConfigurator.cs
@@ -107,6 +107,7 @@ protected override async ValueTask ConnectAsync(EndPoint remoteEndPoint,
DefaultCloseErrorCode = 0,
DefaultStreamErrorCode = 0,
RemoteEndPoint = remoteEndPoint,
+ LocalEndPoint = LocalEndPoint,
ClientAuthenticationOptions = new SslClientAuthenticationOptions
{
ApplicationProtocols = new List { SslApplicationProtocol.Http3 },
From 44787ff47c1162804c8f1e67c2ea2fa7d65f8ea4 Mon Sep 17 00:00:00 2001
From: mockingjay <8400684@qq.com>
Date: Thu, 2 May 2024 19:34:13 +0800
Subject: [PATCH 11/18] add quic
---
.../QuicPipeConnection.cs | 18 +++++++++---------
test/SuperSocket.Tests/ClientTest.cs | 4 ++--
2 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs b/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
index 2fde2b614..251f8f394 100644
--- a/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
+++ b/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
@@ -13,7 +13,7 @@ namespace SuperSocket.Quic.Connection
public class QuicPipeConnection : PipeConnection
{
private QuicStream _stream;
- private ValueTask _readStreamTask;
+ private QuicStream _readStreamTask;
private readonly QuicConnection _quicConnection;
public QuicPipeConnection(QuicConnection quicConnection, ConnectionOptions options) : base(options)
@@ -28,25 +28,25 @@ protected override async Task StartInputPipeTask(IObjectPipe FillPipeWithDataAsync(Memory memor
CancellationToken cancellationToken)
{
ThrowIfStreamNull();
-
+
return await _stream.ReadAsync(memory, cancellationToken).ConfigureAwait(false);
}
@@ -68,7 +68,7 @@ protected override async ValueTask SendOverIOAsync(ReadOnlySequence b
CancellationToken cancellationToken)
{
ThrowIfStreamNull();
-
+
var total = 0;
foreach (var data in buffer)
diff --git a/test/SuperSocket.Tests/ClientTest.cs b/test/SuperSocket.Tests/ClientTest.cs
index e902680b0..0f1103425 100644
--- a/test/SuperSocket.Tests/ClientTest.cs
+++ b/test/SuperSocket.Tests/ClientTest.cs
@@ -98,8 +98,8 @@ public async Task TestEcho(Type hostConfiguratorType, bool clientReadAsDemand)
}
[Theory]
- // [InlineData(typeof(RegularHostConfigurator))]
- // [InlineData(typeof(GzipHostConfigurator))]
+ [InlineData(typeof(RegularHostConfigurator))]
+ [InlineData(typeof(GzipHostConfigurator))]
[InlineData(typeof(QuicHostConfigurator))]
[Trait("Category", "Client.TestBindLocalEndPoint")]
public async Task TestBindLocalEndPoint(Type hostConfiguratorType)
From d714a5b6034fab01740839e2b6859c640eb4bccf Mon Sep 17 00:00:00 2001
From: mockingjay <8400684@qq.com>
Date: Thu, 2 May 2024 19:37:30 +0800
Subject: [PATCH 12/18] add quic
---
.../QuicPipeConnection.cs | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs b/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
index 251f8f394..2fde2b614 100644
--- a/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
+++ b/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
@@ -13,7 +13,7 @@ namespace SuperSocket.Quic.Connection
public class QuicPipeConnection : PipeConnection
{
private QuicStream _stream;
- private QuicStream _readStreamTask;
+ private ValueTask _readStreamTask;
private readonly QuicConnection _quicConnection;
public QuicPipeConnection(QuicConnection quicConnection, ConnectionOptions options) : base(options)
@@ -28,25 +28,25 @@ protected override async Task StartInputPipeTask(IObjectPipe FillPipeWithDataAsync(Memory memor
CancellationToken cancellationToken)
{
ThrowIfStreamNull();
-
+
return await _stream.ReadAsync(memory, cancellationToken).ConfigureAwait(false);
}
@@ -68,7 +68,7 @@ protected override async ValueTask SendOverIOAsync(ReadOnlySequence b
CancellationToken cancellationToken)
{
ThrowIfStreamNull();
-
+
var total = 0;
foreach (var data in buffer)
From 4b491b99b936a7eb763576a7405cd5cd2ec3e98e Mon Sep 17 00:00:00 2001
From: mockingjay <8400684@qq.com>
Date: Thu, 2 May 2024 23:01:13 +0800
Subject: [PATCH 13/18] fix bugs
---
src/SuperSocket.Quic.Connection/QuicPipeConnection.cs | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs b/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
index 2fde2b614..5331cfcb7 100644
--- a/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
+++ b/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
@@ -86,13 +86,14 @@ protected override bool IsIgnorableException(Exception e)
if (base.IsIgnorableException(e))
return true;
- if (e is SocketException se)
+ switch (e)
{
- if (se.IsIgnorableSocketException())
+ case QuicException:
+ case SocketException se when se.IsIgnorableSocketException():
return true;
+ default:
+ return false;
}
-
- return false;
}
private void ThrowIfStreamNull()
From 77f48fd0c74ecf5c66914c8e2be8dcd5d28e0389 Mon Sep 17 00:00:00 2001
From: mockingjay <8400684@qq.com>
Date: Fri, 3 May 2024 12:04:58 +0800
Subject: [PATCH 14/18] add quic
---
.../QuicPipeConnection.cs | 78 ++++---------------
.../QuicPipeStream.cs | 75 ++++++++++++++++++
src/SuperSocket.Quic/QuicConnectionFactory.cs | 5 +-
.../QuicConnectionListener.cs | 2 +-
.../QuicServerHostBuilderExtensions.cs | 4 +-
src/SuperSocket.Quic/QuicTransportOptions.cs | 28 +++++++
.../SuperSocket.Tests/QuicHostConfigurator.cs | 6 +-
test/SuperSocket.Tests/TestClassBase.cs | 3 +-
8 files changed, 128 insertions(+), 73 deletions(-)
create mode 100644 src/SuperSocket.Quic.Connection/QuicPipeStream.cs
create mode 100644 src/SuperSocket.Quic/QuicTransportOptions.cs
diff --git a/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs b/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
index 5331cfcb7..f09c6ebf8 100644
--- a/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
+++ b/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
@@ -1,5 +1,5 @@
using System;
-using System.Buffers;
+using System.Net;
using System.Net.Quic;
using System.Net.Sockets;
using System.Threading;
@@ -10,75 +10,28 @@
namespace SuperSocket.Quic.Connection
{
- public class QuicPipeConnection : PipeConnection
+ public class QuicPipeConnection : StreamPipeConnection
{
- private QuicStream _stream;
- private ValueTask _readStreamTask;
- private readonly QuicConnection _quicConnection;
+ private readonly QuicPipeStream _stream;
- public QuicPipeConnection(QuicConnection quicConnection, ConnectionOptions options) : base(options)
+ public QuicPipeConnection(QuicPipeStream stream, EndPoint remoteEndPoint, ConnectionOptions options)
+ : this(stream, remoteEndPoint, null, options)
{
- _quicConnection = quicConnection;
- RemoteEndPoint = quicConnection.RemoteEndPoint;
- LocalEndPoint = quicConnection.LocalEndPoint;
+ _stream = stream;
}
- protected override async Task StartInputPipeTask(IObjectPipe packagePipe,
- CancellationToken cancellationToken)
- {
- ArgumentNullException.ThrowIfNull(_readStreamTask);
-
- _stream = await _readStreamTask.ConfigureAwait(false);
-
- await base.StartInputPipeTask(packagePipe, cancellationToken).ConfigureAwait(false);
- }
-
- public void OpenOutboundStream(QuicStreamType quicStreamType, CancellationToken cancellationToken)
- {
- _readStreamTask = _quicConnection.OpenOutboundStreamAsync(quicStreamType, cancellationToken);
- }
-
- public void AcceptInboundStream(CancellationToken cancellationToken)
- {
- _readStreamTask = _quicConnection.AcceptInboundStreamAsync(cancellationToken);
- }
-
- protected override void Close()
- {
- ThrowIfStreamNull();
-
- _stream.Close();
- }
-
- protected override void OnClosed()
+ public QuicPipeConnection(QuicPipeStream stream, EndPoint remoteEndPoint, EndPoint localEndPoint,
+ ConnectionOptions options)
+ : base(stream, remoteEndPoint, localEndPoint, options)
{
- _stream = null;
- base.OnClosed();
+ _stream = stream;
}
- protected override async ValueTask FillPipeWithDataAsync(Memory memory,
- CancellationToken cancellationToken)
- {
- ThrowIfStreamNull();
-
- return await _stream.ReadAsync(memory, cancellationToken).ConfigureAwait(false);
- }
-
- protected override async ValueTask SendOverIOAsync(ReadOnlySequence buffer,
+ protected override async Task StartInputPipeTask(IObjectPipe packagePipe,
CancellationToken cancellationToken)
{
- ThrowIfStreamNull();
-
- var total = 0;
-
- foreach (var data in buffer)
- {
- await _stream.WriteAsync(data, cancellationToken).ConfigureAwait(false);
- total += data.Length;
- }
-
- await _stream.FlushAsync(cancellationToken).ConfigureAwait(false);
- return total;
+ await _stream.OpenStreamAsync(cancellationToken);
+ await base.StartInputPipeTask(packagePipe, cancellationToken);
}
protected override bool IsIgnorableException(Exception e)
@@ -95,11 +48,6 @@ protected override bool IsIgnorableException(Exception e)
return false;
}
}
-
- private void ThrowIfStreamNull()
- {
- ArgumentNullException.ThrowIfNull(_stream);
- }
}
}
diff --git a/src/SuperSocket.Quic.Connection/QuicPipeStream.cs b/src/SuperSocket.Quic.Connection/QuicPipeStream.cs
new file mode 100644
index 000000000..5acf7a724
--- /dev/null
+++ b/src/SuperSocket.Quic.Connection/QuicPipeStream.cs
@@ -0,0 +1,75 @@
+using System;
+using System.IO;
+using System.Net.Quic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace SuperSocket.Quic.Connection;
+
+#pragma warning disable CA2252
+
+public sealed class QuicPipeStream : Stream
+{
+ private Stream _stream;
+
+ private readonly bool _serverStream;
+ private readonly QuicConnection _connection;
+
+ public QuicPipeStream(QuicConnection connection, bool serverStream)
+ {
+ _connection = connection;
+ _serverStream = serverStream;
+ }
+
+ public override bool CanRead => _stream.CanRead;
+ public override bool CanSeek => _stream.CanSeek;
+ public override bool CanWrite => _stream.CanWrite;
+ public override long Length => _stream.Length;
+
+ public override long Position
+ {
+ get => _stream.Position;
+ set => _stream.Position = value;
+ }
+
+ public async ValueTask OpenStreamAsync(CancellationToken cancellationToken)
+ {
+ if (_serverStream)
+ {
+ _stream = await _connection.AcceptInboundStreamAsync(cancellationToken);
+ }
+ else
+ {
+ _stream = await _connection.OpenOutboundStreamAsync(QuicStreamType.Bidirectional, cancellationToken);
+ }
+ }
+
+ public override void Flush() => _stream.Flush();
+
+ public override int Read(byte[] buffer, int offset, int count) => _stream.Read(buffer, offset, count);
+
+ public override long Seek(long offset, SeekOrigin origin) => _stream.Seek(offset, origin);
+
+ public override void SetLength(long value) => _stream.Flush();
+
+ public override void Close() => _stream.Close();
+
+ public override Task FlushAsync(CancellationToken cancellationToken) => _stream.FlushAsync(cancellationToken);
+
+ public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) =>
+ _stream.ReadAsync(buffer, offset, count, cancellationToken);
+
+ public override ValueTask ReadAsync(Memory buffer,
+ CancellationToken cancellationToken = default) => _stream.ReadAsync(buffer, cancellationToken);
+
+ public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) =>
+ _stream.WriteAsync(buffer, offset, count, cancellationToken);
+
+ public override ValueTask WriteAsync(ReadOnlyMemory buffer,
+ CancellationToken cancellationToken = default) =>
+ _stream.WriteAsync(buffer, cancellationToken);
+
+ public override void Write(ReadOnlySpan buffer) => _stream.Flush();
+
+ public override void Write(byte[] buffer, int offset, int count) => _stream.Flush();
+}
\ No newline at end of file
diff --git a/src/SuperSocket.Quic/QuicConnectionFactory.cs b/src/SuperSocket.Quic/QuicConnectionFactory.cs
index 795808556..62694c3d6 100644
--- a/src/SuperSocket.Quic/QuicConnectionFactory.cs
+++ b/src/SuperSocket.Quic/QuicConnectionFactory.cs
@@ -28,9 +28,10 @@ public Task CreateConnection(object connection, CancellationToken c
{
var quicConnection = connection as QuicConnection;
- var pipcPipeConnection = new QuicPipeConnection(quicConnection, _connectionOptions);
+ var quicStream = new QuicPipeStream(quicConnection, true);
- pipcPipeConnection.AcceptInboundStream(cancellationToken);
+ var pipcPipeConnection = new QuicPipeConnection(quicStream, quicConnection.RemoteEndPoint,
+ quicConnection.LocalEndPoint, _connectionOptions);
return Task.FromResult(pipcPipeConnection);
}
diff --git a/src/SuperSocket.Quic/QuicConnectionListener.cs b/src/SuperSocket.Quic/QuicConnectionListener.cs
index 43dcc9fca..6e2809d2d 100644
--- a/src/SuperSocket.Quic/QuicConnectionListener.cs
+++ b/src/SuperSocket.Quic/QuicConnectionListener.cs
@@ -53,7 +53,7 @@ public bool Start()
{
DefaultStreamErrorCode = 0,
DefaultCloseErrorCode = 0,
- //IdleTimeout = 0,
+ IdleTimeout = TimeSpan.FromMicroseconds(10),
//MaxInboundBidirectionalStreams = 0,
//MaxInboundUnidirectionalStreams = 0,
ServerAuthenticationOptions = new SslServerAuthenticationOptions()
diff --git a/src/SuperSocket.Quic/QuicServerHostBuilderExtensions.cs b/src/SuperSocket.Quic/QuicServerHostBuilderExtensions.cs
index 8d13e0d93..a8f275141 100644
--- a/src/SuperSocket.Quic/QuicServerHostBuilderExtensions.cs
+++ b/src/SuperSocket.Quic/QuicServerHostBuilderExtensions.cs
@@ -13,8 +13,8 @@ public static class QuicServerHostBuilderExtensions
{
public static ISuperSocketHostBuilder UseQuic(this ISuperSocketHostBuilder hostBuilder)
{
- if (!QuicListener.IsSupported)
- throw new PlatformNotSupportedException("System.Net.Quic is not supported on this platform.");
+ // if (!QuicListener.IsSupported)
+ // throw new PlatformNotSupportedException("System.Net.Quic is not supported on this platform.");
return hostBuilder.ConfigureServices((_, services) =>
{
diff --git a/src/SuperSocket.Quic/QuicTransportOptions.cs b/src/SuperSocket.Quic/QuicTransportOptions.cs
new file mode 100644
index 000000000..9857b9378
--- /dev/null
+++ b/src/SuperSocket.Quic/QuicTransportOptions.cs
@@ -0,0 +1,28 @@
+namespace SuperSocket.Quic;
+
+public sealed class QuicTransportOptions
+{
+ public int MaxBidirectionalStreamCount { get; set; } = 100;
+
+ ///
+ /// The maximum number of concurrent inbound uni-directional streams per connection.
+ ///
+ public int MaxUnidirectionalStreamCount { get; set; } = 10;
+
+ /// The maximum read size.
+ public long MaxReadBufferSize { get; set; } = 1048576L;
+
+ /// The maximum write size.
+ public long MaxWriteBufferSize { get; set; } = 65536L;
+
+ /// The maximum length of the pending connection queue.
+ public int Backlog { get; set; } = 512;
+
+ ///
+ /// Error code used when the stream needs to abort the read or write side of the stream internally.
+ ///
+ public long DefaultStreamErrorCode { get; set; }
+
+ /// Error code used when an open connection is disposed.
+ public long DefaultCloseErrorCode { get; set; }
+}
\ No newline at end of file
diff --git a/test/SuperSocket.Tests/QuicHostConfigurator.cs b/test/SuperSocket.Tests/QuicHostConfigurator.cs
index 4210bf45c..80e1444fd 100644
--- a/test/SuperSocket.Tests/QuicHostConfigurator.cs
+++ b/test/SuperSocket.Tests/QuicHostConfigurator.cs
@@ -18,6 +18,7 @@
using SuperSocket.Server.Abstractions.Host;
using SuperSocket.Client;
using SuperSocket.ProtoBase;
+using SuperSocket.Quic;
using SuperSocket.Quic.Connection;
namespace SuperSocket.Tests
@@ -124,9 +125,10 @@ protected override async ValueTask ConnectAsync(EndPoint remoteEndPoint,
return false;
}
- var connection = new QuicPipeConnection(quicConnection, Options);
+ var quicStream = new QuicPipeStream(quicConnection, false);
- connection.OpenOutboundStream(QuicStreamType.Bidirectional, cancellationToken);
+ var connection = new QuicPipeConnection(quicStream, quicConnection.RemoteEndPoint,
+ quicConnection.LocalEndPoint, Options);
SetupConnection(connection);
diff --git a/test/SuperSocket.Tests/TestClassBase.cs b/test/SuperSocket.Tests/TestClassBase.cs
index eaf9c24e4..17dbe06d0 100644
--- a/test/SuperSocket.Tests/TestClassBase.cs
+++ b/test/SuperSocket.Tests/TestClassBase.cs
@@ -10,6 +10,7 @@
using Microsoft.Extensions.Logging;
using SuperSocket;
using SuperSocket.ProtoBase;
+using SuperSocket.Quic;
using SuperSocket.Server;
using SuperSocket.Server.Host;
using SuperSocket.Server.Abstractions.Host;
@@ -87,7 +88,7 @@ protected ISuperSocketHostBuilder Configure(ISuperSocketHostBuilder hostBuilder,
{ "serverOptions:name", "TestServer" },
{ "serverOptions:listeners:0:ip", "Any" },
{ "serverOptions:listeners:0:backLog", "100" },
- { "serverOptions:listeners:0:port", DefaultServerPort.ToString() }
+ { "serverOptions:listeners:0:port", DefaultServerPort.ToString() },
});
})
.ConfigureLogging((hostCtx, loggingBuilder) =>
From e3ed393ae686f4bee4190a681245ddf9edfaa210 Mon Sep 17 00:00:00 2001
From: mockingjay <8400684@qq.com>
Date: Fri, 3 May 2024 12:34:10 +0800
Subject: [PATCH 15/18] add quic
---
src/SuperSocket.Quic/QuicConnectionFactory.cs | 21 ++++++++++++----
.../QuicConnectionFactoryBuilder.cs | 9 ++++++-
.../QuicConnectionListener.cs | 12 +++++-----
...QuicConnectionStreamInitializersFactory.cs | 23 ++++++++++++++++++
.../QuicPipeStreamInitializer.cs | 24 +++++++++++++++++++
.../QuicServerHostBuilderExtensions.cs | 1 +
src/SuperSocket.Quic/SuperSocket.Quic.csproj | 1 +
.../IConnectionStreamInitializer.cs | 2 +-
.../Connection/GZipStreamInitializer.cs | 4 +++-
.../Connection/NetworkStreamInitializer.cs | 4 +++-
.../Connection/SslStreamInitializer.cs | 4 +++-
.../Connection/TcpConnectionFactory.cs | 2 +-
12 files changed, 90 insertions(+), 17 deletions(-)
create mode 100644 src/SuperSocket.Quic/QuicConnectionStreamInitializersFactory.cs
create mode 100644 src/SuperSocket.Quic/QuicPipeStreamInitializer.cs
diff --git a/src/SuperSocket.Quic/QuicConnectionFactory.cs b/src/SuperSocket.Quic/QuicConnectionFactory.cs
index 62694c3d6..42ff815e4 100644
--- a/src/SuperSocket.Quic/QuicConnectionFactory.cs
+++ b/src/SuperSocket.Quic/QuicConnectionFactory.cs
@@ -1,3 +1,6 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
using System.Net.Quic;
using System.Threading;
using System.Threading.Tasks;
@@ -5,6 +8,7 @@
using SuperSocket.Connection;
using SuperSocket.Quic.Connection;
using SuperSocket.Server.Abstractions;
+using SuperSocket.Server.Abstractions.Connections;
#pragma warning disable CA2252
namespace SuperSocket.Quic
@@ -14,26 +18,33 @@ internal class QuicConnectionFactory : IConnectionFactory
private readonly ILogger _logger;
private readonly ListenOptions _listenOptions;
private readonly ConnectionOptions _connectionOptions;
+ private readonly IEnumerable _connectionStreamInitializers;
public QuicConnectionFactory(
+ IConnectionStreamInitializersFactory connectionStreamInitializersFactory,
ListenOptions listenOptions,
ConnectionOptions connectionOptions)
{
_listenOptions = listenOptions;
_connectionOptions = connectionOptions;
_logger = connectionOptions.Logger;
+ _connectionStreamInitializers = connectionStreamInitializersFactory.Create(_listenOptions);
}
- public Task CreateConnection(object connection, CancellationToken cancellationToken)
+ public async Task CreateConnection(object connection, CancellationToken cancellationToken)
{
+ Stream stream = null;
var quicConnection = connection as QuicConnection;
- var quicStream = new QuicPipeStream(quicConnection, true);
+ foreach (var initializer in _connectionStreamInitializers)
+ {
+ stream = await initializer.InitializeAsync(quicConnection, cancellationToken);
+ }
- var pipcPipeConnection = new QuicPipeConnection(quicStream, quicConnection.RemoteEndPoint,
- quicConnection.LocalEndPoint, _connectionOptions);
+ var quicStream = (QuicPipeStream)stream;
- return Task.FromResult(pipcPipeConnection);
+ return new QuicPipeConnection(quicStream, quicConnection.RemoteEndPoint,
+ quicConnection.LocalEndPoint, _connectionOptions);
}
}
}
diff --git a/src/SuperSocket.Quic/QuicConnectionFactoryBuilder.cs b/src/SuperSocket.Quic/QuicConnectionFactoryBuilder.cs
index ee4df7c9f..b4f1dd36d 100644
--- a/src/SuperSocket.Quic/QuicConnectionFactoryBuilder.cs
+++ b/src/SuperSocket.Quic/QuicConnectionFactoryBuilder.cs
@@ -6,9 +6,16 @@ namespace SuperSocket.Quic
{
internal class QuicConnectionFactoryBuilder : IConnectionFactoryBuilder
{
+ private readonly IConnectionStreamInitializersFactory _connectionStreamInitializersFactory;
+
+ public QuicConnectionFactoryBuilder(IConnectionStreamInitializersFactory connectionStreamInitializersFactory)
+ {
+ _connectionStreamInitializersFactory = connectionStreamInitializersFactory;
+ }
+
public IConnectionFactory Build(ListenOptions listenOptions, ConnectionOptions connectionOptions)
{
- return new QuicConnectionFactory(listenOptions, connectionOptions);
+ return new QuicConnectionFactory(_connectionStreamInitializersFactory,listenOptions, connectionOptions);
}
}
}
\ No newline at end of file
diff --git a/src/SuperSocket.Quic/QuicConnectionListener.cs b/src/SuperSocket.Quic/QuicConnectionListener.cs
index 6e2809d2d..93f2111fb 100644
--- a/src/SuperSocket.Quic/QuicConnectionListener.cs
+++ b/src/SuperSocket.Quic/QuicConnectionListener.cs
@@ -16,7 +16,7 @@ internal sealed class QuicConnectionListener : IConnectionListener
{
private readonly ILogger _logger;
- private QuicListener _listenSocket;
+ private QuicListener _listenQuic;
private CancellationTokenSource _cancellationTokenSource;
private TaskCompletionSource _stopTaskCompletionSource;
public IConnectionFactory ConnectionFactory { get; }
@@ -70,11 +70,11 @@ public bool Start()
var result = QuicListener.ListenAsync(quicListenerOptions);
if (result.IsCompleted)
- _listenSocket = result.Result;
+ _listenQuic = result.Result;
else
- _listenSocket = result.GetAwaiter().GetResult();
+ _listenQuic = result.GetAwaiter().GetResult();
- var listenSocket = _listenSocket;
+ var listenSocket = _listenQuic;
IsRunning = true;
@@ -138,7 +138,7 @@ private async void OnNewClientAccept(QuicConnection quicConnection, Cancellation
public async Task StopAsync()
{
- var listenSocket = _listenSocket;
+ var listenSocket = _listenQuic;
if (listenSocket == null)
return;
@@ -146,7 +146,7 @@ public async Task StopAsync()
_stopTaskCompletionSource = new TaskCompletionSource();
_cancellationTokenSource.Cancel();
- await _listenSocket.DisposeAsync();
+ await _listenQuic.DisposeAsync();
await _stopTaskCompletionSource.Task;
}
diff --git a/src/SuperSocket.Quic/QuicConnectionStreamInitializersFactory.cs b/src/SuperSocket.Quic/QuicConnectionStreamInitializersFactory.cs
new file mode 100644
index 000000000..a274ac093
--- /dev/null
+++ b/src/SuperSocket.Quic/QuicConnectionStreamInitializersFactory.cs
@@ -0,0 +1,23 @@
+using System.Collections.Generic;
+using SuperSocket.Server.Abstractions;
+using SuperSocket.Server.Abstractions.Connections;
+using SuperSocket.Server.Connection;
+
+namespace SuperSocket.Quic;
+
+internal class QuicConnectionStreamInitializersFactory : DefaultConnectionStreamInitializersFactory
+{
+ public override IEnumerable Create(ListenOptions listenOptions)
+ {
+ var connectionStreamInitializers = new List();
+
+ if (CompressionLevel != System.IO.Compression.CompressionLevel.NoCompression)
+ connectionStreamInitializers.Add(new GZipStreamInitializer());
+
+ connectionStreamInitializers.Add(new QuicPipeStreamInitializer());
+
+ connectionStreamInitializers.ForEach(initializer => initializer.Setup(listenOptions));
+
+ return connectionStreamInitializers;
+ }
+}
\ No newline at end of file
diff --git a/src/SuperSocket.Quic/QuicPipeStreamInitializer.cs b/src/SuperSocket.Quic/QuicPipeStreamInitializer.cs
new file mode 100644
index 000000000..1dd2cb57b
--- /dev/null
+++ b/src/SuperSocket.Quic/QuicPipeStreamInitializer.cs
@@ -0,0 +1,24 @@
+using System.IO;
+using System.Net.Quic;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+using SuperSocket.Quic.Connection;
+using SuperSocket.Server.Abstractions;
+using SuperSocket.Server.Abstractions.Connections;
+
+namespace SuperSocket.Quic;
+
+internal class QuicPipeStreamInitializer : IConnectionStreamInitializer
+{
+ public void Setup(ListenOptions listenOptions)
+ {
+ }
+
+ public Task InitializeAsync(object connection, CancellationToken cancellationToken)
+ {
+ var quicConnection = (QuicConnection)connection;
+
+ return Task.FromResult(new QuicPipeStream(quicConnection, true));
+ }
+}
\ No newline at end of file
diff --git a/src/SuperSocket.Quic/QuicServerHostBuilderExtensions.cs b/src/SuperSocket.Quic/QuicServerHostBuilderExtensions.cs
index a8f275141..e712077f0 100644
--- a/src/SuperSocket.Quic/QuicServerHostBuilderExtensions.cs
+++ b/src/SuperSocket.Quic/QuicServerHostBuilderExtensions.cs
@@ -18,6 +18,7 @@ public static ISuperSocketHostBuilder UseQuic(this ISuperSocketHostBuilder hostB
return hostBuilder.ConfigureServices((_, services) =>
{
+ services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
}) as ISuperSocketHostBuilder;
diff --git a/src/SuperSocket.Quic/SuperSocket.Quic.csproj b/src/SuperSocket.Quic/SuperSocket.Quic.csproj
index ce7765350..d2241818c 100644
--- a/src/SuperSocket.Quic/SuperSocket.Quic.csproj
+++ b/src/SuperSocket.Quic/SuperSocket.Quic.csproj
@@ -9,5 +9,6 @@
+
diff --git a/src/SuperSocket.Server.Abstractions/Connections/IConnectionStreamInitializer.cs b/src/SuperSocket.Server.Abstractions/Connections/IConnectionStreamInitializer.cs
index 78c7dc2ab..6bb003f25 100644
--- a/src/SuperSocket.Server.Abstractions/Connections/IConnectionStreamInitializer.cs
+++ b/src/SuperSocket.Server.Abstractions/Connections/IConnectionStreamInitializer.cs
@@ -9,6 +9,6 @@ public interface IConnectionStreamInitializer
{
void Setup(ListenOptions listenOptions);
- Task InitializeAsync(Socket socket, Stream stream, CancellationToken cancellationToken);
+ Task InitializeAsync(object connection, CancellationToken cancellationToken);
}
}
\ No newline at end of file
diff --git a/src/SuperSocket.Server/Connection/GZipStreamInitializer.cs b/src/SuperSocket.Server/Connection/GZipStreamInitializer.cs
index 0990bf847..2bbe15920 100644
--- a/src/SuperSocket.Server/Connection/GZipStreamInitializer.cs
+++ b/src/SuperSocket.Server/Connection/GZipStreamInitializer.cs
@@ -13,8 +13,10 @@ public class GZipStreamInitializer : IConnectionStreamInitializer
{
public CompressionLevel CompressionLevel { get; private set; }
- public Task InitializeAsync(Socket socket, Stream stream, CancellationToken cancellationToken)
+ public Task InitializeAsync(object connection, CancellationToken cancellationToken)
{
+ var stream = (Stream)connection;
+
var connectionStream = new ReadWriteDelegateStream(
stream,
new GZipStream(stream, CompressionMode.Decompress),
diff --git a/src/SuperSocket.Server/Connection/NetworkStreamInitializer.cs b/src/SuperSocket.Server/Connection/NetworkStreamInitializer.cs
index cfc2531f0..cdf8b2277 100644
--- a/src/SuperSocket.Server/Connection/NetworkStreamInitializer.cs
+++ b/src/SuperSocket.Server/Connection/NetworkStreamInitializer.cs
@@ -13,8 +13,10 @@ public void Setup(ListenOptions listenOptions)
{
}
- public Task InitializeAsync(Socket socket, Stream stream, CancellationToken cancellationToken)
+ public Task InitializeAsync(object connection, CancellationToken cancellationToken)
{
+ var socket = (Socket)connection;
+
return Task.FromResult(new NetworkStream(socket, true));
}
}
diff --git a/src/SuperSocket.Server/Connection/SslStreamInitializer.cs b/src/SuperSocket.Server/Connection/SslStreamInitializer.cs
index 68715f04e..1b18738e3 100644
--- a/src/SuperSocket.Server/Connection/SslStreamInitializer.cs
+++ b/src/SuperSocket.Server/Connection/SslStreamInitializer.cs
@@ -32,8 +32,10 @@ public void Setup(ListenOptions listenOptions)
_authOptions = authOptions;
}
- public async Task InitializeAsync(Socket socket, Stream stream, CancellationToken cancellationToken)
+ public async Task InitializeAsync(object connection, CancellationToken cancellationToken)
{
+ var stream = (Stream)connection;
+
var sslStream = new SslStream(stream, false);
await sslStream.AuthenticateAsServerAsync(_authOptions, cancellationToken);
return sslStream;
diff --git a/src/SuperSocket.Server/Connection/TcpConnectionFactory.cs b/src/SuperSocket.Server/Connection/TcpConnectionFactory.cs
index 9c6ff92a9..95bfb6166 100644
--- a/src/SuperSocket.Server/Connection/TcpConnectionFactory.cs
+++ b/src/SuperSocket.Server/Connection/TcpConnectionFactory.cs
@@ -37,7 +37,7 @@ public override async Task CreateConnection(object connection, Canc
foreach (var initializer in connectionStreamInitializers)
{
- stream = await initializer.InitializeAsync(socket, stream, cancellationToken);
+ stream = await initializer.InitializeAsync(socket, cancellationToken);
}
return new StreamPipeConnection(stream, socket.RemoteEndPoint, socket.LocalEndPoint, ConnectionOptions);
From f4bb0a282fc593c42e5aeb3556370389ea1cd1e8 Mon Sep 17 00:00:00 2001
From: mockingjay <8400684@qq.com>
Date: Fri, 3 May 2024 12:39:52 +0800
Subject: [PATCH 16/18] add quic
---
src/SuperSocket.Quic/QuicConnectionFactory.cs | 4 ----
src/SuperSocket.Quic/QuicConnectionListener.cs | 1 -
src/SuperSocket.Quic/QuicServerHostBuilderExtensions.cs | 6 ++----
3 files changed, 2 insertions(+), 9 deletions(-)
diff --git a/src/SuperSocket.Quic/QuicConnectionFactory.cs b/src/SuperSocket.Quic/QuicConnectionFactory.cs
index 42ff815e4..b99c46230 100644
--- a/src/SuperSocket.Quic/QuicConnectionFactory.cs
+++ b/src/SuperSocket.Quic/QuicConnectionFactory.cs
@@ -1,6 +1,5 @@
using System.Collections.Generic;
using System.IO;
-using System.Linq;
using System.Net.Quic;
using System.Threading;
using System.Threading.Tasks;
@@ -15,7 +14,6 @@ namespace SuperSocket.Quic
{
internal class QuicConnectionFactory : IConnectionFactory
{
- private readonly ILogger _logger;
private readonly ListenOptions _listenOptions;
private readonly ConnectionOptions _connectionOptions;
private readonly IEnumerable _connectionStreamInitializers;
@@ -27,7 +25,6 @@ public QuicConnectionFactory(
{
_listenOptions = listenOptions;
_connectionOptions = connectionOptions;
- _logger = connectionOptions.Logger;
_connectionStreamInitializers = connectionStreamInitializersFactory.Create(_listenOptions);
}
@@ -48,4 +45,3 @@ public async Task CreateConnection(object connection, CancellationT
}
}
}
-#pragma warning restore CA2252
\ No newline at end of file
diff --git a/src/SuperSocket.Quic/QuicConnectionListener.cs b/src/SuperSocket.Quic/QuicConnectionListener.cs
index 93f2111fb..86916c9ee 100644
--- a/src/SuperSocket.Quic/QuicConnectionListener.cs
+++ b/src/SuperSocket.Quic/QuicConnectionListener.cs
@@ -157,4 +157,3 @@ public override string ToString()
}
}
}
-#pragma warning restore CA2252
\ No newline at end of file
diff --git a/src/SuperSocket.Quic/QuicServerHostBuilderExtensions.cs b/src/SuperSocket.Quic/QuicServerHostBuilderExtensions.cs
index e712077f0..c83107345 100644
--- a/src/SuperSocket.Quic/QuicServerHostBuilderExtensions.cs
+++ b/src/SuperSocket.Quic/QuicServerHostBuilderExtensions.cs
@@ -1,5 +1,4 @@
using System;
-using System.Linq;
using System.Net.Quic;
using Microsoft.Extensions.DependencyInjection;
using SuperSocket.Server.Abstractions.Connections;
@@ -13,8 +12,8 @@ public static class QuicServerHostBuilderExtensions
{
public static ISuperSocketHostBuilder UseQuic(this ISuperSocketHostBuilder hostBuilder)
{
- // if (!QuicListener.IsSupported)
- // throw new PlatformNotSupportedException("System.Net.Quic is not supported on this platform.");
+ if (!QuicListener.IsSupported)
+ throw new PlatformNotSupportedException("System.Net.Quic is not supported on this platform.");
return hostBuilder.ConfigureServices((_, services) =>
{
@@ -30,4 +29,3 @@ public static ISuperSocketHostBuilder UseQuic(
}
}
}
-#pragma warning disable CA2252
\ No newline at end of file
From 2ce8e8e53d19c5461948285740f80c67724b7d06 Mon Sep 17 00:00:00 2001
From: mockingjay <8400684@qq.com>
Date: Fri, 3 May 2024 12:41:41 +0800
Subject: [PATCH 17/18] add quic
---
src/SuperSocket.Quic/QuicConnectionFactory.cs | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/SuperSocket.Quic/QuicConnectionFactory.cs b/src/SuperSocket.Quic/QuicConnectionFactory.cs
index b99c46230..9659a1be3 100644
--- a/src/SuperSocket.Quic/QuicConnectionFactory.cs
+++ b/src/SuperSocket.Quic/QuicConnectionFactory.cs
@@ -3,7 +3,6 @@
using System.Net.Quic;
using System.Threading;
using System.Threading.Tasks;
-using Microsoft.Extensions.Logging;
using SuperSocket.Connection;
using SuperSocket.Quic.Connection;
using SuperSocket.Server.Abstractions;
From c78b9b729b86a86363e47659058dfa5fbca4e831 Mon Sep 17 00:00:00 2001
From: mockingjay <8400684@qq.com>
Date: Fri, 3 May 2024 12:43:02 +0800
Subject: [PATCH 18/18] add quic
---
src/SuperSocket.Quic.Connection/QuicPipeConnection.cs | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs b/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
index f09c6ebf8..56e3f2772 100644
--- a/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
+++ b/src/SuperSocket.Quic.Connection/QuicPipeConnection.cs
@@ -49,6 +49,4 @@ protected override bool IsIgnorableException(Exception e)
}
}
}
-}
-
-#pragma warning disable CA2252
\ No newline at end of file
+}
\ No newline at end of file