delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/2013/02/05/01:40:05

X-Recipient: archive-cygwin AT delorie DOT com
X-SWARE-Spam-Status: No, hits=-3.7 required=5.0 tests=AWL,BAYES_00,DKIM_SIGNED,DKIM_VALID,FREEMAIL_FROM,KHOP_RCVD_TRUST,RCVD_IN_DNSWL_LOW,RCVD_IN_HOSTKARMA_YE
X-Spam-Check-By: sourceware.org
MIME-Version: 1.0
X-Received: by 10.49.24.132 with SMTP id u4mr22066992qef.55.1360046379471; Mon, 04 Feb 2013 22:39:39 -0800 (PST)
Date: Tue, 5 Feb 2013 15:39:39 +0900
Message-ID: <CANjopZGmp+xaUg1Sn2FTmb77igMk8R=Lp9yBWyeDtDj3RP5R=g@mail.gmail.com>
Subject: non-blocking accept() can hang.
From: Tanaka Akira <akr AT fsij DOT org>
To: cygwin AT cygwin DOT com
X-IsSubscribed: yes
Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm
List-Id: <cygwin.cygwin.com>
List-Subscribe: <mailto:cygwin-subscribe AT cygwin DOT com>
List-Archive: <http://sourceware.org/ml/cygwin/>
List-Post: <mailto:cygwin AT cygwin DOT com>
List-Help: <mailto:cygwin-help AT cygwin DOT com>, <http://sourceware.org/ml/#faqs>
Sender: cygwin-owner AT cygwin DOT com
Mail-Followup-To: cygwin AT cygwin DOT com
Delivered-To: mailing list cygwin AT cygwin DOT com

Hi.

I found that non-blocking accept() can hang.

The following test program shows the problem.

  % uname -mrsv
  CYGWIN_NT-5.1 1.7.17(0.262/5/3) 2012-10-19 14:39 i686
  % cat tst-nonblocking.c
  #include <stddef.h>
  #include <stdlib.h>
  #include <stdio.h>
  #include <errno.h>
  #include <unistd.h>
  #include <fcntl.h>
  #include <sys/socket.h>
  #include <sys/un.h>

  void set_nonblock(int fd)
  {
    int ret;
    ret = fcntl(fd, F_GETFL);
    if (ret == -1) { perror("fcntl(F_GETFL)"); exit(EXIT_FAILURE); }
    ret |= O_NONBLOCK;
    ret = fcntl(fd, F_SETFL, ret);
    if (ret == -1) { perror("fcntl(F_SETFL)"); exit(EXIT_FAILURE); }
  }

  int main(int argc, char *argv[])
  {
    int s, c, ret;
    struct sockaddr_un addr;
    socklen_t addrlen;

    unlink("socketfile");

    addrlen = sizeof(addr);
    memset(&addr, '\0', addrlen);
    addr.sun_family = AF_UNIX;
    strcpy(addr.sun_path, "socketfile");

    s = socket(AF_UNIX, SOCK_STREAM, 0);
    if (s == -1) { perror("socket(server)"); exit(EXIT_FAILURE); }

    set_nonblock(s);

    ret = bind(s, (struct sockaddr *)&addr, addrlen);
    if (ret == -1) { perror("bind"); exit(EXIT_FAILURE); }

    ret = listen(s, SOMAXCONN);
    if (ret == -1) { perror("listen"); exit(EXIT_FAILURE); }

    c = socket(AF_UNIX, SOCK_STREAM, 0);
    if (c == -1) { perror("socket(client)"); exit(EXIT_FAILURE); }

    set_nonblock(c);

    ret = connect(c, (struct sockaddr *)&addr, addrlen);
    if (ret == -1 && errno == EINPROGRESS) { perror("connect"); }
    else if (ret == -1) { perror("connect"); exit(EXIT_FAILURE); }

    ret = accept(s, NULL, 0);
    if (ret == -1) { perror("accept"); exit(EXIT_FAILURE); }

    return EXIT_SUCCESS;
  }

  % gcc -Wall tst-nonblocking.c -o tst-nonblocking
  % ./tst-nonblocking
  connect: Operation now in progress
  (^C and ^Z is not effective.  I used Windows task manager to kill
the process.)

I found this problem when I investigate why the following program blocks.
The following program doesn't use O_NONBLOCK but other OS (GNU/Linux,
FreeBSD, NetBSD, OpenBSD and SunOS) doesn't block.

Is it intentional behavior?

  % cat tst-blocking.c
  #include <stddef.h>
  #include <stdlib.h>
  #include <stdio.h>
  #include <errno.h>
  #include <unistd.h>
  #include <fcntl.h>
  #include <sys/socket.h>
  #include <sys/un.h>

  int main(int argc, char *argv[])
  {
    int s, c, ret;
    struct sockaddr_un addr;
    socklen_t addrlen;

    unlink("socketfile");

    addrlen = sizeof(addr);
    memset(&addr, '\0', addrlen);
    addr.sun_family = AF_UNIX;
    strcpy(addr.sun_path, "socketfile");

    s = socket(AF_UNIX, SOCK_STREAM, 0);
    if (s == -1) { perror("socket(server)"); exit(EXIT_FAILURE); }

    ret = bind(s, (struct sockaddr *)&addr, addrlen);
    if (ret == -1) { perror("bind"); exit(EXIT_FAILURE); }

    ret = listen(s, SOMAXCONN);
    if (ret == -1) { perror("listen"); exit(EXIT_FAILURE); }

    c = socket(AF_UNIX, SOCK_STREAM, 0);
    if (c == -1) { perror("socket(client)"); exit(EXIT_FAILURE); }

    ret = connect(c, (struct sockaddr *)&addr, addrlen);
    if (ret == -1 && errno == EINPROGRESS) { perror("connect"); }
    else if (ret == -1) { perror("connect"); exit(EXIT_FAILURE); }

    return EXIT_SUCCESS;
  }

  % gcc -Wall tst-nonblocking.c -o tst-nonblocking
  % ./tst-blocking
  (^C can interrupt the process.)
-- 
Tanaka Akira

--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019