Fix setting timeout too early for QuicConnectionlistener (#46549)
authorJustin Kotalik <jukotali@microsoft.com>
Tue, 5 Jan 2021 01:32:04 +0000 (17:32 -0800)
committerGitHub <noreply@github.com>
Tue, 5 Jan 2021 01:32:04 +0000 (17:32 -0800)
src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicConnection.cs
src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicListener.cs
src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs

index a3442c2..b5af96b 100644 (file)
@@ -54,7 +54,7 @@ namespace System.Net.Quic.Implementations.MsQuic
         });
 
         // constructor for inbound connections
-        public MsQuicConnection(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, IntPtr nativeObjPtr)
+        public MsQuicConnection(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, IntPtr nativeObjPtr, TimeSpan idleTimeout)
         {
             _localEndPoint = localEndPoint;
             _remoteEndPoint = remoteEndPoint;
@@ -62,6 +62,8 @@ namespace System.Net.Quic.Implementations.MsQuic
             _connected = true;
 
             SetCallbackHandler();
+
+            SetIdleTimeout(idleTimeout);
         }
 
         // constructor for outbound connections
index d100d79..69b0c14 100644 (file)
@@ -50,8 +50,6 @@ namespace System.Net.Quic.Implementations.MsQuic
             _sslOptions = options.ServerAuthenticationOptions!;
             _listenEndPoint = options.ListenEndPoint!;
 
-            SetIdleTimeout(options.IdleTimeout);
-
             _ptr = _session.ListenerOpen(options);
         }
 
@@ -141,11 +139,6 @@ namespace System.Net.Quic.Implementations.MsQuic
             SetListenPort();
         }
 
-        private void SetIdleTimeout(TimeSpan timeout)
-        {
-            MsQuicParameterHelpers.SetULongParam(MsQuicApi.Api, _ptr, (uint)QUIC_PARAM_LEVEL.LISTENER, (uint)QUIC_PARAM_CONN.IDLE_TIMEOUT, (ulong)timeout.TotalMilliseconds);
-        }
-
         internal override void Close()
         {
             ThrowIfDisposed();
@@ -173,7 +166,7 @@ namespace System.Net.Quic.Implementations.MsQuic
                             IPEndPoint localEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref *(SOCKADDR_INET*)connectionInfo.LocalAddress);
                             IPEndPoint remoteEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref *(SOCKADDR_INET*)connectionInfo.RemoteAddress);
 
-                            MsQuicConnection msQuicConnection = new MsQuicConnection(localEndPoint, remoteEndPoint, evt.Data.NewConnection.Connection);
+                            MsQuicConnection msQuicConnection = new MsQuicConnection(localEndPoint, remoteEndPoint, evt.Data.NewConnection.Connection, _options.IdleTimeout);
                             msQuicConnection.SetNegotiatedAlpn(connectionInfo.NegotiatedAlpn, connectionInfo.NegotiatedAlpnLength);
 
                             _acceptConnectionQueue.Writer.TryWrite(msQuicConnection);
index 2614a7a..39d2eeb 100644 (file)
@@ -56,6 +56,32 @@ namespace System.Net.Quic.Tests
             Assert.Equal(100, serverConnection.GetRemoteAvailableUnidirectionalStreamCount());
         }
 
+        [Fact]
+        [OuterLoop("May take serveral seconds")]
+        public async Task SetListenerTimeoutWorksWithSmallTimeout()
+        {
+            var quicOptions = new QuicListenerOptions();
+            quicOptions.IdleTimeout = TimeSpan.FromSeconds(10);
+            quicOptions.ServerAuthenticationOptions = GetSslServerAuthenticationOptions();
+            quicOptions.ListenEndPoint = new IPEndPoint(IPAddress.Loopback, 0);
+
+            using QuicListener listener = new QuicListener(QuicImplementationProviders.MsQuic, quicOptions);
+            listener.Start();
+
+            QuicClientConnectionOptions options = new QuicClientConnectionOptions()
+            {
+                RemoteEndPoint = listener.ListenEndPoint,
+                ClientAuthenticationOptions = GetSslClientAuthenticationOptions(),
+            };
+
+            using QuicConnection clientConnection = new QuicConnection(QuicImplementationProviders.MsQuic, options);
+            ValueTask clientTask = clientConnection.ConnectAsync();
+            using QuicConnection serverConnection = await listener.AcceptConnectionAsync();
+            await clientTask;
+
+            await Assert.ThrowsAsync<QuicOperationAbortedException>(async () => await serverConnection.AcceptStreamAsync().TimeoutAfter(100000));
+        }
+
         [Theory]
         [MemberData(nameof(WriteData))]
         public async Task WriteTests(int[][] writes, WriteType writeType)