⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 channels.c

📁 OpenSSH 是 SSH (Secure SHell) 协议的免费开源实现。它用安全、加密的网络连接工具代替了 telnet、ftp、 rlogin、rsh 和 rcp 工具。OpenSSH 支持
💻 C
📖 第 1 页 / 共 5 页
字号:
			if (len <= 0) {				debug2("channel %d: closing write-efd %d",				    c->self, c->efd);				channel_close_fd(&c->efd);			} else {				buffer_consume(&c->extended, len);				c->local_consumed += len;			}		} else if (c->extended_usage == CHAN_EXTENDED_READ &&		    FD_ISSET(c->efd, readset)) {			len = read(c->efd, buf, sizeof(buf));			debug2("channel %d: read %d from efd %d",			    c->self, len, c->efd);			if (len < 0 && (errno == EINTR || errno == EAGAIN))				return 1;			if (len <= 0) {				debug2("channel %d: closing read-efd %d",				    c->self, c->efd);				channel_close_fd(&c->efd);			} else {				buffer_append(&c->extended, buf, len);			}		}	}	return 1;}static intchannel_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 intchannel_check_window(Channel *c){	if (c->type == SSH_CHANNEL_OPEN &&	    !(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) &&	    c->local_window < c->local_window_max/2 &&	    c->local_consumed > 0) {		packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);		packet_put_int(c->remote_id);		packet_put_int(c->local_consumed);		packet_send();		debug2("channel %d: window %d sent adjust %d",		    c->self, c->local_window,		    c->local_consumed);		c->local_window += c->local_consumed;		c->local_consumed = 0;	}	return 1;}static voidchannel_post_open(Channel *c, fd_set * readset, fd_set * writeset){	if (c->delayed)		return;	channel_handle_rfd(c, readset, writeset);	channel_handle_wfd(c, readset, writeset);	if (!compat20)		return;	channel_handle_efd(c, readset, writeset);	channel_handle_ctl(c, readset, writeset);	channel_check_window(c);}static voidchannel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset){	int len;	/* Send buffered output data to the socket. */	if (FD_ISSET(c->sock, writeset) && buffer_len(&c->output) > 0) {		len = write(c->sock, buffer_ptr(&c->output),			    buffer_len(&c->output));		if (len <= 0)			buffer_clear(&c->output);		else			buffer_consume(&c->output, len);	}}static voidchannel_handler_init_20(void){	channel_pre[SSH_CHANNEL_OPEN] =			&channel_pre_open;	channel_pre[SSH_CHANNEL_X11_OPEN] =		&channel_pre_x11_open;	channel_pre[SSH_CHANNEL_PORT_LISTENER] =	&channel_pre_listener;	channel_pre[SSH_CHANNEL_RPORT_LISTENER] =	&channel_pre_listener;	channel_pre[SSH_CHANNEL_X11_LISTENER] =		&channel_pre_listener;	channel_pre[SSH_CHANNEL_AUTH_SOCKET] =		&channel_pre_listener;	channel_pre[SSH_CHANNEL_CONNECTING] =		&channel_pre_connecting;	channel_pre[SSH_CHANNEL_DYNAMIC] =		&channel_pre_dynamic;	channel_post[SSH_CHANNEL_OPEN] =		&channel_post_open;	channel_post[SSH_CHANNEL_PORT_LISTENER] =	&channel_post_port_listener;	channel_post[SSH_CHANNEL_RPORT_LISTENER] =	&channel_post_port_listener;	channel_post[SSH_CHANNEL_X11_LISTENER] =	&channel_post_x11_listener;	channel_post[SSH_CHANNEL_AUTH_SOCKET] =		&channel_post_auth_listener;	channel_post[SSH_CHANNEL_CONNECTING] =		&channel_post_connecting;	channel_post[SSH_CHANNEL_DYNAMIC] =		&channel_post_open;}static voidchannel_handler_init_13(void){	channel_pre[SSH_CHANNEL_OPEN] =			&channel_pre_open_13;	channel_pre[SSH_CHANNEL_X11_OPEN] =		&channel_pre_x11_open_13;	channel_pre[SSH_CHANNEL_X11_LISTENER] =		&channel_pre_listener;	channel_pre[SSH_CHANNEL_PORT_LISTENER] =	&channel_pre_listener;	channel_pre[SSH_CHANNEL_AUTH_SOCKET] =		&channel_pre_listener;	channel_pre[SSH_CHANNEL_INPUT_DRAINING] =	&channel_pre_input_draining;	channel_pre[SSH_CHANNEL_OUTPUT_DRAINING] =	&channel_pre_output_draining;	channel_pre[SSH_CHANNEL_CONNECTING] =		&channel_pre_connecting;	channel_pre[SSH_CHANNEL_DYNAMIC] =		&channel_pre_dynamic;	channel_post[SSH_CHANNEL_OPEN] =		&channel_post_open;	channel_post[SSH_CHANNEL_X11_LISTENER] =	&channel_post_x11_listener;	channel_post[SSH_CHANNEL_PORT_LISTENER] =	&channel_post_port_listener;	channel_post[SSH_CHANNEL_AUTH_SOCKET] =		&channel_post_auth_listener;	channel_post[SSH_CHANNEL_OUTPUT_DRAINING] =	&channel_post_output_drain_13;	channel_post[SSH_CHANNEL_CONNECTING] =		&channel_post_connecting;	channel_post[SSH_CHANNEL_DYNAMIC] =		&channel_post_open;}static voidchannel_handler_init_15(void){	channel_pre[SSH_CHANNEL_OPEN] =			&channel_pre_open;	channel_pre[SSH_CHANNEL_X11_OPEN] =		&channel_pre_x11_open;	channel_pre[SSH_CHANNEL_X11_LISTENER] =		&channel_pre_listener;	channel_pre[SSH_CHANNEL_PORT_LISTENER] =	&channel_pre_listener;	channel_pre[SSH_CHANNEL_AUTH_SOCKET] =		&channel_pre_listener;	channel_pre[SSH_CHANNEL_CONNECTING] =		&channel_pre_connecting;	channel_pre[SSH_CHANNEL_DYNAMIC] =		&channel_pre_dynamic;	channel_post[SSH_CHANNEL_X11_LISTENER] =	&channel_post_x11_listener;	channel_post[SSH_CHANNEL_PORT_LISTENER] =	&channel_post_port_listener;	channel_post[SSH_CHANNEL_AUTH_SOCKET] =		&channel_post_auth_listener;	channel_post[SSH_CHANNEL_OPEN] =		&channel_post_open;	channel_post[SSH_CHANNEL_CONNECTING] =		&channel_post_connecting;	channel_post[SSH_CHANNEL_DYNAMIC] =		&channel_post_open;}static voidchannel_handler_init(void){	int i;	for (i = 0; i < SSH_CHANNEL_MAX_TYPE; i++) {		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;		debug2("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;		debug2("channel %d: gc: user detached", c->self);	}	if (!chan_is_dead(c, 1))		return;	debug2("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;	u_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,    u_int *nallocp, int rekeying){	u_int n, 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;	u_int i, 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;	/* Get the data. */	data = packet_get_string(&data_len);	/*	 * Ignore data for protocol > 1.3 if output end is no longer open.	 * For protocol 2 the sending side is reducing its window as it sends	 * data, so we must 'fake' consumption of the data in order to ensure	 * that window updates are sent back.  Otherwise the connection might	 * deadlock.	 */	if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN) {		if (compat20) {			c->local_window -= data_len;			c->local_consumed += data_len;		}		xfree(data);		return;	}	if (compat20) {		if (data_len > c->local_maxpacket) {			logit("channel %d: rcvd big packet %d, maxpack %d",			    c->self, data_len, c->local_maxpacket);		}		if (data_len > c->local_window) {			logit("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) {		logit("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) {		logit("channel %d: bad ext data", c->self);		return;	}	data = packet_get_string(&data_len);	packet_check_eom();	if (data_len > c->local_window) {		logit("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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -