1
0
mirror of https://github.com/libssh2/libssh2.git synced 2026-10-24 03:48:58 +03:00

src: use abstract internal time type, bump resolution to milliseconds

To honor the actual millisecond timeout set via
`libssh2_session_set_timeout()`, to open the possibility for the same in
other APIs, and to use monotonic time if available.

- add internal abstract time types and macros for handling point in time
  and time intervals, and use them throughout the codebase.
- bump internal abstract time resolution to milliseconds (from seconds).
  Use signed 64-bit integers.
- replace existing millisecond-resolution code in `libssh2_poll()` with
  the internal abstract time interface.
- bump 'now' function to retrieve millisecond-resolution monotonic time
  from the system, if available.

Also:
- append `_s` or `_ms` to public API arguments to tell the time unit.
- keepalive: minor tidy-ups.
- make `ssh2_now()` return at least 1 in the fallback,
  `time(NULL)`-based codepath to not confuse a zero value with unset
  time.
  Credits: Stefan Eissing
  Ref: 5649b21297
  Ref: https://github.com/curl/curl/pull/21034
- this leaves existing `ssh2_gettimeofday()` (together with its
  Windows-specific local implementation) with a single caller,
  `ssh2_deb_low()`.

Refs:
https://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_gettime.html
https://www.man7.org/linux/man-pages/man3/clock_gettime.3.html
https://pubs.opengroup.org/onlinepubs/009604599/functions/gettimeofday.html
https://www.man7.org/linux/man-pages/man2/gettimeofday.2.html
https://learn.microsoft.com/windows/win32/api/profileapi/nf-profileapi-queryperformancefrequency
https://learn.microsoft.com/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter
https://stackoverflow.com/questions/5404277/porting-clock-gettime-to-windows

Reported-and-patch-proposal-by: Trzik on github
Based-on-patch-proposals-by: Ryan Kelley
Fixes #1497
Ref: #1818
Closes #1893
Follow-up to 772abc7a85 #1919

Closes #2341
This commit is contained in:
Viktor Szakats
2026-07-17 18:13:03 +02:00
parent 035d28c07b
commit 9c421761bc
13 changed files with 143 additions and 92 deletions

View File

@@ -19,16 +19,16 @@ libssh2_keepalive_config - short function description
void libssh2_keepalive_config(LIBSSH2_SESSION *session,
int want_reply,
unsigned int interval);
unsigned int interval_s);
~~~
# DESCRIPTION
Set how often keepalive messages should be sent. **want_reply** indicates
whether the keepalive messages should request a response from the server.
**interval** is number of seconds that can pass without any I/O, use 0 (the
**interval_s** is number of seconds that can pass without any I/O, use 0 (the
default) to disable keepalives. To avoid some busy-loop corner-cases, if you
specify an interval of 1 it is treated as 2.
specify an **interval_s** of 1 it is treated as 2.
Note that non-blocking applications are responsible for sending the keepalive
messages using **libssh2_keepalive_send(3)**.

View File

@@ -17,7 +17,7 @@ libssh2_poll - poll for activity on a socket, channel or listener
~~~c
#include <libssh2.h>
int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout);
int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout_ms);
~~~
# DESCRIPTION

View File

@@ -17,12 +17,13 @@ libssh2_session_set_read_timeout - set timeout for packet read functions
~~~c
#include <libssh2.h>
void libssh2_session_set_read_timeout(LIBSSH2_SESSION *session, long timeout);
void libssh2_session_set_read_timeout(LIBSSH2_SESSION *session,
long timeout_s);
~~~
# DESCRIPTION
Set the **timeout** in seconds for how long libssh2 packet read
Set the **timeout_s** in seconds for how long libssh2 packet read
function calls may wait until they consider the situation an error and return
LIBSSH2_ERROR_TIMEOUT.

View File

@@ -17,13 +17,13 @@ libssh2_session_set_timeout - set timeout for blocking functions
~~~c
#include <libssh2.h>
void libssh2_session_set_timeout(LIBSSH2_SESSION *session, long timeout);
void libssh2_session_set_timeout(LIBSSH2_SESSION *session, long timeout_ms);
~~~
# DESCRIPTION
Set the **timeout** in milliseconds for how long a blocking the libssh2
function calls may wait until they consider the situation an error and return
Set the **timeout_ms** in milliseconds for how long a blocking libssh2 function
call may wait before it considers the situation an error and returns
LIBSSH2_ERROR_TIMEOUT.
By default or if you set the timeout to zero, libssh2 has no timeout for

View File

@@ -781,7 +781,7 @@ LIBSSH2_API int libssh2_sign_sk(LIBSSH2_SESSION *session,
#ifndef LIBSSH2_NO_DEPRECATED
LIBSSH2_DEPRECATED(1.2.0, "Use system poll() or select()")
LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds,
long timeout);
long timeout_ms);
#endif
/* Channel API */
@@ -957,11 +957,11 @@ LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel,
int blocking);
LIBSSH2_API void libssh2_session_set_timeout(LIBSSH2_SESSION *session,
long timeout);
long timeout_ms);
LIBSSH2_API long libssh2_session_get_timeout(LIBSSH2_SESSION *session);
LIBSSH2_API void libssh2_session_set_read_timeout(LIBSSH2_SESSION *session,
long timeout);
long timeout_s);
LIBSSH2_API long libssh2_session_get_read_timeout(LIBSSH2_SESSION *session);
#ifndef LIBSSH2_NO_DEPRECATED
@@ -1430,7 +1430,7 @@ LIBSSH2_API const char *libssh2_agent_get_identity_path(LIBSSH2_AGENT *agent);
*/
LIBSSH2_API void libssh2_keepalive_config(LIBSSH2_SESSION *session,
int want_reply,
unsigned int interval);
unsigned int interval_s);
/*
* libssh2_keepalive_send()

View File

@@ -37,21 +37,21 @@
void libssh2_keepalive_config(LIBSSH2_SESSION *session,
int want_reply,
unsigned int interval)
unsigned int interval_s)
{
if(!session)
return;
if(interval == 1)
session->keepalive_interval = 2;
if(interval_s == 1)
session->keepalive_interval = ssh2_sec_to_timediff(2);
else
session->keepalive_interval = interval;
session->keepalive_interval = ssh2_sec_to_timediff(interval_s);
session->keepalive_want_reply = want_reply ? 1 : 0;
}
int libssh2_keepalive_send(LIBSSH2_SESSION *session, int *seconds_to_next)
{
time_t now;
ssh2_time_t now;
if(!session)
return LIBSSH2_ERROR_BAD_USE;
@@ -62,9 +62,9 @@ int libssh2_keepalive_send(LIBSSH2_SESSION *session, int *seconds_to_next)
return LIBSSH2_ERROR_NONE;
}
now = time(NULL);
now = ssh2_now();
if(session->keepalive_last_sent + session->keepalive_interval <= now) {
if(now >= session->keepalive_last_sent + session->keepalive_interval) {
/* Format is
"SSH_MSG_GLOBAL_REQUEST || 4-byte len || str || want-reply". */
unsigned char keepalive_data[] =
@@ -84,12 +84,14 @@ int libssh2_keepalive_send(LIBSSH2_SESSION *session, int *seconds_to_next)
}
session->keepalive_last_sent = now;
if(seconds_to_next)
*seconds_to_next = session->keepalive_interval;
}
else if(seconds_to_next)
*seconds_to_next = (int)(session->keepalive_last_sent - now) +
session->keepalive_interval;
if(seconds_to_next) {
ssh2_timediff_t to_next = ssh2_timediff_to_sec(
session->keepalive_interval +
(session->keepalive_last_sent - now));
*seconds_to_next = (int)SSH2_MIN(to_next, INT_MAX);
}
return LIBSSH2_ERROR_NONE;
}

View File

