package hudson.cli; import hudson.Extension; import hudson.Util; import hudson.model.Computer; import hudson.remoting.Channel; import hudson.remoting.Channel.Mode; import hudson.remoting.ChannelBuilder; import jenkins.AgentProtocol; import jenkins.model.Jenkins; import jenkins.slaves.NioChannelSelector; import org.jenkinsci.Symbol; import org.jenkinsci.remoting.nio.NioChannelHub; import javax.inject.Inject; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.Socket; /** * {@link AgentProtocol} that accepts connection from CLI clients. * * @author Kohsuke Kawaguchi * @since 1.467 */ @Extension @Symbol("cli") public class CliProtocol extends AgentProtocol { @Inject NioChannelSelector nio; /** * {@inheritDoc} */ @Override public boolean isOptIn() { return OPT_IN; } @Override public String getName() { return "CLI-connect"; } /** * {@inheritDoc} */ @Override public String getDisplayName() { return "Jenkins CLI Protocol/1"; } @Override public void handle(Socket socket) throws IOException, InterruptedException { new Handler(nio.getHub(),socket).run(); } protected static class Handler { protected final NioChannelHub hub; protected final Socket socket; /** * @deprecated as of 1.559 * Use {@link #Handler(NioChannelHub, Socket)} */ @Deprecated public Handler(Socket socket) { this(null,socket); } public Handler(NioChannelHub hub, Socket socket) { this.hub = hub; this.socket = socket; } public void run() throws IOException, InterruptedException { PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),"UTF-8")),true); out.println("Welcome"); runCli(new Connection(socket)); } protected void runCli(Connection c) throws IOException, InterruptedException { ChannelBuilder cb; String name = "CLI channel from " + socket.getInetAddress(); // Connection can contain cipher wrapper, which can't be NIO-ed. // if (hub!=null) // cb = hub.newChannelBuilder(name, Computer.threadPoolForRemoting); // else cb = new ChannelBuilder(name, Computer.threadPoolForRemoting); Channel channel = cb .withMode(Mode.BINARY) .withRestricted(true) .withBaseLoader(Jenkins.getActiveInstance().pluginManager.uberClassLoader) .build(new BufferedInputStream(c.in), new BufferedOutputStream(c.out)); channel.setProperty(CliEntryPoint.class.getName(),new CliManagerImpl(channel)); channel.join(); } } /** * A/B test turning off this protocol by default. */ private static final boolean OPT_IN; static { byte hash = Util.fromHexString(Jenkins.getInstance().getLegacyInstanceId())[0]; OPT_IN = (hash % 10) == 0; } }