Repository: mina-sshd Updated Branches: refs/heads/master 4b19c2a53 -> 57c5ed623
Take into account the timeout value provided in RemoteSession#exec call Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/57c5ed62 Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/57c5ed62 Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/57c5ed62 Branch: refs/heads/master Commit: 57c5ed6234b5102e09603178246739d81c3ceea8 Parents: 4b19c2a Author: Lyor Goldstein <[email protected]> Authored: Mon Sep 21 08:41:28 2015 +0300 Committer: Lyor Goldstein <[email protected]> Committed: Mon Sep 21 08:41:28 2015 +0300 ---------------------------------------------------------------------- .../sshd/git/pack/GitPackCommandFactory.java | 1 - .../sshd/git/pgm/GitPgmCommandFactory.java | 5 +- .../sshd/git/transport/GitSshdSession.java | 132 +++++++++++++++++++ .../git/transport/GitSshdSessionFactory.java | 131 +----------------- .../git/transport/GitSshdSessionProcess.java | 102 ++++++++++++++ 5 files changed, 238 insertions(+), 133 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/57c5ed62/sshd-git/src/main/java/org/apache/sshd/git/pack/GitPackCommandFactory.java ---------------------------------------------------------------------- diff --git a/sshd-git/src/main/java/org/apache/sshd/git/pack/GitPackCommandFactory.java b/sshd-git/src/main/java/org/apache/sshd/git/pack/GitPackCommandFactory.java index 191ca5d..1eeefdf 100644 --- a/sshd-git/src/main/java/org/apache/sshd/git/pack/GitPackCommandFactory.java +++ b/sshd-git/src/main/java/org/apache/sshd/git/pack/GitPackCommandFactory.java @@ -51,5 +51,4 @@ public class GitPackCommandFactory implements CommandFactory { return new UnknownCommand(command); } } - } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/57c5ed62/sshd-git/src/main/java/org/apache/sshd/git/pgm/GitPgmCommandFactory.java ---------------------------------------------------------------------- diff --git a/sshd-git/src/main/java/org/apache/sshd/git/pgm/GitPgmCommandFactory.java b/sshd-git/src/main/java/org/apache/sshd/git/pgm/GitPgmCommandFactory.java index 86db60e..f508ab9 100644 --- a/sshd-git/src/main/java/org/apache/sshd/git/pgm/GitPgmCommandFactory.java +++ b/sshd-git/src/main/java/org/apache/sshd/git/pgm/GitPgmCommandFactory.java @@ -28,6 +28,7 @@ import org.apache.sshd.server.command.UnknownCommand; * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> */ public class GitPgmCommandFactory implements CommandFactory { + public static final String GIT_COMMAND_PREFIX = "git "; private final String rootDir; private final CommandFactory delegate; @@ -43,8 +44,8 @@ public class GitPgmCommandFactory implements CommandFactory { @Override public Command createCommand(String command) { - if (command.startsWith("git ")) { - return new GitPgmCommand(rootDir, command.substring("git ".length())); + if (command.startsWith(GIT_COMMAND_PREFIX)) { + return new GitPgmCommand(rootDir, command.substring(GIT_COMMAND_PREFIX.length())); } else if (delegate != null) { return delegate.createCommand(command); } else { http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/57c5ed62/sshd-git/src/main/java/org/apache/sshd/git/transport/GitSshdSession.java ---------------------------------------------------------------------- diff --git a/sshd-git/src/main/java/org/apache/sshd/git/transport/GitSshdSession.java b/sshd-git/src/main/java/org/apache/sshd/git/transport/GitSshdSession.java new file mode 100644 index 0000000..ff2191e --- /dev/null +++ b/sshd-git/src/main/java/org/apache/sshd/git/transport/GitSshdSession.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sshd.git.transport; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +import org.apache.sshd.client.SshClient; +import org.apache.sshd.client.channel.ChannelExec; +import org.apache.sshd.client.session.ClientSession; +import org.apache.sshd.common.FactoryManagerUtils; +import org.apache.sshd.common.util.logging.AbstractLoggingBean; +import org.eclipse.jgit.transport.CredentialItem; +import org.eclipse.jgit.transport.CredentialsProvider; +import org.eclipse.jgit.transport.RemoteSession; +import org.eclipse.jgit.transport.URIish; +import org.eclipse.jgit.util.FS; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +public class GitSshdSession extends AbstractLoggingBean implements RemoteSession { + /** + * Property used to configure the SSHD {@link org.apache.sshd.common.FactoryManager} with + * the default timeout (millis) to connect to the remote SSH server. + * If not specified then {@link #DEFAULT_CONNECT_TIMEOUT} is used. + */ + public static final String CONNECT_TIMEOUT_PROP = "git-ssh-connect-timeout"; + public static final long DEFAULT_CONNECT_TIMEOUT = TimeUnit.SECONDS.toMillis(30L); + + /** + * Property used to configure the SSHD {@link org.apache.sshd.common.FactoryManager} with + * the default timeout (millis) to authenticate with the remote SSH server. + * If not specified then {@link #DEFAULT_AUTH_TIMEOUT} is used. + */ + public static final String AUTH_TIMEOUT_PROP = "git-ssh-connect-timeout"; + public static final long DEFAULT_AUTH_TIMEOUT = TimeUnit.SECONDS.toMillis(15L); + + /** + * Property used to configure the SSHD {@link org.apache.sshd.common.FactoryManager} with + * the default timeout (millis) to open a channel to the remote SSH server. + * If not specified then {@link #DEFAULT_CHANNEL_OPEN__TIMEOUT) is used. + */ + public static final String CHANNEL_OPEN_TIMEOUT_PROPT = "git-ssh-channel-open-timeout"; + public static final long DEFAULT_CHANNEL_OPEN_TIMEOUT = TimeUnit.SECONDS.toMillis(7L); + + private final SshClient client; + private final ClientSession session; + + public GitSshdSession(URIish uri, CredentialsProvider credentialsProvider, FS fs, int tms) throws IOException, InterruptedException { + String user = uri.getUser(); + final String pass = uri.getPass(); + String host = uri.getHost(); + int port = uri.getPort(); + char[] pass2 = null; + + if (!credentialsProvider.isInteractive()) { + CredentialItem.Username usrItem = new CredentialItem.Username(); + CredentialItem.Password pwdItem = new CredentialItem.Password(); + if (credentialsProvider.get(uri, usrItem, pwdItem)) { + if (user == null) { + user = usrItem.getValue(); + } else if (user.equals(usrItem.getValue())) { + pass2 = pwdItem.getValue(); + } + } + } + + client = createClient(); + + client.start(); + + session = client.connect(user, host, port) + .verify(FactoryManagerUtils.getLongProperty(client, CONNECT_TIMEOUT_PROP, DEFAULT_CONNECT_TIMEOUT)) + .getSession(); + if (log.isDebugEnabled()) { + log.debug("Connected to {}:{}", host, port); + } + if (pass != null) { + session.addPasswordIdentity(pass); + } + if (pass2 != null) { + session.addPasswordIdentity(new String(pass2)); + } + session.auth().verify(FactoryManagerUtils.getLongProperty(session, AUTH_TIMEOUT_PROP, DEFAULT_AUTH_TIMEOUT)); + if (log.isDebugEnabled()) { + log.debug("Authenticated: {}", session); + } + } + + @Override + public Process exec(String commandName, int timeout) throws IOException { + if (log.isTraceEnabled()) { + log.trace("exec({}) session={}, timeout={} sec.", commandName, session, timeout); + } + + ChannelExec channel = session.createExecChannel(commandName); + channel.open().verify(FactoryManagerUtils.getLongProperty(channel, CHANNEL_OPEN_TIMEOUT_PROPT, DEFAULT_CHANNEL_OPEN_TIMEOUT)); + return new GitSshdSessionProcess(channel, commandName, timeout); + } + + @Override + public void disconnect() { + if (session.isOpen()) { + if (log.isDebugEnabled()) { + log.debug("Disconnecting from {}", session); + } + } + + client.close(true); + } + + protected SshClient createClient() { + return SshClient.setUpDefaultClient(); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/57c5ed62/sshd-git/src/main/java/org/apache/sshd/git/transport/GitSshdSessionFactory.java ---------------------------------------------------------------------- diff --git a/sshd-git/src/main/java/org/apache/sshd/git/transport/GitSshdSessionFactory.java b/sshd-git/src/main/java/org/apache/sshd/git/transport/GitSshdSessionFactory.java index 0e19278..545657d 100644 --- a/sshd-git/src/main/java/org/apache/sshd/git/transport/GitSshdSessionFactory.java +++ b/sshd-git/src/main/java/org/apache/sshd/git/transport/GitSshdSessionFactory.java @@ -18,21 +18,7 @@ */ package org.apache.sshd.git.transport; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Collection; -import java.util.EnumSet; -import java.util.concurrent.TimeUnit; - -import org.apache.sshd.client.SshClient; -import org.apache.sshd.client.channel.ChannelExec; -import org.apache.sshd.client.channel.ClientChannel; -import org.apache.sshd.client.session.ClientSession; -import org.apache.sshd.common.FactoryManagerUtils; -import org.apache.sshd.common.util.ValidateUtils; import org.eclipse.jgit.errors.TransportException; -import org.eclipse.jgit.transport.CredentialItem; import org.eclipse.jgit.transport.CredentialsProvider; import org.eclipse.jgit.transport.RemoteSession; import org.eclipse.jgit.transport.SshSessionFactory; @@ -45,30 +31,6 @@ import org.eclipse.jgit.util.FS; * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> */ public class GitSshdSessionFactory extends SshSessionFactory { - /** - * Property used to configure the SSHD {@link org.apache.sshd.common.FactoryManager} with - * the default timeout (millis) to connect to the remote SSH server. - * If not specified then {@link #DEFAULT_CONNECT_TIMEOUT} is used - */ - public static final String CONNECT_TIMEOUT_PROP = "git-ssh-connect-timeout"; - public static final long DEFAULT_CONNECT_TIMEOUT = TimeUnit.SECONDS.toMillis(30L); - - /** - * Property used to configure the SSHD {@link org.apache.sshd.common.FactoryManager} with - * the default timeout (millis) to authenticate with the remote SSH server. - * If not specified then {@link #DEFAULT_AUTH_TIMEOUT} is used - */ - public static final String AUTH_TIMEOUT_PROP = "git-ssh-connect-timeout"; - public static final long DEFAULT_AUTH_TIMEOUT = TimeUnit.SECONDS.toMillis(15L); - - /** - * Property used to configure the SSHD {@link org.apache.sshd.common.FactoryManager} with - * the default timeout (millis) to open a channel to the remote SSH server. - * If not specified then {@link #DEFAULT_CHANNEL_OPEN__TIMEOUT); - */ - public static final String CHANNEL_OPEN_TIMEOUT_PROPT = "git-ssh-channel-open-timeout"; - public static final long DEFAULT_CHANNEL_OPEN_TIMEOUT = TimeUnit.SECONDS.toMillis(7L); - public GitSshdSessionFactory() { super(); } @@ -76,100 +38,9 @@ public class GitSshdSessionFactory extends SshSessionFactory { @Override public RemoteSession getSession(URIish uri, CredentialsProvider credentialsProvider, FS fs, int tms) throws TransportException { try { - return new SshdSession(uri, credentialsProvider, fs, tms); + return new GitSshdSession(uri, credentialsProvider, fs, tms); } catch (Exception e) { throw new TransportException("Unable to connect", e); } } - - protected SshClient createClient() { - return SshClient.setUpDefaultClient(); - } - - public class SshdSession implements RemoteSession { - private final SshClient client; - private final ClientSession session; - - public SshdSession(URIish uri, CredentialsProvider credentialsProvider, FS fs, int tms) throws IOException, InterruptedException { - String user = uri.getUser(); - final String pass = uri.getPass(); - String host = uri.getHost(); - int port = uri.getPort(); - char[] pass2 = null; - - if (!credentialsProvider.isInteractive()) { - CredentialItem.Username usrItem = new CredentialItem.Username(); - CredentialItem.Password pwdItem = new CredentialItem.Password(); - if (credentialsProvider.get(uri, usrItem, pwdItem)) { - if (user == null) { - user = usrItem.getValue(); - } else if (user.equals(usrItem.getValue())) { - pass2 = pwdItem.getValue(); - } - } - } - - client = createClient(); - - client.start(); - session = client.connect(user, host, port) - .verify(FactoryManagerUtils.getLongProperty(client, CONNECT_TIMEOUT_PROP, DEFAULT_CONNECT_TIMEOUT)) - .getSession(); - if (pass != null) { - session.addPasswordIdentity(pass); - } - if (pass2 != null) { - session.addPasswordIdentity(new String(pass2)); - } - session.auth().verify(FactoryManagerUtils.getLongProperty(client, AUTH_TIMEOUT_PROP, DEFAULT_AUTH_TIMEOUT)); - } - - @Override - public Process exec(String commandName, int timeout) throws IOException { - final ChannelExec channel = session.createExecChannel(commandName); - channel.open().verify(FactoryManagerUtils.getLongProperty(client, CHANNEL_OPEN_TIMEOUT_PROPT, DEFAULT_CHANNEL_OPEN_TIMEOUT)); - return new Process() { - @Override - public OutputStream getOutputStream() { - return channel.getInvertedIn(); - } - - @Override - public InputStream getInputStream() { - return channel.getInvertedOut(); - } - - @Override - public InputStream getErrorStream() { - return channel.getInvertedErr(); - } - - @Override - public int waitFor() throws InterruptedException { - Collection<ClientChannel.ClientChannelEvent> res = - channel.waitFor(EnumSet.of(ClientChannel.ClientChannelEvent.CLOSED), Long.MAX_VALUE); - if (res.contains(ClientChannel.ClientChannelEvent.CLOSED)) { - return 0; - } else { - return -1; - } - } - @Override - public int exitValue() { - Integer status = ValidateUtils.checkNotNull(channel.getExitStatus(), "No channel status available"); - return status.intValue(); - } - - @Override - public void destroy() { - channel.close(true); - } - }; - } - - @Override - public void disconnect() { - client.close(true); - } - } } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/57c5ed62/sshd-git/src/main/java/org/apache/sshd/git/transport/GitSshdSessionProcess.java ---------------------------------------------------------------------- diff --git a/sshd-git/src/main/java/org/apache/sshd/git/transport/GitSshdSessionProcess.java b/sshd-git/src/main/java/org/apache/sshd/git/transport/GitSshdSessionProcess.java new file mode 100644 index 0000000..a96b5f3 --- /dev/null +++ b/sshd-git/src/main/java/org/apache/sshd/git/transport/GitSshdSessionProcess.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.sshd.git.transport; + +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Collection; +import java.util.EnumSet; +import java.util.concurrent.TimeUnit; + +import org.apache.sshd.client.channel.ChannelExec; +import org.apache.sshd.client.channel.ClientChannel; +import org.apache.sshd.common.util.ValidateUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +public class GitSshdSessionProcess extends Process { + protected final ChannelExec channel; + protected final String commandName; + protected final long waitTimeout; + protected final Logger log; + + public GitSshdSessionProcess(ChannelExec channel, String commandName, int timeoutSec) { + this.channel = ValidateUtils.checkNotNull(channel, "No exec channel"); + this.commandName = commandName; + this.waitTimeout = (timeoutSec > 0) ? TimeUnit.SECONDS.toMillis(timeoutSec) : Long.MAX_VALUE; + this.log = LoggerFactory.getLogger(getClass()); + } + + @Override + public OutputStream getOutputStream() { + return channel.getInvertedIn(); + } + + @Override + public InputStream getInputStream() { + return channel.getInvertedOut(); + } + + @Override + public InputStream getErrorStream() { + return channel.getInvertedErr(); + } + + @Override // TODO in Java-8 implement also waitFor(long, TimeUnit) + public int waitFor() throws InterruptedException { + Collection<ClientChannel.ClientChannelEvent> res = + channel.waitFor(EnumSet.of(ClientChannel.ClientChannelEvent.CLOSED), waitTimeout); + if (log.isTraceEnabled()) { + log.trace("waitFor({}) channel={}, timeout={} millis.: {}", + commandName, channel, waitTimeout, res); + } + if (res.contains(ClientChannel.ClientChannelEvent.CLOSED)) { + return 0; + } else { + return -1; + } + } + + @Override + public int exitValue() { + Integer status = channel.getExitStatus(); + if (status == null) { // NOTE: MUST use IllegalThreadStateException as per the Javadoc + throw new IllegalThreadStateException("No channel status available"); + } + if (log.isTraceEnabled()) { + log.trace("exitValue({}) channel={}, timeout={} millis.: {}", + commandName, channel, waitTimeout, status); + } + return status.intValue(); + } + + @Override + public void destroy() { + channel.close(true); + } + + @Override + public String toString() { + return "channel=" + channel + ", cmd=" + commandName + ", timeout=" + waitTimeout; + } +}
