1
0
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:
Aris Adamantiadis
2011-08-25 16:50:44 +03:00
parent 7363b29427
commit f9dad9ad68
2 changed files with 106 additions and 33 deletions

View File

@@ -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;

View File

@@ -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);