jdb@mordor.UUCP (John Bruner) (08/30/85)
Index: ucb/rlogin.c 4.2 Fix Description: "rlogin" throws away output whenever the stop/start characters are changed to/from ^S/^Q. This is most noticeable when using a shell which provides its own input line editing (e.g. "tcsh"), and often causes the last portion of the output from the previous program to be lost. Repeat-By: Use "rlogin" to connect to a machine which has such a shell and enable that shell's line editor. Then run some commands which produce quite a bit of output (e.g. "cat /etc/passwd"). The problem is timing dependent, but it will probably show up after a couple of attempts. Fix: "rlogind", the remote daemon for "rlogin", operates the remote pseudo-terminal in packet mode. Each time that the stop/start characters are changed to/from ^S/^Q it receives a TIOCPKT_DOSTOP or TIOCPKT_NOSTOP packet from the master side of the pty. It sends this as an out-of-band message to the local "rlogin". "rlogind" also sends an out-of-band message if it receives a TIOCPKT_FLUSHWRITE packet from the master side of the pty. (I haven't look at the code myself, but I'm told that the kernel never produces this packet type.) The local "rlogin" process always flushes pending output when it receives an out-of-band message. After flushing output it examines the message to determine if it was TIOCPKT_[DN]OSTOP; if so, then it sets or resets the stop/start characters on the local tty. Because it unconditionally flushes output, a TIOCPKT_[DN]OSTOP message causes output to be lost. "rlogin" cannot simply recv() the out-of-band message because it uses the position of this message among the in-band data to determine how much output must be flushed. (It does this with the undocumented SIOCATMARK ioctl.) In order to handle this properly, it must "peek" at the message first to determine its contents, flush output if necessary, and then recv() the message and take any other appropriate actions. Guy Harris at Sun suggested that I include code to handle TIOCKPT_FLUSHREAD messages for completeness. The following includes that change as well: *************** *** 20,25 #include <sys/types.h> #include <sys/socket.h> #include <sys/wait.h> #include <netinet/in.h> --- 20,26 ----- #include <sys/types.h> #include <sys/socket.h> #include <sys/wait.h> + #include <sys/file.h> #include <netinet/in.h> *************** *** 362,368 oob() { ! int out = 1+1, atmark; char waste[BUFSIZ], mark; ioctl(1, TIOCFLUSH, (char *)&out); --- 363,369 ----- oob() { ! int out = FWRITE, in = FREAD, atmark; char waste[BUFSIZ], mark; recv(rem, &mark, 1, MSG_OOB|MSG_PEEK); *************** *** 365,375 int out = 1+1, atmark; char waste[BUFSIZ], mark; ! ioctl(1, TIOCFLUSH, (char *)&out); ! for (;;) { ! if (ioctl(rem, SIOCATMARK, &atmark) < 0) { ! perror("ioctl"); ! break; } if (atmark) break; --- 366,383 ----- int out = FWRITE, in = FREAD, atmark; char waste[BUFSIZ], mark; ! recv(rem, &mark, 1, MSG_OOB|MSG_PEEK); ! if (mark & TIOCPKT_FLUSHWRITE) { ! ioctl(1, TIOCFLUSH, (char *)&out); ! for (;;) { ! if (ioctl(rem, SIOCATMARK, &atmark) < 0) { ! perror("ioctl"); ! break; ! } ! if (atmark) ! break; ! if (read(rem, waste, sizeof (waste)) <= 0) ! break; } } recv(rem, &mark, 1, MSG_OOB); *************** *** 371,380 perror("ioctl"); break; } - if (atmark) - break; - if (read(rem, waste, sizeof (waste)) <= 0) - break; } recv(rem, &mark, 1, MSG_OOB); if (mark & TIOCPKT_NOSTOP) { --- 379,384 ----- if (read(rem, waste, sizeof (waste)) <= 0) break; } } recv(rem, &mark, 1, MSG_OOB); if (mark & TIOCPKT_FLUSHREAD) *************** *** 377,382 break; } recv(rem, &mark, 1, MSG_OOB); if (mark & TIOCPKT_NOSTOP) { notc.t_stopc = -1; notc.t_startc = -1; --- 381,388 ----- } } recv(rem, &mark, 1, MSG_OOB); + if (mark & TIOCPKT_FLUSHREAD) + ioctl(0, TIOCFLUSH, (char *)&in); if (mark & TIOCPKT_NOSTOP) { notc.t_stopc = -1; notc.t_startc = -1; -- John Bruner (S-1 Project, Lawrence Livermore National Laboratory) MILNET: jdb@mordor [jdb@s1-c.ARPA] (415) 422-0758 UUCP: ...!ucbvax!dual!mordor!jdb ...!seismo!mordor!jdb
chris@umcp-cs.UUCP (Chris Torek) (08/31/85)
> "rlogin" cannot simply recv() the out-of-band message because it > uses the position of this message among the in-band data to determine > how much output must be flushed. (It does this with the undocumented > SIOCATMARK ioctl.) Undocumented it is not: the 4.2BSD IPC primer explains SIOCATMARK. Would that this were not the only place. > In order to handle this properly, it must "peek" at the message > first to determine its contents, flush output if necessary, and > then recv() the message and take any other appropriate actions. It is interesting to note that recv(fd, buf, len, MSG_OOB) and recv(fd, buf, len, MSG_OOB|MSG_PEEK) perform the same operation. OOB data is only consumed in the kernel by reading the in-band data past the out-of-band mark. This is odd at best. In addition some of the kernel code that implements out of band data is very strange. I would suggest that you check the return values from the two recv calls. I'm not yet convinced that this fix actually does the right things, if only because the OOB kernel code is so odd. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@maryland
chris@umcp-cs.UUCP (Chris Torek) (08/31/85)
(Oops, one more. I do not wish to seem wroth with your fix: rlogin's handling of out of band data has long been a sore point with me, and you have finally prodded me enough that I am investigating it.) > "rlogind" also sends an out-of-band message if it receives a > TIOCPKT_FLUSHWRITE packet from the master side of the pty. (I > haven't look at the code myself, but I'm told that the kernel never > produces this packet type.) Ah, but it does! Look at the code for ptsstop and note the comment; and compare the values of TIOCPKT_FLUSHREAD and FREAD, and those of TIOCPKT_FLUSHWRITE and FWRITE. Recall that a TTY stop routine is called both for flow control (^S/^Q) and for I/O flushes (TIOCFLUSH and signals). The new code is certainly correct; I hope the kernel is as well. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@maryland
guy@sun.uucp (Guy Harris) (09/02/85)
> > "rlogind" also sends an out-of-band message if it receives a > > TIOCPKT_FLUSHWRITE packet from the master side of the pty. (I > > haven't look at the code myself, but I'm told that the kernel never > > produces this packet type.) > > Ah, but it does! Look at the code for ptsstop and note the comment; > and compare the values of TIOCPKT_FLUSHREAD and FREAD, and those of > TIOCPKT_FLUSHWRITE and FWRITE. Recall that a TTY stop routine is > called both for flow control (^S/^Q) and for I/O flushes (TIOCFLUSH > and signals). Interestingly (or grossly, take your pick) enough, when ttyflush is called with FREAD but not FWRITE, not TIOCPKT_FLUSHREAD will be generated. The d_stop routine is called only if output is being flushed. (The S5 generic tty driver/unit driver interface is much cleaner; there's a general "special function" call and it has separate commands for "block input", "unblock input", "restart output", "suspend output", "resume suspended output", "transmit break", "flush output", and "flush input". Overloading "freeze output" with "flush output and maybe input too" is asking for trouble.) Guy Harris