+ fd_set *readset = NULL, *writeset = NULL;
+ int max_fd = 0;
+ u_int 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);
+
+ if (!use_privsep) {
+ signal(SIGTERM, sigterm_handler);
+ signal(SIGINT, sigterm_handler);
+ signal(SIGQUIT, sigterm_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);
+
+ if (received_sigterm) {
+ logit("Exiting on signal %d", received_sigterm);
+ /* Clean up sessions, utmp, etc. */
+ cleanup_exit(255);
+ }
+
+ /* 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);