Merge branch 'stable-2.7' into stable-2.8 * stable-2.7: Bump SSHD version to 0.9.0.201311081 Conflicts: gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowConnections.java pom.xml Change-Id: I29487ae1efb5bdf6f18fc76fe14790a530481c9f
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt index 814472a..6d00dfa 100644 --- a/Documentation/config-gerrit.txt +++ b/Documentation/config-gerrit.txt
@@ -2507,6 +2507,14 @@ [[sshd]] Section sshd ~~~~~~~~~~~~~~~~~~~~~ +[[sshd.backend]]sshd.backend:: ++ +Starting from version 0.9.0 Apache SSHD project added support for NIO2 +IoSession. To use the new NIO2 session the `backend` option must be set +to `NIO2`. ++ +By default, `MINA`. + [[sshd.listenAddress]]sshd.listenAddress:: + Specifies the local addresses the internal SSHD should listen @@ -2545,20 +2553,13 @@ + By default, sshd.listenAddress. -[[sshd.reuseAddress]]sshd.reuseAddress:: -+ -If true, permits the daemon to bind to the port even if the port -is already in use. If false, the daemon ensures the port is not -in use before starting. Busy sites may need to set this to true -to permit fast restarts. -+ -By default, true. - [[sshd.tcpKeepAlive]]sshd.tcpKeepAlive:: + If true, enables TCP keepalive messages to the other side, so the daemon can terminate connections if the peer disappears. + +Only effective when `sshd.backend` is set to `MINA`. ++ By default, true. [[sshd.threads]]sshd.threads::
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/GerritServerSession.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/GerritServerSession.java new file mode 100644 index 0000000..b7f7c22 --- /dev/null +++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/GerritServerSession.java
@@ -0,0 +1,34 @@ +// Copyright (C) 2013 The Android Open Source Project +// +// Licensed 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 com.google.gerrit.sshd; + +import org.apache.sshd.common.future.CloseFuture; +import org.apache.sshd.common.future.SshFutureListener; +import org.apache.sshd.common.io.IoSession; +import org.apache.sshd.server.ServerFactoryManager; +import org.apache.sshd.server.session.ServerSession; + +/* Expose addition of close session listeners */ +class GerritServerSession extends ServerSession { + + GerritServerSession(ServerFactoryManager server, + IoSession ioSession) throws Exception { + super(server, ioSession); + } + + void addCloseSessionListener(SshFutureListener<CloseFuture> l) { + closeFuture.addListener(l); + } +}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java index 8519e94..bafc388 100644 --- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java +++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java
@@ -15,7 +15,6 @@ package com.google.gerrit.sshd; import static com.google.gerrit.server.ssh.SshAddressesModule.IANA_SSH_PORT; - import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.SECONDS; @@ -35,20 +34,18 @@ import com.jcraft.jsch.HostKey; import com.jcraft.jsch.JSchException; -import org.apache.mina.core.future.IoFuture; -import org.apache.mina.core.future.IoFutureListener; -import org.apache.mina.core.service.IoAcceptor; -import org.apache.mina.core.session.IoSession; import org.apache.mina.transport.socket.SocketSessionConfig; import org.apache.sshd.SshServer; import org.apache.sshd.common.Channel; import org.apache.sshd.common.Cipher; import org.apache.sshd.common.Compression; +import org.apache.sshd.common.ForwardingFilter; import org.apache.sshd.common.KeyExchange; import org.apache.sshd.common.KeyPairProvider; import org.apache.sshd.common.NamedFactory; import org.apache.sshd.common.Session; import org.apache.sshd.common.Signature; +import org.apache.sshd.common.SshdSocketAddress; import org.apache.sshd.common.cipher.AES128CBC; import org.apache.sshd.common.cipher.AES192CBC; import org.apache.sshd.common.cipher.AES256CBC; @@ -56,6 +53,19 @@ import org.apache.sshd.common.cipher.CipherNone; import org.apache.sshd.common.cipher.TripleDESCBC; import org.apache.sshd.common.compression.CompressionNone; +import org.apache.sshd.common.file.FileSystemFactory; +import org.apache.sshd.common.file.FileSystemView; +import org.apache.sshd.common.file.SshFile; +import org.apache.sshd.common.forward.DefaultTcpipForwarderFactory; +import org.apache.sshd.common.forward.TcpipServerChannel; +import org.apache.sshd.common.future.CloseFuture; +import org.apache.sshd.common.future.SshFutureListener; +import org.apache.sshd.common.io.IoAcceptor; +import org.apache.sshd.common.io.IoServiceFactory; +import org.apache.sshd.common.io.IoSession; +import org.apache.sshd.common.io.mina.MinaServiceFactory; +import org.apache.sshd.common.io.mina.MinaSession; +import org.apache.sshd.common.io.nio2.Nio2ServiceFactory; import org.apache.sshd.common.mac.HMACMD5; import org.apache.sshd.common.mac.HMACMD596; import org.apache.sshd.common.mac.HMACSHA1; @@ -63,26 +73,21 @@ import org.apache.sshd.common.random.BouncyCastleRandom; import org.apache.sshd.common.random.JceRandom; import org.apache.sshd.common.random.SingletonRandomFactory; +import org.apache.sshd.common.session.AbstractSession; import org.apache.sshd.common.signature.SignatureDSA; import org.apache.sshd.common.signature.SignatureRSA; import org.apache.sshd.common.util.Buffer; import org.apache.sshd.common.util.SecurityUtils; import org.apache.sshd.server.Command; import org.apache.sshd.server.CommandFactory; -import org.apache.sshd.server.FileSystemFactory; -import org.apache.sshd.server.FileSystemView; -import org.apache.sshd.server.ForwardingFilter; import org.apache.sshd.server.PublickeyAuthenticator; -import org.apache.sshd.server.SshFile; import org.apache.sshd.server.UserAuth; import org.apache.sshd.server.auth.UserAuthPublicKey; import org.apache.sshd.server.auth.gss.GSSAuthenticator; import org.apache.sshd.server.auth.gss.UserAuthGSS; -import org.apache.sshd.server.channel.ChannelDirectTcpip; import org.apache.sshd.server.channel.ChannelSession; import org.apache.sshd.server.kex.DHG1; import org.apache.sshd.server.kex.DHG14; -import org.apache.sshd.server.session.ServerSession; import org.apache.sshd.server.session.SessionFactory; import org.eclipse.jgit.lib.Config; import org.slf4j.Logger; @@ -91,7 +96,6 @@ import java.io.File; import java.io.IOException; import java.net.InetAddress; -import java.net.InetSocketAddress; import java.net.SocketAddress; import java.net.UnknownHostException; import java.security.InvalidKeyException; @@ -126,6 +130,11 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener { private static final Logger log = LoggerFactory.getLogger(SshDaemon.class); + public static enum SshSessionBackend { + MINA, + NIO2 + } + private final List<SocketAddress> listen; private final List<String> advertised; private final boolean keepAlive; @@ -144,7 +153,6 @@ this.listen = listen; this.advertised = advertised; - reuseAddress = cfg.getBoolean("sshd", "reuseaddress", true); keepAlive = cfg.getBoolean("sshd", "tcpkeepalive", true); getProperties().put(SERVER_IDENTIFICATION, @@ -161,12 +169,6 @@ long idleTimeoutSeconds = ConfigUtil.getTimeUnit(cfg, "sshd", null, "idleTimeout", 0, SECONDS); - if (idleTimeoutSeconds == 0) { - // Since Apache SSHD does not allow to turn off closing idle connections, - // we fake it by using the highest timeout allowed by Apache SSHD, which - // amounts to ~24 days. - idleTimeoutSeconds = MILLISECONDS.toSeconds(Integer.MAX_VALUE); - } getProperties().put( IDLE_TIMEOUT, String.valueOf(SECONDS.toMillis(idleTimeoutSeconds))); @@ -183,6 +185,14 @@ final String kerberosPrincipal = cfg.getString( "sshd", null, "kerberosPrincipal"); + SshSessionBackend backend = cfg.getEnum( + "sshd", null, "backend", SshSessionBackend.MINA); + + System.setProperty(IoServiceFactory.class.getName(), + backend == SshSessionBackend.MINA + ? MinaServiceFactory.class.getName() + : Nio2ServiceFactory.class.getName()); + if (SecurityUtils.isBouncyCastleRegistered()) { initProviderBouncyCastle(); } else { @@ -192,7 +202,7 @@ initMacs(cfg); initSignatures(); initChannels(); - initForwardingFilter(); + initForwarding(); initFileSystemFactory(); initSubsystems(); initCompression(); @@ -202,24 +212,28 @@ setShellFactory(noShell); setSessionFactory(new SessionFactory() { @Override - protected ServerSession createSession(final IoSession io) + protected AbstractSession createSession(final IoSession io) throws Exception { - if (io.getConfig() instanceof SocketSessionConfig) { - final SocketSessionConfig c = (SocketSessionConfig) io.getConfig(); - c.setKeepAlive(keepAlive); + if (io instanceof MinaSession) { + if (((MinaSession) io).getSession() + .getConfig() instanceof SocketSessionConfig) { + ((SocketSessionConfig) ((MinaSession) io).getSession() + .getConfig()) + .setKeepAlive(keepAlive); + } } - final ServerSession s = (ServerSession) super.createSession(io); - final int id = idGenerator.next(); - final SocketAddress peer = io.getRemoteAddress(); + GerritServerSession s = (GerritServerSession)super.createSession(io); + int id = idGenerator.next(); + SocketAddress peer = io.getRemoteAddress(); final SshSession sd = new SshSession(id, peer); s.setAttribute(SshSession.KEY, sd); // Log a session close without authentication as a failure. // - io.getCloseFuture().addListener(new IoFutureListener<IoFuture>() { + s.addCloseSessionListener(new SshFutureListener<CloseFuture>() { @Override - public void operationComplete(IoFuture future) { + public void operationComplete(CloseFuture future) { if (sd.isAuthenticationError()) { sshLog.onAuthFail(sd); } @@ -227,6 +241,12 @@ }); return s; } + + @Override + protected AbstractSession doCreateSession(IoSession ioSession) + throws Exception { + return new GerritServerSession(server, ioSession); + } }); hostKeys = computeHostKeys(); @@ -245,13 +265,11 @@ public synchronized void start() { if (acceptor == null && !listen.isEmpty()) { checkConfig(); - + if (sessionFactory == null) { + sessionFactory = createSessionFactory(); + } + sessionFactory.setServer(this); acceptor = createAcceptor(); - configure(acceptor); - - final SessionFactory handler = getSessionFactory(); - handler.setServer(this); - acceptor.setHandler(handler); try { acceptor.bind(listen); @@ -259,7 +277,8 @@ throw new IllegalStateException("Cannot bind to " + addressList(), e); } - log.info("Started Gerrit SSHD on " + addressList()); + log.info(String.format("Started Gerrit %s on %s", + version, addressList())); } } @@ -473,7 +492,7 @@ private void initChannels() { setChannelFactories(Arrays.<NamedFactory<Channel>> asList( new ChannelSession.Factory(), // - new ChannelDirectTcpip.Factory() // + new TcpipServerChannel.DirectTcpipFactory() // )); } @@ -514,28 +533,29 @@ setPublickeyAuthenticator(pubkey); } - private void initForwardingFilter() { - setForwardingFilter(new ForwardingFilter() { + private void initForwarding() { + setTcpipForwardingFilter(new ForwardingFilter() { @Override - public boolean canForwardAgent(ServerSession session) { - return false; + public boolean canForwardAgent(Session session) { + return false; } @Override - public boolean canForwardX11(ServerSession session) { - return false; + public boolean canForwardX11(Session session) { + return false; } @Override - public boolean canConnect(InetSocketAddress address, ServerSession session) { - return false; + public boolean canListen(SshdSocketAddress address, Session session) { + return false; } @Override - public boolean canListen(InetSocketAddress address, ServerSession session) { - return false; + public boolean canConnect(SshdSocketAddress address, Session session) { + return false; } }); + setTcpipForwarderFactory(new DefaultTcpipForwarderFactory()); } private void initFileSystemFactory() {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshUtil.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshUtil.java index fc1303c..a2f2c1d 100644 --- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshUtil.java +++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshUtil.java
@@ -21,8 +21,8 @@ import com.google.gerrit.sshd.SshScope.Context; import org.apache.commons.codec.binary.Base64; -import org.apache.mina.core.future.IoFuture; -import org.apache.mina.core.future.IoFutureListener; +import org.apache.sshd.common.future.CloseFuture; +import org.apache.sshd.common.future.SshFutureListener; import org.apache.sshd.common.KeyPairProvider; import org.apache.sshd.common.SshException; import org.apache.sshd.common.util.Buffer; @@ -138,10 +138,11 @@ sshScope.set(old); } - session.getIoSession().getCloseFuture().addListener( - new IoFutureListener<IoFuture>() { + GerritServerSession s = (GerritServerSession) session; + s.addCloseSessionListener( + new SshFutureListener<CloseFuture>() { @Override - public void operationComplete(IoFuture future) { + public void operationComplete(CloseFuture future) { final Context ctx = sshScope.newContext(null, sd, null); final Context old = sshScope.set(ctx); try {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java index 89ba6ba..ff1de80 100644 --- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java +++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java
@@ -32,8 +32,9 @@ import com.google.inject.Inject; import com.google.inject.Provider; -import org.apache.mina.core.service.IoAcceptor; -import org.apache.mina.core.session.IoSession; +import org.apache.sshd.common.io.IoAcceptor; +import org.apache.sshd.common.io.IoSession; +import org.apache.sshd.common.io.mina.MinaSession; import org.apache.sshd.server.Environment; import org.eclipse.jgit.internal.storage.file.WindowCacheStatAccessor; import org.kohsuke.args4j.Option; @@ -274,8 +275,12 @@ long now = TimeUtil.nowMs(); Collection<IoSession> list = acceptor.getManagedSessions().values(); long oldest = now; + for (IoSession s : list) { - oldest = Math.min(oldest, s.getCreationTime()); + if (s instanceof MinaSession) { + MinaSession minaSession = (MinaSession)s; + oldest = Math.min(oldest, minaSession.getSession().getCreationTime()); + } } stdout.format(
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowConnections.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowConnections.java index f8531ed..d97d750 100644 --- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowConnections.java +++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowConnections.java
@@ -26,8 +26,9 @@ import com.google.gerrit.sshd.SshSession; import com.google.inject.Inject; -import org.apache.mina.core.service.IoAcceptor; -import org.apache.mina.core.session.IoSession; +import org.apache.sshd.common.io.IoAcceptor; +import org.apache.sshd.common.io.IoSession; +import org.apache.sshd.common.io.mina.MinaSession; import org.apache.sshd.server.Environment; import org.apache.sshd.server.session.ServerSession; import org.kohsuke.args4j.Option; @@ -84,10 +85,16 @@ Collections.sort(list, new Comparator<IoSession>() { @Override public int compare(IoSession arg0, IoSession arg1) { - if (arg0.getCreationTime() < arg1.getCreationTime()) { - return -1; - } else if (arg0.getCreationTime() > arg1.getCreationTime()) { - return 1; + if (arg0 instanceof MinaSession) { + MinaSession mArg0 = (MinaSession) arg0; + MinaSession mArg1 = (MinaSession) arg1; + if (mArg0.getSession().getCreationTime() < mArg1.getSession() + .getCreationTime()) { + return -1; + } else if (mArg0.getSession().getCreationTime() > mArg1.getSession() + .getCreationTime()) { + return 1; + } } return (int) (arg0.getId() - arg1.getId()); } @@ -104,8 +111,15 @@ SshSession sd = s != null ? s.getAttribute(SshSession.KEY) : null; final SocketAddress remoteAddress = io.getRemoteAddress(); - final long start = io.getCreationTime(); - final long idle = now - io.getLastIoTime(); + MinaSession minaSession = io instanceof MinaSession + ? (MinaSession) io + : null; + final long start = minaSession == null + ? 0 + : minaSession.getSession().getCreationTime(); + final long idle = minaSession == null + ? now + : now - minaSession.getSession().getLastIoTime(); stdout.print(String.format("%8s %8s %8s %-15.15s %s\n", // id(sd), //
diff --git a/gerrit-war/src/main/resources/log4j.properties b/gerrit-war/src/main/resources/log4j.properties index 1fcca6d..cb14916 100644 --- a/gerrit-war/src/main/resources/log4j.properties +++ b/gerrit-war/src/main/resources/log4j.properties
@@ -26,7 +26,7 @@ log4j.logger.org.apache.sshd.common=WARN log4j.logger.org.apache.sshd.server=WARN log4j.logger.org.apache.sshd.common.keyprovider.FileKeyPairProvider=INFO -log4j.logger.com.google.gerrit.server.ssh.GerritServerSession=WARN +log4j.logger.com.google.gerrit.sshd.GerritServerSession=WARN # Silence non-critical messages from Jetty. #
diff --git a/lib/mina/BUCK b/lib/mina/BUCK index 3e9558a..9467cc4 100644 --- a/lib/mina/BUCK +++ b/lib/mina/BUCK
@@ -8,17 +8,18 @@ maven_jar( name = 'core', - id = 'org.apache.mina:mina-core:2.0.5', - sha1 = '0e134a3761833a3c28c79331e806f64f985a9eec', + id = 'org.apache.mina:mina-core:2.0.7', + sha1 = 'c878e2aa82de748474a624ec3933e4604e446dec', license = 'Apache2.0', exclude = EXCLUDE, ) maven_jar( name = 'sshd', - id = 'org.apache.sshd:sshd-core:0.6.0', - sha1 = '2b9a119dd77a1decec78b0c511ba400c8655e96e', + id = 'org.apache.sshd:sshd-core:0.9.0.201311081', + sha1 = '38f7ac8602e70fa05fdc6147d204198e9cefe5bc', license = 'Apache2.0', deps = [':core'], exclude = EXCLUDE, + repository = GERRIT, )