NetBSD-Bugs archive

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

kern/48292: paccept creates sockets that cannot be made blocking



>Number:         48292
>Category:       kern
>Synopsis:       paccept creates sockets that cannot be made blocking
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Oct 08 21:25:00 +0000 2013
>Originator:     Justin Cormack
>Release:        6.1 (and revent cvs)
>Organization:
>Environment:
NetBSD netbsd32.myriabit.eu 6.1 NetBSD 6.1 (XEN3PAE_DOMU) i386
>Description:
sockets created with paccept(2) when the parent socket is non blocking remain 
nonblocking even when set explicitly to blocking with fcntl. They report that 
they are blocking but still return EAGAIN. This does not happen with accept(2).

>How-To-Repeat:
/* Example code. Should block; does with accept not paccept. */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

int main(int argc, char **argv) {

  int ss, cs, as;
  int ok, fl, n;
  int addrlen = sizeof(struct sockaddr_in);
  char buf[10];
  struct sockaddr_in sa = {.sin_family = AF_INET, .sin_port = htons(0), 
.sin_addr = htonl(INADDR_LOOPBACK)};
  struct sockaddr_in ba;

  ss = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
  if (ss == -1) {perror("socket"); return 1;}
  ok = bind(ss, (struct sockaddr *)&sa, sizeof(sa));
  if (ok == -1) {perror("bind"); return 1;}
  ok = getsockname(ss, (struct sockaddr *)&ba, &addrlen);
  if (ok == -1) {perror("getsockname"); return 1;}
  ok = listen(ss, 128);
  if (ok == -1) {perror("listen"); return 1;}
  cs = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
  if (cs == -1) {perror("socket"); return 1;}
  /* may not connect first time */
  ok = connect(cs, (struct sockaddr *)&ba, addrlen);
  /* may get EAGAIN here */
  //as = accept(ss, NULL, NULL);
  as = paccept(ss, NULL, NULL, NULL, 0);
  ok = connect(cs, (struct sockaddr *)&ba, addrlen);
  if (ok == -1 && errno != EISCONN) {printf("both connects failed\n"); return 
1;}

  fl = fcntl(ss, F_GETFL, 0);
  if (fl == -1) {perror("fnctl getfl"); return 1;}
  ok = fcntl(ss, F_SETFL, fl & ~O_NONBLOCK);
  if (ok == -1) {perror("fnctl setfl"); return 1;}

  if (as == -1) { /* not true under NetBSD */
  //as = accept(ss, NULL, NULL);
  as = paccept(ss, NULL, NULL, NULL, 0);
    if (as == -1) {perror("accept/paccept"); return 1;}
  }

 /* this has no effect, not possible to force blocking, same issue if removed */
  fl = fcntl(as, F_GETFL, 0);
  if (fl == -1) {perror("fnctl getfl"); return 1;}
  ok = fcntl(as, F_SETFL, fl & ~O_NONBLOCK);
  if (ok == -1) {perror("fnctl setfl"); return 1;}

  fl = fcntl(as, F_GETFL, 0);
  if (fl & O_NONBLOCK) {printf("accepted sock nonblocking, something wrong\n");}
  n = read(as, buf, 10);
  if (n == -1) {perror("read"); return 1;}

  return 0;
}

>Fix:
its in do_sys_accept I presume. The difference is clrflags which should clear 
nonblock in child if not set in flags. The code looks ok, but there must be an 
issue.



Home | Main Index | Thread Index | Old Index