Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 17 Jun 2001 13:25:16 +0900 (JST)
From:      tak@st.rim.or.jp (NAKAMURA Takayuki)
To:        FreeBSD-gnats-submit@freebsd.org
Cc:        tak@st.rim.or.jp
Subject:   kern/28218: A peer of TCP socket cannot detect termination of another peer
Message-ID:  <200106170425.NAA11988@reverse.takn.yi.org>

next in thread | raw e-mail | index | archive | help

>Number:         28218
>Category:       kern
>Synopsis:       A peer of TCP socket cannot detect termination of another peer
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sat Jun 16 21:30:01 PDT 2001
>Closed-Date:
>Last-Modified:
>Originator:     NAKAMURA Takayuki
>Release:        FreeBSD 4.3-RELEASE i386
>Organization:
(none)
>Environment:
System: FreeBSD parsley 4.3-RELEASE FreeBSD 4.3-RELEASE #0: Mon May 21 20:46:55 JST 2001 takayuki@parsley.ma.onlab.ntt.co.jp:/usr/src/sys/compile/TAKA i386

>Description:

The following sequence shows the problem of the socket implementation.

[server side]
|takayuki@parsley:~/sample>uname -a
|FreeBSD parsley 4.3-RELEASE FreeBSD 4.3-RELEASE #0: Mon May 21 20:46:55 JST 2001     takayuki@parsley.ma.onlab.ntt.co.jp:/usr/src/sys/compile/TAKA  i386
|takayuki@parsley:~/sample>ls -l
|total 5
|-rw-r--r--   1 takayuki staff        2945 Jun 17 12:56 client.el
|-rw-r--r--   1 takayuki staff        1819 Jun 17 12:56 server.c
|takayuki@parsley:~/sample>gcc server.c 
|takayuki@parsley:~/sample>./a.out 

[client side]
|takayuki@parsley:~/sample>emacs -q -nw
M-x load-file[ret]
Load file: ~/sample/client.el
M-x client-start[ret]
hello[ret]
^Z
|Suspended
|takayuki@parsley:~/sample>kill %1
|takayuki@parsley:~/sample>
|[1]    Terminated                    emacs -q -nw

*****
Now, the server side cannot detect termination of the client process.

|takayuki@parsley:~/sample>ps uxg | grep a.out
|takayuki 61304  0.0  0.1   332  200  p1  R+    1:00PM   0:00.00 grep a.out
|takayuki 61297  0.0  0.1   848  308  p2  I+   12:56PM   0:00.00 ./a.out
|takayuki 61302  0.0  0.1   860  384  p2  I+   12:58PM   0:00.00 ./a.out

*****
"M-x telnet" is not affected.

[client side]
|takayuki@parsley:~/sample>emacs -q -nw
M-x telnet[ret]
Open connection to host: localhost 12345
hello[ret]
^Z
|Suspended
|takayuki@parsley:~/sample>kill %1
|takayuki@parsley:~/sample>
|[1]    Terminated                    emacs -q -nw

*****
In this time the server side detects termination.

|takayuki@parsley:~/sample>./a.out
|received: hoge
|
|child process: end.

|takayuki@parsley:~/sample>ps uxg | grep a.out
|takayuki 61342  0.0  0.0   300  172  p1  R+    1:06PM   0:00.00 grep a.out
|takayuki 61334  0.0  0.1   848  332  p2  I+    1:04PM   0:00.00 ./a.out

*****
This problem can be reproduced on any 4.3-RELEASE system,
but 4.1-RELEASE does not perform the problem.
4.2-RELASE is not tested.

In the above operation sequence, the problem appears on both localhost
and other Ethernet connected server hosts where any OSs run.
Tcpdump says that TCP FIN packet is not sent.
Client side must be FreeBSD 4.3-RELEASE.

In the above operation sequence, "emacs" is introduced from packages-4.3.
Both emacs 20.x and ja-mule-19.x reproduce the problem.

This problem can be reproduced on client side.
I don't know whether server side has the same problem.



>How-To-Repeat:

[server.c]
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>

/* Sample Port */
#define serverPortNum 12345

static void sigchld_handler(int sig)
{
    int pid;
    int status;

    for (;;) {
        pid = waitpid(-1, &status, WNOHANG);
        if (pid <= 0) break;
    }
}

