aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAris Adamantiadis <aris@0xbadc0de.be>2011-08-25 17:42:22 +0300
committerAris Adamantiadis <aris@0xbadc0de.be>2011-09-02 11:42:59 +0300
commita2c94abb92ead1503a0d6284609af41e53bef402 (patch)
tree414751cb928fd1dbb49dcd30b181226744fa72c0
parent510c74122938549aaf53718e1fc05741e75ead41 (diff)
downloadlibssh-a2c94abb92ead1503a0d6284609af41e53bef402.tar.gz
libssh-a2c94abb92ead1503a0d6284609af41e53bef402.tar.xz
libssh-a2c94abb92ead1503a0d6284609af41e53bef402.zip
channels: made the remaining calls nonblocking + fix #52
-rw-r--r--src/channels.c81
1 files changed, 59 insertions, 22 deletions
diff --git a/src/channels.c b/src/channels.c
index 622cefcb..b7cc2d4c 100644
--- a/src/channels.c
+++ b/src/channels.c
@@ -1169,6 +1169,8 @@ int channel_write_common(ssh_channel channel, const void *data,
uint32_t origlen = len;
size_t effectivelen;
size_t maxpacketlen;
+ int timeout;
+ int rc;
if(channel == NULL) {
return -1;
@@ -1186,7 +1188,10 @@ int channel_write_common(ssh_channel channel, const void *data,
}
enter_function();
-
+ if(ssh_is_blocking(session))
+ timeout = -2;
+ else
+ timeout = 0;
/*
* Handle the max packet len from remote side, be nice
* 10 bytes for the headers
@@ -1227,7 +1232,10 @@ int channel_write_common(ssh_channel channel, const void *data,
/* nothing can be written */
ssh_log(session, SSH_LOG_PROTOCOL,
"Wait for a growing window message...");
- goto out;
+ rc = ssh_handle_packets(session, timeout);
+ if (rc == SSH_ERROR || (channel->remote_window == 0 && timeout==0))
+ goto out;
+ continue;
}
effectivelen = len > channel->remote_window ? channel->remote_window : len;
} else {
@@ -1266,7 +1274,10 @@ int channel_write_common(ssh_channel channel, const void *data,
len -= effectivelen;
data = ((uint8_t*)data + effectivelen);
}
-
+ /* it's a good idea to flush the socket now */
+ do {
+ rc = ssh_handle_packets(session, timeout);
+ } while(ssh_socket_buffered_write_bytes(session->socket) > 0 && timeout != 0);
out:
leave_function();
return (int)(origlen - len);
@@ -1985,19 +1996,20 @@ SSH_PACKET_CALLBACK(ssh_request_denied){
*
* @param[in] reply Set if you expect a reply from server.
*
- * @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.
*/
static int global_request(ssh_session session, const char *request,
ssh_buffer buffer, int reply) {
ssh_string req = NULL;
int rc = SSH_ERROR;
+ int timeout;
enter_function();
- if(session->global_req_state != SSH_CHANNEL_REQ_STATE_NONE){
- ssh_set_error(session,SSH_FATAL,"Invalid state in start of global_request()");
- leave_function();
- return rc;
- }
+ if(session->global_req_state != SSH_CHANNEL_REQ_STATE_NONE)
+ goto pending;
req = ssh_string_from_char(request);
if (req == NULL) {
ssh_set_error_oom(session);
@@ -2033,12 +2045,20 @@ static int global_request(ssh_session session, const char *request,
leave_function();
return SSH_OK;
}
+pending:
+ if(ssh_is_blocking(session))
+ timeout=-2;
+ else
+ timeout=0;
while(session->global_req_state == SSH_CHANNEL_REQ_STATE_PENDING){
- rc=ssh_handle_packets(session, -2);
+ rc=ssh_handle_packets(session, timeout);
if(rc==SSH_ERROR){
session->global_req_state = SSH_CHANNEL_REQ_STATE_ERROR;
break;
}
+ if(session->global_req_state == SSH_CHANNEL_REQ_STATE_PENDING
+ && timeout == 0)
+ break;
}
switch(session->global_req_state){
case SSH_CHANNEL_REQ_STATE_ACCEPTED:
@@ -2054,10 +2074,11 @@ static int global_request(ssh_session session, const char *request,
break;
case SSH_CHANNEL_REQ_STATE_ERROR:
case SSH_CHANNEL_REQ_STATE_NONE:
- case SSH_CHANNEL_REQ_STATE_PENDING:
rc=SSH_ERROR;
break;
-
+ case SSH_CHANNEL_REQ_STATE_PENDING:
+ rc=SSH_AGAIN;
+ break;
}
leave_function();
@@ -2093,6 +2114,9 @@ int ssh_forward_listen(ssh_session session, const char *address, int port, int *
int rc = SSH_ERROR;
uint32_t tmp;
+ if(session->global_req_state != SSH_CHANNEL_REQ_STATE_NONE)
+ goto pending;
+
buffer = ssh_buffer_new();
if (buffer == NULL) {
ssh_set_error_oom(session);
@@ -2110,9 +2134,11 @@ int ssh_forward_listen(ssh_session session, const char *address, int port, int *
ssh_set_error_oom(session);
goto error;
}
-
+pending:
rc = global_request(session, "tcpip-forward", buffer, 1);
+ /* TODO: FIXME no guarantee the last packet we received contains
+ * that info */
if (rc == SSH_OK && port == 0 && bound_port) {
buffer_get_u32(session->in_buffer, &tmp);
*bound_port = ntohl(tmp);
@@ -2155,6 +2181,9 @@ int ssh_forward_cancel(ssh_session session, const char *address, int port) {
ssh_string addr = NULL;
int rc = SSH_ERROR;
+ if(session->global_req_state != SSH_CHANNEL_REQ_STATE_NONE)
+ goto pending;
+
buffer = ssh_buffer_new();
if (buffer == NULL) {
ssh_set_error_oom(session);
@@ -2172,7 +2201,7 @@ int ssh_forward_cancel(ssh_session session, const char *address, int port) {
ssh_set_error_oom(session);
goto error;
}
-
+pending:
rc = global_request(session, "cancel-tcpip-forward", buffer, 1);
error:
@@ -2726,17 +2755,21 @@ ssh_session ssh_channel_get_session(ssh_channel channel) {
* or eof not sent.
*/
int ssh_channel_get_exit_status(ssh_channel channel) {
+ int timeout;
if(channel == NULL) {
return SSH_ERROR;
}
if (channel->local_eof == 0) {
- return -1;
+ return channel->exit_status;
}
-
+ if(ssh_is_blocking(channel->session))
+ timeout = -2;
+ else
+ timeout = 0;
while ((channel->remote_eof == 0 || channel->exit_status == -1) && channel->session->alive) {
/* Parse every incoming packet */
- if (ssh_handle_packets(channel->session, -2) != SSH_OK) {
+ if (ssh_handle_packets(channel->session, timeout) != SSH_OK) {
return -1;
}
/* XXX We should actually wait for a close packet and not a close
@@ -2747,6 +2780,8 @@ int ssh_channel_get_exit_status(ssh_channel channel) {
* come anymore */
break;
}
+ if (timeout == 0)
+ break;
}
return channel->exit_status;
@@ -3022,7 +3057,8 @@ int ssh_channel_open_reverse_forward(ssh_channel channel, const char *remotehost
session = channel->session;
enter_function();
-
+ if(channel->state != SSH_CHANNEL_STATE_NOT_OPEN)
+ goto pending;
payload = ssh_buffer_new();
if (payload == NULL) {
ssh_set_error_oom(session);
@@ -3052,7 +3088,7 @@ int ssh_channel_open_reverse_forward(ssh_channel channel, const char *remotehost
ssh_set_error_oom(session);
goto error;
}
-
+pending:
rc = channel_open(channel,
"forwarded-tcpip",
CHANNEL_INITIAL_WINDOW,
@@ -3096,12 +3132,13 @@ int ssh_channel_open_x11(ssh_channel channel,
ssh_set_error_invalid(channel->session, __FUNCTION__);
return rc;
}
-
-
session = channel->session;
enter_function();
+ if(channel->state != SSH_CHANNEL_STATE_NOT_OPEN)
+ goto pending;
+
payload = ssh_buffer_new();
if (payload == NULL) {
ssh_set_error_oom(session);
@@ -3119,7 +3156,7 @@ int ssh_channel_open_x11(ssh_channel channel,
ssh_set_error_oom(session);
goto error;
}
-
+pending:
rc = channel_open(channel,
"x11",
CHANNEL_INITIAL_WINDOW,