001: // serverPortForwardingSch.java
002: // -------------------------------------
003: // part of YACY
004: // (C) by Michael Peter Christen; mc@anomic.de
005: // first published on http://www.anomic.de
006: // Frankfurt, Germany, 2004
007: //
008: // This file ist contributed by Martin Thelian
009: //
010: // $LastChangedDate: 2006-02-20 23:57:42 +0100 (Mo, 20 Feb 2006) $
011: // $LastChangedRevision: 1715 $
012: // $LastChangedBy: borg-0300 $
013: //
014: // This program is free software; you can redistribute it and/or modify
015: // it under the terms of the GNU General Public License as published by
016: // the Free Software Foundation; either version 2 of the License, or
017: // (at your option) any later version.
018: //
019: // This program is distributed in the hope that it will be useful,
020: // but WITHOUT ANY WARRANTY; without even the implied warranty of
021: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
022: // GNU General Public License for more details.
023: //
024: // You should have received a copy of the GNU General Public License
025: // along with this program; if not, write to the Free Software
026: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
027: //
028: // Using this software in any meaning (reading, learning, copying, compiling,
029: // running) means that you agree that the Author(s) is (are) not responsible
030: // for cost, loss of data or any harm that may be caused directly or indirectly
031: // by usage of this softare or this documentation. The usage of this software
032: // is on your own risk. The installation and usage (starting/running) of this
033: // software may allow other people or application to access your computer and
034: // any attached devices and is highly dependent on the configuration of the
035: // software which must be done by the user of the software; the author(s) is
036: // (are) also not responsible for proper configuration and usage of the
037: // software, even if provoked by documentation provided together with
038: // the software.
039: //
040: // Any changes to this file according to the GPL as documented in the file
041: // gpl.txt aside this file in the shipment you received can be done to the
042: // lines that follows this copyright notice here, but changes must not be
043: // done inside the copyright notive above. A re-distribution must contain
044: // the intact and unchanged copyright notice.
045: // Contributions and changes to the program code must be marked as such.
046:
047: package de.anomic.server.portForwarding.sch;
048:
049: import java.io.IOException;
050:
051: import com.jcraft.jsch.JSch;
052: import com.jcraft.jsch.ProxyHTTP;
053: import com.jcraft.jsch.Session;
054: import com.jcraft.jsch.UIKeyboardInteractive;
055: import com.jcraft.jsch.UserInfo;
056:
057: import de.anomic.server.serverInstantThread;
058: import de.anomic.server.serverSwitch;
059: import de.anomic.server.logging.serverLog;
060: import de.anomic.server.portForwarding.serverPortForwarding;
061: import de.anomic.yacy.yacyClient;
062: import de.anomic.yacy.yacyCore;
063:
064: public class serverPortForwardingSch implements serverPortForwarding {
065:
066: /* ========================================================================
067: * Constants needed to read properties from the configuration file
068: * ======================================================================== */
069: public static final String FORWARDING_HOST = "portForwarding.sch.Host";
070: public static final String FORWARDING_HOST_PORT = "portForwarding.sch.HostPort";
071: public static final String FORWARDING_HOST_USER = "portForwarding.sch.HostUser";
072: public static final String FORWARDING_HOST_PWD = "portForwarding.sch.HostPwd";
073:
074: public static final String FORWARDING_PORT = "portForwarding.sch.Port";
075: public static final String FORWARDING_USE_PROXY = "portForwarding.sch.UseProxy";
076:
077: /* ========================================================================
078: * Other object fields
079: * ======================================================================== */
080: private serverSwitch switchboard;
081:
082: private String forwardingHost;
083: private int forwardingHostPort;
084: private String forwardingHostUser;
085: private String forwardingHostPwd;
086:
087: private int forwardingPort;
088: private boolean useProxy;
089:
090: private String remoteProxyHost;
091: private int remoteProxyPort;
092:
093: private String localHost;
094: private int localHostPort;
095:
096: private static Session session;
097: private static serverInstantThread sessionWatcher;
098:
099: private serverLog log;
100:
101: public serverPortForwardingSch() {
102: super ();
103: this .log = new serverLog("PORT_FORWARDING_SCH");
104: }
105:
106: public void init(serverSwitch switchboard, String localHost,
107: int localPort) throws Exception {
108: try {
109: this .log
110: .logFine("Initializing port forwarding via sch ...");
111:
112: this .switchboard = switchboard;
113:
114: this .forwardingHost = switchboard.getConfig(
115: FORWARDING_HOST, "localhost");
116: this .forwardingHostPort = Integer
117: .valueOf(
118: switchboard.getConfig(FORWARDING_HOST_PORT,
119: "8080")).intValue();
120: this .forwardingHostUser = switchboard.getConfig(
121: FORWARDING_HOST_USER, "xxx");
122: this .forwardingHostPwd = switchboard.getConfig(
123: FORWARDING_HOST_PWD, "xxx");
124:
125: this .forwardingPort = Integer.valueOf(
126: switchboard.getConfig(FORWARDING_PORT, "8080"))
127: .intValue();
128: this .useProxy = Boolean.valueOf(
129: switchboard
130: .getConfig(FORWARDING_USE_PROXY, "false"))
131: .booleanValue();
132:
133: this .localHost = localHost;
134: this .localHostPort = localPort;
135:
136: // load remote proxy data
137: this .remoteProxyHost = switchboard.getConfig(
138: "remoteProxyHost", "");
139: try {
140: this .remoteProxyPort = Integer.parseInt(switchboard
141: .getConfig("remoteProxyPort", "3128"));
142: } catch (NumberFormatException e) {
143: remoteProxyPort = 3128;
144: }
145:
146: // checking if all needed libs are availalbe
147: String javaClassPath = System
148: .getProperty("java.class.path");
149: if (javaClassPath.indexOf("jsch") == -1) {
150: throw new IllegalStateException("Missing library.");
151: }
152: } catch (Exception e) {
153: this .log.logSevere("Unable to initialize port forwarding.",
154: e);
155: throw e;
156: }
157: }
158:
159: public String getHost() {
160: return this .forwardingHost;
161: }
162:
163: public int getPort() {
164: return this .forwardingPort;
165: }
166:
167: public synchronized void connect() throws IOException {
168: try {
169: if ((session != null) && (session.isConnected()))
170: throw new IOException("Session already connected");
171:
172: this .log
173: .logInfo("Trying to connect to remote port forwarding host "
174: + this .forwardingHostUser
175: + "@"
176: + this .forwardingHost
177: + ":"
178: + this .forwardingHostPort);
179:
180: JSch jsch = new JSch();
181: session = jsch.getSession(this .forwardingHostUser,
182: this .forwardingHost, this .forwardingHostPort);
183: session.setPassword(this .forwardingHostPwd);
184:
185: /*
186: * Setting the StrictHostKeyChecking to ignore unknown
187: * hosts because of a missing known_hosts file ...
188: */
189: java.util.Properties config = new java.util.Properties();
190: config.put("StrictHostKeyChecking", "no");
191: session.setConfig(config);
192:
193: // setting the proxy that should be used
194: if (this .useProxy) {
195: session.setProxy(new ProxyHTTP(this .remoteProxyHost,
196: this .remoteProxyPort));
197: }
198:
199: // username and password will be given via UserInfo interface.
200: UserInfo ui = new MyUserInfo(this .forwardingHostPwd);
201: session.setUserInfo(ui);
202:
203: // trying to connect ...
204: session.connect();
205:
206: // activating remote port forwarding
207: session.setPortForwardingR(this .forwardingPort,
208: this .localHost, this .localHostPort);
209:
210: // using a timer task to control if the session remains open
211: if (sessionWatcher == null) {
212: this .log
213: .logFine("Deploying port forwarding session watcher thread.");
214: this .switchboard
215: .deployThread(
216: "portForwardingWatcher",
217: "Remote Port Forwarding Watcher",
218: "this thread is used to detect broken connections and to re-establish it if necessary.",
219: null,
220: sessionWatcher = new serverInstantThread(
221: this , "reconnect", null, null),
222: 30000, 30000, 30000, 1000);
223: sessionWatcher.setSyncObject(new Object());
224: }
225:
226: this .log
227: .logInfo("Remote port forwarding connection established: "
228: + this .forwardingHost
229: + ":"
230: + this .forwardingPort
231: + " -> "
232: + this .localHost + ":" + this .localHostPort);
233: } catch (Exception e) {
234: this .log
235: .logSevere(
236: "Unable to connect to remote port forwarding host.",
237: e);
238: throw new IOException(e.getMessage());
239: }
240: }
241:
242: public synchronized boolean reconnect() throws IOException {
243: if ((!this .isConnected())
244: && (!Thread.currentThread().isInterrupted())) {
245: this .log
246: .logFine("Trying to reconnect to port forwarding host.");
247: this .disconnect();
248: this .connect();
249: return this .isConnected();
250: }
251: return false;
252: }
253:
254: public synchronized void disconnect() throws IOException {
255: if (session == null)
256: throw new IOException("No connection established.");
257:
258: // terminating port watcher thread
259: this .log
260: .logFine("Terminating port forwarding session watcher thread.");
261: this .switchboard.terminateThread("portForwardingWatcher", true);
262: sessionWatcher = null;
263:
264: // disconnection the session
265: try {
266: session.disconnect();
267: this .log
268: .logFine("Successfully disconnected from port forwarding host.");
269: } catch (Exception e) {
270: this .log
271: .logSevere(
272: "Error while trying to disconnect from port forwarding host.",
273: e);
274: throw new IOException(e.getMessage());
275: }
276: }
277:
278: public synchronized boolean isConnected() {
279: if (session == null)
280: return false;
281: if (!session.isConnected())
282: return false;
283: int urls = yacyClient.queryUrlCount(yacyCore.seedDB.mySeed());
284: return !(urls < 0);
285: }
286:
287: class MyUserInfo implements UserInfo, UIKeyboardInteractive {
288: String passwd;
289:
290: public MyUserInfo(String password) {
291: this .passwd = password;
292: }
293:
294: public String getPassword() {
295: return this .passwd;
296: }
297:
298: public boolean promptYesNo(String str) {
299: System.err.println("User was prompted from: " + str);
300: return true;
301: }
302:
303: public String getPassphrase() {
304: return null;
305: }
306:
307: public boolean promptPassphrase(String message) {
308: System.out.println("promptPassphrase : " + message);
309: return false;
310: }
311:
312: public boolean promptPassword(String message) {
313: System.out.println("promptPassword : " + message);
314: return true;
315: }
316:
317: /**
318: * @see com.jcraft.jsch.UserInfo#showMessage(java.lang.String)
319: */
320: public void showMessage(String message) {
321: System.out
322: .println("Sch has tried to show the following message to the user: "
323: + message);
324: }
325:
326: public String[] promptKeyboardInteractive(String destination,
327: String name, String instruction, String[] prompt,
328: boolean[] echo) {
329: System.out
330: .println("User was prompted using interactive-keyboard: "
331: + "\n\tDestination: "
332: + destination
333: + "\n\tName: "
334: + name
335: + "\n\tInstruction: "
336: + instruction
337: + "\n\tPrompt: "
338: + arrayToString2(prompt, "|")
339: + "\n\techo: "
340: + arrayToString2(echo, "|"));
341:
342: if ((prompt.length >= 1)
343: && (prompt[0].startsWith("Password")))
344: return new String[] { this .passwd };
345: return new String[] {};
346: }
347:
348: String arrayToString2(String[] a, String separator) {
349: StringBuffer result = new StringBuffer(); // start with first element
350: if (a.length > 0) {
351: result.append(a[0]);
352: for (int i = 1; i < a.length; i++) {
353: result.append(separator);
354: result.append(a[i]);
355: }
356: }
357: return result.toString();
358: }
359:
360: String arrayToString2(boolean[] a, String separator) {
361: StringBuffer result = new StringBuffer(); // start with first element
362: if (a.length > 0) {
363: result.append(a[0]);
364: for (int i = 1; i < a.length; i++) {
365: result.append(separator);
366: result.append(a[i]);
367: }
368: }
369: return result.toString();
370: }
371: }
372:
373: }
|