non-blocking accept() can hang.

Tanaka Akira akr@fsij.org
Tue Feb 5 06:39:00 GMT 2013


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



More information about the Cygwin mailing list