@@ -300,13 +300,21 @@ typedef enum {
ssh2_NB_state_jumpauthagent
} ssh2_NB_states;
#define ssh2_time_t libssh2_int64_t /* ms */
#define ssh2_timediff_t libssh2_int64_t /* ms */
#define ssh2_sec_to_timediff(sec) ((ssh2_time_t)(sec) * 1000)
#define ssh2_timediff_to_sec(td) ((td) / 1000)
#define ssh2_ms_to_timediff(ms) ((ssh2_time_t)(ms))
#define ssh2_timediff_to_ms(td) (td)
ssh2_time_t ssh2_now(void);
struct packet_require_state {
ssh2_NB_states state;
time_t start;
ssh2_time_t start;
};
struct packet_requirev_state {
time_t start;
ssh2_time_t start;
};
struct kmdhgGPshakex_state {
@@ -713,7 +721,7 @@ struct _LIBSSH2_SESSION {
int api_block_mode;
/* Timeout used when blocking API behavior is active */
long api_timeout;
long api_timeout_ms;
/* Server's public key */
const struct hostkey_method *hostkey;
@@ -948,12 +956,12 @@ struct _LIBSSH2_SESSION {
LIBSSH2_CHANNEL *scpSend_channel;
/* Keepalive variables used by keepalive.c. */
int keepalive_interval;
ssh2_timediff_t keepalive_interval;
int keepalive_want_reply;
time_t keepalive_last_sent;
ssh2_time_t keepalive_last_sent;
/* Configurable timeout for packets. Replaces LIBSSH2_READ_TIMEOUT */
long packet_read_timeout;
ssh2_timediff_t packet_read_timeout;
};
#if defined(__clang__) && __clang_major__ >= 13
#pragma clang diagnostic pop

View File

@@ -718,6 +718,41 @@ void ssh2_list_insert(struct list_node *after, /* insert before this */
}
#endif
ssh2_time_t ssh2_now(void) /* ms */
{
#ifdef _WIN32
ssh2_time_t sec, ns;
LARGE_INTEGER freq, count;
/* These never fail on supported Windows versions */
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&count);
sec = (ssh2_time_t)(count.QuadPart / freq.QuadPart);
ns = (ssh2_time_t)(((count.QuadPart % freq.QuadPart) *
1000000000) / freq.QuadPart);
return sec * 1000 + ns / 1000000;
#else /* !_WIN32 */
#if defined(CLOCK_MONOTONIC_RAW) /* Apple/Linux */
struct timespec ts;
if(!clock_gettime(CLOCK_MONOTONIC_RAW, &ts))
return (ssh2_time_t)ts.tv_sec * 1000 +
(ssh2_time_t)ts.tv_nsec / 1000000;
#elif defined(CLOCK_MONOTONIC) /* POSIX */
struct timespec ts;
if(!clock_gettime(CLOCK_MONOTONIC, &ts))
return (ssh2_time_t)ts.tv_sec * 1000 +
(ssh2_time_t)ts.tv_nsec / 1000000;
#elif defined(HAVE_GETTIMEOFDAY)
struct timeval tv;
if(!gettimeofday(&tv, NULL))
return (ssh2_time_t)tv.tv_sec * 1000 + (ssh2_time_t)tv.tv_usec / 1000;
#endif
{
ssh2_time_t ms = (ssh2_time_t)time(NULL) * 1000;
return ms ? ms : 1;
}
#endif /* _WIN32 */
}
#ifndef HAVE_GETTIMEOFDAY
/*
* Implementation according to:

View File

@@ -1461,7 +1461,7 @@ int ssh2_packet_require(LIBSSH2_SESSION *session,
match_len) == 0)
return 0; /* A packet was available in the packet brigade */
state->start = time(NULL);
state->start = ssh2_now();
}
while(session->socket_state == SSH2_SOCKET_CONNECTED) {
@@ -1485,8 +1485,8 @@ int ssh2_packet_require(LIBSSH2_SESSION *session,
}
else if(ret == 0) {
/* nothing available, wait until data arrives or we time out */
long left = session->packet_read_timeout - (long)(time(NULL) -
state->start);
ssh2_timediff_t left = session->packet_read_timeout -
(ssh2_now() - state->start);
if(left <= 0) {
state->start = 0;
@@ -1575,7 +1575,7 @@ int ssh2_packet_requirev(LIBSSH2_SESSION *session,
}
if(state->start == 0)
state->start = time(NULL);
state->start = ssh2_now();
while(session->socket_state != SSH2_SOCKET_DISCONNECTED) {
int ret = ssh2_transport_read(session);
@@ -1584,8 +1584,8 @@ int ssh2_packet_requirev(LIBSSH2_SESSION *session,
return ret;
}
if(ret <= 0) {
long left = session->packet_read_timeout -
(long)(time(NULL) - state->start);
ssh2_timediff_t left = session->packet_read_timeout -
(ssh2_now() - state->start);
if(left <= 0) {
state->start = 0;

View File

@@ -412,11 +412,12 @@ LIBSSH2_SESSION *libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC(*my_alloc),
session->send = ssh2_send;
session->recv = ssh2_recv;
session->abstract = abstract;
session->api_timeout = 0; /* timeout-free API by default */
session->api_timeout_ms = 0; /* timeout-free API by default */
session->api_block_mode = 1; /* blocking API by default */
session->state = SSH2_STATE_INITIAL_KEX;
session->fullpacket_required_type = 0;
session->packet_read_timeout = SSH2_DEFAULT_READ_TIMEOUT;
session->packet_read_timeout =
ssh2_sec_to_timediff(SSH2_DEFAULT_READ_TIMEOUT);
session->flag.quote_paths = 1; /* default behavior is to quote paths
for the scp subsystem */
session->kex = NULL;
@@ -539,14 +540,15 @@ void *libssh2_session_callback_set(LIBSSH2_SESSION *session,
* Utility function that waits for action on the socket. Returns 0 when ready
* to run again or error on timeout.
*/
int ssh2_wait_socket(LIBSSH2_SESSION *session, time_t start_time)
int ssh2_wait_socket(LIBSSH2_SESSION *session, ssh2_time_t start_time)
{
int rc;
int seconds_to_next;
int dir;
int has_timeout;
long ms_to_next = 0;
long elapsed_ms;
ssh2_timediff_t time_to_next = 0;
ssh2_timediff_t elapsed_time;
ssh2_timediff_t api_timeout = ssh2_ms_to_timediff(session->api_timeout_ms);
/* since libssh2 often sets EAGAIN internally before this function is
called, we can decrease some amount of confusion in user programs by
@@ -558,7 +560,7 @@ int ssh2_wait_socket(LIBSSH2_SESSION *session, time_t start_time)
if(rc)
return rc;
ms_to_next = seconds_to_next * 1000;
time_to_next = ssh2_sec_to_timediff(seconds_to_next);
/* figure out what to wait for */
dir = libssh2_session_block_directions(session);
@@ -568,27 +570,28 @@ int ssh2_wait_socket(LIBSSH2_SESSION *session, time_t start_time)
/* To avoid that we hang below because there is nothing set to
wait for, we timeout on 1 second to also avoid busy-looping
during this condition */
ms_to_next = 1000;
time_to_next = ssh2_ms_to_timediff(1000);
}
if(session->api_timeout > 0 &&
(seconds_to_next == 0 || ms_to_next > session->api_timeout)) {
time_t now = time(NULL);
elapsed_ms = (long)(1000 * difftime(now, start_time));
if(elapsed_ms > session->api_timeout)
if(api_timeout > 0 &&
(seconds_to_next == 0 || time_to_next > api_timeout)) {
ssh2_time_t now = ssh2_now();
elapsed_time = now > start_time ? (now - start_time) : 0;
if(elapsed_time > api_timeout)
return ssh2_err(session, LIBSSH2_ERROR_TIMEOUT,
"API timeout expired");
ms_to_next = session->api_timeout - elapsed_ms;
time_to_next = api_timeout - elapsed_time;
has_timeout = 1;
}
else if(ms_to_next > 0)
else if(time_to_next > 0)
has_timeout = 1;
else
has_timeout = 0;
#ifdef HAVE_POLL
{
ssh2_timediff_t time_to_next_ms = ssh2_timediff_to_ms(time_to_next);
struct pollfd sockets[1];
sockets[0].fd = session->socket_fd;
@@ -601,7 +604,8 @@ int ssh2_wait_socket(LIBSSH2_SESSION *session, time_t start_time)
if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
sockets[0].events |= POLLOUT;
rc = poll(sockets, 1, has_timeout ? (int)ms_to_next : -1);
rc = poll(sockets, 1,
has_timeout ? (int)SSH2_MIN(time_to_next_ms, INT_MAX) : -1);
}
#else
{
@@ -610,8 +614,9 @@ int ssh2_wait_socket(LIBSSH2_SESSION *session, time_t start_time)
fd_set *writefd = NULL;
fd_set *readfd = NULL;
struct timeval tv;
ssh2_timediff_t ms_to_next = ssh2_timediff_to_ms(time_to_next);
tv.tv_sec = ms_to_next / 1000;
tv.tv_sec = (long)(ms_to_next / 1000);
#ifdef libssh2_usec_t
tv.tv_usec = (libssh2_usec_t)((ms_to_next - tv.tv_sec * 1000) * 1000);
#else
@@ -1337,12 +1342,12 @@ int libssh2_session_get_blocking(LIBSSH2_SESSION *session)
* Set a session's timeout (in msec) for blocking mode,
* or 0 to disable timeouts.
*/
void libssh2_session_set_timeout(LIBSSH2_SESSION *session, long timeout)
void libssh2_session_set_timeout(LIBSSH2_SESSION *session, long timeout_ms)
{
if(!session)
return;
session->api_timeout = timeout;
session->api_timeout_ms = timeout_ms;
}
/*
@@ -1353,22 +1358,22 @@ long libssh2_session_get_timeout(LIBSSH2_SESSION *session)
if(!session)
return 0;
return session->api_timeout;
return session->api_timeout_ms;
}
/*
* Set a session's timeout (in sec) when reading packets,
* or 0 to use default of 60 seconds.
*/
void libssh2_session_set_read_timeout(LIBSSH2_SESSION *session, long timeout)
void libssh2_session_set_read_timeout(LIBSSH2_SESSION *session, long timeout_s)
{
if(!session)
return;
if(timeout <= 0)
timeout = SSH2_DEFAULT_READ_TIMEOUT;
if(timeout_s <= 0)
timeout_s = SSH2_DEFAULT_READ_TIMEOUT;
session->packet_read_timeout = timeout;
session->packet_read_timeout = ssh2_sec_to_timediff(timeout_s);
}
/*
@@ -1379,7 +1384,7 @@ long libssh2_session_get_read_timeout(LIBSSH2_SESSION *session)
if(!session)
return 0;
return session->packet_read_timeout;
return (long)ssh2_timediff_to_sec(session->packet_read_timeout);
}
#ifndef LIBSSH2_NO_DEPRECATED
@@ -1446,9 +1451,9 @@ static SSH2_INLINE int session_poll_listener_queued(LIBSSH2_LISTENER *listener)
*
* Poll sockets, channels, and listeners for activity
*/
int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout)
int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout_ms)
{
long timeout_remaining;
ssh2_timediff_t timeout_remaining;
unsigned int i, active_fds;
#ifdef HAVE_POLL
LIBSSH2_SESSION *session = NULL;
@@ -1503,7 +1508,6 @@ int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout)
LIBSSH2_SESSION *session = NULL;
libssh2_socket_t maxfd = 0;
fd_set rfds, wfds;
struct timeval tv;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
@@ -1575,10 +1579,10 @@ int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout)
}
}
#else /* !HAVE_POLL && !HAVE_SELECT */
timeout = 0; /* no sockets structure to setup */
timeout_ms = 0; /* no sockets structure to setup */
#endif /* HAVE_POLL || HAVE_SELECT */
timeout_remaining = timeout;
timeout_remaining = ssh2_ms_to_timediff(timeout_ms);
do {
#if defined(HAVE_POLL) || defined(HAVE_SELECT)
int sysret;
@@ -1655,12 +1659,13 @@ int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout)
#ifdef HAVE_POLL
{
struct timeval tv_begin, tv_end;
ssh2_gettimeofday(&tv_begin, NULL);
sysret = poll(sockets, nfds, (int)timeout_remaining);
ssh2_gettimeofday(&tv_end, NULL);
timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000;
ssh2_timediff_t timeout_remaining_ms =
ssh2_timediff_to_ms(timeout_remaining);
ssh2_time_t start_time = ssh2_now(), now;
sysret = poll(sockets, nfds,
(int)SSH2_MIN(timeout_remaining_ms, INT_MAX));
now = ssh2_now();
timeout_remaining -= now > start_time ? (now - start_time) : 0;
}
if(sysret > 0) {
@@ -1704,19 +1709,19 @@ int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout)
#elif defined(HAVE_SELECT)
tv.tv_sec = timeout_remaining / 1000;
#ifdef libssh2_usec_t
tv.tv_usec = (libssh2_usec_t)((timeout_remaining % 1000) * 1000);
#else
tv.tv_usec = (timeout_remaining % 1000) * 1000;
#endif
{
struct timeval tv_begin, tv_end;
ssh2_gettimeofday(&tv_begin, NULL);
ssh2_time_t start_time, now;
struct timeval tv;
tv.tv_sec = (long)(timeout_remaining / 1000);
#ifdef libssh2_usec_t
tv.tv_usec = (libssh2_usec_t)((timeout_remaining % 1000) * 1000);
#else
tv.tv_usec = (timeout_remaining % 1000) * 1000;
#endif
start_time = ssh2_now();
sysret = select((int)(maxfd + 1), &rfds, &wfds, NULL, &tv);
ssh2_gettimeofday(&tv_end, NULL);
timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000;
now = ssh2_now();
timeout_remaining -= now > start_time ? (now - start_time) : 0;
}
if(sysret > 0) {
@@ -1758,8 +1763,8 @@ int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout)
}
}
}
#endif /* !HAVE_POLL && !HAVE_SELECT -- timeout (and by extension
* timeout_remaining) is equal to 0 */
#endif /* !HAVE_POLL && !HAVE_SELECT -- timeout_ms (and by extension
timeout_remaining) is equal to 0 */
} while(timeout_remaining > 0 && !active_fds);
#ifdef HAVE_POLL

