diff --git a/remoting/pom.xml b/remoting/pom.xml index a009a8f1503068e329b599ea7065e6b9bd95cb86..4409651640d3a20bb22502705b1c7c4711cdd9f7 100644 --- a/remoting/pom.xml +++ b/remoting/pom.xml @@ -121,8 +121,8 @@ THE SOFTWARE. args4j args4j - 2.0.10 + 2.0.13 provided - \ No newline at end of file + diff --git a/remoting/src/main/java/hudson/remoting/Launcher.java b/remoting/src/main/java/hudson/remoting/Launcher.java index 92de5341d40758c5b1c78c24bb87ca44921b798d..b2131d5e2e6c4e1466a764db8cbf968a883eca1e 100644 --- a/remoting/src/main/java/hudson/remoting/Launcher.java +++ b/remoting/src/main/java/hudson/remoting/Launcher.java @@ -27,6 +27,9 @@ import hudson.remoting.Channel.Mode; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; +import org.kohsuke.args4j.Option; +import org.kohsuke.args4j.CmdLineParser; +import org.kohsuke.args4j.CmdLineException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -60,6 +63,8 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.security.cert.X509Certificate; import java.security.cert.CertificateException; +import java.security.NoSuchAlgorithmException; +import java.security.KeyManagementException; /** * Entry point for running a {@link Channel}. This is the main method of the slave JVM. @@ -71,120 +76,104 @@ import java.security.cert.CertificateException; * @author Kohsuke Kawaguchi */ public class Launcher { - public static void main(String[] args) throws Exception { - Mode m = Mode.BINARY; - boolean ping = true; - URL slaveJnlpURL = null; - File tcpPortFile = null; - InetSocketAddress connectionTarget=null; - - for(int i=0; i : instead of talking to the master via stdin/stdout, emulate a JNLP client\n" + - " by making a TCP connection to the master. Connection parameters\n" + - " are obtained by parsing the JNLP file.\n" + - " -cp paths : add the given classpath elements to the system classloader\n" + - " -noCertificateCheck :\n" + - " bypass HTTPS certificate checks altogether.\n" + - " -connectTo : :\n" + - " make a TCP connection to the given host and port, then start communication.\n" + - " -tcp : instead of talking to the master via stdin/stdout, listens to a random\n" + - " local port, write that port number to the given file, then wait for the\n" + - " master to connect to that port.\n"); - System.exit(-1); + @Option(name="-cp",aliases="-classpath",metaVar="PATH", + usage="add the given classpath elements to the system classloader.") + public void addClasspath(String pathList) throws Exception { + Method $addURL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); + $addURL.setAccessible(true); + + for(String token : pathList.split(File.pathSeparator)) + $addURL.invoke(ClassLoader.getSystemClassLoader(),new File(token).toURI().toURL()); + + // fix up the system.class.path to pretend that those jar files + // are given through CLASSPATH or something. + // some tools like JAX-WS RI and Hadoop relies on this. + System.setProperty("java.class.path",System.getProperty("java.class.path")+File.pathSeparatorChar+pathList); + } + + @Option(name="-tcp",usage="instead of talking to the master via stdin/stdout, " + + "listens to a random local port, write that port number to the given file, " + + "then wait for the master to connect to that port.") + public File tcpPortFile=null; + + public InetSocketAddress connectionTarget = null; + + @Option(name="-connectTo",usage="make a TCP connection to the given host and port, then start communication.",metaVar="HOST:PORT") + public void setConnectTo(String target) { + String[] tokens = target.split(":"); + if(tokens.length!=2) { + System.err.println("Illegal parameter: "+target); + System.exit(1); } + connectionTarget = new InetSocketAddress(tokens[0],Integer.valueOf(tokens[1])); + } + /** + * Bypass HTTPS security check by using free-for-all trust manager. + * + * @param _ + * This is ignored. + */ + @Option(name="-noCertificateCheck") + public void setNoCertificateCheck(boolean _) throws NoSuchAlgorithmException, KeyManagementException { + System.out.println("Skipping HTTPS certificate checks altoghether. Note that this is not secure at all."); + SSLContext context = SSLContext.getInstance("TLS"); + context.init(null, new TrustManager[]{new NoCheckTrustManager()}, new java.security.SecureRandom()); + HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory()); + // bypass host name check, too. + HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { + public boolean verify(String s, SSLSession sslSession) { + return true; + } + }); + } + + public static void main(String[] args) throws Exception { + Launcher launcher = new Launcher(); + CmdLineParser parser = new CmdLineParser(launcher); + try { + parser.parseArgument(args); + launcher.run(); + } catch (CmdLineException e) { + System.err.println(e.getMessage()); + System.err.println("java -jar slave.jar [options...]"); + parser.printUsage(System.err); + System.err.println(); + } + } + public void run() throws Exception { if(connectionTarget!=null) { - runAsTcpClient(connectionTarget,m,ping); + runAsTcpClient(); System.exit(0); } else if(slaveJnlpURL!=null) { - List jnlpArgs = parseJnlpArguments(slaveJnlpURL); + List jnlpArgs = parseJnlpArguments(); hudson.remoting.jnlp.Main.main(jnlpArgs.toArray(new String[jnlpArgs.size()])); } else if(tcpPortFile!=null) { - runAsTcpServer(tcpPortFile,m,ping); + runAsTcpServer(); System.exit(0); } else { - runWithStdinStdout(m, ping); + runWithStdinStdout(); System.exit(0); } } @@ -192,7 +181,7 @@ public class Launcher { /** * Parses the connection arguments from JNLP file given in the URL. */ - private static List parseJnlpArguments(URL slaveJnlpURL) throws ParserConfigurationException, SAXException, IOException, InterruptedException { + private List parseJnlpArguments() throws ParserConfigurationException, SAXException, IOException, InterruptedException { while (true) { try { URLConnection con = slaveJnlpURL.openConnection(); @@ -257,14 +246,14 @@ public class Launcher { * Listens on an ephemeral port, record that port number in a port file, * then accepts one TCP connection. */ - private static void runAsTcpServer(File portFile, Mode m, boolean ping) throws IOException, InterruptedException { + private void runAsTcpServer() throws IOException, InterruptedException { // if no one connects for too long, assume something went wrong // and avoid hanging foreever ServerSocket ss = new ServerSocket(0,1); ss.setSoTimeout(30*1000); // write a port file to report the port number - FileWriter w = new FileWriter(portFile); + FileWriter w = new FileWriter(tcpPortFile); w.write(String.valueOf(ss.getLocalPort())); w.close(); @@ -275,29 +264,29 @@ public class Launcher { s = ss.accept(); ss.close(); } finally { - portFile.delete(); + tcpPortFile.delete(); } - runOnSocket(m, ping, s); + runOnSocket(s); } - private static void runOnSocket(Mode m, boolean ping, Socket s) throws IOException, InterruptedException { + private void runOnSocket(Socket s) throws IOException, InterruptedException { main(new BufferedInputStream(new SocketInputStream(s)), - new BufferedOutputStream(new SocketOutputStream(s)),m,ping); + new BufferedOutputStream(new SocketOutputStream(s)), mode,ping); } /** * Connects to the given TCP port and then start running */ - private static void runAsTcpClient(InetSocketAddress target, Mode m, boolean ping) throws IOException, InterruptedException { + private void runAsTcpClient() throws IOException, InterruptedException { // if no one connects for too long, assume something went wrong // and avoid hanging foreever - Socket s = new Socket(target.getAddress(),target.getPort()); + Socket s = new Socket(connectionTarget.getAddress(),connectionTarget.getPort()); - runOnSocket(m, ping, s); + runOnSocket(s); } - private static void runWithStdinStdout(Mode m, boolean ping) throws IOException, InterruptedException { + private void runWithStdinStdout() throws IOException, InterruptedException { // use stdin/stdout for channel communication ttyCheck(); @@ -305,7 +294,7 @@ public class Launcher { // and messing up the stream. OutputStream os = System.out; System.setOut(System.err); - main(System.in,os,m,ping); + main(System.in,os, mode,ping); } private static void ttyCheck() {