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