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