aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/libssh/channels.h9
-rw-r--r--libssh/channels.c113
-rw-r--r--libssh/channels1.c4
-rw-r--r--libssh/messages.c2
4 files changed, 68 insertions, 60 deletions
diff --git a/include/libssh/channels.h b/include/libssh/channels.h
index 5e4901ba..56e660fc 100644
--- a/include/libssh/channels.h
+++ b/include/libssh/channels.h
@@ -40,6 +40,13 @@ enum ssh_channel_request_state_e {
SSH_CHANNEL_REQ_STATE_ERROR
};
+enum ssh_channel_state_e {
+ SSH_CHANNEL_STATE_NOT_OPEN = 0,
+ SSH_CHANNEL_STATE_OPEN_DENIED,
+ SSH_CHANNEL_STATE_OPEN,
+ SSH_CHANNEL_STATE_CLOSED
+};
+
struct ssh_channel_struct {
struct ssh_channel_struct *prev;
struct ssh_channel_struct *next;
@@ -53,7 +60,7 @@ struct ssh_channel_struct {
uint32_t remote_window;
int remote_eof; /* end of file received */
uint32_t remote_maxpacket;
- int open; /* shows if the channel is still opened */
+ enum ssh_channel_state_e state;
int delayed_close;
ssh_buffer stdout_buffer;
ssh_buffer stderr_buffer;
diff --git a/libssh/channels.c b/libssh/channels.c
index aa310095..2731843c 100644
--- a/libssh/channels.c
+++ b/libssh/channels.c
@@ -55,6 +55,8 @@
* @{
*/
+static ssh_channel channel_from_msg(ssh_session session, ssh_buffer packet);
+
/**
* @brief Allocate a new channel.
*
@@ -158,18 +160,46 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf){
(long unsigned int) channel->remote_window,
(long unsigned int) channel->remote_maxpacket);
- channel->open = 1;
+ channel->state = SSH_CHANNEL_STATE_OPEN;
leave_function();
return SSH_PACKET_USED;
}
-/* TODO: implement and comment */
+/** @internal
+ * @brief handles a SSH_CHANNEL_OPEN_FAILURE and set the state of the channel.
+ */
SSH_PACKET_CALLBACK(ssh_packet_channel_open_fail){
- (void)packet;
+
+ ssh_channel channel;
+ ssh_string error_s;
+ char *error;
+ uint32_t code;
(void)user;
(void)type;
- (void)session;
- return 0;
+ channel=channel_from_msg(session,packet);
+ if(channel==NULL){
+ ssh_log(session,SSH_LOG_RARE,"Invalid channel in packet");
+ return SSH_PACKET_USED;
+ }
+ buffer_get_u32(packet, &code);
+
+ error_s = buffer_get_ssh_string(packet);
+ if(error_s != NULL)
+ error = string_to_char(error_s);
+ string_free(error_s);
+ if (error == NULL) {
+ ssh_set_error_oom(session);
+ return SSH_PACKET_USED;
+ }
+
+ ssh_set_error(session, SSH_REQUEST_DENIED,
+ "Channel opening failure: channel %u error (%lu) %s",
+ channel->local_channel,
+ (long unsigned int) ntohl(code),
+ error);
+ SAFE_FREE(error);
+
+ return SSH_PACKET_USED;
}
/** @internal
@@ -186,7 +216,7 @@ static int channel_open(ssh_channel channel, const char *type_c, int window,
int maxpacket, ssh_buffer payload) {
ssh_session session = channel->session;
ssh_string type = NULL;
- uint32_t tmp = 0;
+ int err=SSH_ERROR;
enter_function();
channel->local_channel = ssh_channel_new_id(session);
@@ -200,7 +230,7 @@ static int channel_open(ssh_channel channel, const char *type_c, int window,
type = string_from_char(type_c);
if (type == NULL) {
leave_function();
- return -1;
+ return err;
}
if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_OPEN) < 0 ||
@@ -210,7 +240,7 @@ static int channel_open(ssh_channel channel, const char *type_c, int window,
buffer_add_u32(session->out_buffer, htonl(channel->local_maxpacket)) < 0) {
string_free(type);
leave_function();
- return -1;
+ return err;
}
string_free(type);
@@ -218,13 +248,13 @@ static int channel_open(ssh_channel channel, const char *type_c, int window,
if (payload != NULL) {
if (buffer_add_buffer(session->out_buffer, payload) < 0) {
leave_function();
- return -1;
+ return err;
}
}
if (packet_send(session) != SSH_OK) {
leave_function();
- return -1;
+ return err;
}
ssh_log(session, SSH_LOG_PACKET,
@@ -233,45 +263,13 @@ static int channel_open(ssh_channel channel, const char *type_c, int window,
/* Todo: fix this into a correct loop */
/* wait until channel is opened by server */
- while(!channel->open){
+ while(channel->state == SSH_CHANNEL_STATE_NOT_OPEN){
ssh_handle_packets(session,-1);
}
+ if(channel->state == SSH_CHANNEL_STATE_OPEN)
+ err=SSH_OK;
leave_function();
- return SSH_OK;
-
- /* TODO: put this into the correct packet handler */
- switch(session->in_packet.type) {
- case SSH2_MSG_CHANNEL_OPEN_FAILURE:
- {
- ssh_string error_s;
- char *error;
- uint32_t code;
-
- buffer_get_u32(session->in_buffer, &tmp);
- buffer_get_u32(session->in_buffer, &code);
-
- error_s = buffer_get_ssh_string(session->in_buffer);
- error = string_to_char(error_s);
- string_free(error_s);
- if (error == NULL) {
- leave_function();
- return -1;
- }
-
- ssh_set_error(session, SSH_REQUEST_DENIED,
- "Channel opening failure: channel %u error (%lu) %s",
- channel->local_channel,
- (long unsigned int) ntohl(code),
- error);
- SAFE_FREE(error);
-
- leave_function();
- return -1;
- }
- }
-
- leave_function();
- return -1;
+ return err;
}
/* get ssh channel from local session? */
@@ -517,7 +515,7 @@ SSH_PACKET_CALLBACK(channel_rcv_close) {
buffer_get_rest_len(channel->stderr_buffer) > 0)) {
channel->delayed_close = 1;
} else {
- channel->open = 0;
+ channel->state = SSH_CHANNEL_STATE_CLOSED;
}
if (channel->remote_eof == 0) {
@@ -775,7 +773,7 @@ void channel_free(ssh_channel channel) {
return;
}
- if (session->alive && channel->open) {
+ if (session->alive && channel->state == SSH_CHANNEL_STATE_OPEN) {
channel_close(channel);
}
@@ -885,7 +883,7 @@ int channel_close(ssh_channel channel){
channel->remote_channel);
if(rc == SSH_OK) {
- channel->open = 0;
+ channel->state=SSH_CHANNEL_STATE_CLOSED;
}
leave_function();
@@ -914,7 +912,7 @@ int channel_write_common(ssh_channel channel, const void *data,
return -1;
}
- if (channel->open == 0 || channel->delayed_close != 0) {
+ if (channel->state != SSH_CHANNEL_STATE_OPEN || channel->delayed_close != 0) {
ssh_set_error(session, SSH_REQUEST_DENIED, "Remote channel is closed");
leave_function();
return -1;
@@ -1007,7 +1005,7 @@ int channel_write(ssh_channel channel, const void *data, uint32_t len) {
* @see channel_is_closed()
*/
int channel_is_open(ssh_channel channel) {
- return (channel->open != 0 && channel->session->alive != 0);
+ return (channel->state == SSH_CHANNEL_STATE_OPEN && channel->session->alive != 0);
}
/**
@@ -1020,7 +1018,7 @@ int channel_is_open(ssh_channel channel) {
* @see channel_is_open()
*/
int channel_is_closed(ssh_channel channel) {
- return (channel->open == 0 || channel->session->alive == 0);
+ return (channel->state != SSH_CHANNEL_STATE_OPEN || channel->session->alive == 0);
}
/**
@@ -2202,7 +2200,10 @@ int channel_get_exit_status(ssh_channel channel) {
if (ssh_handle_packets(channel->session,-1) != SSH_OK) {
return -1;
}
- if (channel->open == 0) {
+ /* XXX We should actually wait for a close packet and not a close
+ * we issued ourselves
+ */
+ if (channel->state != SSH_CHANNEL_STATE_OPEN) {
/* When a channel is closed, no exit status message can
* come anymore */
break;
@@ -2230,7 +2231,7 @@ static int channel_protocol_select(ssh_channel *rchans, ssh_channel *wchans,
for (i = 0; rchans[i] != NULL; i++) {
chan = rchans[i];
- while (chan->open && ssh_socket_data_available(chan->session->socket)) {
+ while (channel_is_open(chan) && ssh_socket_data_available(chan->session->socket)) {
ssh_handle_packets(chan->session,-1);
}
@@ -2248,7 +2249,7 @@ static int channel_protocol_select(ssh_channel *rchans, ssh_channel *wchans,
chan = wchans[i];
/* It's not our business to seek if the file descriptor is writable */
if (ssh_socket_data_writable(chan->session->socket) &&
- chan->open && (chan->remote_window > 0)) {
+ channel_is_open(chan) && (chan->remote_window > 0)) {
wout[j] = chan;
j++;
}
@@ -2259,7 +2260,7 @@ static int channel_protocol_select(ssh_channel *rchans, ssh_channel *wchans,
for (i = 0; echans[i] != NULL; i++) {
chan = echans[i];
- if (!ssh_socket_is_open(chan->session->socket) || !chan->open) {
+ if (!ssh_socket_is_open(chan->session->socket) || channel_is_closed(chan)) {
eout[j] = chan;
j++;
}
diff --git a/libssh/channels1.c b/libssh/channels1.c
index 55f9e91e..19e77b80 100644
--- a/libssh/channels1.c
+++ b/libssh/channels1.c
@@ -57,7 +57,7 @@ int channel_open_session1(ssh_channel chan) {
return -1;
}
session->exec_channel_opened = 1;
- chan->open = 1;
+ chan->state = SSH_CHANNEL_STATE_OPEN;
chan->local_maxpacket = 32000;
chan->local_window = 64000;
ssh_log(session, SSH_LOG_PACKET, "Opened a SSH1 channel session");
@@ -253,7 +253,7 @@ SSH_PACKET_CALLBACK(ssh_packet_close1){
*/
/* actually status is lost somewhere */
- channel->open = 0;
+ channel->state = SSH_CHANNEL_STATE_CLOSED;
channel->remote_eof = 1;
buffer_add_u8(session->out_buffer, SSH_CMSG_EXIT_CONFIRMATION);
diff --git a/libssh/messages.c b/libssh/messages.c
index bbd7e439..8cd9ab55 100644
--- a/libssh/messages.c
+++ b/libssh/messages.c
@@ -467,7 +467,7 @@ ssh_channel ssh_message_channel_request_open_reply_accept(ssh_message msg) {
chan->remote_channel = msg->channel_request_open.sender;
chan->remote_maxpacket = msg->channel_request_open.packet_size;
chan->remote_window = msg->channel_request_open.window;
- chan->open = 1;
+ chan->state = SSH_CHANNEL_STATE_OPEN;
if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) < 0) {
goto error;