Close Channel upon exceptions during bootstrap to avoid leaking (#10110)
Motivation: We need to ensure we always close the Channel when we see an exception during bootstrapping it. Modification: Ensure we correct close the Channel if we see an exception during retrieving the Resolver from the group while bootstrapping. Result: Fixes #10109 Co-authored-by: Norman Maurer <norman_maurer@apple.com>
This commit is contained in:
parent
c74469bc6c
commit
286f14f04a
@ -189,7 +189,13 @@ public class Bootstrap extends AbstractBootstrap<Bootstrap, Channel> {
|
||||
final SocketAddress localAddress, final ChannelPromise promise) {
|
||||
try {
|
||||
final EventLoop eventLoop = channel.eventLoop();
|
||||
final AddressResolver<SocketAddress> resolver = this.resolver.getResolver(eventLoop);
|
||||
AddressResolver<SocketAddress> resolver;
|
||||
try {
|
||||
resolver = this.resolver.getResolver(eventLoop);
|
||||
} catch (Throwable cause) {
|
||||
channel.close();
|
||||
return promise.setFailure(cause);
|
||||
}
|
||||
|
||||
if (!resolver.isSupported(remoteAddress) || resolver.isResolved(remoteAddress)) {
|
||||
// Resolver has no idea about what to do with the specified remote address or it's resolved already.
|
||||
|
@ -30,7 +30,6 @@ import io.netty.channel.ChannelPromise;
|
||||
import io.netty.channel.DefaultChannelConfig;
|
||||
import io.netty.channel.DefaultEventLoop;
|
||||
import io.netty.channel.DefaultEventLoopGroup;
|
||||
import io.netty.channel.EventLoop;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.ServerChannel;
|
||||
import io.netty.channel.local.LocalAddress;
|
||||
@ -52,7 +51,6 @@ import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
@ -278,6 +276,38 @@ public class BootstrapTest {
|
||||
assertThat(connectFuture.channel().isOpen(), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetResolverFailed() throws Exception {
|
||||
class TestException extends RuntimeException { }
|
||||
|
||||
final Bootstrap bootstrapA = new Bootstrap();
|
||||
bootstrapA.group(groupA);
|
||||
bootstrapA.channel(LocalChannel.class);
|
||||
|
||||
bootstrapA.resolver(new AddressResolverGroup<SocketAddress>() {
|
||||
@Override
|
||||
protected AddressResolver<SocketAddress> newResolver(EventExecutor executor) {
|
||||
throw new TestException();
|
||||
}
|
||||
});
|
||||
bootstrapA.handler(dummyHandler);
|
||||
|
||||
final ServerBootstrap bootstrapB = new ServerBootstrap();
|
||||
bootstrapB.group(groupB);
|
||||
bootstrapB.channel(LocalServerChannel.class);
|
||||
bootstrapB.childHandler(dummyHandler);
|
||||
SocketAddress localAddress = bootstrapB.bind(LocalAddress.ANY).sync().channel().localAddress();
|
||||
|
||||
// Connect to the server using the asynchronous resolver.
|
||||
ChannelFuture connectFuture = bootstrapA.connect(localAddress);
|
||||
|
||||
// Should fail with the IllegalStateException.
|
||||
assertThat(connectFuture.await(10000), is(true));
|
||||
assertThat(connectFuture.cause(), instanceOf(IllegalStateException.class));
|
||||
assertThat(connectFuture.cause().getCause(), instanceOf(TestException.class));
|
||||
assertThat(connectFuture.channel().isOpen(), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChannelFactoryFailureNotifiesPromise() throws Exception {
|
||||
final RuntimeException exception = new RuntimeException("newChannel crash");
|
||||
|
Loading…
x
Reference in New Issue
Block a user