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

📄 clientloop.c

📁 OpenSSH 是 SSH (Secure SHell) 协议的免费开源实现。它用安全、加密的网络连接工具代替了 telnet、ftp、 rlogin、rsh 和 rcp 工具。OpenSSH 支持
💻 C
📖 第 1 页 / 共 4 页
字号:
				if (pid < 0) {					error("fork: %.100s", strerror(errno));					continue;				}				if (pid != 0) {	/* This is the parent. */					/* The parent just exits. */					exit(0);				}				/* The child continues serving connections. */				if (compat20) {					buffer_append(bin, "\004", 1);					/* fake EOF on stdin */					return -1;				} else if (!stdin_eof) {					/*					 * Sending SSH_CMSG_EOF alone does not always appear					 * to be enough.  So we try to send an EOF character					 * first.					 */					packet_start(SSH_CMSG_STDIN_DATA);					packet_put_string("\004", 1);					packet_send();					/* Close stdin. */					stdin_eof = 1;					if (buffer_len(bin) == 0) {						packet_start(SSH_CMSG_EOF);						packet_send();					}				}				continue;			case '?':				snprintf(string, sizeof string,"%c?\r\n\Supported escape sequences:\r\n\%c.  - terminate connection\r\n\%cB  - send a BREAK to the remote system\r\n\%cC  - open a command line\r\n\%cR  - Request rekey (SSH protocol 2 only)\r\n\%c^Z - suspend ssh\r\n\%c#  - list forwarded connections\r\n\%c&  - background ssh (when waiting for connections to terminate)\r\n\%c?  - this message\r\n\%c%c  - send the escape character by typing it twice\r\n\(Note that escapes are only recognized immediately after newline.)\r\n",				    escape_char, escape_char, escape_char, escape_char,				    escape_char, escape_char, escape_char, escape_char,				    escape_char, escape_char, escape_char);				buffer_append(berr, string, strlen(string));				continue;			case '#':				snprintf(string, sizeof string, "%c#\r\n", escape_char);				buffer_append(berr, string, strlen(string));				s = channel_open_message();				buffer_append(berr, s, strlen(s));				xfree(s);				continue;			case 'C':				process_cmdline();				continue;			default:				if (ch != escape_char) {					buffer_put_char(bin, escape_char);					bytes++;				}				/* Escaped characters fall through here */				break;			}		} else {			/*			 * The previous character was not an escape char. Check if this			 * is an escape.			 */			if (last_was_cr && ch == escape_char) {				/* It is. Set the flag and continue to next character. */				escape_pending = 1;				continue;			}		}		/*		 * Normal character.  Record whether it was a newline,		 * and append it to the buffer.		 */		last_was_cr = (ch == '\r' || ch == '\n');		buffer_put_char(bin, ch);		bytes++;	}	return bytes;}static voidclient_process_input(fd_set * readset){	int len;	char buf[8192];	/* Read input from stdin. */	if (FD_ISSET(fileno(stdin), readset)) {		/* Read as much as possible. */		len = read(fileno(stdin), buf, sizeof(buf));		if (len < 0 && (errno == EAGAIN || errno == EINTR))			return;		/* we'll try again later */		if (len <= 0) {			/*			 * Received EOF or error.  They are treated			 * similarly, except that an error message is printed			 * if it was an error condition.			 */			if (len < 0) {				snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno));				buffer_append(&stderr_buffer, buf, strlen(buf));			}			/* Mark that we have seen EOF. */			stdin_eof = 1;			/*			 * Send an EOF message to the server unless there is			 * data in the buffer.  If there is data in the			 * buffer, no message will be sent now.  Code			 * elsewhere will send the EOF when the buffer			 * becomes empty if stdin_eof is set.			 */			if (buffer_len(&stdin_buffer) == 0) {				packet_start(SSH_CMSG_EOF);				packet_send();			}		} else if (escape_char == SSH_ESCAPECHAR_NONE) {			/*			 * Normal successful read, and no escape character.			 * Just append the data to buffer.			 */			buffer_append(&stdin_buffer, buf, len);		} else {			/*			 * Normal, successful read.  But we have an escape character			 * and have to process the characters one by one.			 */			if (process_escapes(&stdin_buffer, &stdout_buffer,			    &stderr_buffer, buf, len) == -1)				return;		}	}}static voidclient_process_output(fd_set * writeset){	int len;	char buf[100];	/* Write buffered output to stdout. */	if (FD_ISSET(fileno(stdout), writeset)) {		/* Write as much data as possible. */		len = write(fileno(stdout), buffer_ptr(&stdout_buffer),		    buffer_len(&stdout_buffer));		if (len <= 0) {			if (errno == EINTR || errno == EAGAIN)				len = 0;			else {				/*				 * An error or EOF was encountered.  Put an				 * error message to stderr buffer.				 */				snprintf(buf, sizeof buf, "write stdout: %.50s\r\n", strerror(errno));				buffer_append(&stderr_buffer, buf, strlen(buf));				quit_pending = 1;				return;			}		}		/* Consume printed data from the buffer. */		buffer_consume(&stdout_buffer, len);		stdout_bytes += len;	}	/* Write buffered output to stderr. */	if (FD_ISSET(fileno(stderr), writeset)) {		/* Write as much data as possible. */		len = write(fileno(stderr), buffer_ptr(&stderr_buffer),		    buffer_len(&stderr_buffer));		if (len <= 0) {			if (errno == EINTR || errno == EAGAIN)				len = 0;			else {				/* EOF or error, but can't even print error message. */				quit_pending = 1;				return;			}		}		/* Consume printed characters from the buffer. */		buffer_consume(&stderr_buffer, len);		stderr_bytes += len;	}}/* * Get packets from the connection input buffer, and process them as long as * there are packets available. * * Any unknown packets received during the actual * session cause the session to terminate.  This is * intended to make debugging easier since no * confirmations are sent.  Any compatible protocol * extensions must be negotiated during the * preparatory phase. */static voidclient_process_buffered_input_packets(void){	dispatch_run(DISPATCH_NONBLOCK, &quit_pending, compat20 ? xxx_kex : NULL);}/* scan buf[] for '~' before sending data to the peer */static intsimple_escape_filter(Channel *c, char *buf, int len){	/* XXX we assume c->extended is writeable */	return process_escapes(&c->input, &c->output, &c->extended, buf, len);}static voidclient_channel_closed(int id, void *arg){	channel_cancel_cleanup(id);	session_closed = 1;	leave_raw_mode();}/* * Implements the interactive session with the server.  This is called after * the user has been authenticated, and a command has been started on the * remote host.  If escape_char != SSH_ESCAPECHAR_NONE, it is the character * used as an escape character for terminating or suspending the session. */intclient_loop(int have_pty, int escape_char_arg, int ssh2_chan_id){	fd_set *readset = NULL, *writeset = NULL;	double start_time, total_time;	int max_fd = 0, max_fd2 = 0, len, rekeying = 0;	u_int nalloc = 0;	char buf[100];	debug("Entering interactive session.");	start_time = get_current_time();	/* Initialize variables. */	escape_pending = 0;	last_was_cr = 1;	exit_status = -1;	stdin_eof = 0;	buffer_high = 64 * 1024;	connection_in = packet_get_connection_in();	connection_out = packet_get_connection_out();	max_fd = MAX(connection_in, connection_out);	if (control_fd != -1)		max_fd = MAX(max_fd, control_fd);	if (!compat20) {		/* enable nonblocking unless tty */		if (!isatty(fileno(stdin)))			set_nonblock(fileno(stdin));		if (!isatty(fileno(stdout)))			set_nonblock(fileno(stdout));		if (!isatty(fileno(stderr)))			set_nonblock(fileno(stderr));		max_fd = MAX(max_fd, fileno(stdin));		max_fd = MAX(max_fd, fileno(stdout));		max_fd = MAX(max_fd, fileno(stderr));	}	stdin_bytes = 0;	stdout_bytes = 0;	stderr_bytes = 0;	quit_pending = 0;	escape_char = escape_char_arg;	/* Initialize buffers. */	buffer_init(&stdin_buffer);	buffer_init(&stdout_buffer);	buffer_init(&stderr_buffer);	client_init_dispatch();	/*	 * Set signal handlers, (e.g. to restore non-blocking mode)	 * but don't overwrite SIG_IGN, matches behaviour from rsh(1)	 */	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)		signal(SIGHUP, signal_handler);	if (signal(SIGINT, SIG_IGN) != SIG_IGN)		signal(SIGINT, signal_handler);	if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)		signal(SIGQUIT, signal_handler);	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)		signal(SIGTERM, signal_handler);	signal(SIGWINCH, window_change_handler);	if (have_pty)		enter_raw_mode();	if (compat20) {		session_ident = ssh2_chan_id;		if (escape_char != SSH_ESCAPECHAR_NONE)			channel_register_filter(session_ident,			    simple_escape_filter);		if (session_ident != -1)			channel_register_cleanup(session_ident,			    client_channel_closed);	} else {		/* Check if we should immediately send eof on stdin. */		client_check_initial_eof_on_stdin();	}	/* Main loop of the client for the interactive session mode. */	while (!quit_pending) {		/* Process buffered packets sent by the server. */		client_process_buffered_input_packets();		if (compat20 && session_closed && !channel_still_open())			break;		rekeying = (xxx_kex != NULL && !xxx_kex->done);		if (rekeying) {			debug("rekeying in progress");		} else {			/*			 * Make packets of buffered stdin data, and buffer			 * them for sending to the server.			 */			if (!compat20)				client_make_packets_from_stdin_data();			/*			 * Make packets from buffered channel data, and			 * enqueue them for sending to the server.			 */			if (packet_not_very_much_data_to_write())				channel_output_poll();			/*			 * Check if the window size has changed, and buffer a			 * message about it to the server if so.			 */			client_check_window_change();			if (quit_pending)				break;		}		/*		 * Wait until we have something to do (something becomes		 * available on one of the descriptors).		 */		max_fd2 = max_fd;		client_wait_until_can_do_something(&readset, &writeset,		    &max_fd2, &nalloc, rekeying);		if (quit_pending)			break;		/* Do channel operations unless rekeying in progress. */		if (!rekeying) {			channel_after_select(readset, writeset);			if (need_rekeying || packet_need_rekeying()) {				debug("need rekeying");				xxx_kex->done = 0;				kex_send_kexinit(xxx_kex);				need_rekeying = 0;			}		}		/* Buffer input from the connection.  */		client_process_net_input(readset);		/* Accept control connections.  */		client_process_control(readset);		if (quit_pending)			break;		if (!compat20) {			/* Buffer data from stdin */			client_process_input(readset);			/*			 * Process output to stdout and stderr.  Output to			 * the connection is processed elsewhere (above).			 */			client_process_output(writeset);		}		/* Send as much buffered packet data as possible to the sender. */		if (FD_ISSET(connection_out, writeset))			packet_write_poll();	}	if (readset)		xfree(readset);	if (writeset)		xfree(writeset);	/* Terminate the session. */	/* Stop watching for window change. */	signal(SIGWINCH, SIG_DFL);	channel_free_all();	if (have_pty)		leave_raw_mode();	/* restore blocking io */	if (!isatty(fileno(stdin)))		unset_nonblock(fileno(stdin));	if (!isatty(fileno(stdout)))		unset_nonblock(fileno(stdout));	if (!isatty(fileno(stderr)))		unset_nonblock(fileno(stderr));	/*	 * If there was no shell or command requested, there will be no remote	 * exit status to be returned.  In that case, clear error code if the	 * connection was deliberately terminated at this end.	 */	if (no_shell_flag && received_signal == SIGTERM) {		received_signal = 0;		exit_status = 0;	}	if (received_signal)		fatal("Killed by signal %d.", (int) received_signal);	/*	 * In interactive mode (with pseudo tty) display a message indicating	 * that the connection has been closed.	 */	if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) {		snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host);		buffer_append(&stderr_buffer, buf, strlen(buf));	}	/* Output any buffered data for stdout. */	while (buffer_len(&stdout_buffer) > 0) {		len = write(fileno(stdout), buffer_ptr(&stdout_buffer),		    buffer_len(&stdout_buffer));		if (len <= 0) {			error("Write failed flushing stdout buffer.");			break;		}		buffer_consume(&stdout_buffer, len);		stdout_bytes += len;	}	/* Output any buffered data for stderr. */	while (buffer_len(&stderr_buffer) > 0) {		len = write(fileno(stderr), buffer_ptr(&stderr_buffer),		    buffer_len(&stderr_buffer));		if (len <= 0) {			error("Write failed flushing stderr buffer.");			break;		}		buffer_consume(&stderr_buffer, len);		stderr_bytes += len;	}

⌨️ 快捷键说明

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