diff --git a/driver-core/src/main/com/mongodb/internal/connection/TlsChannelStreamFactoryFactory.java b/driver-core/src/main/com/mongodb/internal/connection/TlsChannelStreamFactoryFactory.java index df8b3c2fe4..527bd2d637 100644 --- a/driver-core/src/main/com/mongodb/internal/connection/TlsChannelStreamFactoryFactory.java +++ b/driver-core/src/main/com/mongodb/internal/connection/TlsChannelStreamFactoryFactory.java @@ -39,6 +39,7 @@ import java.io.IOException; import java.net.StandardSocketOptions; import java.nio.ByteBuffer; +import java.nio.channels.Channel; import java.nio.channels.CompletionHandler; import java.nio.channels.InterruptedByTimeoutException; import java.nio.channels.SelectionKey; @@ -164,9 +165,13 @@ void start() { } } finally { try { - selector.close(); - } catch (IOException e) { - // ignore + closePendingSockets(); + } finally { + try { + selector.close(); + } catch (IOException e) { + // ignore + } } } }); @@ -174,9 +179,34 @@ void start() { selectorThread.start(); } + private void closePendingSockets() { + for (SocketRegistration pendingRegistration : pendingRegistrations) { + close(pendingRegistration.socketChannel); + } + for (SelectionKey key : selector.keys()) { + close(key.channel()); + } + } + + private void close(final Channel channel) { + try { + channel.close(); + } catch (IOException e) { + LOGGER.debug("Exception closing channel", e); + } + } + void register(final SocketRegistration registration) { pendingRegistrations.add(registration); selector.wakeup(); + + // Selector could become closed while we were trying to register the socket. + // if it becomes closed, then no pending registrations will be cleaned up. + // Therefore, we might end up with a hanging socket channel. + if (!selector.isOpen()) { + pendingRegistrations.remove(registration); + close(registration.socketChannel); + } } @Override