2005-09-05 10:01:54 +02:00
//serverPortForwardingSch.java
//-------------------------------------
//part of YACY
//(C) by Michael Peter Christen; mc@anomic.de
//first published on http://www.anomic.de
//Frankfurt, Germany, 2004
//
//This file ist contributed by Martin Thelian
//last major change: $LastChangedDate$ by $LastChangedBy$
//Revision: $LastChangedRevision$
//
//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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
//Using this software in any meaning (reading, learning, copying, compiling,
//running) means that you agree that the Author(s) is (are) not responsible
//for cost, loss of data or any harm that may be caused directly or indirectly
//by usage of this softare or this documentation. The usage of this software
//is on your own risk. The installation and usage (starting/running) of this
//software may allow other people or application to access your computer and
//any attached devices and is highly dependent on the configuration of the
//software which must be done by the user of the software; the author(s) is
//(are) also not responsible for proper configuration and usage of the
//software, even if provoked by documentation provided together with
//the software.
//
//Any changes to this file according to the GPL as documented in the file
//gpl.txt aside this file in the shipment you received can be done to the
//lines that follows this copyright notice here, but changes must not be
//done inside the copyright notive above. A re-distribution must contain
//the intact and unchanged copyright notice.
//Contributions and changes to the program code must be marked as such.
2005-06-16 12:36:23 +02:00
package de.anomic.server ;
import java.io.IOException ;
import com.jcraft.jsch.JSch ;
2005-07-04 13:09:48 +02:00
import com.jcraft.jsch.ProxyHTTP ;
2005-06-16 12:36:23 +02:00
import com.jcraft.jsch.Session ;
import com.jcraft.jsch.UIKeyboardInteractive ;
import com.jcraft.jsch.UserInfo ;
2005-07-04 13:09:48 +02:00
import de.anomic.server.logging.serverLog ;
2005-08-29 13:39:10 +02:00
import de.anomic.yacy.yacyClient ;
import de.anomic.yacy.yacyCore ;
2005-07-04 13:09:48 +02:00
2005-06-16 12:36:23 +02:00
public class serverPortForwardingSch implements serverPortForwarding {
2005-07-04 13:09:48 +02:00
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* Constants needed to read properties from the configuration file
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = * /
public static final String FORWARDING_HOST = " portForwardingHost " ;
public static final String FORWARDING_HOST_PORT = " portForwardingHostPort " ;
public static final String FORWARDING_HOST_USER = " portForwardingHostUser " ;
public static final String FORWARDING_HOST_PWD = " portForwardingHostPwd " ;
public static final String FORWARDING_PORT = " portForwardingPort " ;
public static final String FORWARDING_USE_PROXY = " portForwardingUseProxy " ;
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* Other object fields
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = * /
private serverSwitch switchboard ;
private String forwardingHost ;
private int forwardingHostPort ;
private String forwardingHostUser ;
private String forwardingHostPwd ;
private int forwardingPort ;
private boolean useProxy ;
private String remoteProxyHost ;
private int remoteProxyPort ;
2005-06-16 12:36:23 +02:00
2005-07-04 13:09:48 +02:00
private String localHost ;
private int localHostPort ;
2005-06-16 12:36:23 +02:00
2005-07-04 13:09:48 +02:00
private static Session session ;
private static serverInstantThread sessionWatcher ;
private serverLog log ;
2005-06-16 12:36:23 +02:00
public serverPortForwardingSch ( ) {
super ( ) ;
2005-07-04 13:09:48 +02:00
this . log = new serverLog ( " PORT_FORWARDING_SCH " ) ;
2005-06-16 12:36:23 +02:00
}
public void init (
2005-07-04 13:09:48 +02:00
serverSwitch switchboard ,
2005-06-16 12:36:23 +02:00
String localHost ,
int localPort
2005-07-04 13:09:48 +02:00
) throws Exception {
try {
2005-08-30 23:10:39 +02:00
this . log . logFine ( " Initializing port forwarding via sch ... " ) ;
2005-07-04 13:09:48 +02:00
this . switchboard = switchboard ;
this . forwardingHost = switchboard . getConfig ( FORWARDING_HOST , " localhost " ) ;
this . forwardingHostPort = Integer . valueOf ( switchboard . getConfig ( FORWARDING_HOST_PORT , " 8080 " ) ) . intValue ( ) ;
this . forwardingHostUser = switchboard . getConfig ( FORWARDING_HOST_USER , " xxx " ) ;
this . forwardingHostPwd = switchboard . getConfig ( FORWARDING_HOST_PWD , " xxx " ) ;
this . forwardingPort = Integer . valueOf ( switchboard . getConfig ( FORWARDING_PORT , " 8080 " ) ) . intValue ( ) ;
this . useProxy = Boolean . valueOf ( switchboard . getConfig ( FORWARDING_USE_PROXY , " false " ) ) . booleanValue ( ) ;
this . localHost = localHost ;
this . localHostPort = localPort ;
// load remote proxy data
this . remoteProxyHost = switchboard . getConfig ( " remoteProxyHost " , " " ) ;
try {
this . remoteProxyPort = Integer . parseInt ( switchboard . getConfig ( " remoteProxyPort " , " 3128 " ) ) ;
} catch ( NumberFormatException e ) {
remoteProxyPort = 3128 ;
}
// checking if all needed libs are availalbe
String javaClassPath = System . getProperty ( " java.class.path " ) ;
if ( javaClassPath . indexOf ( " jsch " ) = = - 1 ) {
throw new IllegalStateException ( " Missing library. " ) ;
}
} catch ( Exception e ) {
2005-08-30 23:32:59 +02:00
this . log . logSevere ( " Unable to initialize port forwarding. " , e ) ;
2005-07-04 13:09:48 +02:00
throw e ;
2005-06-16 12:36:23 +02:00
}
}
public String getHost ( ) {
2005-07-04 13:09:48 +02:00
return this . forwardingHost ;
2005-06-16 12:36:23 +02:00
}
public int getPort ( ) {
2005-07-04 13:09:48 +02:00
return this . forwardingPort ;
2005-06-16 12:36:23 +02:00
}
2005-07-04 13:09:48 +02:00
2005-06-16 12:36:23 +02:00
2005-07-04 13:09:48 +02:00
public synchronized void connect ( ) throws IOException {
2005-06-16 12:36:23 +02:00
try {
2005-07-04 13:09:48 +02:00
if ( ( session ! = null ) & & ( session . isConnected ( ) ) )
throw new IOException ( " Session already connected " ) ;
this . log . logInfo ( " Trying to connect to remote port forwarding host " + this . forwardingHostUser + " @ " + this . forwardingHost + " : " + this . forwardingHostPort ) ;
2005-06-16 12:36:23 +02:00
JSch jsch = new JSch ( ) ;
2005-07-04 13:09:48 +02:00
session = jsch . getSession ( this . forwardingHostUser , this . forwardingHost , this . forwardingHostPort ) ;
session . setPassword ( this . forwardingHostPwd ) ;
2005-06-16 12:36:23 +02:00
/ *
* Setting the StrictHostKeyChecking to ignore unknown
* hosts because of a missing known_hosts file . . .
* /
java . util . Properties config = new java . util . Properties ( ) ;
config . put ( " StrictHostKeyChecking " , " no " ) ;
2005-07-04 13:09:48 +02:00
session . setConfig ( config ) ;
// setting the proxy that should be used
if ( this . useProxy ) {
session . setProxy ( new ProxyHTTP ( this . remoteProxyHost , this . remoteProxyPort ) ) ;
}
2005-06-16 12:36:23 +02:00
// username and password will be given via UserInfo interface.
2005-07-04 13:09:48 +02:00
UserInfo ui = new MyUserInfo ( this . forwardingHostPwd ) ;
session . setUserInfo ( ui ) ;
2005-06-16 12:36:23 +02:00
// trying to connect ...
2005-07-04 13:09:48 +02:00
session . connect ( ) ;
// activating remote port forwarding
session . setPortForwardingR ( this . forwardingPort , this . localHost , this . localHostPort ) ;
2005-06-16 12:36:23 +02:00
2005-07-04 13:09:48 +02:00
// using a timer task to control if the session remains open
if ( sessionWatcher = = null ) {
2005-08-30 23:10:39 +02:00
this . log . logFine ( " Deploying port forwarding session watcher thread. " ) ;
2005-07-20 15:03:41 +02:00
this . switchboard . deployThread ( " portForwardingWatcher " , " Remote Port Forwarding Watcher " , " this thread is used to detect broken connections and to re-establish it if necessary. " , null ,
2005-07-04 13:09:48 +02:00
sessionWatcher = new serverInstantThread ( this , " reconnect " , null ) , 30000 , 30000 , 30000 , 1000 ) ;
2005-07-07 15:58:54 +02:00
sessionWatcher . setSyncObject ( new Object ( ) ) ;
2005-07-04 13:09:48 +02:00
}
2005-06-16 12:36:23 +02:00
2005-07-04 13:09:48 +02:00
this . log . logInfo ( " Remote port forwarding connection established: " +
this . forwardingHost + " : " + this . forwardingPort + " -> " +
this . localHost + " : " + this . localHostPort ) ;
2005-06-16 12:36:23 +02:00
}
catch ( Exception e ) {
2005-08-30 23:32:59 +02:00
this . log . logSevere ( " Unable to connect to remote port forwarding host. " , e ) ;
2005-06-16 12:36:23 +02:00
throw new IOException ( e . getMessage ( ) ) ;
}
}
2005-07-04 13:09:48 +02:00
public synchronized boolean reconnect ( ) throws IOException {
if ( ( ! this . isConnected ( ) ) & & ( ! Thread . currentThread ( ) . isInterrupted ( ) ) ) {
2005-08-30 23:10:39 +02:00
this . log . logFine ( " Trying to reconnect to port forwarding host. " ) ;
2005-09-01 09:52:46 +02:00
this . disconnect ( ) ;
2005-07-04 13:09:48 +02:00
this . connect ( ) ;
return this . isConnected ( ) ;
}
return false ;
}
public synchronized void disconnect ( ) throws IOException {
if ( session = = null ) throw new IOException ( " No connection established. " ) ;
// terminating port watcher thread
2005-08-30 23:10:39 +02:00
this . log . logFine ( " Terminating port forwarding session watcher thread. " ) ;
2005-07-04 13:09:48 +02:00
this . switchboard . terminateThread ( " portForwardingWatcher " , true ) ;
sessionWatcher = null ;
2005-06-16 12:36:23 +02:00
2005-07-04 13:09:48 +02:00
// disconnection the session
2005-06-16 12:36:23 +02:00
try {
2005-07-04 13:09:48 +02:00
session . disconnect ( ) ;
2005-08-30 23:10:39 +02:00
this . log . logFine ( " Successfully disconnected from port forwarding host. " ) ;
2005-06-16 12:36:23 +02:00
} catch ( Exception e ) {
2005-08-30 23:32:59 +02:00
this . log . logSevere ( " Error while trying to disconnect from port forwarding host. " , e ) ;
2005-06-16 12:36:23 +02:00
throw new IOException ( e . getMessage ( ) ) ;
}
}
2005-07-04 13:09:48 +02:00
public synchronized boolean isConnected ( ) {
if ( session = = null ) return false ;
2005-08-29 13:39:10 +02:00
if ( ! session . isConnected ( ) ) return false ;
int urls = yacyClient . queryUrlCount ( yacyCore . seedDB . mySeed ) ;
return ! ( urls < 0 ) ;
2005-06-17 09:57:00 +02:00
}
2005-06-16 12:36:23 +02:00
class MyUserInfo
implements UserInfo , UIKeyboardInteractive {
String passwd ;
public MyUserInfo ( String password ) {
this . passwd = password ;
}
public String getPassword ( ) {
return this . passwd ;
}
public boolean promptYesNo ( String str ) {
System . err . println ( " User was prompted from: " + str ) ;
return true ;
}
public String getPassphrase ( ) {
return null ;
}
public boolean promptPassphrase ( String message ) {
System . out . println ( " promptPassphrase : " + message ) ;
return false ;
}
public boolean promptPassword ( String message ) {
System . out . println ( " promptPassword : " + message ) ;
return true ;
}
/ * *
* @see com . jcraft . jsch . UserInfo # showMessage ( java . lang . String )
* /
public void showMessage ( String message ) {
System . out . println ( " Sch has tried to show the following message to the user: " + message ) ;
}
public String [ ] promptKeyboardInteractive ( String destination ,
String name ,
String instruction ,
String [ ] prompt ,
boolean [ ] echo ) {
System . out . println ( " User was prompted using interactive-keyboard: " +
" \ n \ tDestination: " + destination +
" \ n \ tName: " + name +
" \ n \ tInstruction: " + instruction +
" \ n \ tPrompt: " + arrayToString2 ( prompt , " | " ) +
" \ n \ techo: " + arrayToString2 ( echo , " | " ) ) ;
if ( ( prompt . length > = 1 ) & & ( prompt [ 0 ] . startsWith ( " Password " ) ) )
return new String [ ] { this . passwd } ;
return new String [ ] { } ;
}
String arrayToString2 ( String [ ] a , String separator ) {
StringBuffer result = new StringBuffer ( ) ; // start with first element
if ( a . length > 0 ) {
result . append ( a [ 0 ] ) ;
for ( int i = 1 ; i < a . length ; i + + ) {
result . append ( separator ) ;
result . append ( a [ i ] ) ;
}
}
return result . toString ( ) ;
}
String arrayToString2 ( boolean [ ] a , String separator ) {
StringBuffer result = new StringBuffer ( ) ; // start with first element
if ( a . length > 0 ) {
result . append ( a [ 0 ] ) ;
for ( int i = 1 ; i < a . length ; i + + ) {
result . append ( separator ) ;
result . append ( a [ i ] ) ;
}
}
return result . toString ( ) ;
}
}
}