Commit b3f6b741 authored by Niels Möller's avatar Niels Möller
Browse files

The open handler now does more of the book-keeping. Bugfixes.

Rev: src/channel.c:1.8
Rev: src/channel.h:1.10
parent f37cbcaf
...@@ -81,6 +81,37 @@ struct lsh_string *format_global_failure(void) ...@@ -81,6 +81,37 @@ struct lsh_string *format_global_failure(void)
return ssh_format("%c", SSH_MSG_REQUEST_FAILURE); return ssh_format("%c", SSH_MSG_REQUEST_FAILURE);
} }
struct lsh_string *format_open_confirmation(struct ssh_channel *channel,
UINT32 channel_number,
char *format, ...)
{
va_list args;
UINT32 l1, l2;
struct lsh_string *packet;
#define CONFIRM_FORMAT "%c%i%i%i%i"
#define CONFIRM_ARGS SSH_MSG_CHANNEL_OPEN_CONFIRMATION, channel->channel_number, \
channel_number, channel->rec_window_size, channel->rec_max_packet
l1 = ssh_format_length(CONFIRM_FORMAT, CONFIRM_ARGS);
va_start(args, format);
l2 = ssh_vformat_length(format, args);
va_end(args);
packet = lsh_string_alloc(l1 + l2);
ssh_format_write(CONFIRM_FORMAT, l1, packet->data, CONFIRM_ARGS);
va_start(args, format);
ssh_format_write(format, l2, packet->data+l1, args);
va_end(args);
return packet;
#undef CONFIRM_FORMAT
#undef CONFIRM_ARGS
}
struct lsh_string *format_open_failure(UINT32 channel, UINT32 reason, struct lsh_string *format_open_failure(UINT32 channel, UINT32 reason,
char *msg, char *language) char *msg, char *language)
{ {
...@@ -88,6 +119,11 @@ struct lsh_string *format_open_failure(UINT32 channel, UINT32 reason, ...@@ -88,6 +119,11 @@ struct lsh_string *format_open_failure(UINT32 channel, UINT32 reason,
channel, reason, msg, language); channel, reason, msg, language);
} }
struct lsh_string *format_channel_success(UINT32 channel)
{
return ssh_format("%c%i", SSH_MSG_CHANNEL_SUCCESS, channel);
}
struct lsh_string *format_channel_failure(UINT32 channel) struct lsh_string *format_channel_failure(UINT32 channel)
{ {
return ssh_format("%c%i", SSH_MSG_CHANNEL_FAILURE, channel); return ssh_format("%c%i", SSH_MSG_CHANNEL_FAILURE, channel);
...@@ -229,9 +265,9 @@ static int do_channel_open(struct packet_handler *c, ...@@ -229,9 +265,9 @@ static int do_channel_open(struct packet_handler *c,
struct simple_buffer buffer; struct simple_buffer buffer;
int msg_number; int msg_number;
int type; int type;
UINT32 channel_number; UINT32 remote_channel_number;
UINT32 rec_window_size; UINT32 window_size;
UINT32 rec_max_packet; UINT32 max_packet;
MDEBUG(closure); MDEBUG(closure);
...@@ -240,20 +276,60 @@ static int do_channel_open(struct packet_handler *c, ...@@ -240,20 +276,60 @@ static int do_channel_open(struct packet_handler *c,
if (parse_uint8(&buffer, &msg_number) if (parse_uint8(&buffer, &msg_number)
&& (msg_number == SSH_MSG_CHANNEL_OPEN) && (msg_number == SSH_MSG_CHANNEL_OPEN)
&& parse_atom(&buffer, &type) && parse_atom(&buffer, &type)
&& parse_uint32(&buffer, &rec_window_size) && parse_uint32(&buffer, &remote_channel_number)
&& parse_uint32(&buffer, &rec_max_packet)) && parse_uint32(&buffer, &window_size)
&& parse_uint32(&buffer, &max_packet))
{ {
struct channel_open *open; struct channel_open *open;
struct ssh_channel *channel;
UINT32 error = 0;
char *error_msg;
struct lsh_string *args = NULL;
int local_channel_number;
lsh_string_free(packet); lsh_string_free(packet);
if (!type || !(open = ALIST_GET(closure->channel_types, type))) if (!type || !(open = ALIST_GET(closure->channel_types, type)))
return A_WRITE(connection->write, return A_WRITE(connection->write,
format_open_failure(channel_number, format_open_failure(remote_channel_number,
SSH_OPEN_UNKNOWN_CHANNEL_TYPE, SSH_OPEN_UNKNOWN_CHANNEL_TYPE,
"Unknown channel type", "")); "Unknown channel type", ""));
return CHANNEL_OPEN(open, channel_number, rec_window_size,
rec_max_packet, &buffer); channel = CHANNEL_OPEN(open, &buffer, &error, &error_msg, &args);
if (!channel)
{
if (error)
return A_WRITE(connection->write,
format_open_failure(remote_channel_number,
error, error_msg, ""));
/* The request was invalid */
return LSH_FAIL | LSH_DIE;
}
if ( (local_channel_number
= register_channel(closure->super.table, channel)) < 0)
{
werror("Could not allocate a channel number for pened channel!\n");
return A_WRITE(connection->write,
format_open_failure(remote_channel_number,
SSH_OPEN_RESOURCE_SHORTAGE,
"Could not allocate a channel number "
"(shouldn't happen...)", ""));
}
channel->send_window_size = window_size;
channel->send_max_packet = max_packet;
channel->channel_number = remote_channel_number;
channel->write = connection->write;
return A_WRITE(connection->write,
args
? format_open_confirmation(channel, local_channel_number,
"%lfS", args)
: format_open_confirmation(channel, local_channel_number, ""));
} }
lsh_string_free(packet); lsh_string_free(packet);
...@@ -295,8 +371,11 @@ static int do_channel_request(struct packet_handler *c, ...@@ -295,8 +371,11 @@ static int do_channel_request(struct packet_handler *c,
&& ( (req = ALIST_GET(channel->request_types, type)) )) && ( (req = ALIST_GET(channel->request_types, type)) ))
return CHANNEL_REQUEST(req, channel, want_reply, &buffer); return CHANNEL_REQUEST(req, channel, want_reply, &buffer);
else else
return A_WRITE(connection->write, return want_reply
format_channel_failure(channel->channel_number)); ? A_WRITE(connection->write,
format_channel_failure(channel->channel_number))
: LSH_OK | LSH_GOON;
} }
werror("SSH_MSG_CHANNEL_REQUEST on nonexistant channel %d\n", werror("SSH_MSG_CHANNEL_REQUEST on nonexistant channel %d\n",
channel_number); channel_number);
...@@ -389,15 +468,27 @@ static int do_channel_data(struct packet_handler *c, ...@@ -389,15 +468,27 @@ static int do_channel_data(struct packet_handler *c,
} }
else else
{ {
int res = 0;
if (data->length > channel->rec_window_size) if (data->length > channel->rec_window_size)
{ {
/* Truncate data to fit window */ /* Truncate data to fit window */
werror("Channel data overflow. Extra data ignored.\n"); werror("Channel data overflow. Extra data ignored.\n");
data->length = channel->rec_window_size; data->length = channel->rec_window_size;
} }
channel->rec_window_size -= data->length; channel->rec_window_size -= data->length;
return CHANNEL_RECIEVE(channel,
CHANNEL_DATA, data); if (channel->rec_window_size < channel->max_window / 2)
{
res = A_WRITE(channel->write, prepare_window_adjust
(channel,
channel->max_window - channel->rec_window_size));
if (LSH_CLOSEDP(res))
return res;
}
return res | CHANNEL_RECIEVE(channel,
CHANNEL_DATA, data);
} }
return LSH_OK | LSH_GOON; return LSH_OK | LSH_GOON;
} }
...@@ -449,6 +540,8 @@ static int do_channel_extended_data(struct packet_handler *c, ...@@ -449,6 +540,8 @@ static int do_channel_extended_data(struct packet_handler *c,
} }
else else
{ {
int res = 0;
if (data->length > channel->rec_window_size) if (data->length > channel->rec_window_size)
{ {
/* Truncate data to fit window */ /* Truncate data to fit window */
...@@ -458,11 +551,21 @@ static int do_channel_extended_data(struct packet_handler *c, ...@@ -458,11 +551,21 @@ static int do_channel_extended_data(struct packet_handler *c,
} }
channel->rec_window_size -= data->length; channel->rec_window_size -= data->length;
if (channel->rec_window_size < channel->max_window / 2)
{
res = A_WRITE(channel->write, prepare_window_adjust
(channel,
channel->max_window - channel->rec_window_size));
if (LSH_CLOSEDP(res))
return res;
}
switch(type) switch(type)
{ {
case SSH_EXTENDED_DATA_STDERR: case SSH_EXTENDED_DATA_STDERR:
return CHANNEL_RECIEVE(channel, return res | CHANNEL_RECIEVE(channel,
CHANNEL_DATA, data); CHANNEL_STDERR_DATA, data);
default: default:
werror("Unknown type %d of extended data.\n", werror("Unknown type %d of extended data.\n",
type); type);
......
...@@ -36,6 +36,8 @@ struct ssh_channel ...@@ -36,6 +36,8 @@ struct ssh_channel
UINT32 channel_number; /* Remote channel number */ UINT32 channel_number; /* Remote channel number */
UINT32 max_window; /* We try to keep the rec_window_size
* between max_window / 2 and max_window. */
UINT32 rec_window_size; UINT32 rec_window_size;
UINT32 rec_max_packet; UINT32 rec_max_packet;
...@@ -144,15 +146,15 @@ struct channel_open ...@@ -144,15 +146,15 @@ struct channel_open
{ {
struct lsh_object *header; struct lsh_object *header;
int (*handler)(struct channel_open *closure, struct ssh_channel * (*handler)(struct channel_open *closure,
UINT32 channel_number, /* Remote channel number */ struct simple_buffer *args,
UINT32 rec_window_size, UINT32 *error,
UINT32 rec_max_packet, char **error_msg,
struct simple_buffer *args); struct lsh_string **data);
}; };
#define CHANNEL_OPEN(c, n, w, m, a) \ #define CHANNEL_OPEN(c, a, e, m, d) \
((c)->handler((c), (n), (w), (m), (a))) ((c)->handler((c), (a), (e), (m), (d)))
/* SSH_MSH_CHANNEL_REQUEST */ /* SSH_MSH_CHANNEL_REQUEST */
struct channel_request struct channel_request
...@@ -195,8 +197,14 @@ struct read_handler *make_channel_read_data(struct ssh_channel *channel); ...@@ -195,8 +197,14 @@ struct read_handler *make_channel_read_data(struct ssh_channel *channel);
struct read_handler *make_channel_read_stderr(struct ssh_channel *channel); struct read_handler *make_channel_read_stderr(struct ssh_channel *channel);
struct lsh_string *format_global_failure(void); struct lsh_string *format_global_failure(void);
struct lsh_string *format_open_failure(UINT32 channel, UINT32 reason, struct lsh_string *format_open_failure(UINT32 channel, UINT32 reason,
char *msg, char *language); char *msg, char *language);
struct lsh_string *format_open_confirmation(struct ssh_channel *channel,
UINT32 channel_number,
char *format, ...);
struct lsh_string *format_channel_success(UINT32 channel);
struct lsh_string *format_channel_failure(UINT32 channel); struct lsh_string *format_channel_failure(UINT32 channel);
struct lsh_string *prepare_window_adjust(struct ssh_channel *channel, struct lsh_string *prepare_window_adjust(struct ssh_channel *channel,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment