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

More or less completed.

Rev: src/channel.c:1.7
Rev: src/client.c:1.28
parent 09ac6373
......@@ -25,6 +25,7 @@
#include "channel.h"
#include "format.h"
#include "read_data.h"
#include "service.h"
#include "ssh.h"
#include "werror.h"
......@@ -331,17 +332,20 @@ static int do_window_adjust(struct packet_handler *c,
lsh_string_free(packet);
if (channel)
if (channel
&& !(channel->flags & (CHANNEL_RECIEVED_EOF | CHANNEL_RECIEVED_CLOSE)))
{
channel->send_window_size += size;
if (channel->send_window_size && channel->send)
CHANNEL_SEND(channel);
if (! (channel->flags & CHANNEL_SENT_CLOSE))
{
channel->send_window_size += size;
if (channel->send_window_size && channel->send)
CHANNEL_SEND(channel);
}
return LSH_OK | LSH_GOON;
}
/* FIXME: What to do now? Should unknown channel numbers be
* ignored silently? */
werror("SSH_MSG_CHANNEL_WINDOW_ADJUST on nonexistant channel %d\n",
werror("SSH_MSG_CHANNEL_WINDOW_ADJUST on nonexistant or closed channel %d\n",
channel_number);
return LSH_FAIL | LSH_DIE;
}
......@@ -375,17 +379,27 @@ static int do_channel_data(struct packet_handler *c,
lsh_string_free(packet);
if (channel && channel->recieve)
if (channel && channel->recieve
&& !(channel->flags & (CHANNEL_RECIEVED_EOF | CHANNEL_RECIEVED_CLOSE)))
{
if (data->length > channel->rec_window_size)
if (channel->flags & CHANNEL_SENT_CLOSE)
{
/* Truncate data to fit window */
werror("Channel data overflow. Extra data ignored.\n");
data->length = channel->rec_window_size;
werror("Ignoring data on channel which is closing\n");
return LSH_OK | LSH_GOON;
}
channel->rec_window_size -= data->length;
return CHANNEL_RECIEVE(channel,
CHANNEL_DATA, data);
else
{
if (data->length > channel->rec_window_size)
{
/* Truncate data to fit window */
werror("Channel data overflow. Extra data ignored.\n");
data->length = channel->rec_window_size;
}
channel->rec_window_size -= data->length;
return CHANNEL_RECIEVE(channel,
CHANNEL_DATA, data);
}
return LSH_OK | LSH_GOON;
}
werror("Data on closed or non-existant channel %d\n",
......@@ -425,26 +439,36 @@ static int do_channel_extended_data(struct packet_handler *c,
lsh_string_free(packet);
if (channel && channel->recieve)
if (channel && channel->recieve
&& !(channel->flags & (CHANNEL_RECIEVED_EOF | CHANNEL_RECIEVED_CLOSE)))
{
if (data->length > channel->rec_window_size)
if (channel->flags & CHANNEL_SENT_CLOSE)
{
/* Truncate data to fit window */
werror("Channel extended data overflow. "
"Extra data ignored.\n");
data->length = channel->rec_window_size;
werror("Ignoring extended data on channel which is closing\n");
return LSH_OK | LSH_GOON;
}
channel->rec_window_size -= data->length;
switch(type)
else
{
case SSH_EXTENDED_DATA_STDERR:
return CHANNEL_RECIEVE(channel,
CHANNEL_DATA, data);
default:
werror("Unknown type %d of extended data.\n",
type);
lsh_string_free(data);
return LSH_FAIL | LSH_DIE;
if (data->length > channel->rec_window_size)
{
/* Truncate data to fit window */
werror("Channel extended data overflow. "
"Extra data ignored.\n");
data->length = channel->rec_window_size;
}
channel->rec_window_size -= data->length;
switch(type)
{
case SSH_EXTENDED_DATA_STDERR:
return CHANNEL_RECIEVE(channel,
CHANNEL_DATA, data);
default:
werror("Unknown type %d of extended data.\n",
type);
lsh_string_free(data);
return LSH_FAIL | LSH_DIE;
}
}
}
werror("Extended data on closed or non-existant channel %d\n",
......@@ -480,9 +504,35 @@ static int do_channel_eof(struct packet_handler *c,
lsh_string_free(packet);
if (channel && channel->eof)
return CHANNEL_EOF(channel);
if (channel)
{
if (channel->flags & (CHANNEL_RECIEVED_EOF | CHANNEL_RECIEVED_CLOSE))
{
werror("Recieving EOF on channel on closed channel.\n");
return LSH_FAIL | LSH_DIE;
}
channel->flags |= CHANNEL_RECIEVED_EOF;
if (channel->flags & CHANNEL_SENT_CLOSE)
/* Do nothing */
return LSH_OK | LSH_GOON;
if (channel->flags & CHANNEL_SENT_EOF)
{
/* Both parties have sent EOF. Initiate close, if we
* havn't done that already. */
return (channel->flags & CHANNEL_SENT_CLOSE)
? LSH_OK | LSH_GOON
: channel_close(channel);
}
}
werror("EOF on non-existant channel %d\n",
channel_number);
return LSH_FAIL | LSH_DIE;
}
lsh_string_free(packet);
return LSH_FAIL | LSH_DIE;
}
......@@ -510,8 +560,28 @@ static int do_channel_close(struct packet_handler *c,
lsh_string_free(packet);
if (channel && channel->close)
return CHANNEL_CLOSE(channel);
if (channel)
{
if (channel->flags & CHANNEL_RECIEVED_CLOSE)
{
werror("Recieving multiple CLOSE on channel.\n");
return LSH_FAIL | LSH_DIE;
}
channel->flags |= CHANNEL_RECIEVED_CLOSE;
if (channel->flags & (CHANNEL_RECIEVED_EOF | CHANNEL_SENT_EOF))
{
werror("Unexpected channel CLOSE.\n");
}
return (channel->flags & (CHANNEL_SENT_CLOSE))
? LSH_OK | LSH_CHANNEL_FINISHED
: LSH_OK | LSH_GOON;
}
werror("CLOSE on non-existant channel %d\n",
channel_number);
return LSH_FAIL | LSH_DIE;
}
lsh_string_free(packet);
......@@ -789,6 +859,68 @@ struct ssh_service *make_connection_service(struct alist *global_requests,
return &self->super;
}
struct lsh_string *format_channel_close(struct ssh_channel *channel)
{
return ssh_format("%c%i",
SSH_MSG_CHANNEL_CLOSE,
channel->channel_number);
}
int channel_close(struct ssh_channel *channel)
{
channel->flags |= CHANNEL_SENT_CLOSE;
return A_WRITE(channel->write, format_channel_close(channel))
| ( (channel->flags & CHANNEL_RECIEVED_CLOSE)
? LSH_CHANNEL_FINISHED : 0);
}
struct lsh_string *format_channel_eof(struct ssh_channel *channel)
{
return ssh_format("%c%i",
SSH_MSG_CHANNEL_EOF,
channel->channel_number);
}
int channel_eof(struct ssh_channel *channel)
{
int res ;
channel->flags |= CHANNEL_SENT_CLOSE;
res = A_WRITE(channel->write, format_channel_eof(channel));
if (LSH_CLOSEDP(res))
return res;
if (channel->flags & CHANNEL_RECIEVED_EOF)
{
/* Initiate close */
res |= channel_close(channel);
}
return res;
}
void init_channel(struct ssh_channel *channel)
{
/* channel->super.handler = do_read_channel; */
channel->write = NULL;
channel->flags = 0;
channel->request_types = NULL;
channel->recieve = NULL;
channel->send = NULL;
#if 0
channel->close = NULL;
channel->eof = NULL;
#endif
channel->open_confirm = NULL;
channel->open_failure = NULL;
channel->channel_success = NULL;
channel->channel_failure = NULL;
}
struct lsh_string *channel_transmit_data(struct ssh_channel *channel,
struct lsh_string *data)
{
......@@ -815,65 +947,77 @@ struct lsh_string *channel_transmit_extended(struct ssh_channel *channel,
data);
}
static int do_read_channel(struct read_handler **h,
struct abstract_read *read)
/* Writing data to a channel */
struct channel_write
{
struct ssh_channel *closure = (struct ssh_channel *) *h;
int to_read;
int n;
struct lsh_string *packet;
MDEBUG_SUBTYPE(closure);
struct abstract_write super;
struct ssh_channel *channel;
};
to_read = MIN(closure->send_max_packet, closure->send_window_size);
struct channel_write_extended
{
struct channel_write super;
UINT32 type;
};
if (!to_read)
{
/* Stop reading */
*h = NULL;
return LSH_OK | LSH_GOON;
}
packet = lsh_string_alloc(to_read);
n = A_READ(read, to_read, packet->data);
static int do_channel_write(struct abstract_write **c,
struct lsh_string *packet)
{
struct channel_write *closure = (struct channel_write *) *c;
switch(n)
{
case 0:
lsh_string_free(packet);
return LSH_OK | LSH_GOON;
case A_FAIL:
/* Send a channel close, and prepare the channel for closing */
channel_close(channel);
return LSH_FAIL | LSH_DIE;
case A_EOF:
/* Send eof (but no close). */
channel_eof(channel);
return LSH_OK | LSH_DIE;
default:
packet->length = n;
/* FIXME: Should we consider the error code here? */
return A_WRITE(closure->write, channel_transmit_data(closure, packet));
}
return A_WRITE(closure->channel->write,
channel_transmit_data(closure->channel, packet));
}
static int do_channel_write_extended(struct abstract_write **c,
struct lsh_string *packet)
{
struct channel_write_extended *closure = (struct channel_write_extended *) *c;
return A_WRITE(closure->super.channel->write,
channel_transmit_extended(closure->super.channel,
closure->type,
packet));
}
void init_channel(struct ssh_channel *channel, struct abstract_write *write)
struct abstract_write *make_channel_write(struct ssh_channel *channel)
{
channel->super.handler = do_read_channel;
channel->write = write;
struct channel_write *closure;
NEW(closure);
closure->super.write = do_channel_write;
closure->channel = channel;
return &closure->super;
}
struct abstract_write *make_channel_write_extended(struct ssh_channel *channel,
UINT32 type)
{
struct channel_write_extended *closure;
NEW(closure);
closure->super.super.write = do_channel_write_extended;
closure->super.channel = channel;
closure->type = type;
channel->request_types = NULL;
channel->recieve = NULL;
channel->send = NULL;
channel->close = NULL;
channel->eof = NULL;
channel->open_confirm = NULL;
channel->open_failure = NULL;
channel->channel_success = NULL;
channel->channel_failure = NULL;
return &closure->super.super;
}
struct read_handler *make_channel_read_data(struct ssh_channel *channel)
{
return make_read_data(channel, make_channel_write(channel));
}
struct read_handler *make_channel_read_stderr(struct ssh_channel *channel)
{
return make_read_data(channel,
make_channel_write_extended(channel,
SSH_EXTENDED_DATA_STDERR));
}
struct lsh_string *prepare_channel_open(struct channel_table *table,
int type, struct ssh_channel *channel,
char *format, ...)
......
......@@ -217,7 +217,7 @@ struct close_callback *make_client_close_handler(void)
return c;
}
/* Request a service (for instance ssh-userauth). */
/* Start a service that the servar has accepted (for instance ssh-userauth). */
struct accept_service_handler
{
struct packet_handler super;
......@@ -254,8 +254,8 @@ static int do_accept_service(struct packet_handler *c,
return LSH_FAIL | LSH_DIE;
}
struct ssh_service *make_accept_service_handler(int service_name,
struct ssh_service *service)
struct packet_handler *make_accept_service_handler(int service_name,
struct ssh_service *service)
{
struct accept_service_handler *closure;
......@@ -275,7 +275,6 @@ struct service_request
struct ssh_service *service;
};
static int do_request_service(struct ssh_service *c,
struct ssh_connection *connection)
{
......@@ -308,10 +307,11 @@ struct session
{
struct ssh_channel super;
int expect_close;
UINT32 min_window;
UINT32 max_window;
/* Exec or shell request. */
int final_request;
struct lsh_string *args;
/* To access stdio */
struct io_fd *in;
......@@ -319,22 +319,22 @@ struct session
struct abstract_write *err;
};
static int client_session_die(struct ssh_channel *c, struct abstract_write *write)
static int client_session_die(struct ssh_channel *c)
{
struct session *closure = (struct session *) c;
MDEBUG(closure);
/* FIXME: Don't die this hard. Should send proper close messages,
* wait for buffers to be flushed, etc. */
if (closure->expect_close)
/* FIXME: Don't die this hard. */
if ( (closure->super.flags & (CHANNEL_SENT_CLOSE | CHANNEL_RECIEVED_CLOSE))
== (CHANNEL_SENT_CLOSE | CHANNEL_RECIEVED_CLOSE))
exit(EXIT_SUCCESS);
exit(EXIT_FAILURE);
}
/* Recieve channel data */
static int do_recieve(struct ssh_channel *c, struct abstract_write *write,
static int do_recieve(struct ssh_channel *c,
int type, struct lsh_string *data)
{
struct session *closure = (struct session *) c;
......@@ -342,9 +342,9 @@ static int do_recieve(struct ssh_channel *c, struct abstract_write *write,
MDEBUG(closure);
if (closure->super.rec_window_size < closure->min_window)
if (closure->super.rec_window_size < closure->max_window / 2)
{
res = A_WRITE(write, prepare_window_adjust
res = A_WRITE(closure->super.write, prepare_window_adjust
(&closure->super,
closure->max_window - closure->super.rec_window_size));
if (LSH_CLOSEDP(res))
......@@ -362,54 +362,81 @@ static int do_recieve(struct ssh_channel *c, struct abstract_write *write,
}
}
/* We may send more data */
static int do_send(struct ssh_channel *c)
{
struct session *closure = (struct session *) c;
MDEBUG(closure);
closure->in->on_hold = 0;
return LSH_OK | LSH_GOON;
}
/* We have a remote shell */
static int do_shell(struct ssh_channel *c, struct abstract_write *write)
static int do_io(struct ssh_channel *c)
{
struct session *closure = (struct session *) c;
MDEBUG(closure);
closure->super.recieve = do_recieve;
closure->in->handler = read_data
closure->in->handler = make_channel_read_data(&closure->super);
closure->super.send = do_send;
return LSH_OK | LSH_GOON;
}
/* We have opened a channel of type "session" */
static int do_open_confirm(struct ssh_channel *c, struct abstract_write *write)
static int do_open_confirm(struct ssh_channel *c)
{
struct session *closure = (struct session *) c;
struct lsh_string *args;
MDEBUG(closure);
closure->super.open_confirm = NULL;
closure->super.open_failure = NULL;
closure->super.channel_success = do_shell;
closure->super.channel_success = do_io;
closure->super.channel_failure = client_session_die;
return A_WRITE(write, format_channel_request(ATOM_SHELL, c, 1, ""));
args = closure->args;
closure->args = NULL; /* for gc */
return A_WRITE(closure->super.write,
format_channel_request(closure->final_request, c, 1,
"%lfS", args));
}
struct ssh_channel *make_session(struct io_fd *in,
abstract_write *out, abstract_write *err)
static struct ssh_channel *make_session(struct io_fd *in,
struct abstract_write *out,
struct abstract_write *err,
UINT32 max_window,
int final_request,
struct lsh_string *args)
{
struct session *self;
NEW(self);
self->super.request_types = make_alist(0, -1);
self->super.recieve = NULL;
self->super.close = NULL;
self->super.eof = NULL;
self->super.open_confirm = do_open_confirm;
self->super.open_failure = client_session_die;
self->super.channel_success = NULL;
self->super.channel_failure = NULL;
init_channel(&self->super);
self->max_window = max_window;
self->super.rec_window_size = max_window;
/* FIXME: Make maximum packet size configurable */
self->super.rec_max_packet = SSH_MAX_PACKET;
self->expect_close = 0;
/* self->expect_close = 0; */
self->in = in;
self->out = out;
self->err = err;
self->final_request = final_request;
self->args = args;
return &self->super;
}
......@@ -417,8 +444,17 @@ struct client_startup
{
struct connection_startup super;
/* Whether to request pty, forwarding, exec ... */
int shell;
struct ssh_channel *session;
#if 0
/* Exec or shell request. */
int final_request;
struct lsh_string *args;
/* To access stdio */
struct io_fd *in;
struct abstract_write *out;
struct abstract_write *err;
#endif
};
static int do_client_startup(struct connection_startup *c,
......@@ -426,27 +462,34 @@ static int do_client_startup(struct connection_startup *c,
struct abstract_write *write)
{
struct client_startup *closure = (struct client_startup *) c;
MDEBUG(closure);
A_WRITE(write, prepare_channel_open(table, ATOM_SESSION,
closure->session->write = write;
closure->session->open_confirm = do_open_confirm;
closure->session->open_failure = client_session_die;
return A_WRITE(write, prepare_channel_open(table, ATOM_SESSION,
closure->session, ""));
}
#define WINDOW_SIZE (SSH_MAX_PACKET << 3)
/* Request opening a session. */
struct connection_startup *make_client_startup(struct io_fd in,
struct abstract_write out,
struct abstract_write err,
int want_shell)
struct connection_startup *make_client_startup(struct io_fd *in,
struct abstract_write *out,
struct abstract_write *err,
int final_request,
struct lsh_string *args)
{
struct client_startup *closure;
struct ssh_channel *session;
NEW(closure);
closure->super.start = do_client_startup;
closure->session = make_session(in, out, err);
closure->shell = want_shell;
closure->session = make_session(in, out, err,
WINDOW_SIZE,
final_request, args);
return &closure->super;
}
......
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