fix: sftp_packet_read stuck in an infinite loop in blocking mode

Signed-off-by: Liu Husong <huliu@janestreet.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
This commit is contained in:
Liu Husong
2024-06-04 00:53:31 +08:00
committed by husong998
parent c662bcc466
commit 2d3b7e07af
5 changed files with 104 additions and 43 deletions

View File

@@ -2925,7 +2925,6 @@ error:
return rc;
}
/**
* @brief Read data from a channel into a buffer.
*
@@ -2939,8 +2938,8 @@ error:
*
* @param is_stderr A boolean value to mark reading from the stderr stream.
*
* @return The number of bytes read, 0 on end of file or SSH_ERROR
* on error.
* @return The number of bytes read, 0 on end of file, SSH_AGAIN on
* timeout and SSH_ERROR on error.
* @deprecated Please use ssh_channel_read instead
* @warning This function doesn't work in nonblocking/timeout mode
* @see ssh_channel_read
@@ -3032,8 +3031,6 @@ static int ssh_channel_read_termination(void *s)
return 0;
}
/* TODO: FIXME Fix the blocking behaviours */
/**
* @brief Reads data from a channel.
*
@@ -3045,9 +3042,8 @@ static int ssh_channel_read_termination(void *s)
*
* @param[in] is_stderr A boolean value to mark reading from the stderr flow.
*
* @return The number of bytes read, 0 on end of file or SSH_ERROR
* on error. In nonblocking mode it can return 0 if no data
* is available or SSH_AGAIN.
* @return The number of bytes read, 0 on end of file, SSH_AGAIN on
* timeout and SSH_ERROR on error.
*
* @warning This function may return less than count bytes of data, and won't
* block until count bytes have been read.
@@ -3075,9 +3071,8 @@ int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_std
* @param[in] timeout_ms A timeout in milliseconds. A value of -1 means
* infinite timeout.
*
* @return The number of bytes read, 0 on end of file or SSH_ERROR
* on error. In nonblocking mode it Can return 0 if no data
* is available or SSH_AGAIN.
* @return The number of bytes read, 0 on end of file, SSH_AGAIN on
* timeout, SSH_ERROR on error.
*
* @warning This function may return less than count bytes of data, and won't
* block until count bytes have been read.
@@ -3133,8 +3128,8 @@ int ssh_channel_read_timeout(ssh_channel channel,
timeout_ms,
ssh_channel_read_termination,
&ctx);
if (rc == SSH_ERROR){
return rc;
if (rc == SSH_ERROR || rc == SSH_AGAIN) {
return rc;
}
/*
@@ -3188,8 +3183,8 @@ int ssh_channel_read_timeout(ssh_channel channel,
*
* @param[in] is_stderr A boolean to select the stderr stream.
*
* @return The number of bytes read (0 if nothing is available),
* SSH_ERROR on error, and SSH_EOF if the channel is EOF.
* @return The number of bytes read, SSH_AGAIN if nothing is
* available, SSH_ERROR on error, and SSH_EOF if the channel is EOF.
*
* @see ssh_channel_is_eof()
*/

View File

@@ -266,7 +266,7 @@ int ssh_scp_close(ssh_scp scp)
*/
while (!ssh_channel_is_eof(scp->channel)) {
rc = ssh_channel_read(scp->channel, buffer, sizeof(buffer), 0);
if (rc == SSH_ERROR || rc == 0) {
if (rc == SSH_ERROR || rc == SSH_AGAIN || rc == 0) {
break;
}
}
@@ -603,6 +603,12 @@ int ssh_scp_response(ssh_scp scp, char **response)
rc = ssh_channel_read(scp->channel, &code, 1, 0);
if (rc == SSH_ERROR) {
scp->state = SSH_SCP_ERROR;
return SSH_ERROR;
}
if (rc == SSH_AGAIN) {
ssh_set_error(scp->session, SSH_FATAL, "SCP: ssh_channel_read timeout");
scp->state = SSH_SCP_ERROR;
return SSH_ERROR;
}
@@ -760,6 +766,14 @@ int ssh_scp_read_string(ssh_scp scp, char *buffer, size_t len)
break;
}
if (err == SSH_AGAIN) {
ssh_set_error(scp->session,
SSH_FATAL,
"SCP: ssh_channel_read timeout");
err = SSH_ERROR;
break;
}
read++;
if (buffer[read - 1] == '\n') {
break;
@@ -1027,12 +1041,16 @@ int ssh_scp_read(ssh_scp scp, void *buffer, size_t size)
}
rc = ssh_channel_read(scp->channel, buffer, size, 0);
if (rc != SSH_ERROR) {
scp->processed += rc;
} else {
if (rc == SSH_ERROR) {
scp->state = SSH_SCP_ERROR;
return SSH_ERROR;
}
if (rc == SSH_AGAIN) {
ssh_set_error(scp->session, SSH_FATAL, "SCP: ssh_channel_read timeout");
scp->state = SSH_SCP_ERROR;
return SSH_ERROR;
}
scp->processed += rc;
/* Check if we arrived at end of file */
if (scp->processed == scp->filelen) {

View File

@@ -87,6 +87,12 @@ sftp_packet sftp_packet_read(sftp_session sftp)
"Received EOF while reading sftp packet size");
sftp_set_error(sftp, SSH_FX_EOF);
goto error;
} else {
ssh_set_error(sftp->session,
SSH_FATAL,
"Timeout while reading sftp packet size");
sftp_set_error(sftp, SSH_FX_FAILURE);
goto error;
}
} else {
nread += s;
@@ -112,6 +118,12 @@ sftp_packet sftp_packet_read(sftp_session sftp)
"Received EOF while reading sftp packet type");
sftp_set_error(sftp, SSH_FX_EOF);
goto error;
} else {
ssh_set_error(sftp->session,
SSH_FATAL,
"Timeout while reading sftp packet type");
sftp_set_error(sftp, SSH_FX_FAILURE);
goto error;
}
}
} while (nread < 1);
@@ -147,6 +159,12 @@ sftp_packet sftp_packet_read(sftp_session sftp)
"Received EOF while reading sftp packet");
sftp_set_error(sftp, SSH_FX_EOF);
goto error;
} else {
ssh_set_error(sftp->session,
SSH_FATAL,
"Timeout while reading sftp packet");
sftp_set_error(sftp, SSH_FX_FAILURE);
goto error;
}
}
}
@@ -697,7 +715,8 @@ static void request_queue_free(sftp_request_queue queue)
SAFE_FREE(queue);
}
static int sftp_enqueue(sftp_session sftp, sftp_message msg)
static int
sftp_enqueue(sftp_session sftp, sftp_message msg)
{
sftp_request_queue queue = NULL;
sftp_request_queue ptr;