blob: 410dc54de20c55a24024bf254cca2dc0f5ef3a1c [file] [log] [blame]
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001/*
2
3clientloop.c
4
5Author: Tatu Ylonen <ylo@cs.hut.fi>
6
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved
9
10
11Created: Sat Sep 23 12:23:57 1995 ylo
12
13The main loop for the interactive session (client side).
14
15*/
16
17#include "includes.h"
Damien Miller6d7b2cd1999-11-12 15:19:27 +110018RCSID("$Id: clientloop.c,v 1.3 1999/11/12 04:19:27 damien Exp $");
Damien Millerd4a8b7e1999-10-27 13:42:43 +100019
20#include "xmalloc.h"
21#include "ssh.h"
22#include "packet.h"
23#include "buffer.h"
24#include "authfd.h"
Damien Miller5ce662a1999-11-11 17:57:39 +110025#include "readconf.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100026
Damien Millerd4a8b7e1999-10-27 13:42:43 +100027/* Flag indicating that stdin should be redirected from /dev/null. */
28extern int stdin_null_flag;
29
30/* Name of the host we are connecting to. This is the name given on the
31 command line, or the HostName specified for the user-supplied name
32 in a configuration file. */
33extern char *host;
34
35/* Flag to indicate that we have received a window change signal which has
36 not yet been processed. This will cause a message indicating the new
37 window size to be sent to the server a little later. This is volatile
38 because this is updated in a signal handler. */
39static volatile int received_window_change_signal = 0;
40
41/* Terminal modes, as saved by enter_raw_mode. */
42static struct termios saved_tio;
43
44/* Flag indicating whether we are in raw mode. This is used by enter_raw_mode
45 and leave_raw_mode. */
46static int in_raw_mode = 0;
47
48/* Flag indicating whether the user\'s terminal is in non-blocking mode. */
49static int in_non_blocking_mode = 0;
50
51/* Common data for the client loop code. */
52static int escape_pending; /* Last character was the escape character */
53static int last_was_cr; /* Last character was a newline. */
54static int exit_status; /* Used to store the exit status of the command. */
55static int stdin_eof; /* EOF has been encountered on standard error. */
56static Buffer stdin_buffer; /* Buffer for stdin data. */
57static Buffer stdout_buffer; /* Buffer for stdout data. */
58static Buffer stderr_buffer; /* Buffer for stderr data. */
59static unsigned int buffer_high; /* Soft max buffer size. */
60static int max_fd; /* Maximum file descriptor number in select(). */
61static int connection_in; /* Connection to server (input). */
62static int connection_out; /* Connection to server (output). */
63static unsigned long stdin_bytes, stdout_bytes, stderr_bytes;
64static int quit_pending; /* Set to non-zero to quit the client loop. */
65static int escape_char; /* Escape character. */
66
67/* Returns the user\'s terminal to normal mode if it had been put in raw
68 mode. */
69
70void leave_raw_mode()
71{
72 if (!in_raw_mode)
73 return;
74 in_raw_mode = 0;
75 if (tcsetattr(fileno(stdin), TCSADRAIN, &saved_tio) < 0)
76 perror("tcsetattr");
77
78 fatal_remove_cleanup((void (*)(void *))leave_raw_mode, NULL);
79}
80
81/* Puts the user\'s terminal in raw mode. */
82
83void enter_raw_mode()
84{
85 struct termios tio;
86
87 if (tcgetattr(fileno(stdin), &tio) < 0)
88 perror("tcgetattr");
89 saved_tio = tio;
90 tio.c_iflag |= IGNPAR;
91 tio.c_iflag &= ~(ISTRIP|INLCR|IGNCR|ICRNL|IXON|IXANY|IXOFF);
92 tio.c_lflag &= ~(ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHONL);
93#ifdef IEXTEN
94 tio.c_lflag &= ~IEXTEN;
95#endif /* IEXTEN */
96 tio.c_oflag &= ~OPOST;
97 tio.c_cc[VMIN] = 1;
98 tio.c_cc[VTIME] = 0;
99 if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) < 0)
100 perror("tcsetattr");
101 in_raw_mode = 1;
102
103 fatal_add_cleanup((void (*)(void *))leave_raw_mode, NULL);
104}
105
106/* Puts stdin terminal in non-blocking mode. */
107
108/* Restores stdin to blocking mode. */
109
110void leave_non_blocking()
111{
112 if (in_non_blocking_mode)
113 {
114 (void)fcntl(fileno(stdin), F_SETFL, 0);
115 in_non_blocking_mode = 0;
116 fatal_remove_cleanup((void (*)(void *))leave_non_blocking, NULL);
117 }
118}
119
120void enter_non_blocking()
121{
122 in_non_blocking_mode = 1;
123 (void)fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);
124 fatal_add_cleanup((void (*)(void *))leave_non_blocking, NULL);
125}
126
127/* Signal handler for the window change signal (SIGWINCH). This just
128 sets a flag indicating that the window has changed. */
129
130void window_change_handler(int sig)
131{
132 received_window_change_signal = 1;
133 signal(SIGWINCH, window_change_handler);
134}
135
136/* Signal handler for signals that cause the program to terminate. These
137 signals must be trapped to restore terminal modes. */
138
139void signal_handler(int sig)
140{
141 if (in_raw_mode)
142 leave_raw_mode();
143 if (in_non_blocking_mode)
144 leave_non_blocking();
145 channel_stop_listening();
146 packet_close();
147 fatal("Killed by signal %d.", sig);
148}
149
150/* Returns current time in seconds from Jan 1, 1970 with the maximum available
151 resolution. */
152
153double get_current_time()
154{
155 struct timeval tv;
156 gettimeofday(&tv, NULL);
157 return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
158}
159
160/* This is called when the interactive is entered. This checks if there
161 is an EOF coming on stdin. We must check this explicitly, as select()
162 does not appear to wake up when redirecting from /dev/null. */
163
164void client_check_initial_eof_on_stdin()
165{
166 int len;
167 char buf[1];
168
169 /* If standard input is to be "redirected from /dev/null", we simply
170 mark that we have seen an EOF and send an EOF message to the server.
171 Otherwise, we try to read a single character; it appears that for some
172 files, such /dev/null, select() never wakes up for read for this
173 descriptor, which means that we never get EOF. This way we will get
174 the EOF if stdin comes from /dev/null or similar. */
175 if (stdin_null_flag)
176 {
177 /* Fake EOF on stdin. */
178 debug("Sending eof.");
179 stdin_eof = 1;
180 packet_start(SSH_CMSG_EOF);
181 packet_send();
182 }
183 else
184 {
185 /* Enter non-blocking mode for stdin. */
186 enter_non_blocking();
187
188 /* Check for immediate EOF on stdin. */
189 len = read(fileno(stdin), buf, 1);
190 if (len == 0)
191 {
192 /* EOF. Record that we have seen it and send EOF to server. */
193 debug("Sending eof.");
194 stdin_eof = 1;
195 packet_start(SSH_CMSG_EOF);
196 packet_send();
197 }
198 else
199 if (len > 0)
200 {
201 /* Got data. We must store the data in the buffer, and also
202 process it as an escape character if appropriate. */
203 if ((unsigned char)buf[0] == escape_char)
204 escape_pending = 1;
205 else
206 {
207 buffer_append(&stdin_buffer, buf, 1);
208 stdin_bytes += 1;
209 }
210 }
211
212 /* Leave non-blocking mode. */
213 leave_non_blocking();
214 }
215}
216
217/* Get packets from the connection input buffer, and process them as long
218 as there are packets available. */
219
220void client_process_buffered_input_packets()
221{
222 int type;
223 char *data;
224 unsigned int data_len;
225 int payload_len;
226
227 /* Process any buffered packets from the server. */
228 while (!quit_pending && (type = packet_read_poll(&payload_len)) != SSH_MSG_NONE)
229 {
230 switch (type)
231 {
232
233 case SSH_SMSG_STDOUT_DATA:
234 data = packet_get_string(&data_len);
235 packet_integrity_check(payload_len, 4 + data_len, type);
236 buffer_append(&stdout_buffer, data, data_len);
237 stdout_bytes += data_len;
238 memset(data, 0, data_len);
239 xfree(data);
240 break;
241
242 case SSH_SMSG_STDERR_DATA:
243 data = packet_get_string(&data_len);
244 packet_integrity_check(payload_len, 4 + data_len, type);
245 buffer_append(&stderr_buffer, data, data_len);
246 stdout_bytes += data_len;
247 memset(data, 0, data_len);
248 xfree(data);
249 break;
250
251 case SSH_SMSG_EXITSTATUS:
252 packet_integrity_check(payload_len, 4, type);
253 exit_status = packet_get_int();
254 /* Acknowledge the exit. */
255 packet_start(SSH_CMSG_EXIT_CONFIRMATION);
256 packet_send();
257 /* Must wait for packet to be sent since we are exiting the
258 loop. */
259 packet_write_wait();
260 /* Flag that we want to exit. */
261 quit_pending = 1;
262 break;
263
264 case SSH_SMSG_X11_OPEN:
265 x11_input_open(payload_len);
266 break;
267
268 case SSH_MSG_PORT_OPEN:
269 channel_input_port_open(payload_len);
270 break;
271
272 case SSH_SMSG_AGENT_OPEN:
273 packet_integrity_check(payload_len, 4, type);
274 auth_input_open_request();
275 break;
276
277 case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
278 packet_integrity_check(payload_len, 4 + 4, type);
279 channel_input_open_confirmation();
280 break;
281
282 case SSH_MSG_CHANNEL_OPEN_FAILURE:
283 packet_integrity_check(payload_len, 4, type);
284 channel_input_open_failure();
285 break;
286
287 case SSH_MSG_CHANNEL_DATA:
288 channel_input_data(payload_len);
289 break;
290
291 case SSH_MSG_CHANNEL_CLOSE:
292 packet_integrity_check(payload_len, 4, type);
293 channel_input_close();
294 break;
295
296 case SSH_MSG_CHANNEL_CLOSE_CONFIRMATION:
297 packet_integrity_check(payload_len, 4, type);
298 channel_input_close_confirmation();
299 break;
300
301 default:
302 /* Any unknown packets received during the actual session
303 cause the session to terminate. This is intended to make
304 debugging easier since no confirmations are sent. Any
305 compatible protocol extensions must be negotiated during
306 the preparatory phase. */
307 packet_disconnect("Protocol error during session: type %d",
308 type);
309 }
310 }
311}
312
313/* Make packets from buffered stdin data, and buffer them for sending to
314 the connection. */
315
316void client_make_packets_from_stdin_data()
317{
318 unsigned int len;
319
320 /* Send buffered stdin data to the server. */
321 while (buffer_len(&stdin_buffer) > 0 &&
322 packet_not_very_much_data_to_write())
323 {
324 len = buffer_len(&stdin_buffer);
325 if (len > 32768)
326 len = 32768; /* Keep the packets at reasonable size. */
327 packet_start(SSH_CMSG_STDIN_DATA);
328 packet_put_string(buffer_ptr(&stdin_buffer), len);
329 packet_send();
330 buffer_consume(&stdin_buffer, len);
331 /* If we have a pending EOF, send it now. */
332 if (stdin_eof && buffer_len(&stdin_buffer) == 0)
333 {
334 packet_start(SSH_CMSG_EOF);
335 packet_send();
336 }
337 }
338}
339
340/* Checks if the client window has changed, and sends a packet about it to
341 the server if so. The actual change is detected elsewhere (by a software
342 interrupt on Unix); this just checks the flag and sends a message if
343 appropriate. */
344
345void client_check_window_change()
346{
347 /* Send possible window change message to the server. */
348 if (received_window_change_signal)
349 {
350 struct winsize ws;
351
352 /* Clear the window change indicator. */
353 received_window_change_signal = 0;
354
355 /* Read new window size. */
356 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) >= 0)
357 {
358 /* Successful, send the packet now. */
359 packet_start(SSH_CMSG_WINDOW_SIZE);
360 packet_put_int(ws.ws_row);
361 packet_put_int(ws.ws_col);
362 packet_put_int(ws.ws_xpixel);
363 packet_put_int(ws.ws_ypixel);
364 packet_send();
365 }
366 }
367}
368
369/* Waits until the client can do something (some data becomes available on
370 one of the file descriptors). */
371
372void client_wait_until_can_do_something(fd_set *readset, fd_set *writeset)
373{
374 /* Initialize select masks. */
375 FD_ZERO(readset);
376
377 /* Read from the connection, unless our buffers are full. */
378 if (buffer_len(&stdout_buffer) < buffer_high &&
379 buffer_len(&stderr_buffer) < buffer_high &&
380 channel_not_very_much_buffered_data())
381 FD_SET(connection_in, readset);
382
383 /* Read from stdin, unless we have seen EOF or have very much buffered
384 data to send to the server. */
385 if (!stdin_eof && packet_not_very_much_data_to_write())
386 FD_SET(fileno(stdin), readset);
387
388 FD_ZERO(writeset);
389
390 /* Add any selections by the channel mechanism. */
391 channel_prepare_select(readset, writeset);
392
393 /* Select server connection if have data to write to the server. */
394 if (packet_have_data_to_write())
395 FD_SET(connection_out, writeset);
396
397 /* Select stdout if have data in buffer. */
398 if (buffer_len(&stdout_buffer) > 0)
399 FD_SET(fileno(stdout), writeset);
400
401 /* Select stderr if have data in buffer. */
402 if (buffer_len(&stderr_buffer) > 0)
403 FD_SET(fileno(stderr), writeset);
404
405 /* Update maximum file descriptor number, if appropriate. */
406 if (channel_max_fd() > max_fd)
407 max_fd = channel_max_fd();
408
409 /* Wait for something to happen. This will suspend the process until
410 some selected descriptor can be read, written, or has some other
411 event pending. Note: if you want to implement SSH_MSG_IGNORE
412 messages to fool traffic analysis, this might be the place to do
413 it: just have a random timeout for the select, and send a random
414 SSH_MSG_IGNORE packet when the timeout expires. */
415 if (select(max_fd + 1, readset, writeset, NULL, NULL) < 0)
416 {
417 char buf[100];
418 /* Some systems fail to clear these automatically. */
419 FD_ZERO(readset);
420 FD_ZERO(writeset);
421 if (errno == EINTR)
422 return;
423 /* Note: we might still have data in the buffers. */
424 snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno));
425 buffer_append(&stderr_buffer, buf, strlen(buf));
426 stderr_bytes += strlen(buf);
427 quit_pending = 1;
428 }
429}
430
431void client_suspend_self()
432{
433 struct winsize oldws, newws;
434
435 /* Flush stdout and stderr buffers. */
436 if (buffer_len(&stdout_buffer) > 0)
437 write(fileno(stdout),
438 buffer_ptr(&stdout_buffer),
439 buffer_len(&stdout_buffer));
440 if (buffer_len(&stderr_buffer) > 0)
441 write(fileno(stderr),
442 buffer_ptr(&stderr_buffer),
443 buffer_len(&stderr_buffer));
444
445 /* Leave raw mode. */
446 leave_raw_mode();
447
448 /* Free (and clear) the buffer to reduce the
449 amount of data that gets written to swap. */
450 buffer_free(&stdin_buffer);
451 buffer_free(&stdout_buffer);
452 buffer_free(&stderr_buffer);
453
454 /* Save old window size. */
455 ioctl(fileno(stdin), TIOCGWINSZ, &oldws);
456
457 /* Send the suspend signal to the program
458 itself. */
459 kill(getpid(), SIGTSTP);
460
461 /* Check if the window size has changed. */
462 if (ioctl(fileno(stdin), TIOCGWINSZ, &newws) >= 0 &&
463 (oldws.ws_row != newws.ws_row || oldws.ws_col != newws.ws_col ||
464 oldws.ws_xpixel != newws.ws_xpixel ||
465 oldws.ws_ypixel != newws.ws_ypixel))
466 received_window_change_signal = 1;
467
468 /* OK, we have been continued by the user.
469 Reinitialize buffers. */
470 buffer_init(&stdin_buffer);
471 buffer_init(&stdout_buffer);
472 buffer_init(&stderr_buffer);
473
474 /* Re-enter raw mode. */
475 enter_raw_mode();
476}
477
478void client_process_input(fd_set *readset)
479{
480 int len, pid;
481 char buf[8192], *s;
482
483 /* Read input from the server, and add any such data to the buffer of the
484 packet subsystem. */
485 if (FD_ISSET(connection_in, readset))
486 {
487 /* Read as much as possible. */
488 len = read(connection_in, buf, sizeof(buf));
489 if (len == 0)
490 {
491 /* Received EOF. The remote host has closed the connection. */
492 snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n",
493 host);
494 buffer_append(&stderr_buffer, buf, strlen(buf));
495 stderr_bytes += strlen(buf);
496 quit_pending = 1;
497 return;
498 }
499
500 /* There is a kernel bug on Solaris that causes select to sometimes
501 wake up even though there is no data available. */
502 if (len < 0 && errno == EAGAIN)
503 len = 0;
504
505 if (len < 0)
506 {
507 /* An error has encountered. Perhaps there is a network
508 problem. */
509 snprintf(buf, sizeof buf, "Read from remote host %.300s: %.100s\r\n",
510 host, strerror(errno));
511 buffer_append(&stderr_buffer, buf, strlen(buf));
512 stderr_bytes += strlen(buf);
513 quit_pending = 1;
514 return;
515 }
516 packet_process_incoming(buf, len);
517 }
518
519 /* Read input from stdin. */
520 if (FD_ISSET(fileno(stdin), readset))
521 {
522 /* Read as much as possible. */
523 len = read(fileno(stdin), buf, sizeof(buf));
524 if (len <= 0)
525 {
526 /* Received EOF or error. They are treated similarly,
527 except that an error message is printed if it was
528 an error condition. */
529 if (len < 0)
530 {
531 snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno));
532 buffer_append(&stderr_buffer, buf, strlen(buf));
533 stderr_bytes += strlen(buf);
534 }
535 /* Mark that we have seen EOF. */
536 stdin_eof = 1;
537 /* Send an EOF message to the server unless there is data
538 in the buffer. If there is data in the buffer, no message
539 will be sent now. Code elsewhere will send the EOF
540 when the buffer becomes empty if stdin_eof is set. */
541 if (buffer_len(&stdin_buffer) == 0)
542 {
543 packet_start(SSH_CMSG_EOF);
544 packet_send();
545 }
546 }
547 else
548 if (escape_char == -1)
549 {
550 /* Normal successful read, and no escape character. Just
551 append the data to buffer. */
552 buffer_append(&stdin_buffer, buf, len);
553 stdin_bytes += len;
554 }
555 else
556 {
557 /* Normal, successful read. But we have an escape character
558 and have to process the characters one by one. */
559 unsigned int i;
560 for (i = 0; i < len; i++)
561 {
562 unsigned char ch;
563 /* Get one character at a time. */
564 ch = buf[i];
565
566 /* Check if we have a pending escape character. */
567 if (escape_pending)
568 {
569 /* We have previously seen an escape character. */
570 /* Clear the flag now. */
571 escape_pending = 0;
572 /* Process the escaped character. */
573 switch (ch)
574 {
575 case '.':
576 /* Terminate the connection. */
577 snprintf(buf, sizeof buf, "%c.\r\n", escape_char);
578 buffer_append(&stderr_buffer, buf, strlen(buf));
579 stderr_bytes += strlen(buf);
580 quit_pending = 1;
581 return;
582
583 case 'Z' - 64:
584 /* Suspend the program. */
585 /* Print a message to that effect to the user. */
586 snprintf(buf, sizeof buf, "%c^Z\r\n", escape_char);
587 buffer_append(&stderr_buffer, buf, strlen(buf));
588 stderr_bytes += strlen(buf);
589
590 /* Restore terminal modes and suspend. */
591 client_suspend_self();
592
593 /* We have been continued. */
594 continue;
595
596 case '&':
597 /* Detach the program (continue to serve connections,
598 but put in background and no more new
599 connections). */
600 if (!stdin_eof)
601 {
602 /* Sending SSH_CMSG_EOF alone does not always
603 appear to be enough. So we try to send an
604 EOF character first. */
605 packet_start(SSH_CMSG_STDIN_DATA);
606 packet_put_string("\004", 1);
607 packet_send();
608 /* Close stdin. */
609 stdin_eof = 1;
610 if (buffer_len(&stdin_buffer) == 0)
611 {
612 packet_start(SSH_CMSG_EOF);
613 packet_send();
614 }
615 }
616 /* Restore tty modes. */
617 leave_raw_mode();
618
619 /* Stop listening for new connections. */
620 channel_stop_listening();
621
622 printf("%c& [backgrounded]\n", escape_char);
623
624 /* Fork into background. */
625 pid = fork();
626 if (pid < 0)
627 {
628 error("fork: %.100s", strerror(errno));
629 continue;
630 }
631 if (pid != 0)
632 { /* This is the parent. */
633 /* The parent just exits. */
634 exit(0);
635 }
636
637 /* The child continues serving connections. */
638 continue;
639
640 case '?':
641 snprintf(buf, sizeof buf, "%c?\r\n\
642Supported escape sequences:\r\n\
643~. - terminate connection\r\n\
644~^Z - suspend ssh\r\n\
645~# - list forwarded connections\r\n\
646~& - background ssh (when waiting for connections to terminate)\r\n\
647~? - this message\r\n\
648~~ - send the escape character by typing it twice\r\n\
649(Note that escapes are only recognized immediately after newline.)\r\n",
650 escape_char);
651 buffer_append(&stderr_buffer, buf, strlen(buf));
652 continue;
653
654 case '#':
655 snprintf(buf, sizeof buf, "%c#\r\n", escape_char);
656 buffer_append(&stderr_buffer, buf, strlen(buf));
657 s = channel_open_message();
658 buffer_append(&stderr_buffer, s, strlen(s));
659 xfree(s);
660 continue;
661
662 default:
663 if (ch != escape_char)
664 {
665 /* Escape character followed by non-special
666 character. Append both to the input
667 buffer. */
668 buf[0] = escape_char;
669 buf[1] = ch;
670 buffer_append(&stdin_buffer, buf, 2);
671 stdin_bytes += 2;
672 continue;
673 }
674 /* Note that escape character typed twice falls through
675 here; the latter gets processed as a normal
676 character below. */
677 break;
678 }
679 }
680 else
681 {
682 /* The previous character was not an escape char.
683 Check if this is an escape. */
684 if (last_was_cr && ch == escape_char)
685 {
686 /* It is. Set the flag and continue to next
687 character. */
688 escape_pending = 1;
689 continue;
690 }
691 }
692
693 /* Normal character. Record whether it was a newline,
694 and append it to the buffer. */
695 last_was_cr = (ch == '\r' || ch == '\n');
696 buf[0] = ch;
697 buffer_append(&stdin_buffer, buf, 1);
698 stdin_bytes += 1;
699 continue;
700 }
701 }
702 }
703}
704
705void client_process_output(fd_set *writeset)
706{
707 int len;
708 char buf[100];
709
710 /* Write buffered output to stdout. */
711 if (FD_ISSET(fileno(stdout), writeset))
712 {
713 /* Write as much data as possible. */
714 len = write(fileno(stdout), buffer_ptr(&stdout_buffer),
715 buffer_len(&stdout_buffer));
716 if (len <= 0)
717 {
718 if (errno == EAGAIN)
719 len = 0;
720 else
721 {
722 /* An error or EOF was encountered. Put an error message
723 to stderr buffer. */
724 snprintf(buf, sizeof buf, "write stdout: %.50s\r\n", strerror(errno));
725 buffer_append(&stderr_buffer, buf, strlen(buf));
726 stderr_bytes += strlen(buf);
727 quit_pending = 1;
728 return;
729 }
730 }
731 /* Consume printed data from the buffer. */
732 buffer_consume(&stdout_buffer, len);
733 }
734
735 /* Write buffered output to stderr. */
736 if (FD_ISSET(fileno(stderr), writeset))
737 {
738 /* Write as much data as possible. */
739 len = write(fileno(stderr), buffer_ptr(&stderr_buffer),
740 buffer_len(&stderr_buffer));
741 if (len <= 0) {
742 if (errno == EAGAIN)
743 len = 0;
744 else
745 {
746 /* EOF or error, but can't even print error message. */
747 quit_pending = 1;
748 return;
749 }
750 }
751 /* Consume printed characters from the buffer. */
752 buffer_consume(&stderr_buffer, len);
753 }
754}
755
756/* Implements the interactive session with the server. This is called
757 after the user has been authenticated, and a command has been
758 started on the remote host. If escape_char != -1, it is the character
759 used as an escape character for terminating or suspending the
760 session. */
761
762int client_loop(int have_pty, int escape_char_arg)
763{
Damien Miller6d7b2cd1999-11-12 15:19:27 +1100764 extern Options options;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000765 double start_time, total_time;
766 int len;
767 char buf[100];
768
769 debug("Entering interactive session.");
770
771 start_time = get_current_time();
772
773 /* Initialize variables. */
774 escape_pending = 0;
775 last_was_cr = 1;
776 exit_status = -1;
777 stdin_eof = 0;
778 buffer_high = 64 * 1024;
779 connection_in = packet_get_connection_in();
780 connection_out = packet_get_connection_out();
781 max_fd = connection_in;
782 if (connection_out > max_fd)
783 max_fd = connection_out;
784 stdin_bytes = 0;
785 stdout_bytes = 0;
786 stderr_bytes = 0;
787 quit_pending = 0;
788 escape_char = escape_char_arg;
789
790 /* Initialize buffers. */
791 buffer_init(&stdin_buffer);
792 buffer_init(&stdout_buffer);
793 buffer_init(&stderr_buffer);
794
795 /* Set signal handlers to restore non-blocking mode. */
796 signal(SIGINT, signal_handler);
797 signal(SIGQUIT, signal_handler);
798 signal(SIGTERM, signal_handler);
799 signal(SIGPIPE, SIG_IGN);
800 if (have_pty)
801 signal(SIGWINCH, window_change_handler);
802
803 /* Enter raw mode if have a pseudo terminal. */
804 if (have_pty)
805 enter_raw_mode();
806
807 /* Check if we should immediately send of on stdin. */
808 client_check_initial_eof_on_stdin();
809
810 /* Main loop of the client for the interactive session mode. */
811 while (!quit_pending)
812 {
813 fd_set readset, writeset;
814
815 /* Precess buffered packets sent by the server. */
816 client_process_buffered_input_packets();
817
818 /* Make packets of buffered stdin data, and buffer them for sending
819 to the server. */
820 client_make_packets_from_stdin_data();
821
822 /* Make packets from buffered channel data, and buffer them for sending
823 to the server. */
824 if (packet_not_very_much_data_to_write())
825 channel_output_poll();
826
827 /* Check if the window size has changed, and buffer a message about
828 it to the server if so. */
829 client_check_window_change();
830
831 if (quit_pending)
832 break;
833
834 /* Wait until we have something to do (something becomes available
835 on one of the descriptors). */
836 client_wait_until_can_do_something(&readset, &writeset);
837
838 if (quit_pending)
839 break;
840
841 /* Do channel operations. */
842 channel_after_select(&readset, &writeset);
843
844 /* Process input from the connection and from stdin. Buffer any data
845 that is available. */
846 client_process_input(&readset);
847
848 /* Process output to stdout and stderr. Output to the connection
849 is processed elsewhere (above). */
850 client_process_output(&writeset);
851
852 /* Send as much buffered packet data as possible to the sender. */
853 if (FD_ISSET(connection_out, &writeset))
854 packet_write_poll();
855 }
856
857 /* Terminate the session. */
858
859 /* Stop watching for window change. */
860 if (have_pty)
861 signal(SIGWINCH, SIG_DFL);
862
863 /* Stop listening for connections. */
864 channel_stop_listening();
865
866 /* In interactive mode (with pseudo tty) display a message indicating that
867 the connection has been closed. */
Damien Miller5ce662a1999-11-11 17:57:39 +1100868 if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000869 {
870 snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host);
871 buffer_append(&stderr_buffer, buf, strlen(buf));
872 stderr_bytes += strlen(buf);
873 }
874
875 /* Output any buffered data for stdout. */
876 while (buffer_len(&stdout_buffer) > 0)
877 {
878 len = write(fileno(stdout), buffer_ptr(&stdout_buffer),
879 buffer_len(&stdout_buffer));
880 if (len <= 0)
881 {
882 error("Write failed flushing stdout buffer.");
883 break;
884 }
885 buffer_consume(&stdout_buffer, len);
886 }
887
888 /* Output any buffered data for stderr. */
889 while (buffer_len(&stderr_buffer) > 0)
890 {
891 len = write(fileno(stderr), buffer_ptr(&stderr_buffer),
892 buffer_len(&stderr_buffer));
893 if (len <= 0)
894 {
895 error("Write failed flushing stderr buffer.");
896 break;
897 }
898 buffer_consume(&stderr_buffer, len);
899 }
900
901 /* Leave raw mode. */
902 if (have_pty)
903 leave_raw_mode();
904
905 /* Clear and free any buffers. */
906 memset(buf, 0, sizeof(buf));
907 buffer_free(&stdin_buffer);
908 buffer_free(&stdout_buffer);
909 buffer_free(&stderr_buffer);
910
911 /* Report bytes transferred, and transfer rates. */
912 total_time = get_current_time() - start_time;
913 debug("Transferred: stdin %lu, stdout %lu, stderr %lu bytes in %.1f seconds",
914 stdin_bytes, stdout_bytes, stderr_bytes, total_time);
915 if (total_time > 0)
916 debug("Bytes per second: stdin %.1f, stdout %.1f, stderr %.1f",
917 stdin_bytes / total_time, stdout_bytes / total_time,
918 stderr_bytes / total_time);
919
920 /* Return the exit status of the program. */
921 debug("Exit status %d", exit_status);
922 return exit_status;
923}