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