Hello,

We've been using libssh2 for a while in some internal tests. It generally works very well, but there's an annoying problem where badly behaved ssh servers can cause lockups inside libssh2. Jan Van Boghout posted some patches to implement a simple workaround for this last year (http://www.libssh2.org/mail/libssh2-devel-archive-2010-02/0073.shtml), and I see there's a bug (http://trac.libssh2.org/ticket/160) for it as well, currently partially complete but not fully integrated (and now almost a year old)

I've attached an updated patch against the tip of the master git repository which preserves the recently added keepalive support, while ensuring in the end we don't block forever. While the keepalive support works very well after the session is established, until that point, it seems that sending keepalives will cause the server to boot us off; that means we are exposed to potential endless blocking during a session creation.

Since I'm new to the mailing list, I may have missed recent discussion, but the bug hasn't really moved in a year, so I thought it might be worth reinvorigating debate - comments very welcome.

Regards,
Matt

--
_____________________________________________
Matt Lilley
Software Engineer
SecuritEase

Tel:    +64 4 912-2100
Fax:    +64 4 912-2101
E-mail: [email protected]
Web:    http://www.securitease.com
_____________________________________________

This e-mail has passed our content security scan.
It is covered by the confidentiality clauses at 
http://www.securitease.com/content_and_confidentiality

>From 2acaa39fd4681f505b62dc4faf34c23d3d4c4ca3 Mon Sep 17 00:00:00 2001
From: Matt Lilley <[email protected]>
Date: Mon, 2 May 2011 17:21:19 +1200
Subject: [PATCH] Implement timeout as per Jan Van Boghout's suggestion in 2010

---
 include/libssh2.h  |    4 ++++
 src/libssh2_priv.h |    3 +++
 src/session.c      |   43 ++++++++++++++++++++++++++++++++++++++-----
 3 files changed, 45 insertions(+), 5 deletions(-)

diff --git a/include/libssh2.h b/include/libssh2.h
index e207411..9462360 100644
--- a/include/libssh2.h
+++ b/include/libssh2.h
@@ -705,6 +705,10 @@ LIBSSH2_API int 
libssh2_session_get_blocking(LIBSSH2_SESSION* session);
 LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel,
                                               int blocking);
 
+LIBSSH2_API void libssh2_session_set_timeout(LIBSSH2_SESSION* session,
+                                             long timeout);
+LIBSSH2_API long libssh2_session_get_timeout(LIBSSH2_SESSION* session);
+
 /* libssh2_channel_handle_extended_data is DEPRECATED, do not use! */
 LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel,
                                                       int ignore_mode);
diff --git a/src/libssh2_priv.h b/src/libssh2_priv.h
index 231401e..5a697c7 100644
--- a/src/libssh2_priv.h
+++ b/src/libssh2_priv.h
@@ -559,6 +559,9 @@ struct _LIBSSH2_SESSION
     /* this is set to TRUE if a blocking API behavior is requested */
     int api_block_mode;
 
+    /* Timeout used when blocking API behavior is active */
+    long api_timeout;
+
     /* Server's public key */
     const LIBSSH2_HOSTKEY_METHOD *hostkey;
     void *server_hostkey_abstract;
diff --git a/src/session.c b/src/session.c
index e4714e8..cc5e23a 100644
--- a/src/session.c
+++ b/src/session.c
@@ -481,6 +481,7 @@ libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)),
         session->free = local_free;
         session->realloc = local_realloc;
         session->abstract = abstract;
+        session->api_timeout = 0; /* timeout-free API by default */
         session->api_block_mode = 1; /* blocking API by default */
         _libssh2_debug(session, LIBSSH2_TRACE_TRANS,
                        "New session resource allocated");
@@ -547,6 +548,7 @@ int _libssh2_wait_socket(LIBSSH2_SESSION *session)
     int rc;
     int seconds_to_next;
     int dir;
+    int has_timeout;
 
     /* since libssh2 often sets EAGAIN internally before this function is
        called, we can decrease some amount of confusion in user programs by
@@ -592,8 +594,19 @@ int _libssh2_wait_socket(LIBSSH2_SESSION *session)
             fd_set *readfd = NULL;
             struct timeval tv;
 
-            tv.tv_sec = seconds_to_next;
-            tv.tv_usec = 0;
+            if (seconds_to_next > 0) {
+                tv.tv_sec = seconds_to_next;
+                tv.tv_usec = 0;
+                has_timeout = 1;
+            } else if (session->api_timeout > 0) {
+                /* Seconds */
+                tv.tv_sec = session->api_timeout / 1000;
+                /* Microseconds */
+                tv.tv_usec = (session->api_timeout % 1000) * 1000;
+                has_timeout = 1;
+            } else {
+                has_timeout = 0;
+            }
 
             if(dir & LIBSSH2_SESSION_BLOCK_INBOUND) {
                 FD_ZERO(&rfd);
@@ -607,10 +620,8 @@ int _libssh2_wait_socket(LIBSSH2_SESSION *session)
                 writefd = &wfd;
             }
 
-            /* Note that this COULD be made to use a timeout that perhaps
-               could be customizable by the app or something... */
             rc = select(session->socket_fd + 1, readfd, writefd, NULL,
-                        seconds_to_next ? &tv : NULL);
+                        has_timeout ? &tv : NULL);
 #endif
         }
     }
@@ -1281,6 +1292,28 @@ libssh2_session_get_blocking(LIBSSH2_SESSION * session)
     return session->api_block_mode;
 }
 
+
+/* libssh2_session_set_timeout
+ *
+ * Set a session's timeout (in msec) for blocking mode, 
+ * or 0 to disable timeouts.
+ */
+LIBSSH2_API void
+libssh2_session_set_timeout(LIBSSH2_SESSION * session, long timeout)
+{
+    session->api_timeout = timeout;
+}
+
+/* libssh2_session_get_timeout
+ *
+ * Returns a session's timeout, or 0 if disabled
+ */
+LIBSSH2_API long
+libssh2_session_get_timeout(LIBSSH2_SESSION * session)
+{
+    return session->api_timeout;
+}
+
 /*
  * libssh2_poll_channel_read
  *
-- 
1.7.2.3.msysgit.0

_______________________________________________
libssh2-devel http://cool.haxx.se/cgi-bin/mailman/listinfo/libssh2-devel

Reply via email to