2 * Copyright (c) 2023 PANTHEON.tech, s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netconf.transport.ssh;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import com.google.common.util.concurrent.SettableFuture;
14 import io.netty.channel.ChannelHandlerContext;
15 import java.io.IOException;
16 import java.lang.invoke.MethodHandles;
17 import java.lang.invoke.VarHandle;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.opendaylight.netconf.shaded.sshd.common.io.IoSession;
20 import org.opendaylight.netconf.shaded.sshd.server.session.ServerSessionImpl;
21 import org.opendaylight.netconf.transport.api.TransportChannel;
24 * A {@link ServerSessionImpl}, bound to a backend Netty channel.
26 final class TransportServerSession extends ServerSessionImpl {
27 private record State(String subsystem, TransportChannel underlay, SettableFuture<ChannelHandlerContext> future) {
29 subsystem = requireNonNull(subsystem);
30 underlay = requireNonNull(underlay);
31 future = requireNonNull(future);
35 private static final VarHandle STATE;
39 STATE = MethodHandles.lookup().findVarHandle(TransportServerSession.class, "state", State.class);
40 } catch (NoSuchFieldException | IllegalAccessException e) {
41 throw new ExceptionInInitializerError(e);
45 @SuppressWarnings("unused")
46 private volatile State state;
48 TransportServerSession(final TransportSshServer server, final IoSession ioSession) throws Exception {
49 super(server, ioSession);
52 ListenableFuture<ChannelHandlerContext> attachUnderlay(final String subsystem, final TransportChannel underlay) {
53 final var newState = new State(subsystem, underlay, SettableFuture.create());
54 final var witness = STATE.compareAndExchange(this, null, newState);
55 if (witness != null) {
56 throw new IllegalStateException("Already set up for " + witness);
58 return newState.future;
61 @Nullable TransportServerSubsystem openSubsystem(final String subsystem) {
62 final var local = (State) STATE.getAndSet(this, null);
64 if (subsystem.equals(local.subsystem)) {
65 return new TransportServerSubsystem(subsystem, local.underlay, local.future);
67 local.future.setException(new IOException("Mismatched subsystem " + subsystem));