mirror of
https://git.libssh.org/projects/libssh.git
synced 2025-11-30 13:01:23 +03:00
channels: made all channel requests nonblocking
This commit is contained in:
@@ -42,6 +42,7 @@ enum ssh_channel_request_state_e {
|
|||||||
|
|
||||||
enum ssh_channel_state_e {
|
enum ssh_channel_state_e {
|
||||||
SSH_CHANNEL_STATE_NOT_OPEN = 0,
|
SSH_CHANNEL_STATE_NOT_OPEN = 0,
|
||||||
|
SSH_CHANNEL_STATE_OPENING,
|
||||||
SSH_CHANNEL_STATE_OPEN_DENIED,
|
SSH_CHANNEL_STATE_OPEN_DENIED,
|
||||||
SSH_CHANNEL_STATE_OPEN,
|
SSH_CHANNEL_STATE_OPEN,
|
||||||
SSH_CHANNEL_STATE_CLOSED
|
SSH_CHANNEL_STATE_CLOSED
|
||||||
@@ -66,7 +67,6 @@ struct ssh_channel_struct {
|
|||||||
ssh_buffer stderr_buffer;
|
ssh_buffer stderr_buffer;
|
||||||
void *userarg;
|
void *userarg;
|
||||||
int version;
|
int version;
|
||||||
int blocking;
|
|
||||||
int exit_status;
|
int exit_status;
|
||||||
enum ssh_channel_request_state_e request_state;
|
enum ssh_channel_request_state_e request_state;
|
||||||
ssh_channel_callbacks callbacks;
|
ssh_channel_callbacks callbacks;
|
||||||
|
|||||||
131
src/channels.c
131
src/channels.c
@@ -246,9 +246,22 @@ static int channel_open(ssh_channel channel, const char *type_c, int window,
|
|||||||
int maxpacket, ssh_buffer payload) {
|
int maxpacket, ssh_buffer payload) {
|
||||||
ssh_session session = channel->session;
|
ssh_session session = channel->session;
|
||||||
ssh_string type = NULL;
|
ssh_string type = NULL;
|
||||||
|
int timeout;
|
||||||
int err=SSH_ERROR;
|
int err=SSH_ERROR;
|
||||||
|
|
||||||
enter_function();
|
enter_function();
|
||||||
|
switch(channel->state){
|
||||||
|
case SSH_CHANNEL_STATE_NOT_OPEN:
|
||||||
|
break;
|
||||||
|
case SSH_CHANNEL_STATE_OPENING:
|
||||||
|
goto pending;
|
||||||
|
case SSH_CHANNEL_STATE_OPEN:
|
||||||
|
case SSH_CHANNEL_STATE_CLOSED:
|
||||||
|
case SSH_CHANNEL_STATE_OPEN_DENIED:
|
||||||
|
goto end;
|
||||||
|
default:
|
||||||
|
ssh_set_error(session,SSH_FATAL,"Bad state in channel_open: %d",channel->state);
|
||||||
|
}
|
||||||
channel->local_channel = ssh_channel_new_id(session);
|
channel->local_channel = ssh_channel_new_id(session);
|
||||||
channel->local_maxpacket = maxpacket;
|
channel->local_maxpacket = maxpacket;
|
||||||
channel->local_window = window;
|
channel->local_window = window;
|
||||||
@@ -284,7 +297,7 @@ static int channel_open(ssh_channel channel, const char *type_c, int window,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
channel->state = SSH_CHANNEL_STATE_OPENING;
|
||||||
if (packet_send(session) == SSH_ERROR) {
|
if (packet_send(session) == SSH_ERROR) {
|
||||||
leave_function();
|
leave_function();
|
||||||
return err;
|
return err;
|
||||||
@@ -293,11 +306,14 @@ static int channel_open(ssh_channel channel, const char *type_c, int window,
|
|||||||
ssh_log(session, SSH_LOG_PACKET,
|
ssh_log(session, SSH_LOG_PACKET,
|
||||||
"Sent a SSH_MSG_CHANNEL_OPEN type %s for channel %d",
|
"Sent a SSH_MSG_CHANNEL_OPEN type %s for channel %d",
|
||||||
type_c, channel->local_channel);
|
type_c, channel->local_channel);
|
||||||
|
pending:
|
||||||
/* Todo: fix this into a correct loop */
|
|
||||||
/* wait until channel is opened by server */
|
/* wait until channel is opened by server */
|
||||||
while(channel->state == SSH_CHANNEL_STATE_NOT_OPEN){
|
if(ssh_is_blocking(session))
|
||||||
err = ssh_handle_packets(session, -2);
|
timeout=-2;
|
||||||
|
else
|
||||||
|
timeout=0;
|
||||||
|
while(channel->state == SSH_CHANNEL_STATE_OPENING){
|
||||||
|
err = ssh_handle_packets(session, timeout);
|
||||||
if (err != SSH_OK) {
|
if (err != SSH_OK) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -306,6 +322,7 @@ static int channel_open(ssh_channel channel, const char *type_c, int window,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
end:
|
||||||
if(channel->state == SSH_CHANNEL_STATE_OPEN)
|
if(channel->state == SSH_CHANNEL_STATE_OPEN)
|
||||||
err=SSH_OK;
|
err=SSH_OK;
|
||||||
leave_function();
|
leave_function();
|
||||||
@@ -1342,14 +1359,15 @@ int ssh_channel_is_eof(ssh_channel channel) {
|
|||||||
*
|
*
|
||||||
* @param[in] blocking A boolean for blocking or nonblocking.
|
* @param[in] blocking A boolean for blocking or nonblocking.
|
||||||
*
|
*
|
||||||
* @bug This functionality is still under development and
|
* @warning A side-effect of this is to put the whole session
|
||||||
* doesn't work correctly.
|
* in non-blocking mode.
|
||||||
|
* @see ssh_set_blocking()
|
||||||
*/
|
*/
|
||||||
void ssh_channel_set_blocking(ssh_channel channel, int blocking) {
|
void ssh_channel_set_blocking(ssh_channel channel, int blocking) {
|
||||||
if(channel == NULL) {
|
if(channel == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
channel->blocking = (blocking == 0 ? 0 : 1);
|
ssh_set_blocking(channel->session,blocking);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1423,13 +1441,15 @@ static int channel_request(ssh_channel channel, const char *request,
|
|||||||
ssh_buffer buffer, int reply) {
|
ssh_buffer buffer, int reply) {
|
||||||
ssh_session session = channel->session;
|
ssh_session session = channel->session;
|
||||||
ssh_string req = NULL;
|
ssh_string req = NULL;
|
||||||
|
int timeout;
|
||||||
int rc = SSH_ERROR;
|
int rc = SSH_ERROR;
|
||||||
|
|
||||||
enter_function();
|
enter_function();
|
||||||
if(channel->request_state != SSH_CHANNEL_REQ_STATE_NONE){
|
switch(channel->request_state){
|
||||||
ssh_set_error(session,SSH_REQUEST_DENIED,"channel_request_* used in incorrect state");
|
case SSH_CHANNEL_REQ_STATE_NONE:
|
||||||
leave_function();
|
break;
|
||||||
return SSH_ERROR;
|
default:
|
||||||
|
goto pending;
|
||||||
}
|
}
|
||||||
|
|
||||||
req = ssh_string_from_char(request);
|
req = ssh_string_from_char(request);
|
||||||
@@ -1467,13 +1487,21 @@ static int channel_request(ssh_channel channel, const char *request,
|
|||||||
leave_function();
|
leave_function();
|
||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
}
|
}
|
||||||
|
pending:
|
||||||
|
if(ssh_is_blocking(session))
|
||||||
|
timeout=-2;
|
||||||
|
else
|
||||||
|
timeout=0;
|
||||||
while(channel->request_state == SSH_CHANNEL_REQ_STATE_PENDING){
|
while(channel->request_state == SSH_CHANNEL_REQ_STATE_PENDING){
|
||||||
ssh_handle_packets(session, -2);
|
ssh_handle_packets(session, timeout);
|
||||||
|
if(channel->request_state == SSH_CHANNEL_REQ_STATE_PENDING && timeout==0){
|
||||||
|
leave_function();
|
||||||
|
return SSH_AGAIN;
|
||||||
|
}
|
||||||
if(session->session_state == SSH_SESSION_STATE_ERROR) {
|
if(session->session_state == SSH_SESSION_STATE_ERROR) {
|
||||||
channel->request_state = SSH_CHANNEL_REQ_STATE_ERROR;
|
channel->request_state = SSH_CHANNEL_REQ_STATE_ERROR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
/* we received something */
|
/* we received something */
|
||||||
switch (channel->request_state){
|
switch (channel->request_state){
|
||||||
@@ -1519,7 +1547,10 @@ error:
|
|||||||
*
|
*
|
||||||
* @param[in] row The number of rows.
|
* @param[in] row The number of rows.
|
||||||
*
|
*
|
||||||
* @return SSH_OK on success, SSH_ERROR if an error occured.
|
* @return SSH_OK on success,
|
||||||
|
* SSH_ERROR if an error occurred,
|
||||||
|
* SSH_AGAIN if in nonblocking mode and call has
|
||||||
|
* to be done again.
|
||||||
*/
|
*/
|
||||||
int ssh_channel_request_pty_size(ssh_channel channel, const char *terminal,
|
int ssh_channel_request_pty_size(ssh_channel channel, const char *terminal,
|
||||||
int col, int row) {
|
int col, int row) {
|
||||||
@@ -1544,6 +1575,13 @@ int ssh_channel_request_pty_size(ssh_channel channel, const char *terminal,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
switch(channel->request_state){
|
||||||
|
case SSH_CHANNEL_REQ_STATE_NONE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto pending;
|
||||||
|
}
|
||||||
|
|
||||||
buffer = ssh_buffer_new();
|
buffer = ssh_buffer_new();
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
ssh_set_error_oom(session);
|
ssh_set_error_oom(session);
|
||||||
@@ -1566,7 +1604,7 @@ int ssh_channel_request_pty_size(ssh_channel channel, const char *terminal,
|
|||||||
ssh_set_error_oom(session);
|
ssh_set_error_oom(session);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
pending:
|
||||||
rc = channel_request(channel, "pty-req", buffer, 1);
|
rc = channel_request(channel, "pty-req", buffer, 1);
|
||||||
error:
|
error:
|
||||||
ssh_buffer_free(buffer);
|
ssh_buffer_free(buffer);
|
||||||
@@ -1646,7 +1684,10 @@ error:
|
|||||||
*
|
*
|
||||||
* @param[in] channel The channel to send the request.
|
* @param[in] channel The channel to send the request.
|
||||||
*
|
*
|
||||||
* @return SSH_OK on success, SSH_ERROR if an error occured.
|
* @return SSH_OK on success,
|
||||||
|
* SSH_ERROR if an error occurred,
|
||||||
|
* SSH_AGAIN if in nonblocking mode and call has
|
||||||
|
* to be done again.
|
||||||
*/
|
*/
|
||||||
int ssh_channel_request_shell(ssh_channel channel) {
|
int ssh_channel_request_shell(ssh_channel channel) {
|
||||||
if(channel == NULL) {
|
if(channel == NULL) {
|
||||||
@@ -1667,7 +1708,10 @@ int ssh_channel_request_shell(ssh_channel channel) {
|
|||||||
*
|
*
|
||||||
* @param[in] subsys The subsystem to request (for example "sftp").
|
* @param[in] subsys The subsystem to request (for example "sftp").
|
||||||
*
|
*
|
||||||
* @return SSH_OK on success, SSH_ERROR if an error occured.
|
* @return SSH_OK on success,
|
||||||
|
* SSH_ERROR if an error occurred,
|
||||||
|
* SSH_AGAIN if in nonblocking mode and call has
|
||||||
|
* to be done again.
|
||||||
*
|
*
|
||||||
* @warning You normally don't have to call it for sftp, see sftp_new().
|
* @warning You normally don't have to call it for sftp, see sftp_new().
|
||||||
*/
|
*/
|
||||||
@@ -1683,6 +1727,12 @@ int ssh_channel_request_subsystem(ssh_channel channel, const char *subsys) {
|
|||||||
ssh_set_error_invalid(channel->session, __FUNCTION__);
|
ssh_set_error_invalid(channel->session, __FUNCTION__);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
switch(channel->request_state){
|
||||||
|
case SSH_CHANNEL_REQ_STATE_NONE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto pending;
|
||||||
|
}
|
||||||
|
|
||||||
buffer = ssh_buffer_new();
|
buffer = ssh_buffer_new();
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
@@ -1700,7 +1750,7 @@ int ssh_channel_request_subsystem(ssh_channel channel, const char *subsys) {
|
|||||||
ssh_set_error_oom(channel->session);
|
ssh_set_error_oom(channel->session);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
pending:
|
||||||
rc = channel_request(channel, "subsystem", buffer, 1);
|
rc = channel_request(channel, "subsystem", buffer, 1);
|
||||||
error:
|
error:
|
||||||
ssh_buffer_free(buffer);
|
ssh_buffer_free(buffer);
|
||||||
@@ -1749,7 +1799,10 @@ static ssh_string generate_cookie(void) {
|
|||||||
*
|
*
|
||||||
* @param[in] screen_number The screen number.
|
* @param[in] screen_number The screen number.
|
||||||
*
|
*
|
||||||
* @return SSH_OK on success, SSH_ERROR if an error occured.
|
* @return SSH_OK on success,
|
||||||
|
* SSH_ERROR if an error occurred,
|
||||||
|
* SSH_AGAIN if in nonblocking mode and call has
|
||||||
|
* to be done again.
|
||||||
*/
|
*/
|
||||||
int ssh_channel_request_x11(ssh_channel channel, int single_connection, const char *protocol,
|
int ssh_channel_request_x11(ssh_channel channel, int single_connection, const char *protocol,
|
||||||
const char *cookie, int screen_number) {
|
const char *cookie, int screen_number) {
|
||||||
@@ -1761,6 +1814,12 @@ int ssh_channel_request_x11(ssh_channel channel, int single_connection, const ch
|
|||||||
if(channel == NULL) {
|
if(channel == NULL) {
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
switch(channel->request_state){
|
||||||
|
case SSH_CHANNEL_REQ_STATE_NONE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto pending;
|
||||||
|
}
|
||||||
|
|
||||||
buffer = ssh_buffer_new();
|
buffer = ssh_buffer_new();
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
@@ -1791,7 +1850,7 @@ int ssh_channel_request_x11(ssh_channel channel, int single_connection, const ch
|
|||||||
ssh_set_error_oom(channel->session);
|
ssh_set_error_oom(channel->session);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
pending:
|
||||||
rc = channel_request(channel, "x11-req", buffer, 1);
|
rc = channel_request(channel, "x11-req", buffer, 1);
|
||||||
|
|
||||||
error:
|
error:
|
||||||
@@ -2129,8 +2188,10 @@ error:
|
|||||||
*
|
*
|
||||||
* @param[in] value The value to set.
|
* @param[in] value The value to set.
|
||||||
*
|
*
|
||||||
* @return SSH_OK on success, SSH_ERROR if an error occured.
|
* @return SSH_OK on success,
|
||||||
*
|
* SSH_ERROR if an error occurred,
|
||||||
|
* SSH_AGAIN if in nonblocking mode and call has
|
||||||
|
* to be done again.
|
||||||
* @warning Some environment variables may be refused by security reasons.
|
* @warning Some environment variables may be refused by security reasons.
|
||||||
*/
|
*/
|
||||||
int ssh_channel_request_env(ssh_channel channel, const char *name, const char *value) {
|
int ssh_channel_request_env(ssh_channel channel, const char *name, const char *value) {
|
||||||
@@ -2145,7 +2206,12 @@ int ssh_channel_request_env(ssh_channel channel, const char *name, const char *v
|
|||||||
ssh_set_error_invalid(channel->session, __FUNCTION__);
|
ssh_set_error_invalid(channel->session, __FUNCTION__);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
switch(channel->request_state){
|
||||||
|
case SSH_CHANNEL_REQ_STATE_NONE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto pending;
|
||||||
|
}
|
||||||
buffer = ssh_buffer_new();
|
buffer = ssh_buffer_new();
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
ssh_set_error_oom(channel->session);
|
ssh_set_error_oom(channel->session);
|
||||||
@@ -2174,7 +2240,7 @@ int ssh_channel_request_env(ssh_channel channel, const char *name, const char *v
|
|||||||
ssh_set_error_oom(channel->session);
|
ssh_set_error_oom(channel->session);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
pending:
|
||||||
rc = channel_request(channel, "env", buffer,1);
|
rc = channel_request(channel, "env", buffer,1);
|
||||||
error:
|
error:
|
||||||
ssh_buffer_free(buffer);
|
ssh_buffer_free(buffer);
|
||||||
@@ -2193,8 +2259,10 @@ error:
|
|||||||
* @param[in] cmd The command to execute
|
* @param[in] cmd The command to execute
|
||||||
* (e.g. "ls ~/ -al | grep -i reports").
|
* (e.g. "ls ~/ -al | grep -i reports").
|
||||||
*
|
*
|
||||||
* @return SSH_OK on success, SSH_ERROR if an error occured.
|
* @return SSH_OK on success,
|
||||||
*
|
* SSH_ERROR if an error occurred,
|
||||||
|
* SSH_AGAIN if in nonblocking mode and call has
|
||||||
|
* to be done again.
|
||||||
* @code
|
* @code
|
||||||
* rc = channel_request_exec(channel, "ps aux");
|
* rc = channel_request_exec(channel, "ps aux");
|
||||||
* if (rc > 0) {
|
* if (rc > 0) {
|
||||||
@@ -2228,7 +2296,12 @@ int ssh_channel_request_exec(ssh_channel channel, const char *cmd) {
|
|||||||
return channel_request_exec1(channel, cmd);
|
return channel_request_exec1(channel, cmd);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
switch(channel->request_state){
|
||||||
|
case SSH_CHANNEL_REQ_STATE_NONE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto pending;
|
||||||
|
}
|
||||||
buffer = ssh_buffer_new();
|
buffer = ssh_buffer_new();
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
ssh_set_error_oom(channel->session);
|
ssh_set_error_oom(channel->session);
|
||||||
@@ -2245,7 +2318,7 @@ int ssh_channel_request_exec(ssh_channel channel, const char *cmd) {
|
|||||||
ssh_set_error_oom(channel->session);
|
ssh_set_error_oom(channel->session);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
pending:
|
||||||
rc = channel_request(channel, "exec", buffer, 1);
|
rc = channel_request(channel, "exec", buffer, 1);
|
||||||
error:
|
error:
|
||||||
ssh_buffer_free(buffer);
|
ssh_buffer_free(buffer);
|
||||||
|
|||||||
Reference in New Issue
Block a user