busybox/networking/telnetd.ctrlSQ.patch
<<
>>
Prefs
   1From: "Doug Graham" <dgraham@nortel.com>
   2Date: 2009-01-22 07:20
   3
   4Hello,
   5
   6Busybox's telnetd does not disable local (client-side) flow control
   7properly.  It does not put the pty into packet mode and then notify the
   8client whenever flow control is disabled by an application running under
   9its control.  The result is that ^S/^Q are not passed through to the
  10application, which is painful when the application is an emacs variant.
  11
  12I suppose that support for this might be considered bloat, but the
  13included patch only adds about 200 bytes of text to x86 busybox and 300
  14bytes to mipsel busybox.  Please consider applying.
  15
  16=============================
  17
  18NB: the patch doesn't work as-is because we now have iac_safe_write()
  19which quotes IACs on output.
  20
  21=============================
  22Docs:
  23
  24The following ioctl(2) calls apply only to pseudo terminals:
  25
  26TIOCSTOP Stops output to a terminal (e.g. like typing ^S). Takes no parameter.
  27
  28TIOCSTART Restarts output (stopped by TIOCSTOP or by typing ^S). Takes no parameter.
  29
  30TIOCPKT         Enable/disable packet mode. When applied to the master side of a pseudo terminal, each
  31subsequent read(2) from the terminal will return data written on the slave part of the pseudo terminal preceded by a
  32zero byte (symbolically defined as TIOCPKT_DATA), or a single byte reflecting control status information.
  33In the latter case, the byte is an inclusive-or of zero or more of the bits:
  34
  35TIOCPKT_FLUSHREAD     whenever the read queue for the terminal is flushed.
  36TIOCPKT_FLUSHWRITE    whenever the write queue for the terminal is flushed.
  37TIOCPKT_STOP    whenever output to the terminal is stopped a la ^S.
  38TIOCPKT_START   whenever output to the terminal is restarted.
  39TIOCPKT_DOSTOP  whenever t_stopc is ^S and t_startc is ^Q.
  40TIOCPKT_NOSTOP  whenever the start and stop characters are not ^S/^Q.
  41
  42While this mode is in use, the presence of control status information to be read from the master side may be detected
  43by a select(2) for exceptional conditions.
  44
  45This mode is used by rlogin(1) and rlogind(8) to implement a remote-echoed, locally ^S/^Q flow-controlled remote login
  46with proper back-flushing of output; it can be used by other similar programs.
  47
  48TIOCUCNTL       Enable/disable a mode that allows a small number of simple user ioctl(2) commands to be passed through
  49the pseudo-terminal, using a protocol similar to that of TIOCPKT. The TIOCUCNTL and TIOCPKT modes are mutually
  50exclusive. This mode is enabled from the master side of a pseudo terminal. Each subsequent read(2) from the master side
  51will return data written on the slave part of the pseudo terminal preceded by a zero byte, or a single byte reflecting a
  52user control operation on the slave side. A user control command consists of a special ioctl(2) operation with no data;
  53the command is given as UIOCCMD (n), where n is a number in the range 1-255. The operation value n will be received as
  54a single byte on the next read(2) from the master side. The ioctl(2) UIOCCMD (0) is a no-op that may be used to probe
  55for the existence of this facility. As with TIOCPKT mode, command operations may be detected with a select(2) for
  56exceptional conditions.
  57
  58--- busybox-1.13.2/networking/telnetd.c 2009/01/21 20:02:39     1.1
  59+++ busybox-1.13.2/networking/telnetd.c 2009/01/22 00:35:28
  60@@ -38,6 +38,9 @@
  61        int sockfd_read, sockfd_write, ptyfd;
  62        int shell_pid;
  63 
  64+#ifdef TIOCPKT
  65+       int flowstate;
  66+#endif
  67        /* two circular buffers */
  68        /*char *buf1, *buf2;*/
  69 /*#define TS_BUF1 ts->buf1*/
  70@@ -170,6 +173,9 @@
  71        int fd, pid;
  72        char tty_name[GETPTY_BUFSIZE];
  73        struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE * 2);
  74+#ifdef TIOCPKT
  75+       int on = 1;
  76+#endif
  77 
  78        /*ts->buf1 = (char *)(ts + 1);*/
  79        /*ts->buf2 = ts->buf1 + BUFSIZE;*/
  80@@ -180,6 +186,10 @@
  81                maxfd = fd;
  82        ts->ptyfd = fd;
  83        ndelay_on(fd);
  84+#ifdef TIOCPKT
  85+       ioctl(fd, TIOCPKT, &on);
  86+       ts->flowstate = TIOCPKT_DOSTOP;
  87+#endif
  88 #if ENABLE_FEATURE_TELNETD_STANDALONE
  89        ts->sockfd_read = sock;
  90        /* SO_KEEPALIVE by popular demand */
  91@@ -385,6 +395,16 @@
  92                portnbr = 23,
  93        };
  94 #endif
  95+#ifdef TIOCPKT
  96+       int control;
  97+       static const char lflow_on[] ALIGN1 =
  98+           {IAC, SB, TELOPT_LFLOW, LFLOW_ON, IAC, SE};
  99+       static const char lflow_off[] ALIGN1 =
 100+           {IAC, SB, TELOPT_LFLOW, LFLOW_OFF, IAC, SE};
 101+# define RESERVED sizeof(lflow_on)
 102+#else
 103+# define RESERVED 0
 104+#endif
 105        /* Even if !STANDALONE, we accept (and ignore) -i, thus people
 106         * don't need to guess whether it's ok to pass -i to us */
 107        opt = getopt32(argv, "f:l:Ki" IF_FEATURE_TELNETD_STANDALONE("p:b:F"),
 108@@ -475,7 +495,7 @@
 109                                FD_SET(ts->sockfd_read, &rdfdset);
 110                        if (ts->size2 > 0)       /* can write to socket */
 111                                FD_SET(ts->sockfd_write, &wrfdset);
 112-                       if (ts->size2 < BUFSIZE) /* can read from pty */
 113+                       if (ts->size2 < (BUFSIZE - RESERVED)) /* can read from pty */
 114                                FD_SET(ts->ptyfd, &rdfdset);
 115                }
 116                ts = next;
 117@@ -593,6 +613,52 @@
 118                                        goto skip4;
 119                                goto kill_session;
 120                        }
 121+#ifdef TIOCPKT
 122+                       control = TS_BUF2[ts->rdidx2];
 123+                       if (--count > 0 && control == TIOCPKT_DATA) {
 124+                               /*
 125+                                * If we are in packet mode, and we have
 126+                                * just read a chunk of actual data from
 127+                                * the pty, then there is the TIOCPKT_DATA
 128+                                * byte (zero) that we have got to remove
 129+                                * somehow.  If there were no chars in
 130+                                * TS_BUF2 before we did this read, then
 131+                                * we can optimize by just advancing wridx2.
 132+                                * Otherwise we have to copy the new data down
 133+                                * to close the gap (Could use readv() instead).
 134+                                */
 135+                               if (ts->size2 == 0)
 136+                                       ts->wridx2++;
 137+                               else {
 138+                                       memmove(TS_BUF2 + ts->rdidx2,
 139+                                               TS_BUF2 + ts->rdidx2 + 1, count);
 140+                               }
 141+                       }
 142+
 143+                       /*
 144+                        * If the flow control state changed, notify
 145+                        * the client.  If "control" is not TIOCPKT_DATA,
 146+                        * then there are no data bytes to worry about.
 147+                        */
 148+                       if ((control & (TIOCPKT_DOSTOP|TIOCPKT_NOSTOP)) != 0
 149+                        && ts->flowstate != (control & TIOCPKT_DOSTOP)) {
 150+                               const char *p = ts->flowstate ? lflow_off : lflow_on;
 151+
 152+                               /*
 153+                                * We know we have enough free slots available
 154+                                * (see RESERVED) but they are not necessarily
 155+                                * contiguous; we may have to wrap.
 156+                                */
 157+                               for (count = sizeof(lflow_on); count > 0; count--) {
 158+                                       TS_BUF2[ts->rdidx2++] = *p++;
 159+                                       if (ts->rdidx2 >= BUFSIZE)
 160+                                               ts->rdidx2 = 0;
 161+                                       ts->size2++;
 162+                               }
 163+
 164+                               ts->flowstate = control & TIOCPKT_DOSTOP;
 165+                       }
 166+#endif /* TIOCPKT */
 167                        ts->size2 += count;
 168                        ts->rdidx2 += count;
 169                        if (ts->rdidx2 >= BUFSIZE) /* actually == BUFSIZE */
 170
 171--Doug
 172_______________________________________________
 173busybox mailing list
 174busybox@busybox.net
 175http://lists.busybox.net/mailman/listinfo/busybox
 176