All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.helger.jsch.tunnel.TunnelConnection Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2016-2024 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed 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 com.helger.jsch.tunnel;

import java.io.Closeable;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Nonnull;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.helger.commons.annotation.Nonempty;
import com.helger.commons.io.stream.StreamHelper;
import com.helger.jsch.session.ISessionFactory;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

/**
 * A TunnelConnection represents an ssh connection that opens one or more
 * {@link com.helger.jsch.tunnel.Tunnel Tunnel's}.
 */
public class TunnelConnection implements Closeable
{
  private static final Logger LOGGER = LoggerFactory.getLogger (TunnelConnection.class);

  private final Map  m_aTunnelsByDestination;
  private final ISessionFactory m_aSessionFactory;
  private final Iterable  m_aTunnels;
  private Session m_aSession;

  @Nonnull
  @Nonempty
  private static String _hostnamePortKey (final String hostname, final int port)
  {
    return hostname + ":" + port;
  }

  @Nonnull
  @Nonempty
  private static String _hostnamePortKey (@Nonnull final Tunnel tunnel)
  {
    return _hostnamePortKey (tunnel.getDestinationHostname (), tunnel.getDestinationPort ());
  }

  /**
   * Creates a TunnelConnection using the the sessionFactory to
   * obtain its ssh connection with a single tunnel defined by
   * {@link com.helger.jsch.tunnel.Tunnel#Tunnel(int, String, int)
   * Tunnel(localPort, destinationHostname, destinationPort)}.
   *
   * @param sessionFactory
   *        The sessionFactory
   * @param localPort
   *        The local port to bind to
   * @param destinationHostname
   *        The destination hostname to tunnel to
   * @param destinationPort
   *        The destination port to tunnel to
   */
  public TunnelConnection (final ISessionFactory sessionFactory,
                           final int localPort,
                           final String destinationHostname,
                           final int destinationPort)
  {
    this (sessionFactory, new Tunnel (localPort, destinationHostname, destinationPort));
  }

  /**
   * Creates a TunnelConnection using the the sessionFactory to
   * obtain its ssh connection with a list of
   * {@link com.helger.jsch.tunnel.Tunnel Tunnel's}.
   *
   * @param sessionFactory
   *        The sessionFactory
   * @param tunnels
   *        The tunnels
   */
  public TunnelConnection (final ISessionFactory sessionFactory, final Tunnel... tunnels)
  {
    this (sessionFactory, Arrays.asList (tunnels));
  }

  /**
   * Creates a TunnelConnection using the the sessionFactory to
   * obtain its ssh connection with a list of
   * {@link com.helger.jsch.tunnel.Tunnel Tunnel's}.
   *
   * @param sessionFactory
   *        The sessionFactory
   * @param tunnels
   *        The tunnels
   */
  public TunnelConnection (final ISessionFactory sessionFactory, final List  tunnels)
  {
    m_aSessionFactory = sessionFactory;
    m_aTunnels = tunnels;
    m_aTunnelsByDestination = new HashMap <> ();

    for (final Tunnel tunnel : tunnels)
      m_aTunnelsByDestination.put (_hostnamePortKey (tunnel), tunnel);
  }

  /**
   * Closes the underlying ssh session causing all tunnels to be closed.
   */
  public void close () throws IOException
  {
    if (m_aSession != null && m_aSession.isConnected ())
    {
      m_aSession.disconnect ();
    }
    m_aSession = null;

    // unnecessary, but seems right to undo what we did
    for (final Tunnel tunnel : m_aTunnels)
    {
      tunnel.setAssignedLocalPort (0);
    }
  }

  /**
   * Returns the tunnel matching the supplied values, or null if
   * there isn't one that matches.
   *
   * @param destinationHostname
   *        The tunnels destination hostname
   * @param destinationPort
   *        The tunnels destination port
   * @return The tunnel matching the supplied values
   */
  public Tunnel getTunnel (final String destinationHostname, final int destinationPort)
  {
    return m_aTunnelsByDestination.get (_hostnamePortKey (destinationHostname, destinationPort));
  }

  /**
   * Returns true if the underlying ssh session is open.
   *
   * @return True if the underlying ssh session is open
   */
  public boolean isOpen ()
  {
    return m_aSession != null && m_aSession.isConnected ();
  }

  /**
   * Opens a session and connects all of the tunnels.
   *
   * @throws JSchException
   *         If unable to connect
   */
  public void open () throws JSchException
  {
    if (isOpen ())
      return;

    m_aSession = m_aSessionFactory.createSession ();
    if (!m_aSession.isConnected ())
    {
      if (LOGGER.isDebugEnabled ())
        LOGGER.debug ("Connecting JSCH session");
      m_aSession.connect ();
    }

    for (final Tunnel aTunnel : m_aTunnels)
    {
      int nAssignedPort = 0;
      if (aTunnel.getLocalAlias () == null)
      {
        nAssignedPort = m_aSession.setPortForwardingL (aTunnel.getLocalPort (),
                                                       aTunnel.getDestinationHostname (),
                                                       aTunnel.getDestinationPort ());
      }
      else
      {
        nAssignedPort = m_aSession.setPortForwardingL (aTunnel.getLocalAlias (),
                                                       aTunnel.getLocalPort (),
                                                       aTunnel.getDestinationHostname (),
                                                       aTunnel.getDestinationPort ());
      }
      aTunnel.setAssignedLocalPort (nAssignedPort);
      if (LOGGER.isDebugEnabled ())
        LOGGER.debug ("Added SSH tunnel " + getAsString ());
    }
    LOGGER.info ("Forwarding " + getAsString ());
  }

  /**
   * Closes, and re-opens the session and all its tunnels. Effectively calls
   * {@link #close()} followed by a call to {@link #open()}.
   *
   * @throws JSchException
   *         If unable to connect
   */
  public void reopen () throws JSchException
  {
    StreamHelper.close (this);
    open ();
  }

  @Nonnull
  @Nonempty
  public String getAsString ()
  {
    final StringBuilder ret = new StringBuilder (m_aSessionFactory.getAsString ());
    for (final Tunnel tunnel : m_aTunnels)
      ret.append (" -L ").append (tunnel);
    return ret.toString ();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy