import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import java.io.IOException;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.net.SocketAddress;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
import org.checkerframework.checker.lock.qual.GuardedBy;
import org.checkerframework.checker.lock.qual.Holding;
import org.eclipse.jdt.annotation.Nullable;
*/
public final class AsyncSshHandler extends ChannelOutboundHandlerAdapter {
private static final Logger LOG = LoggerFactory.getLogger(AsyncSshHandler.class);
+ private static final VarHandle DISCONNECTED;
+
+ static {
+ try {
+ DISCONNECTED = MethodHandles.lookup().findVarHandle(AsyncSshHandler.class, "disconnected", boolean.class);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ }
public static final String SUBSYSTEM = "netconf";
DEFAULT_CLIENT = c;
}
- private final AtomicBoolean isDisconnected = new AtomicBoolean();
private final AuthenticationHandler authenticationHandler;
private final Future<?> negotiationFuture;
private final NetconfSshClient sshClient;
private ClientSession session;
private FutureListener<Object> negotiationFutureListener;
+ private volatile boolean disconnected;
+
public AsyncSshHandler(final AuthenticationHandler authenticationHandler, final NetconfSshClient sshClient,
final Future<?> negotiationFuture) {
this.authenticationHandler = requireNonNull(authenticationHandler);
onOpenFailure(ctx, new AuthenticationFailedException("Authentication failed", cause));
return;
}
+ if (disconnected) {
+ LOG.debug("Skipping SSH subsystem allocation, channel: {}", ctx.channel());
+ return;
+ }
LOG.debug("SSH session authenticated on channel: {}, server version: {}", ctx.channel(),
clientSession.getServerVersion());
onOpenFailure(ctx, cause);
return;
}
+ if (disconnected) {
+ LOG.trace("Skipping activation, channel: {}", ctx.channel());
+ return;
+ }
LOG.trace("SSH subsystem channel opened successfully on channel: {}", ctx.channel());
if (negotiationFuture == null) {
@Override
public void disconnect(final ChannelHandlerContext ctx, final ChannelPromise promise) {
- if (isDisconnected.compareAndSet(false, true)) {
+ if (DISCONNECTED.compareAndSet(this, false, true)) {
ctx.executor().execute(() -> safelyDisconnect(ctx, promise));
}
}