mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-04 12:20:42 +09:00
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).
This commit is contained in:
committed by
Andreas Schneider
parent
0764adc82f
commit
558b53a856
@@ -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);
|
||||
|
||||
43
src/misc.c
43
src/misc.c
@@ -923,6 +923,24 @@ static int ssh_timestamp_difference(struct ssh_timestamp *old,
|
||||
return msecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user