diff options
author | rofl0r <retnyg@gmx.net> | 2011-12-31 02:15:16 +0100 |
---|---|---|
committer | Andreas Schneider <asn@cryptomilk.org> | 2012-01-02 12:42:47 +0100 |
commit | 558b53a856c5df5efcee70f1ee0aba6cc10fe9ea (patch) | |
tree | d5471a5d7718dff967a8f40ea04e9f6c306c8888 | |
parent | 0764adc82f2e25c77af73c7ffa03c0653694f0e1 (diff) | |
download | libssh-558b53a856c5df5efcee70f1ee0aba6cc10fe9ea.tar.gz libssh-558b53a856c5df5efcee70f1ee0aba6cc10fe9ea.tar.xz libssh-558b53a856c5df5efcee70f1ee0aba6cc10fe9ea.zip |
session: Cleanup timeout functions and fix packets termination.
It is possible that we get unrelated packets while waiting for
termination, thus waiting indefinitely. As a workaround we have to
check the user-supplied timeout.
Also cleaned up ssh_blocking_flush, which was using the timeout in a
bogus manner (resetting the timeout after each check).
-rw-r--r-- | include/libssh/misc.h | 1 | ||||
-rw-r--r-- | src/misc.c | 43 | ||||
-rw-r--r-- | src/session.c | 32 |
3 files changed, 42 insertions, 34 deletions
diff --git a/include/libssh/misc.h b/include/libssh/misc.h index f19dc00f..6812b0c2 100644 --- a/include/libssh/misc.h +++ b/include/libssh/misc.h @@ -78,6 +78,7 @@ const void *_ssh_list_pop_head(struct ssh_list *list); #define ssh_list_pop_head(type, ssh_list)\ ((type)_ssh_list_pop_head(ssh_list)) +int ssh_make_milliseconds(long sec, long usec); void ssh_timestamp_init(struct ssh_timestamp *ts); int ssh_timeout_elapsed(struct ssh_timestamp *ts, int timeout); int ssh_timeout_update(struct ssh_timestamp *ts, int timeout); @@ -925,6 +925,24 @@ static int ssh_timestamp_difference(struct ssh_timestamp *old, /** * @internal + * @brief turn seconds and microseconds pair (as provided by user-set options) + * into millisecond value + * @param[in] sec number of seconds + * @param[in] usec number of microseconds + * @returns milliseconds, or 10000 if user supplied values are equal to zero + */ +int ssh_make_milliseconds(long sec, long usec) { + int res = usec ? (usec / 1000) : 0; + res += (sec * 1000); + if (res == 0) { + res = 10 * 1000; /* use a reasonable default value in case + * SSH_OPTIONS_TIMEOUT is not set in options. */ + } + return res; +} + +/** + * @internal * @brief Checks if a timeout is elapsed, in function of a previous * timestamp and an assigned timeout * @param[in] ts pointer to an existing timestamp @@ -934,17 +952,20 @@ static int ssh_timestamp_difference(struct ssh_timestamp *old, * 0 otherwise */ int ssh_timeout_elapsed(struct ssh_timestamp *ts, int timeout) { - struct ssh_timestamp now; - if(timeout < 0) - return 0; // -1 means infinite timeout - if(timeout == 0) - return 1; // 0 means no timeout - ssh_timestamp_init(&now); - - if(ssh_timestamp_difference(ts,&now) >= timeout) - return 1; - else - return 0; + struct ssh_timestamp now; + switch(timeout) { + case -2: // -2 means user-defined timeout as available in session->timeout, session->timeout_usec. + fprintf(stderr, "ssh_timeout_elapsed called with -2. this needs to be fixed. " + "please set a breakpoint on %s:%d and fix the caller\n", __FILE__, __LINE__); + case -1: // -1 means infinite timeout + return 0; + case 0: // 0 means no timeout + return 1; + default: + break; + } + ssh_timestamp_init(&now); + return (ssh_timestamp_difference(ts,&now) >= timeout); } /** diff --git a/src/session.c b/src/session.c index 121a6299..61c27b0f 100644 --- a/src/session.c +++ b/src/session.c @@ -304,7 +304,7 @@ int ssh_is_blocking(ssh_session session){ * @brief Blocking flush of the outgoing buffer * @param[in] session The SSH session * @param[in] timeout Set an upper limit on the time for which this function - * will block, in milliseconds. Specifying a negative value + * will block, in milliseconds. Specifying -1 * means an infinite timeout. This parameter is passed to * the poll() function. * @returns SSH_OK on success, SSH_AGAIN if timeout occurred, @@ -313,24 +313,16 @@ int ssh_is_blocking(ssh_session session){ int ssh_blocking_flush(ssh_session session, int timeout){ ssh_socket s; - struct ssh_timestamp ts; int rc = SSH_OK; if(session==NULL) return SSH_ERROR; - enter_function(); s=session->socket; - ssh_timestamp_init(&ts); while (ssh_socket_buffered_write_bytes(s) > 0 && session->alive) { - rc=ssh_handle_packets(session, timeout); - if(ssh_timeout_elapsed(&ts,timeout)){ - rc=SSH_AGAIN; - break; - } - timeout = ssh_timeout_update(&ts, timeout); + rc = ssh_handle_packets(session, timeout); + if(rc == SSH_AGAIN || rc == SSH_ERROR) break; } - leave_function(); return rc; } @@ -407,17 +399,6 @@ void ssh_set_fd_except(ssh_session session) { ssh_socket_set_except(session->socket); } -static int ssh_make_milliseconds(long sec, long usec) { - int res = usec ? (usec / 1000) : 0; - res += (sec * 1000); - if (res == 0) { - res = 10 * 1000; /* use a reasonable default value in case - * SSH_OPTIONS_TIMEOUT is not set in options. */ - } - - return res; -} - /** * @internal * @@ -497,13 +478,18 @@ int ssh_handle_packets(ssh_session session, int timeout) { int ssh_handle_packets_termination(ssh_session session, int timeout, ssh_termination_function fct, void *user){ int ret = SSH_OK; - + struct ssh_timestamp ts; + ssh_timestamp_init(&ts); while(!fct(user)){ ret = ssh_handle_packets(session, timeout); if(ret == SSH_ERROR || ret == SSH_AGAIN) return ret; if(fct(user)) return SSH_OK; + else if(ssh_timeout_elapsed(&ts, timeout == -2 ? ssh_make_milliseconds(session->timeout, session->timeout_usec) : timeout)) + /* it is possible that we get unrelated packets but still timeout our request, + * so simply relying on the poll timeout is not enough */ + return SSH_AGAIN; } return ret; } |