/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.sshd.agent.common;
import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.sshd.agent.SshAgentFactory;
import org.apache.sshd.agent.SshAgentServer;
import org.apache.sshd.common.FactoryManager;
import org.apache.sshd.common.SshException;
import org.apache.sshd.common.session.ConnectionService;
import org.apache.sshd.common.session.Session;
import org.apache.sshd.common.util.closeable.AbstractCloseable;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public class DefaultAgentForwardSupport extends AbstractCloseable implements AgentForwardSupport {
private final ConnectionService serviceInstance;
private final AtomicReference<SshAgentServer> agentServerHolder = new AtomicReference<>();
public DefaultAgentForwardSupport(ConnectionService service) {
serviceInstance = Objects.requireNonNull(service, "No connection service");
}
@Override
public String initialize() throws IOException {
Session session = serviceInstance.getSession();
try {
SshAgentServer agentServer;
synchronized (agentServerHolder) {
agentServer = agentServerHolder.get();
if (agentServer != null) {
return agentServer.getId();
}
agentServer = Objects.requireNonNull(createSshAgentServer(serviceInstance, session), "No agent server created");
agentServerHolder.set(agentServer);
}
String agentId = agentServer.getId();
if (log.isDebugEnabled()) {
log.debug("initialize({}) id={}, server={}", session, agentId, agentServer);
}
return agentId;
} catch (Throwable t) {
if (log.isDebugEnabled()) {
log.debug("initialize({}) failed ({}) to create server: {}",
session, t.getClass().getSimpleName(), t.getMessage());
}
if (log.isTraceEnabled()) {
log.trace("initialize(" + session + ") server creation failure details", t);
}
if (t instanceof IOException) {
throw (IOException) t;
} else {
throw new SshException(t);
}
}
}
protected SshAgentServer createSshAgentServer(ConnectionService service, Session session) throws Throwable {
FactoryManager manager = Objects.requireNonNull(session.getFactoryManager(), "No session factory manager");
SshAgentFactory factory = Objects.requireNonNull(manager.getAgentFactory(), "No agent factory");
return factory.createServer(service);
}
@Override
public void close() throws IOException {
SshAgentServer agentServer = agentServerHolder.getAndSet(null);
if (agentServer != null) {
if (log.isDebugEnabled()) {
log.debug("close({}) closing server={}", serviceInstance.getSession(), agentServer);
}
agentServer.close();
}
}
@Override
protected void doCloseImmediately() {
try {
close();
} catch (IOException e) {
throw new RuntimeException("Failed (" + e.getClass().getSimpleName() + ") to close agent: " + e.getMessage(), e);
}
super.doCloseImmediately();
}
@Override
public String toString() {
return getClass().getSimpleName() + "[" + serviceInstance.getSession() + "]";
}
}