📄 channels.c
字号:
channel_pre[i] = NULL; channel_post[i] = NULL; } if (compat20) channel_handler_init_20(); else if (compat13) channel_handler_init_13(); else channel_handler_init_15();}/* gc dead channels */static voidchannel_garbage_collect(Channel *c){ if (c == NULL) return; if (c->detach_user != NULL) { if (!chan_is_dead(c, 0)) return; debug("channel %d: gc: notify user", c->self); c->detach_user(c->self, NULL); /* if we still have a callback */ if (c->detach_user != NULL) return; debug("channel %d: gc: user detached", c->self); } if (!chan_is_dead(c, 1)) return; debug("channel %d: garbage collecting", c->self); channel_free(c);}static voidchannel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset){ static int did_init = 0; int i; Channel *c; if (!did_init) { channel_handler_init(); did_init = 1; } for (i = 0; i < channels_alloc; i++) { c = channels[i]; if (c == NULL) continue; if (ftab[c->type] != NULL) (*ftab[c->type])(c, readset, writeset); channel_garbage_collect(c); }}/* * Allocate/update select bitmasks and add any bits relevant to channels in * select bitmasks. */voidchannel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, int *nallocp, int rekeying){ int n; u_int sz; n = MAX(*maxfdp, channel_max_fd); sz = howmany(n+1, NFDBITS) * sizeof(fd_mask); /* perhaps check sz < nalloc/2 and shrink? */ if (*readsetp == NULL || sz > *nallocp) { *readsetp = xrealloc(*readsetp, sz); *writesetp = xrealloc(*writesetp, sz); *nallocp = sz; } *maxfdp = n; memset(*readsetp, 0, sz); memset(*writesetp, 0, sz); if (!rekeying) channel_handler(channel_pre, *readsetp, *writesetp);}/* * After select, perform any appropriate operations for channels which have * events pending. */voidchannel_after_select(fd_set * readset, fd_set * writeset){ channel_handler(channel_post, readset, writeset);}/* If there is data to send to the connection, enqueue some of it now. */voidchannel_output_poll(void){ Channel *c; int i; u_int len; for (i = 0; i < channels_alloc; i++) { c = channels[i]; if (c == NULL) continue; /* * We are only interested in channels that can have buffered * incoming data. */ if (compat13) { if (c->type != SSH_CHANNEL_OPEN && c->type != SSH_CHANNEL_INPUT_DRAINING) continue; } else { if (c->type != SSH_CHANNEL_OPEN) continue; } if (compat20 && (c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) { /* XXX is this true? */ debug3("channel %d: will not send data after close", c->self); continue; } /* Get the amount of buffered data for this channel. */ if ((c->istate == CHAN_INPUT_OPEN || c->istate == CHAN_INPUT_WAIT_DRAIN) && (len = buffer_len(&c->input)) > 0) { /* * Send some data for the other side over the secure * connection. */ if (compat20) { if (len > c->remote_window) len = c->remote_window; if (len > c->remote_maxpacket) len = c->remote_maxpacket; } else { if (packet_is_interactive()) { if (len > 1024) len = 512; } else { /* Keep the packets at reasonable size. */ if (len > packet_get_maxsize()/2) len = packet_get_maxsize()/2; } } if (len > 0) { packet_start(compat20 ? SSH2_MSG_CHANNEL_DATA : SSH_MSG_CHANNEL_DATA); packet_put_int(c->remote_id); packet_put_string(buffer_ptr(&c->input), len); packet_send(); buffer_consume(&c->input, len); c->remote_window -= len; } } else if (c->istate == CHAN_INPUT_WAIT_DRAIN) { if (compat13) fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3"); /* * input-buffer is empty and read-socket shutdown: * tell peer, that we will not send more data: send IEOF. * hack for extended data: delay EOF if EFD still in use. */ if (CHANNEL_EFD_INPUT_ACTIVE(c)) debug2("channel %d: ibuf_empty delayed efd %d/(%d)", c->self, c->efd, buffer_len(&c->extended)); else chan_ibuf_empty(c); } /* Send extended data, i.e. stderr */ if (compat20 && !(c->flags & CHAN_EOF_SENT) && c->remote_window > 0 && (len = buffer_len(&c->extended)) > 0 && c->extended_usage == CHAN_EXTENDED_READ) { debug2("channel %d: rwin %u elen %u euse %d", c->self, c->remote_window, buffer_len(&c->extended), c->extended_usage); if (len > c->remote_window) len = c->remote_window; if (len > c->remote_maxpacket) len = c->remote_maxpacket; packet_start(SSH2_MSG_CHANNEL_EXTENDED_DATA); packet_put_int(c->remote_id); packet_put_int(SSH2_EXTENDED_DATA_STDERR); packet_put_string(buffer_ptr(&c->extended), len); packet_send(); buffer_consume(&c->extended, len); c->remote_window -= len; debug2("channel %d: sent ext data %d", c->self, len); } }}/* -- protocol input */voidchannel_input_data(int type, u_int32_t seq, void *ctxt){ int id; char *data; u_int data_len; Channel *c; /* Get the channel number and verify it. */ id = packet_get_int(); c = channel_lookup(id); if (c == NULL) packet_disconnect("Received data for nonexistent channel %d.", id); /* Ignore any data for non-open channels (might happen on close) */ if (c->type != SSH_CHANNEL_OPEN && c->type != SSH_CHANNEL_X11_OPEN) return; /* same for protocol 1.5 if output end is no longer open */ if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN) return; /* Get the data. */ data = packet_get_string(&data_len); if (compat20) { if (data_len > c->local_maxpacket) { log("channel %d: rcvd big packet %d, maxpack %d", c->self, data_len, c->local_maxpacket); } if (data_len > c->local_window) { log("channel %d: rcvd too much data %d, win %d", c->self, data_len, c->local_window); xfree(data); return; } c->local_window -= data_len; } packet_check_eom(); buffer_append(&c->output, data, data_len); xfree(data);}voidchannel_input_extended_data(int type, u_int32_t seq, void *ctxt){ int id; char *data; u_int data_len, tcode; Channel *c; /* Get the channel number and verify it. */ id = packet_get_int(); c = channel_lookup(id); if (c == NULL) packet_disconnect("Received extended_data for bad channel %d.", id); if (c->type != SSH_CHANNEL_OPEN) { log("channel %d: ext data for non open", id); return; } if (c->flags & CHAN_EOF_RCVD) { if (datafellows & SSH_BUG_EXTEOF) debug("channel %d: accepting ext data after eof", id); else packet_disconnect("Received extended_data after EOF " "on channel %d.", id); } tcode = packet_get_int(); if (c->efd == -1 || c->extended_usage != CHAN_EXTENDED_WRITE || tcode != SSH2_EXTENDED_DATA_STDERR) { log("channel %d: bad ext data", c->self); return; } data = packet_get_string(&data_len); packet_check_eom(); if (data_len > c->local_window) { log("channel %d: rcvd too much extended_data %d, win %d", c->self, data_len, c->local_window); xfree(data); return; } debug2("channel %d: rcvd ext data %d", c->self, data_len); c->local_window -= data_len; buffer_append(&c->extended, data, data_len); xfree(data);}voidchannel_input_ieof(int type, u_int32_t seq, void *ctxt){ int id; Channel *c; id = packet_get_int(); packet_check_eom(); c = channel_lookup(id); if (c == NULL) packet_disconnect("Received ieof for nonexistent channel %d.", id); chan_rcvd_ieof(c); /* XXX force input close */ if (c->force_drain && c->istate == CHAN_INPUT_OPEN) { debug("channel %d: FORCE input drain", c->self); c->istate = CHAN_INPUT_WAIT_DRAIN; if (buffer_len(&c->input) == 0) chan_ibuf_empty(c); }}voidchannel_input_close(int type, u_int32_t seq, void *ctxt){ int id; Channel *c; id = packet_get_int(); packet_check_eom(); c = channel_lookup(id); if (c == NULL) packet_disconnect("Received close for nonexistent channel %d.", id); /* * Send a confirmation that we have closed the channel and no more * data is coming for it. */ packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION); packet_put_int(c->remote_id); packet_send(); /* * If the channel is in closed state, we have sent a close request, * and the other side will eventually respond with a confirmation. * Thus, we cannot free the channel here, because then there would be * no-one to receive the confirmation. The channel gets freed when * the confirmation arrives. */ if (c->type != SSH_CHANNEL_CLOSED) { /* * Not a closed channel - mark it as draining, which will * cause it to be freed later. */ buffer_clear(&c->input); c->type = SSH_CHANNEL_OUTPUT_DRAINING; }}/* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */voidchannel_input_oclose(int type, u_int32_t seq, void *ctxt){ int id = packet_get_int(); Channel *c = channel_lookup(id); packet_check_eom(); if (c == NULL) packet_disconnect("Received oclose for nonexistent channel %d.", id); chan_rcvd_oclose(c);}voidchannel_input_close_confirmation(int type, u_int32_t seq, void *ctxt){ int id = packet_get_int(); Channel *c = channel_lookup(id); packet_check_eom(); if (c == NULL) packet_disconnect("Received close confirmation for " "out-of-range channel %d.", id); if (c->type != SSH_CHANNEL_CLOSED) packet_disconnect("Received close confirmation for " "non-closed channel %d (type %d).", id, c->type); channel_free(c);}voidchannel_input_open_confirmation(int type, u_int32_t seq, void *ctxt){ int id, remote_id; Channel *c; id = packet_get_int(); c = channel_lookup(id); if (c==NULL || c->type != SSH_CHANNEL_OPENING) packet_disconnect("Received open confirmation for " "non-opening channel %d.", id); remote_id = packet_get_int(); /* Record the remote channel number and mark that the channel is now open. */ c->remote_id = remote_id; c->type = SSH_CHANNEL_OPEN; if (compat20) { c->remote_window = packet_get_int(); c->remote_maxpacket = packet_get_int(); if (c->confirm) { debug2("callback start"); c->confirm(c->self, NULL); debug2("callback done"); } debug("channel %d: open confirm rwindow %u rmax %u", c->self, c->remote_window, c->remote_maxpacket); } packet_check_eom();}static char *reason2txt(int reason){ switch (reason) { case SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED: return "administratively prohibited"; case SSH2_OPEN_CONNECT_FAILED: return "connect failed"; case SSH2_OPEN_UNKNOWN_CHANNEL_TYPE: return "unknown channel type"; case SSH2_OPEN_RESOURCE_SHORTAGE: return "resource shortage"; } return "unknown reason";}voidchannel_input_open_failure(int type, u_int32_t seq, void *ctxt){ int id, reason; char *msg = NULL, *lang = NULL; Channel *c; id = packet_get_int(); c = channel_lookup(id); if (c==NULL || c->type != SSH_CHANNEL_OPENING) packet_disconnect("Received open failure for " "non-opening channel %d.", id); if (compat20) { reason = packet_get_int(); if (!(datafellows & SSH_BUG_OPENFAILURE)) { msg = packet_get_string(NULL); lang = packet_get_string(NULL); } log("channel %d: open failed: %s%s%s", id, reason2txt(reason), msg ? ": ": "", msg ? msg : ""); if (msg != NULL) xfree(msg); if (lang != NULL) xfree(lang); } packet_check_eom(); /* Free the channel. This will also close the socket. */ channel_free(c);}voidchannel_input_window_adjust(int type, u_int32_t seq, void *ctxt){ Channel *c; int id; u_int adjust; if (!compat20) return; /* Get the channel number and verify it. */ id = packet_get_int(); c = channel_lookup(id); if (c == NULL || c->type != SSH_CHANNEL_OPEN) { log("Received window adjust for " "non-open channel %d.", id); return; } adjust = packet_get_int(); packet_check_eom(); debug2("channel %d: rcvd adjust %u", id, adjust); c->remote_window += adjust;}voidchannel_input_port_open(int type, u_int32_t seq, void *ctxt){ Channel *c = NULL; u_short host_port; char *host, *originator_string; int remote_id, sock = -1; remote_id = packet_get_int(); host = packet_get_string(NULL); host_port = packet_get_int(); if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -