emacs-pretest-bug
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

TCP vs raw-text-dos


From: 山本和彦
Subject: TCP vs raw-text-dos
Date: Tue, 15 Jul 2003 22:11:17 +0900 (JST)

Hello, 

Summary: If a TCP connection is combined with 'raw-text-dos, Emacs
         accidentally closes the connection with a special input
         pattern.

Suppose a process is created by open-network-stream() and its
coding-system is set to 'raw-text-dos:

----
(defvar xxx-pro nil)

(defun xxx ()
  (let ((buf (get-buffer-create "xxx")))
    ;; port 200 does not have special meaning.
    (setq xxx-pro (open-network-stream "xxx" buf "localhost" 200))
    (set-process-filter xxx-pro 'xxx-filter)
    (set-process-coding-system xxx-pro 'raw-text-dos)))

(defun xxx-filter (pro str)
  (set-buffer (process-buffer pro))
  (insert str))
----

Typical mail protocols use CR LF as a line delimiter. Emacs can handle
if this two bytes comes together in an IP packet. 

However, if CR solely comes first, then LF follows, Emacs deactivates
a network process, resulting the TCP connection accidentally closed.

This bug exists in Emacs 20.7, Emacs 21.3 and Emacs 21.3.50.

You can re-produce it as follows:

a) complie the following C code and obtain /tmp/a.out. 

   This program reads one byte from "/tmp/in" and writes it solely to
   stdout. Note that TCP_NODELAY is very important.

b) add the following line to "inetd.conf" and send the HUP signal
   to "inetd".

----
200            stream  tcp     nowait  root    /tmp/a.out      a.out 
----

c) create "/tmp/in" with its contents are "CR LF CR LF CR LF".

d) evaluate the lisp program above and M-: (xxx)

   This program should insert three new lines to the "xxx" buffer.
   Sometimes succeeds. But somtimes no new line is inserted, that is,
   the connection is closed by accident.

When this bug appears, "tcpdump" shows the following:

---
# tcpdump -n -i lo0
tcpdump: listening on lo0
21:58:56.421282 127.0.0.1.64314 > 127.0.0.1.200: S 181607527:181607527(0) win 
16384 <mss 33156,nop,wscale 0,nop,nop,timestamp 0 0> (DF)
21:58:56.421338 127.0.0.1.200 > 127.0.0.1.64314: S 185789817:185789817(0) ack 
181607528 win 16384 <mss 33156,nop,wscale 0,nop,nop,timestamp 0 0> (DF)
21:58:56.421466 127.0.0.1.64314 > 127.0.0.1.200: . ack 1 win 16384 
<nop,nop,timestamp 0 0> (DF)
21:58:56.425274 127.0.0.1.200 > 127.0.0.1.64314: P 1:2(1) ack 1 win 16384 
<nop,nop,timestamp 0 0> (DF)
21:58:56.431504 127.0.0.1.64314 > 127.0.0.1.200: F 1:1(0) ack 2 win 16384 
<nop,nop,timestamp 0 0> (DF)
21:58:56.431542 127.0.0.1.200 > 127.0.0.1.64314: . ack 2 win 16384 
<nop,nop,timestamp 0 0> (DF)
21:58:56.440094 127.0.0.1.200 > 127.0.0.1.64314: P 2:3(1) ack 2 win 16384 
<nop,nop,timestamp 0 0> (DF)
21:58:56.440136 127.0.0.1.64314 > 127.0.0.1.200: R 181607529:181607529(0) win 0
---

Port 200 is the server side (i.e /tmp/a.out). 

Port 64314 is the Emacs side. Emacs sends TCP Fin even if the server
tries to send more bytes. (Since the server closes the TCP connection
in the normal situation, TCP Fin should be sent by the server)

And Emacs sends TCP Reset against the more bytes.

When this bug happens, nchars becomes 0 in
process.c:read_process_output(). And it returns 0 (nchars, not
nbytes).

So, wait_reading_process_input() calls deactivate_process(), resulting
closing the TCP connection.

--Kazu

-----
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>

char buf[BUFSIZ];

main ()
{
        FILE *in;
        int c, on = 1;

        if ((in = fopen("/tmp/in", "r")) == NULL) {
                perror("fopen");
                exit(1);
        }

        if (setsockopt(1, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(int)) == -1) {
                perror("nsetsockopt");
                exit(1);
        }

        while ((c = fgetc(in)) != EOF) {
                write(1, &c, 1);
                usleep(10);
        }
}
-----

----
In GNU Emacs 21.3.50.3 (i386-unknown-netbsdelf1.6T, X toolkit, Xaw3d scroll 
bars)
 of 2003-07-15 on caster.iij.ad.jp
configured using `configure '--without-xim' '--prefix=/usr/local/emacs21' 
'CFLAGS=-I/usr/pkg/include' 'CPPFLAGS=-I/usr/pkg/include -L/usr/pkg/lib' 
'LDFLAGS=-R/usr/pkg/lib -L/usr/pkg/lib -R/usr/X11R6/lib -L/usr/X11R6/lib''

Important settings:
  value of $LC_ALL: nil
  value of $LC_COLLATE: nil
  value of $LC_CTYPE: ja_JP.eucJP
  value of $LC_MESSAGES: nil
  value of $LC_MONETARY: nil
  value of $LC_NUMERIC: nil
  value of $LC_TIME: nil
  value of $LANG: nil
  locale-coding-system: japanese-iso-8bit
  default-enable-multibyte-characters: t

Recent input:
<return> SPC o <return> o <return> C-p . n d d v * 
C-n d C-g C-n d d x . SPC o <return> d d d x s <return> 
s <return> ESC x r e p o r t SPC e SPC b SPC <retu
rn>

Recent messages:
nchars == 0 in read_process_output()
nread == 0 in wait_reading_process_input()
No new messages
Connecting to the IMAP server...done
Communicating with the IMAP server...
No new messages
nchars == 0 in read_process_output()
nread == 0 in wait_reading_process_input()
No new messages
Loading emacsbug...done
----




reply via email to

[Prev in Thread] Current Thread [Next in Thread]