Open sockets non-overlapped?

Lev Bishop lev.bishop@gmail.com
Thu Jun 15 16:08:00 GMT 2006


On 6/13/06, Corinna Vinschen wrote:
> On Jun 13 11:47, Lev Bishop wrote:

> > It seems it's hanging in fhandler_socket::close(), when the child
> > process closes the listening socket.
>
> Hanging?  Or looping endlessly with WSAEWOULDBLOCK?

Actually, it's very strange. It gets stuck on the setsockopt() in
fhandler_socket::close(). There's a race with the parent (which is why
it didn't happen under strace or sshd -d), but if the parent gets
round to doing its select() before the child does the close(), then
the setsockopt() does not return until after the select() returns. I
attach a short testcase which reliably demonstrates the problem for
me. It doesn't use privilege separation or non-blocking sockets, so
that is not the problem. I haven't investigated whether it's something
to do with the way the socket is duplicated into the child
(WSADuplicateSocket() versus DuplicateHandle(), and such).

Just to spell it out: the problem shown in my testcase, is only
exibited with overlapped sockets. Non-overlapped don't have any
problem. Which is strange to me, since MSDN makes no mention of
situations where setsockopt() can block.

>  Any change when not
> setting the linger option, maybe?

Well, yes, because then there's no setsockopt() call to block on, but
it doesn't really solve the problem, because now if the user code
calls setsockopt() it will still unexpectedly block.

I think that's as far as I'm going to go with persuing this issue. If
I need native programs to use sockets, then I'll pipe them through
socat.

L
-------------- next part --------------
#include <netinet/in.h>
#include <err.h>
#include <stdio.h>
#include <unistd.h>

int
main(void)
{
  struct sockaddr_in laddr=
    {.sin_family=AF_INET, .sin_port=htons(5001), .sin_addr={INADDR_ANY}};
  struct sockaddr_storage addr;
  int skt,alen=sizeof(addr);
  fd_set r,w,e;
  struct timeval to;

  if (-1==(skt=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)))err(1,"opening");
  if (-1==bind(skt,(struct sockaddr*)&laddr,sizeof(laddr)))err(1,"bind");
  fprintf(stderr,"Listening....\n");
  if (-1==listen(skt,1))err(1,"listen");
  switch(fork()){
  case -1: err(1,"fork");
  case 0:
    sleep(1); // Ensure parent wins the race.
    fprintf(stderr,"closing...\n");
    close(skt); // block here until parent returns from select()
    fprintf(stderr,"closed\n");
    return 0;
  default:
    FD_ZERO(&r);
    FD_ZERO(&w);
    FD_ZERO(&e);
    to.tv_sec=10;
    to.tv_usec=0;
    FD_SET(skt,&r);
    fprintf(stderr,"selecting...\n");
    if(-1==(s=select(skt+1,&r,&w,&e,&to)))err(1,"select");
    fprintf(stderr,"selected\n");
    }
  }
  return 0;
}


More information about the Cygwin-patches mailing list