[SSHD-386] Allow controlling socket options Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/f3d58b90 Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/f3d58b90 Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/f3d58b90
Branch: refs/heads/master Commit: f3d58b906d795bac587f77eedb4647ad421b260d Parents: 55bc681 Author: Guillaume Nodet <[email protected]> Authored: Fri Dec 12 14:07:55 2014 +0100 Committer: Guillaume Nodet <[email protected]> Committed: Fri Dec 12 14:07:55 2014 +0100 ---------------------------------------------------------------------- .../org/apache/sshd/common/FactoryManager.java | 42 ++++++++++++++++++++ .../sshd/common/io/mina/MinaAcceptor.java | 35 +++++----------- .../sshd/common/io/mina/MinaConnector.java | 6 +-- .../apache/sshd/common/io/mina/MinaService.java | 37 +++++++++++++++++ .../sshd/common/io/nio2/Nio2Acceptor.java | 14 ++++++- .../sshd/common/io/nio2/Nio2Connector.java | 7 ++++ .../apache/sshd/common/io/nio2/Nio2Service.java | 26 ++++++++++++ 7 files changed, 136 insertions(+), 31 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f3d58b90/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java b/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java index 037b718..c78f8e8 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java @@ -71,6 +71,48 @@ public interface FactoryManager { public static final String IDLE_TIMEOUT = "idle-timeout"; /** + * Socket backlog. + * See {@link java.nio.channels.AsynchronousServerSocketChannel#bind(java.net.SocketAddress, int)} + */ + public static final String SOCKET_BACKLOG = "socket-backlog"; + + /** + * Socket keep-alive. + * See {@link java.net.StandardSocketOptions#SO_KEEPALIVE} + */ + public static final String SOCKET_KEEPALIVE = "socket-keepalive"; + + /** + * Socket send buffer size. + * See {@link java.net.StandardSocketOptions#SO_SNDBUF} + */ + public static final String SOCKET_SNDBUF = "socket-sndbuf"; + + /** + * Socket receive buffer size. + * See {@link java.net.StandardSocketOptions#SO_RCVBUF} + */ + public static final String SOCKET_RCVBUF = "socket-rcvbuf"; + + /** + * Socket reuse address. + * See {@link java.net.StandardSocketOptions#SO_REUSEADDR} + */ + public static final String SOCKET_REUSEADDR = "socket-reuseaddr"; + + /** + * Socket linger. + * See {@link java.net.StandardSocketOptions#SO_LINGER} + */ + public static final String SOCKET_LINGER = "socket-linger"; + + /** + * Socket tcp no-delay. + * See {@link java.net.StandardSocketOptions#TCP_NODELAY} + */ + public static final String TCP_NODELAY = "tcp-nodelay"; + + /** * A map of properties that can be used to configure the SSH server * or client. This map will never be changed by either the server or * client and is not supposed to be changed at runtime (changes are not http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f3d58b90/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaAcceptor.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaAcceptor.java b/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaAcceptor.java index 107972e..7a20d78 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaAcceptor.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaAcceptor.java @@ -19,7 +19,6 @@ package org.apache.sshd.common.io.mina; import java.io.IOException; -import java.net.Socket; import java.net.SocketAddress; import java.util.Collection; import java.util.Set; @@ -28,7 +27,6 @@ import org.apache.mina.core.service.IoAcceptor; import org.apache.mina.core.service.IoHandler; import org.apache.mina.core.service.IoProcessor; import org.apache.mina.core.service.IoService; -import org.apache.mina.core.session.IoSessionConfig; import org.apache.mina.transport.socket.nio.NioSession; import org.apache.mina.transport.socket.nio.NioSocketAcceptor; import org.apache.sshd.common.FactoryManager; @@ -39,12 +37,20 @@ public class MinaAcceptor extends MinaService implements org.apache.sshd.common. protected volatile IoAcceptor acceptor; // Acceptor - protected int backlog = 50; + protected int backlog = 0; protected boolean reuseAddress = true; - protected IoSessionConfig sessionConfig; public MinaAcceptor(FactoryManager manager, org.apache.sshd.common.io.IoHandler handler, IoProcessor<NioSession> ioProcessor) { super(manager, handler, ioProcessor); + + String valStr = manager.getProperties().get(FactoryManager.SOCKET_BACKLOG); + if (valStr != null) { + backlog = Integer.parseInt(valStr); + } + valStr = manager.getProperties().get(FactoryManager.SOCKET_REUSEADDR); + if (valStr != null) { + reuseAddress = Boolean.parseBoolean(valStr); + } } protected IoAcceptor createAcceptor() { @@ -52,26 +58,7 @@ public class MinaAcceptor extends MinaService implements org.apache.sshd.common. acceptor.setCloseOnDeactivation(false); acceptor.setReuseAddress(reuseAddress); acceptor.setBacklog(backlog); - - // MINA itself forces our socket receive buffer to 1024 bytes - // by default, despite what the operating system defaults to. - // This limits us to about 3 MB/s incoming data transfer. By - // forcing back to the operating system default we can get a - // decent transfer rate again. - // - final Socket s = new Socket(); - try { - try { - acceptor.getSessionConfig().setReceiveBufferSize(s.getReceiveBufferSize()); - } finally { - s.close(); - } - } catch (IOException e) { - log.warn("cannot adjust SO_RCVBUF back to system default", e); - } - if (sessionConfig != null) { - acceptor.getSessionConfig().setAll(sessionConfig); - } + configure(acceptor.getSessionConfig()); return acceptor; } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f3d58b90/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaConnector.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaConnector.java b/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaConnector.java index 8181652..6e4e368 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaConnector.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaConnector.java @@ -25,7 +25,6 @@ import org.apache.mina.core.future.IoFutureListener; import org.apache.mina.core.service.IoConnector; import org.apache.mina.core.service.IoHandler; import org.apache.mina.core.service.IoProcessor; -import org.apache.mina.core.session.IoSessionConfig; import org.apache.mina.transport.socket.nio.NioSession; import org.apache.mina.transport.socket.nio.NioSocketConnector; import org.apache.sshd.common.FactoryManager; @@ -37,7 +36,6 @@ import org.apache.sshd.common.io.IoConnectFuture; public class MinaConnector extends MinaService implements org.apache.sshd.common.io.IoConnector, IoHandler { protected volatile IoConnector connector; - protected IoSessionConfig sessionConfig; public MinaConnector(FactoryManager manager, org.apache.sshd.common.io.IoHandler handler, IoProcessor<NioSession> ioProcessor) { super(manager, handler, ioProcessor); @@ -45,9 +43,7 @@ public class MinaConnector extends MinaService implements org.apache.sshd.common protected IoConnector createConnector() { NioSocketConnector connector = new NioSocketConnector(ioProcessor); - if (sessionConfig != null) { - connector.getSessionConfig().setAll(sessionConfig); - } + configure(connector.getSessionConfig()); return connector; } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f3d58b90/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaService.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaService.java b/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaService.java index 6d962ed..1981eb8 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaService.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaService.java @@ -28,6 +28,8 @@ import org.apache.mina.core.service.IoProcessor; import org.apache.mina.core.service.IoService; import org.apache.mina.core.session.IdleStatus; import org.apache.mina.core.session.IoSession; +import org.apache.mina.core.session.IoSessionConfig; +import org.apache.mina.transport.socket.SocketSessionConfig; import org.apache.mina.transport.socket.nio.NioSession; import org.apache.sshd.common.Closeable; import org.apache.sshd.common.FactoryManager; @@ -45,6 +47,7 @@ public abstract class MinaService extends IoHandlerAdapter implements org.apache protected final FactoryManager manager; protected final org.apache.sshd.common.io.IoHandler handler; protected final IoProcessor<NioSession> ioProcessor; + protected IoSessionConfig sessionConfig; public MinaService(FactoryManager manager, org.apache.sshd.common.io.IoHandler handler, IoProcessor<NioSession> ioProcessor) { this.manager = manager; @@ -106,4 +109,38 @@ public abstract class MinaService extends IoHandlerAdapter implements org.apache return (org.apache.sshd.common.io.IoSession) session.getAttribute(org.apache.sshd.common.io.IoSession.class); } + + protected void configure(SocketSessionConfig config) { + Integer intVal; + Boolean boolVal; + if ((boolVal = getBoolean(FactoryManager.SOCKET_KEEPALIVE)) != null) { + config.setKeepAlive(boolVal); + } + if ((intVal = getInteger(FactoryManager.SOCKET_SNDBUF)) != null) { + config.setSendBufferSize(intVal); + } + if ((intVal = getInteger(FactoryManager.SOCKET_RCVBUF)) != null) { + config.setReceiveBufferSize(intVal); + } + if ((intVal = getInteger(FactoryManager.SOCKET_LINGER)) != null) { + config.setSoLinger(intVal); + } + if ((boolVal = getBoolean(FactoryManager.SOCKET_LINGER)) != null) { + config.setTcpNoDelay(boolVal); + } + if (sessionConfig != null) { + config.setAll(sessionConfig); + } + } + + protected Integer getInteger(String property) { + String strVal = manager.getProperties().get(property); + return (strVal != null) ? Integer.parseInt(strVal) : null; + } + + protected Boolean getBoolean(String property) { + String strVal = manager.getProperties().get(property); + return (strVal != null) ? Boolean.parseBoolean(strVal) : null; + } + } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f3d58b90/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Acceptor.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Acceptor.java b/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Acceptor.java index f9fab11..9bba704 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Acceptor.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Acceptor.java @@ -41,18 +41,28 @@ import org.apache.sshd.common.io.IoHandler; public class Nio2Acceptor extends Nio2Service implements IoAcceptor { private final Map<SocketAddress, AsynchronousServerSocketChannel> channels; - private int backlog = 50; + private int backlog = 0; public Nio2Acceptor(FactoryManager manager, IoHandler handler, AsynchronousChannelGroup group) { super(manager, handler, group); channels = new ConcurrentHashMap<SocketAddress, AsynchronousServerSocketChannel>(); + + String valStr = manager.getProperties().get(FactoryManager.SOCKET_BACKLOG); + if (valStr != null) { + backlog = Integer.parseInt(valStr); + } } public void bind(Collection<? extends SocketAddress> addresses) throws IOException { for (SocketAddress address : addresses) { logger.debug("Binding Nio2Acceptor to address {}", address); AsynchronousServerSocketChannel socket = AsynchronousServerSocketChannel.open(group); - socket.setOption(StandardSocketOptions.SO_REUSEADDR, Boolean.TRUE); + setOption(socket, FactoryManager.SOCKET_KEEPALIVE, StandardSocketOptions.SO_KEEPALIVE, null); + setOption(socket, FactoryManager.SOCKET_LINGER, StandardSocketOptions.SO_LINGER, null); + setOption(socket, FactoryManager.SOCKET_RCVBUF, StandardSocketOptions.SO_RCVBUF, null); + setOption(socket, FactoryManager.SOCKET_REUSEADDR, StandardSocketOptions.SO_REUSEADDR, Boolean.TRUE); + setOption(socket, FactoryManager.SOCKET_SNDBUF, StandardSocketOptions.SO_SNDBUF, null); + setOption(socket, FactoryManager.TCP_NODELAY, StandardSocketOptions.TCP_NODELAY, null); socket.bind(address, backlog); SocketAddress local = socket.getLocalAddress(); channels.put(local, socket); http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f3d58b90/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Connector.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Connector.java b/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Connector.java index d427ef4..0ad182b 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Connector.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Connector.java @@ -20,6 +20,7 @@ package org.apache.sshd.common.io.nio2; import java.io.IOException; import java.net.SocketAddress; +import java.net.StandardSocketOptions; import java.nio.channels.AsynchronousChannelGroup; import java.nio.channels.AsynchronousSocketChannel; @@ -43,6 +44,12 @@ public class Nio2Connector extends Nio2Service implements IoConnector { final IoConnectFuture future = new DefaultIoConnectFuture(null); try { final AsynchronousSocketChannel socket = AsynchronousSocketChannel.open(group); + setOption(socket, FactoryManager.SOCKET_KEEPALIVE, StandardSocketOptions.SO_KEEPALIVE, null); + setOption(socket, FactoryManager.SOCKET_LINGER, StandardSocketOptions.SO_LINGER, null); + setOption(socket, FactoryManager.SOCKET_RCVBUF, StandardSocketOptions.SO_RCVBUF, null); + setOption(socket, FactoryManager.SOCKET_REUSEADDR, StandardSocketOptions.SO_REUSEADDR, Boolean.TRUE); + setOption(socket, FactoryManager.SOCKET_SNDBUF, StandardSocketOptions.SO_SNDBUF, null); + setOption(socket, FactoryManager.TCP_NODELAY, StandardSocketOptions.TCP_NODELAY, null); socket.connect(address, null, new Nio2CompletionHandler<Void, Object>() { protected void onCompleted(Void result, Object attachment) { try { http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f3d58b90/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Service.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Service.java b/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Service.java index 3c5a2b7..4bdb8f7 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Service.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Service.java @@ -18,7 +18,10 @@ */ package org.apache.sshd.common.io.nio2; +import java.io.IOException; +import java.net.SocketOption; import java.nio.channels.AsynchronousChannelGroup; +import java.nio.channels.NetworkChannel; import java.util.Collections; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -72,4 +75,27 @@ public abstract class Nio2Service extends CloseableUtils.AbstractInnerCloseable public void sessionClosed(Nio2Session session) { sessions.remove(session.getId()); } + + protected <T> void setOption(NetworkChannel socket, String property, SocketOption<T> option, T defaultValue) throws IOException { + String valStr = manager.getProperties().get(property); + T val = defaultValue; + if (valStr != null) { + Class<T> type = option.type(); + if (type == Integer.class) { + val = type.cast(Integer.parseInt(valStr)); + } else if (type == Boolean.class) { + val = type.cast(Boolean.parseBoolean(valStr)); + } else { + throw new IllegalStateException("Unsupported socket option type " + type); + } + } + if (val != null) { + try { + socket.setOption(option, val); + } catch (IOException e) { + logger.warn("Unable to set socket option " + option + " to " + val, e); + } + } + } + }
