Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@ exception.ApplicationErrorCode is long applicationErrorCode ?
new IceRpcException(IceRpcError.ConnectionClosedByPeer),
(long)MultiplexedConnectionCloseError.ServerBusy =>
new IceRpcException(IceRpcError.ServerBusy),
(long)MultiplexedConnectionCloseError.Aborted =>
new IceRpcException(
IceRpcError.ConnectionAborted,
$"The connection was closed by the peer with error '{MultiplexedConnectionCloseError.Aborted}'."),
_ => new IceRpcException(
IceRpcError.ConnectionAborted,
$"The connection was closed by the peer with an unknown application error code: '{applicationErrorCode}'",
exception),
IceRpcError.ConnectionAborted,
$"The connection was aborted by the peer with an unknown application error code: '{applicationErrorCode}'"),
} :
new IceRpcException(IceRpcError.ConnectionAborted, exception), // TODO: does this ever happen?
QuicError.ConnectionRefused => new IceRpcException(IceRpcError.ConnectionRefused, exception),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ internal QuicMultiplexedListener(

_quicServerOptions = new QuicServerConnectionOptions
{
DefaultCloseErrorCode = 0,
DefaultCloseErrorCode = (int)MultiplexedConnectionCloseError.Aborted,
DefaultStreamErrorCode = 0,
IdleTimeout = quicTransportOptions.IdleTimeout,
ServerAuthenticationOptions = authenticationOptions,
Expand Down
2 changes: 1 addition & 1 deletion src/IceRpc.Quic/Transports/QuicClientTransport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public IMultiplexedConnection CreateConnection(
var quicClientOptions = new QuicClientConnectionOptions
{
ClientAuthenticationOptions = clientAuthenticationOptions,
DefaultCloseErrorCode = 0,
DefaultCloseErrorCode = (int)MultiplexedConnectionCloseError.Aborted,
DefaultStreamErrorCode = 0,
IdleTimeout = _quicTransportOptions.IdleTimeout,
LocalEndPoint = _quicTransportOptions.LocalNetworkAddress,
Expand Down
6 changes: 5 additions & 1 deletion src/IceRpc/Transports/Internal/SlicConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1127,9 +1127,13 @@ async Task PerformCloseAsync(ulong errorCode)
new IceRpcException(IceRpcError.ConnectionClosedByPeer),
(ulong)MultiplexedConnectionCloseError.ServerBusy =>
new IceRpcException(IceRpcError.ServerBusy),
(ulong)MultiplexedConnectionCloseError.Aborted =>
new IceRpcException(
IceRpcError.ConnectionAborted,
$"The connection was closed by the peer with error '{MultiplexedConnectionCloseError.Aborted}'."),
_ => new IceRpcException(
IceRpcError.ConnectionAborted,
$"The connection was closed by the peer with an unknown application error code: '{errorCode}'.")
$"The connection was closed by the peer with an unknown application error code: '{errorCode}'")
};

if (await CloseAsyncCore(exception).ConfigureAwait(false))
Expand Down
5 changes: 4 additions & 1 deletion src/IceRpc/Transports/MultiplexedConnectionCloseError.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ public enum MultiplexedConnectionCloseError : byte
/// <summary>The connection was closed without error.</summary>
NoError = 0,

/// <summary>The connection was aborted for some unspecified reason.</summary>
Aborted = 1,

/// <summary>The server rejected the connection establishment attempt because it already has too many connections.
/// </summary>
/// <seealso cref="IceRpcError.ServerBusy" />
ServerBusy = 1,
ServerBusy = 2,
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public async Task Accept_stream_cancellation()

/// <summary>Verifies that AcceptStream fails when the connection is closed.</summary>
[TestCase(MultiplexedConnectionCloseError.NoError, IceRpcError.ConnectionClosedByPeer)]
[TestCase(MultiplexedConnectionCloseError.Aborted, IceRpcError.ConnectionAborted)]
[TestCase(MultiplexedConnectionCloseError.ServerBusy, IceRpcError.ServerBusy)]
[TestCase((MultiplexedConnectionCloseError)255, IceRpcError.ConnectionAborted)]
public async Task Accept_stream_fails_on_close(
Expand Down Expand Up @@ -165,6 +166,7 @@ async Task<List<IMultiplexedStream>> CreateStreamsAsync(int count, bool bidirect

/// <summary>Verify streams cannot be created after closing down the connection.</summary>
[TestCase(MultiplexedConnectionCloseError.NoError, IceRpcError.ConnectionClosedByPeer)]
[TestCase(MultiplexedConnectionCloseError.Aborted, IceRpcError.ConnectionAborted)]
[TestCase(MultiplexedConnectionCloseError.ServerBusy, IceRpcError.ServerBusy)]
[TestCase((MultiplexedConnectionCloseError)255, IceRpcError.ConnectionAborted)]
public async Task Cannot_create_streams_with_a_closed_connection(
Expand Down Expand Up @@ -488,6 +490,48 @@ public async Task Disposing_the_connection_aborts_the_streams([Values(true, fals
Assert.ThrowsAsync<IceRpcException>(async () => await peerStream.Output.WriteAsync(_oneBytePayload));
}

[Test]
public async Task Disposing_the_server_connection_aborts_the_client_connection()
{
// Arrange
await using ServiceProvider provider = CreateServiceCollection()
.AddMultiplexedTransportTest()
.BuildServiceProvider(validateScopes: true);
var clientConnection = provider.GetRequiredService<IMultiplexedConnection>();
var listener = provider.GetRequiredService<IListener<IMultiplexedConnection>>();
await using IMultiplexedConnection serverConnection =
await MultiplexedConformanceTestsHelper.ConnectAndAcceptConnectionAsync(listener, clientConnection);

// Act
await serverConnection.DisposeAsync();

// Assert
Assert.That(
async () => _ = await clientConnection.AcceptStreamAsync(default),
Throws.InstanceOf<IceRpcException>().With.Property("IceRpcError").EqualTo(IceRpcError.ConnectionAborted));
}

[Test]
public async Task Disposing_the_client_connection_aborts_the_server_connection()
{
// Arrange
await using ServiceProvider provider = CreateServiceCollection()
.AddMultiplexedTransportTest()
.BuildServiceProvider(validateScopes: true);
var clientConnection = provider.GetRequiredService<IMultiplexedConnection>();
var listener = provider.GetRequiredService<IListener<IMultiplexedConnection>>();
await using IMultiplexedConnection serverConnection =
await MultiplexedConformanceTestsHelper.ConnectAndAcceptConnectionAsync(listener, clientConnection);

// Act
await clientConnection.DisposeAsync();

// Assert
Assert.That(
async () => _ = await serverConnection.AcceptStreamAsync(default),
Throws.InstanceOf<IceRpcException>().With.Property("IceRpcError").EqualTo(IceRpcError.ConnectionAborted));
}

[Test]
public async Task Disposing_the_connection_closes_the_streams()
{
Expand Down Expand Up @@ -754,6 +798,7 @@ async Task ServerReadAsync(IMultiplexedStream stream)

/// <summary>Verify streams cannot be created after closing down the connection.</summary>
[TestCase(MultiplexedConnectionCloseError.NoError, IceRpcError.ConnectionClosedByPeer)]
[TestCase(MultiplexedConnectionCloseError.Aborted, IceRpcError.ConnectionAborted)]
[TestCase(MultiplexedConnectionCloseError.ServerBusy, IceRpcError.ServerBusy)]
[TestCase((MultiplexedConnectionCloseError)255, IceRpcError.ConnectionAborted)]
public async Task Pending_create_streams_fails_on_connection_close(
Expand Down