Java tutorial
/* * Adito * * Copyright (C) 2003-2006 3SP LTD. All Rights Reserved * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package com.adito.tunnels.agent; import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.maverick.multiplex.Channel; import com.maverick.multiplex.ChannelOpenException; import com.maverick.multiplex.Request; import com.maverick.util.ByteArrayWriter; import com.adito.agent.AgentTunnel; import com.adito.boot.CustomServerSocketFactory; import com.adito.boot.Util; import com.adito.core.stringreplacement.VariableReplacement; import com.adito.policyframework.LaunchSession; import com.adito.policyframework.LaunchSessionFactory; import com.adito.tunnels.Tunnel; import com.adito.tunnels.TunnelingService; /** * Manages the life cycle of a single remote tunnel on the server end. This * object sets up a server socket and listens for conenctions. Whenever a new * connection is made a channel is created to the associated agent which in turn * opens the connection to the required service. */ public class RemoteTunnel extends Thread { final static Log log = LogFactory.getLog(RemoteTunnel.class); private AgentTunnel agent; private Tunnel tunnel; private ServerSocket listeningSocket; private boolean running; private RemoteTunnelManager tunnelManager; private LaunchSession launchSession; /** * Constructor. * * @param tunnel tunnel * @param agent agent * @param tunnelManager tunnel manager * @param launchSession launch session * @throws IOException */ public RemoteTunnel(Tunnel tunnel, AgentTunnel agent, RemoteTunnelManager tunnelManager, LaunchSession launchSession) throws IOException { this.agent = agent; this.tunnel = tunnel; this.launchSession = launchSession; this.tunnelManager = tunnelManager; listeningSocket = CustomServerSocketFactory.getDefault().createServerSocket(tunnel.getSourcePort(), 50, Util.isNullOrTrimmedBlank(tunnel.getSourceInterface()) ? null : InetAddress.getByName(tunnel.getSourceInterface())); } /** * Get the agent that is dealing with this tunnel. * * @return agent */ public AgentTunnel getAgent() { return agent; } /** * Get the tunnel configuration. * * @return tunnel */ public Tunnel getTunnel() { return tunnel; } /** * Get if this remote tunnel is currently running. * * @return running */ public boolean isRunning() { return running; } /** * Stop the listening socket. */ public void stopListener() { if (running) { if (log.isInfoEnabled()) log.info("Stopping remote listener on " + tunnel.getSourcePort()); running = false; try { listeningSocket.close(); } catch (IOException ioe) { log.error("Failed to stop listening socket for remote tunnel.", ioe); } if (log.isInfoEnabled()) log.info("Stopped remote listener on " + tunnel.getSourcePort()); } } /* * (non-Javadoc) * * @see java.lang.Thread#run() */ public void run() { // Process destination host and port for replacement variables VariableReplacement r = new VariableReplacement(); r.setLaunchSession(launchSession); String destHost = r.replace(tunnel.getDestination().getHost()); ByteArrayWriter msg = new ByteArrayWriter(); try { msg.writeInt(tunnel.getResourceId()); msg.writeString(tunnel.getSourceInterface()); msg.writeString(launchSession.getId()); msg.writeString(tunnel.getSourceInterface()); msg.writeInt(tunnel.getSourcePort()); msg.writeString(destHost); msg.writeInt(tunnel.getDestination().getPort()); Request request = new Request(TunnelingService.START_REMOTE_TUNNEL, msg.toByteArray()); agent.sendRequest(request, false); } catch (IOException ex) { ex.printStackTrace(); } running = true; if (log.isInfoEnabled()) log.info("Starting remote listener on " + tunnel.getSourcePort()); try { while (running) { try { Socket s = listeningSocket.accept(); if (log.isInfoEnabled()) log.info("Received new connection on " + tunnel.getSourcePort() + " from " + s.getInetAddress()); RemoteForwardingChannel channel = new RemoteForwardingChannel(this, s, tunnel, launchSession); try { agent.openChannel(channel); } catch (ChannelOpenException e) { log.error("Error opening channel. Remote tunnel remaining open but closing connection.", e); try { s.close(); } catch (IOException ioe) { } } } catch (IOException e) { if (running) { log.error("IO error waiting for connection, stopping remote tunnel.", e); } } } } finally { Request request = new Request(TunnelingService.STOP_REMOTE_TUNNEL, msg.toByteArray()); try { agent.sendRequest(request, false); } catch (IOException e) { } Channel[] c = agent.getActiveChannels(); if (c != null) { for (int i = 0; i < c.length; i++) { if (c[i] instanceof RemoteForwardingChannel) { RemoteForwardingChannel rfc = (RemoteForwardingChannel) c[i]; if (rfc.getRemoteTunnel() == this && rfc.getConnection() != null) { try { rfc.close(); } catch (Throwable t) { // TODO workaround for NPE log.error("Failed to close channel.", t); } } } } } tunnelManager.removeRemoteTunnel(this); LaunchSessionFactory.getInstance().removeLaunchSession(launchSession); running = false; } } }