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

📄 serverloop.c

📁 OpenSSL Source code for SFTP, SSH, and many others
💻 C
📖 第 1 页 / 共 3 页
字号:
		} else {			/* Buffer any received data. */			packet_process_incoming(buf, len);		}	}	if (compat20)		return;	/* Read and buffer any available stdout data from the program. */	if (!fdout_eof && FD_ISSET(fdout, readset)) {		len = read(fdout, buf, sizeof(buf));		if (len < 0 && (errno == EINTR || errno == EAGAIN)) {			/* do nothing */		} else if (len <= 0) {			fdout_eof = 1;		} else {			buffer_append(&stdout_buffer, buf, len);			fdout_bytes += len;		}	}	/* Read and buffer any available stderr data from the program. */	if (!fderr_eof && FD_ISSET(fderr, readset)) {		len = read(fderr, buf, sizeof(buf));		if (len < 0 && (errno == EINTR || errno == EAGAIN)) {			/* do nothing */		} else if (len <= 0) {			fderr_eof = 1;		} else {			buffer_append(&stderr_buffer, buf, len);		}	}}/* * Sends data from internal buffers to client program stdin. */static voidprocess_output(fd_set * writeset){	struct termios tio;	u_char *data;	u_int dlen;	int len;	/* Write buffered data to program stdin. */	if (!compat20 && fdin != -1 && FD_ISSET(fdin, writeset)) {		data = buffer_ptr(&stdin_buffer);		dlen = buffer_len(&stdin_buffer);		len = write(fdin, data, dlen);		if (len < 0 && (errno == EINTR || errno == EAGAIN)) {			/* do nothing */		} else if (len <= 0) {			if (fdin != fdout)				close(fdin);			else				shutdown(fdin, SHUT_WR); /* We will no longer send. */			fdin = -1;		} else {			/* Successful write. */			if (fdin_is_tty && dlen >= 1 && data[0] != '\r' &&			    tcgetattr(fdin, &tio) == 0 &&			    !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {				/*				 * Simulate echo to reduce the impact of				 * traffic analysis				 */				packet_send_ignore(len);				packet_send();			}			/* Consume the data from the buffer. */			buffer_consume(&stdin_buffer, len);			/* Update the count of bytes written to the program. */			stdin_bytes += len;		}	}	/* Send any buffered packet data to the client. */	if (FD_ISSET(connection_out, writeset))		packet_write_poll();}/* * Wait until all buffered output has been sent to the client. * This is used when the program terminates. */static voiddrain_output(void){	/* Send any buffered stdout data to the client. */	if (buffer_len(&stdout_buffer) > 0) {		packet_start(SSH_SMSG_STDOUT_DATA);		packet_put_string(buffer_ptr(&stdout_buffer),				  buffer_len(&stdout_buffer));		packet_send();		/* Update the count of sent bytes. */		stdout_bytes += buffer_len(&stdout_buffer);	}	/* Send any buffered stderr data to the client. */	if (buffer_len(&stderr_buffer) > 0) {		packet_start(SSH_SMSG_STDERR_DATA);		packet_put_string(buffer_ptr(&stderr_buffer),				  buffer_len(&stderr_buffer));		packet_send();		/* Update the count of sent bytes. */		stderr_bytes += buffer_len(&stderr_buffer);	}	/* Wait until all buffered data has been written to the client. */	packet_write_wait();}static voidprocess_buffered_input_packets(void){	dispatch_run(DISPATCH_NONBLOCK, NULL, compat20 ? xxx_kex : NULL);}/* * Performs the interactive session.  This handles data transmission between * the client and the program.  Note that the notion of stdin, stdout, and * stderr in this function is sort of reversed: this function writes to * stdin (of the child program), and reads from stdout and stderr (of the * child program). */voidserver_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg){	fd_set *readset = NULL, *writeset = NULL;	int max_fd = 0, nalloc = 0;	int wait_status;	/* Status returned by wait(). */	pid_t wait_pid;		/* pid returned by wait(). */	int waiting_termination = 0;	/* Have displayed waiting close message. */	u_int max_time_milliseconds;	u_int previous_stdout_buffer_bytes;	u_int stdout_buffer_bytes;	int type;	debug("Entering interactive session.");	/* Initialize the SIGCHLD kludge. */	child_terminated = 0;	mysignal(SIGCHLD, sigchld_handler);	/* Initialize our global variables. */	fdin = fdin_arg;	fdout = fdout_arg;	fderr = fderr_arg;	/* nonblocking IO */	set_nonblock(fdin);	set_nonblock(fdout);	/* we don't have stderr for interactive terminal sessions, see below */	if (fderr != -1)		set_nonblock(fderr);	if (!(datafellows & SSH_BUG_IGNOREMSG) && isatty(fdin))		fdin_is_tty = 1;	connection_in = packet_get_connection_in();	connection_out = packet_get_connection_out();	notify_setup();	previous_stdout_buffer_bytes = 0;	/* Set approximate I/O buffer size. */	if (packet_is_interactive())		buffer_high = 4096;	else		buffer_high = 64 * 1024;#if 0	/* Initialize max_fd to the maximum of the known file descriptors. */	max_fd = MAX(connection_in, connection_out);	max_fd = MAX(max_fd, fdin);	max_fd = MAX(max_fd, fdout);	if (fderr != -1)		max_fd = MAX(max_fd, fderr);#endif	/* Initialize Initialize buffers. */	buffer_init(&stdin_buffer);	buffer_init(&stdout_buffer);	buffer_init(&stderr_buffer);	/*	 * If we have no separate fderr (which is the case when we have a pty	 * - there we cannot make difference between data sent to stdout and	 * stderr), indicate that we have seen an EOF from stderr.  This way	 * we don\'t need to check the descriptor everywhere.	 */	if (fderr == -1)		fderr_eof = 1;	server_init_dispatch();	/* Main loop of the server for the interactive session mode. */	for (;;) {		/* Process buffered packets from the client. */		process_buffered_input_packets();		/*		 * If we have received eof, and there is no more pending		 * input data, cause a real eof by closing fdin.		 */		if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) {			if (fdin != fdout)				close(fdin);			else				shutdown(fdin, SHUT_WR); /* We will no longer send. */			fdin = -1;		}		/* Make packets from buffered stderr data to send to the client. */		make_packets_from_stderr_data();		/*		 * Make packets from buffered stdout data to send to the		 * client. If there is very little to send, this arranges to		 * not send them now, but to wait a short while to see if we		 * are getting more data. This is necessary, as some systems		 * wake up readers from a pty after each separate character.		 */		max_time_milliseconds = 0;		stdout_buffer_bytes = buffer_len(&stdout_buffer);		if (stdout_buffer_bytes != 0 && stdout_buffer_bytes < 256 &&		    stdout_buffer_bytes != previous_stdout_buffer_bytes) {			/* try again after a while */			max_time_milliseconds = 10;		} else {			/* Send it now. */			make_packets_from_stdout_data();		}		previous_stdout_buffer_bytes = buffer_len(&stdout_buffer);		/* Send channel data to the client. */		if (packet_not_very_much_data_to_write())			channel_output_poll();		/*		 * Bail out of the loop if the program has closed its output		 * descriptors, and we have no more data to send to the		 * client, and there is no pending buffered data.		 */		if (fdout_eof && fderr_eof && !packet_have_data_to_write() &&		    buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) {			if (!channel_still_open())				break;			if (!waiting_termination) {				const char *s = "Waiting for forwarded connections to terminate...\r\n";				char *cp;				waiting_termination = 1;				buffer_append(&stderr_buffer, s, strlen(s));				/* Display list of open channels. */				cp = channel_open_message();				buffer_append(&stderr_buffer, cp, strlen(cp));				xfree(cp);			}		}		max_fd = MAX(connection_in, connection_out);		max_fd = MAX(max_fd, fdin);		max_fd = MAX(max_fd, fdout);		max_fd = MAX(max_fd, fderr);		max_fd = MAX(max_fd, notify_pipe[0]);		/* Sleep in select() until we can do something. */		wait_until_can_do_something(&readset, &writeset, &max_fd,		    &nalloc, max_time_milliseconds);		/* Process any channel events. */		channel_after_select(readset, writeset);		/* Process input from the client and from program stdout/stderr. */		process_input(readset);		/* Process output to the client and to program stdin. */		process_output(writeset);	}	if (readset)		xfree(readset);	if (writeset)		xfree(writeset);	/* Cleanup and termination code. */	/* Wait until all output has been sent to the client. */	drain_output();	debug("End of interactive session; stdin %ld, stdout (read %ld, sent %ld), stderr %ld bytes.",	    stdin_bytes, fdout_bytes, stdout_bytes, stderr_bytes);	/* Free and clear the buffers. */	buffer_free(&stdin_buffer);	buffer_free(&stdout_buffer);	buffer_free(&stderr_buffer);	/* Close the file descriptors. */	if (fdout != -1)		close(fdout);	fdout = -1;	fdout_eof = 1;	if (fderr != -1)		close(fderr);	fderr = -1;	fderr_eof = 1;	if (fdin != -1)		close(fdin);	fdin = -1;	channel_free_all();	/* We no longer want our SIGCHLD handler to be called. */	mysignal(SIGCHLD, SIG_DFL);	while ((wait_pid = waitpid(-1, &wait_status, 0)) < 0)		if (errno != EINTR)			packet_disconnect("wait: %.100s", strerror(errno));	if (wait_pid != pid)		error("Strange, wait returned pid %ld, expected %ld",		    (long)wait_pid, (long)pid);	/* Check if it exited normally. */	if (WIFEXITED(wait_status)) {		/* Yes, normal exit.  Get exit status and send it to the client. */		debug("Command exited with status %d.", WEXITSTATUS(wait_status));		packet_start(SSH_SMSG_EXITSTATUS);		packet_put_int(WEXITSTATUS(wait_status));		packet_send();		packet_write_wait();		/*		 * Wait for exit confirmation.  Note that there might be		 * other packets coming before it; however, the program has		 * already died so we just ignore them.  The client is		 * supposed to respond with the confirmation when it receives		 * the exit status.		 */		do {			type = packet_read();		}		while (type != SSH_CMSG_EXIT_CONFIRMATION);		debug("Received exit confirmation.");		return;	}	/* Check if the program terminated due to a signal. */	if (WIFSIGNALED(wait_status))		packet_disconnect("Command terminated on signal %d.",				  WTERMSIG(wait_status));	/* Some weird exit cause.  Just exit. */	packet_disconnect("wait returned status %04x.", wait_status);	/* NOTREACHED */}static voidcollect_children(void){	pid_t pid;	sigset_t oset, nset;

⌨️ 快捷键说明

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