int main(void)
{
    int  server_skt, newskt;
    struct sockaddr_in socketAddress, rsocketAddress;
    socklen_t length;
    int  count;
    char buf[256];
    struct sigaction sa;
    int optval;

    server_skt = socket(PF_INET, SOCK_STREAM, 0);
    socketAddress.sin_family = AF_INET;
    socketAddress.sin_addr.s_addr = INADDR_ANY;
    socketAddress.sin_port = htons(serverPortNum);
    optval = 1;
    setsockopt(server_skt, SOL_SOCKET, SO_REUSEADDR,
               (char *)&optval, sizeof(int));

    if (bind(server_skt, (struct sockaddr *)&socketAddress,
                         sizeof(socketAddress) ) < 0) {
        perror("bind failed");
        return 1;
    }
    listen(server_skt, 4);

    sigaction(SIGCHLD, NULL, &sa);
    sa.sa_handler = sigchld_handler;
    sigaction(SIGCHLD, &sa, NULL);

    for (;;) {
        length = sizeof(rsocketAddress);
        newskt = accept(server_skt, (struct sockaddr *)&rsocketAddress,
                                    &length);
        if (fork() == 0) {  /*  child proess */
            close(server_skt);
            /* processing... */
            for (;;) {
              count = read(newskt, buf, sizeof(buf)-1);
              if (count <= 0) {
                if (count < 0) perror("read on child process");
                break;
              }
              buf[count] = 0;
              printf("received: %s\n", buf);
              write(newskt, buf, count);
            }
            printf("child process: end.\n");
            return 0;
        }
        close(newskt);
    }
    /* NOTREACHED */
    return 0;
}



[client.el]
;;; client sample

(setq server-name "localhost")
(setq server-port 12345)

(defvar client-input-map nil)
(defvar client-process nil)
(defconst client-log-buffer "*client LOG*")
(defconst client-input-buffer "*client INPUT*")

;; functions
(defun client-reconfigure-windows ()
  (switch-to-buffer (get-buffer-create client-input-buffer))
  (client-mode)
  (delete-other-windows)
  (split-window-vertically -4)
  (switch-to-buffer (get-buffer-create client-log-buffer))
  (goto-char (point-max))
  (other-window 1)
  (goto-char (point-max))
  (redraw-frame (selected-frame)))

(defun client-mode ()
  "Major mode for the Client"
  (interactive)
  (if client-input-map
      nil
    (setq client-input-map (make-sparse-keymap))
    (define-key client-input-map "\C-m" 'client-send-message-full))
  (use-local-map client-input-map))

(defun client-get-string ()
  (save-excursion
    (let ((p (point)))
      (beginning-of-line)
      (buffer-substring (point) p))))

(defun client-send-message ()
  (let ((str (client-get-string)))
    (process-send-string client-process (concat str "\n"))))

(defun client-send-message-full ()
  (interactive)
  (end-of-line)
  (client-send-message)
  (newline))

(defun client-start ()
  "Start client"
  (interactive)
  (client-reconfigure-windows)
  (message "trying to connect host %s:%d ..." server-name server-port)
  (setq client-process (open-network-stream
                       "client" client-log-buffer server-name server-port))
  (set-buffer (get-buffer client-log-buffer))
  (set-marker (process-mark client-process) (point))
  (goto-char (point-max))
  (set-buffer (get-buffer client-input-buffer))
  (goto-char (point-min))
  (set-process-sentinel client-process 'client-sentinel)
  (set-process-buffer client-process (get-buffer client-log-buffer))
  (set-process-filter client-process 'client-display-filter)
  (message "client: Connection established. [%s:%d]" server-name server-port))

(defun client-sentinel (process event)
  (let ((stat (process-status process)) mf)
    (save-excursion
      (set-buffer (process-buffer process))
      (goto-char (point-min)))
    (if (or (eq stat 'closed) (eq stat 'exit))
      (progn
        (message "client: Connection closed.")
        (delete-process client-process)
        (force-mode-line-update t)
        (save-excursion
          (set-buffer (process-buffer process))
          (goto-char (point-max))
          (insert "*** Connection closed. ***\n")))
      (error "client: %s" event))))

(defun client-display-filter (proc string)
  (let ((old-buffer (current-buffer)) excess-string p len)
    (unwind-protect
	(let (eqp)
	  (set-buffer (process-buffer proc))
	  (get-buffer-window (current-buffer) 'visible)
	  (setq eqp (= (point) (process-mark proc)))
	  (save-window-excursion
	    (goto-char (process-mark proc))
	    (insert string)
	    (set-marker (process-mark proc) (point)))
      (set-buffer old-buffer)))))

;;; end of file



>Fix:
        no fix is known.
>Release-Note:
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200106170425.NAA11988>