Add a new option SSH_OPTIONS_NODELAY to enable or disable the
Nagle Algorithm (TCP_NODELAY) on the session socket.

Improved performance can be achieved for some applications like
sftp servers by enabling SSH_OPTIONS_NODELAY as typically, the
next request won't arrive until the server replies, which are
typically small writes.

Signed-off-by: Alberto Aguirre <albagui...@gmail.com>
---
 include/libssh/libssh.h  |  3 ++-
 include/libssh/session.h |  1 +
 src/connect.c            | 19 +++++++++++++++++++
 src/options.c            | 10 +++++++++-
 src/session.c            |  1 +
 5 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h
index 496b5774..b00a428a 100644
--- a/include/libssh/libssh.h
+++ b/include/libssh/libssh.h
@@ -355,7 +355,8 @@ enum ssh_options_e {
   SSH_OPTIONS_PUBKEY_AUTH,
   SSH_OPTIONS_KBDINT_AUTH,
   SSH_OPTIONS_GSSAPI_AUTH,
-  SSH_OPTIONS_GLOBAL_KNOWNHOSTS
+  SSH_OPTIONS_GLOBAL_KNOWNHOSTS,
+  SSH_OPTIONS_NODELAY,
 };
 
 enum {
diff --git a/include/libssh/session.h b/include/libssh/session.h
index 69a78dc4..1a069017 100644
--- a/include/libssh/session.h
+++ b/include/libssh/session.h
@@ -205,6 +205,7 @@ struct ssh_session_struct {
         char *gss_client_identity;
         int gss_delegate_creds;
         int flags;
+        int nodelay;
     } opts;
     /* counters */
     ssh_counter socket_counter;
diff --git a/src/connect.c b/src/connect.c
index 50c9e997..d7c2a32c 100644
--- a/src/connect.c
+++ b/src/connect.c
@@ -74,6 +74,7 @@
 #include <sys/socket.h>
 #include <sys/select.h>
 #include <netinet/in.h>
+#include <netinet/tcp.h>
 
 #endif /* _WIN32 */
 
@@ -216,6 +217,12 @@ static int ssh_connect_ai_timeout(ssh_session session, 
const char *host,
   return s;
 }
 
+static int set_tcp_nodelay(socket_t socket)
+{
+    int opt = 1;
+    return setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
+}
+
 /**
  * @internal
  *
@@ -387,6 +394,18 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, 
const char *host,
         continue;
     }
 
+    if (session->opts.nodelay) {
+        /* For winsock, socket options are only effective before connect */
+        rc = set_tcp_nodelay(s);
+        if (rc < 0) {
+            ssh_set_error(session, SSH_FATAL,
+                "Failed to set TCP_NODELAY on socket: %s", strerror(errno));
+            ssh_connect_socket_close(s);
+            s = -1;
+            continue;
+        }
+    }
+
     errno = 0;
     rc = connect(s, itr->ai_addr, itr->ai_addrlen);
     if (rc == -1 && (errno != 0) && (errno != EINPROGRESS)) {
diff --git a/src/options.c b/src/options.c
index 14b9e01e..560df3d6 100644
--- a/src/options.c
+++ b/src/options.c
@@ -938,7 +938,15 @@ int ssh_options_set(ssh_session session, enum 
ssh_options_e type,
                 }
             }
             break;
-
+        case SSH_OPTIONS_NODELAY:
+            if (value == NULL) {
+                ssh_set_error_invalid(session);
+                return -1;
+            } else {
+                int *x = (int *) value;
+                session->opts.nodelay = (*x & 0xff) > 0 ? 1 : 0;
+            }
+            break;
         default:
             ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option 
%d", type);
             return -1;
diff --git a/src/session.c b/src/session.c
index 1c03b62b..deaa1ae1 100644
--- a/src/session.c
+++ b/src/session.c
@@ -107,6 +107,7 @@ ssh_session ssh_new(void) {
     session->opts.fd = -1;
     session->opts.ssh2 = 1;
     session->opts.compressionlevel=7;
+    session->opts.nodelay = 0;
 #ifdef WITH_SSH1
     session->opts.ssh1 = 1;
 #else
-- 
2.14.1


Reply via email to