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