version 1.203, 2004/05/26 23:02:39 |
version 1.204, 2004/06/13 15:03:02 |
|
|
c->rfd = rfd; |
c->rfd = rfd; |
c->wfd = wfd; |
c->wfd = wfd; |
c->sock = (rfd == wfd) ? rfd : -1; |
c->sock = (rfd == wfd) ? rfd : -1; |
|
c->ctl_fd = -1; /* XXX: set elsewhere */ |
c->efd = efd; |
c->efd = efd; |
c->extended_usage = extusage; |
c->extended_usage = extusage; |
|
|
|
|
c->single_connection = 0; |
c->single_connection = 0; |
c->detach_user = NULL; |
c->detach_user = NULL; |
c->confirm = NULL; |
c->confirm = NULL; |
|
c->confirm_ctx = NULL; |
c->input_filter = NULL; |
c->input_filter = NULL; |
debug("channel %d: new [%s]", found, remote_name); |
debug("channel %d: new [%s]", found, remote_name); |
return c; |
return c; |
|
|
static void |
static void |
channel_close_fds(Channel *c) |
channel_close_fds(Channel *c) |
{ |
{ |
debug3("channel %d: close_fds r %d w %d e %d", |
debug3("channel %d: close_fds r %d w %d e %d c %d", |
c->self, c->rfd, c->wfd, c->efd); |
c->self, c->rfd, c->wfd, c->efd, c->ctl_fd); |
|
|
channel_close_fd(&c->sock); |
channel_close_fd(&c->sock); |
|
channel_close_fd(&c->ctl_fd); |
channel_close_fd(&c->rfd); |
channel_close_fd(&c->rfd); |
channel_close_fd(&c->wfd); |
channel_close_fd(&c->wfd); |
channel_close_fd(&c->efd); |
channel_close_fd(&c->efd); |
|
|
|
|
if (c->sock != -1) |
if (c->sock != -1) |
shutdown(c->sock, SHUT_RDWR); |
shutdown(c->sock, SHUT_RDWR); |
|
if (c->ctl_fd != -1) |
|
shutdown(c->ctl_fd, SHUT_RDWR); |
channel_close_fds(c); |
channel_close_fds(c); |
buffer_free(&c->input); |
buffer_free(&c->input); |
buffer_free(&c->output); |
buffer_free(&c->output); |
|
|
case SSH_CHANNEL_X11_OPEN: |
case SSH_CHANNEL_X11_OPEN: |
case SSH_CHANNEL_INPUT_DRAINING: |
case SSH_CHANNEL_INPUT_DRAINING: |
case SSH_CHANNEL_OUTPUT_DRAINING: |
case SSH_CHANNEL_OUTPUT_DRAINING: |
snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d)\r\n", |
snprintf(buf, sizeof buf, |
|
" #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d cfd %d)\r\n", |
c->self, c->remote_name, |
c->self, c->remote_name, |
c->type, c->remote_id, |
c->type, c->remote_id, |
c->istate, buffer_len(&c->input), |
c->istate, buffer_len(&c->input), |
c->ostate, buffer_len(&c->output), |
c->ostate, buffer_len(&c->output), |
c->rfd, c->wfd); |
c->rfd, c->wfd, c->ctl_fd); |
buffer_append(&buffer, buf, strlen(buf)); |
buffer_append(&buffer, buf, strlen(buf)); |
continue; |
continue; |
default: |
default: |
|
|
logit("channel_request_start: %d: unknown channel id", id); |
logit("channel_request_start: %d: unknown channel id", id); |
return; |
return; |
} |
} |
debug2("channel %d: request %s", id, service) ; |
debug2("channel %d: request %s confirm %d", id, service, wantconfirm); |
packet_start(SSH2_MSG_CHANNEL_REQUEST); |
packet_start(SSH2_MSG_CHANNEL_REQUEST); |
packet_put_int(c->remote_id); |
packet_put_int(c->remote_id); |
packet_put_cstring(service); |
packet_put_cstring(service); |
packet_put_char(wantconfirm); |
packet_put_char(wantconfirm); |
} |
} |
void |
void |
channel_register_confirm(int id, channel_callback_fn *fn) |
channel_register_confirm(int id, channel_callback_fn *fn, void *ctx) |
{ |
{ |
Channel *c = channel_lookup(id); |
Channel *c = channel_lookup(id); |
|
|
|
|
return; |
return; |
} |
} |
c->confirm = fn; |
c->confirm = fn; |
|
c->confirm_ctx = ctx; |
} |
} |
void |
void |
channel_register_cleanup(int id, channel_callback_fn *fn) |
channel_register_cleanup(int id, channel_callback_fn *fn) |
|
|
buffer_len(&c->extended) < c->remote_window) |
buffer_len(&c->extended) < c->remote_window) |
FD_SET(c->efd, readset); |
FD_SET(c->efd, readset); |
} |
} |
|
/* XXX: What about efd? races? */ |
|
if (compat20 && c->ctl_fd != -1 && |
|
c->istate == CHAN_INPUT_OPEN && c->ostate == CHAN_OUTPUT_OPEN) |
|
FD_SET(c->ctl_fd, readset); |
} |
} |
|
|
static void |
static void |
|
|
return 1; |
return 1; |
} |
} |
static int |
static int |
|
channel_handle_ctl(Channel *c, fd_set * readset, fd_set * writeset) |
|
{ |
|
char buf[16]; |
|
int len; |
|
|
|
/* Monitor control fd to detect if the slave client exits */ |
|
if (c->ctl_fd != -1 && FD_ISSET(c->ctl_fd, readset)) { |
|
len = read(c->ctl_fd, buf, sizeof(buf)); |
|
if (len < 0 && (errno == EINTR || errno == EAGAIN)) |
|
return 1; |
|
if (len <= 0) { |
|
debug2("channel %d: ctl read<=0", c->self); |
|
if (c->type != SSH_CHANNEL_OPEN) { |
|
debug2("channel %d: not open", c->self); |
|
chan_mark_dead(c); |
|
return -1; |
|
} else { |
|
chan_read_failed(c); |
|
chan_write_failed(c); |
|
} |
|
return -1; |
|
} else |
|
fatal("%s: unexpected data on ctl fd", __func__); |
|
} |
|
return 1; |
|
} |
|
static int |
channel_check_window(Channel *c) |
channel_check_window(Channel *c) |
{ |
{ |
if (c->type == SSH_CHANNEL_OPEN && |
if (c->type == SSH_CHANNEL_OPEN && |
|
|
if (!compat20) |
if (!compat20) |
return; |
return; |
channel_handle_efd(c, readset, writeset); |
channel_handle_efd(c, readset, writeset); |
|
channel_handle_ctl(c, readset, writeset); |
channel_check_window(c); |
channel_check_window(c); |
} |
} |
|
|
|
|
c->remote_maxpacket = packet_get_int(); |
c->remote_maxpacket = packet_get_int(); |
if (c->confirm) { |
if (c->confirm) { |
debug2("callback start"); |
debug2("callback start"); |
c->confirm(c->self, NULL); |
c->confirm(c->self, c->confirm_ctx); |
debug2("callback done"); |
debug2("callback done"); |
} |
} |
debug2("channel %d: open confirm rwindow %u rmax %u", c->self, |
debug2("channel %d: open confirm rwindow %u rmax %u", c->self, |
|
|
return -1; |
return -1; |
} |
} |
return connect_to(host, port); |
return connect_to(host, port); |
|
} |
|
|
|
void |
|
channel_send_window_changes(void) |
|
{ |
|
int i; |
|
struct winsize ws; |
|
|
|
for (i = 0; i < channels_alloc; i++) { |
|
if (channels[i] == NULL || |
|
channels[i]->type != SSH_CHANNEL_OPEN) |
|
continue; |
|
if (ioctl(channels[i]->rfd, TIOCGWINSZ, &ws) < 0) |
|
continue; |
|
channel_request_start(i, "window-change", 0); |
|
packet_put_int(ws.ws_col); |
|
packet_put_int(ws.ws_row); |
|
packet_put_int(ws.ws_xpixel); |
|
packet_put_int(ws.ws_ypixel); |
|
packet_send(); |
|
} |
} |
} |
|
|
/* -- X11 forwarding */ |
/* -- X11 forwarding */ |