View File

@@ -46,7 +46,7 @@
*/
#define BLOCK_ADJUST(rc, session, x) \
do { \
time_t entry_time = time(NULL); \
ssh2_time_t entry_time = ssh2_now(); \
do { \
(rc) = (x); \
/* the order of the check below is important to properly \
@@ -66,7 +66,7 @@
*/
#define BLOCK_ADJUST_ERRNO(ptr, session, x) \
do { \
time_t entry_time = time(NULL); \
ssh2_time_t entry_time = ssh2_now(); \
int rc; \
do { \
(ptr) = (x); \
@@ -77,7 +77,7 @@
} while(!(rc)); \
} while(0)
int ssh2_wait_socket(LIBSSH2_SESSION *session, time_t start_time);
int ssh2_wait_socket(LIBSSH2_SESSION *session, ssh2_time_t start_time);
/* this is the lib-internal set blocking function */
int ssh2_session_set_blocking(LIBSSH2_SESSION *session, int blocking);

View File

@@ -510,7 +510,7 @@ static int sftp_packet_requirev(LIBSSH2_SFTP *sftp, int num_valid_responses,
/* If no timeout is active, start a new one */
if(sftp->requirev_start == 0)
sftp->requirev_start = time(NULL);
sftp->requirev_start = ssh2_now();
while(sftp->channel->session->socket_state == SSH2_SOCKET_CONNECTED) {
for(i = 0; i < num_valid_responses; i++) {
@@ -536,9 +536,9 @@ static int sftp_packet_requirev(LIBSSH2_SFTP *sftp, int num_valid_responses,
}
else if(rc <= 0) {
/* prevent busy-looping */
long left =
ssh2_timediff_t left =
sftp->channel->session->packet_read_timeout -
(long)(time(NULL) - sftp->requirev_start);
(ssh2_now() - sftp->requirev_start);
if(left <= 0) {
sftp->requirev_start = 0;

View File

@@ -143,7 +143,7 @@ struct _LIBSSH2_SFTP {
size_t partial_received; /* Bytes received so far */
/* Time that sftp_packet_requirev() started reading */
time_t requirev_start;
ssh2_time_t requirev_start;
/* State variables used in libssh2_sftp_open_ex() */
ssh2_NB_states open_state;