Subject: RE: 1.3.2: Cygwin && UDP && O_NONBLOCK
From: Troy Noble <[email-masked]>
To: "'Keith Seitz'" <[email-masked]>, Roderick Groesbeek <[email-masked]>
Cc: [email-masked]
Date: Tue, 14 Aug 2001 13:54:27 -0600

Roderick,

Unless I misunderstood entirely, I think you've found a bug.

I got the same blocking behavior you described when testing
(after fixing many of the same things that Keith
described in his mail).  And it does appear to be inconsistent
with behavior on Linux for the same program as you noted.

Looks like there was a fix for some code related to setting up the
non-blocking behavior in fhandler_socket.cc:fctl on Aug 13, 2001
so the flags are set properly now, but the recvfrom appears not
to be checking for the non-blocking flag.  I updated my src tree
from CVS today and tested, and it still exhibits the blocking
behavior you describe.

The problem appears to be the wait for an event at net.cc:93
which looks like:

  switch (WSAWaitForMultipleEvents(2, ev, FALSE, WSA_INFINITE, FALSE))

There seem to be at least two ways to fix it, otherwise I'd just
submit a patch.  But I don't know that I understand the philosopy
entirely, so it'd be best to defer to Corinna's better judgement.

It seems to me in net.cc:recvfrom one of the following
needs to happen:

1. if ((h->get_flags() & O_NONBLOCK_MASK)
       || !(ovr = wsock_evt.prepare ()))
    {
       ...

   which would cause behavior to revert to Winsock 1.1's
   recvfrom which appears to do the right thing, at least in
   my minimal testing.

2. add another check for !(h->get_flags() & O_NONBLOCK_MASK)
   before calling wait(...) in the overlapped section of
   code before net.cc:537.

3. I guess a test of the same sort as #2 above might be
   appropriate inside wait() around line 93 instead.
   It's not entirely as straightforward detecting when
   no data is there when using non-blocking sockets with
   the overlapped calls.

Ok, that's technically 3 ways.

Troy

-----Original Message-----
From: Keith Seitz [mailto:[email-masked]]
Sent: Tuesday, August 14, 2001 10:34 AM
To: Roderick Groesbeek
Cc: [email-masked]
Subject: Re: 1.3.2: Cygwin && UDP && O_NONBLOCK

On Tue, 14 Aug 2001, Roderick Groesbeek wrote:

> #ifdef __linux__
>    #include <linux/in.h>
> #endif
> #ifdef __CYGWIN__
>    #include <cygwin/in.h>
> #endif

Why not just #include <netinet/in.h>?

>
> #include <unistd.h>
> #include <fcntl.h>
>
>
>
> #define BUFSIZE 1024
>
> int main(int argc, char* argv[], char* env[])
> {
>   int sock;
>   int ret;
>   char buf[BUFSIZE];
>   struct sockaddr_in me, from;
>   unsigned int from_len;
>
>   int flags;
>
>
>   sock = socket(PF_INET, SOCK_DGRAM, 0);
>
>   if (sock < 0) {
>         perror("socket");
>         exit(1);
>   }
>
>   flags = fcntl(sock, F_GETFL, 0);
>   ret = fcntl(sock, F_SETFL, flags & ~O_NONBLOCK);
>   printf("ret=%d|\n", ret);

This fcntl stuff shouldn't really be necessary, but it should do no harm.

>   bzero((char*) &from, sizeof(from));

Ugh. You mean "bzero (&me, sizeof (me));"?

>   me.sin_family = AF_INET;
>   me.sin_addr.s_addr = htonl(INADDR_ANY);
>   me.sin_port = htons(1025);
>   ret = bind(sock, (struct sockaddr *) & me, sizeof(me));
>   if (ret < 0) {
>         perror("bind");
>         exit(1);
>   }
>   while(1) {
>         int len;
>
>         len = recvfrom(sock, buf, BUFSIZE, 0, (struct sockaddr *) &from,
> &from_len);

This is not correct. from_len is not initialized (typo?). You MUST set it
to "sizeof (from)". This is a "value/result argument".

>         perror("recvfrom");
>         printf("len=%d|\n", len);
>   }
>
>   return 0;
> }

FWIW, I tried the following program on my system and had no problems
whatsoever, with or without SET_BLOCKING set.

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#ifdef SET_BLOCKING
#include <fcntl.h>
#endif

#ifdef __CYGWIN__
typedef unsigned int socklen_t;
#endif

int
main (int argc, char *argv[])
{
  int ret;
  char buf[1024];
  socklen_t len;
  struct sockaddr_in my_addr, client_addr;
  int sock;
#ifdef SET_BLOCKING
  int flags;
#endif

  sock = socket (AF_INET, SOCK_DGRAM, 0);
  if (sock < 0)
    {
      perror ("couldn't create socket");
      exit (1);
    }

#ifdef SET_BLOCKING
  flags = fcntl (sock, F_GETFL, 0);
  flags &= ~O_NONBLOCK;
  ret = fcntl (sock, F_SETFL, flags);
  if (ret < 0)
   {
     perror ("couldn't force blocking");
     exit (1);
   }
#endif

  bzero (&my_addr, sizeof (my_addr));
  my_addr.sin_family = AF_INET;
  my_addr.sin_addr.s_addr = htonl (INADDR_ANY);
  my_addr.sin_port = htons (10025);
  if (bind (sock, (struct sockaddr *) &my_addr, sizeof (my_addr)) < 0)
    {
      perror ("couldn't bind to address");
      exit (1);
    }

  while (1)
    {
      len = sizeof (client_addr);
      ret = recvfrom (sock, buf, 1024, 0, (struct sockaddr *) &client_addr,
&len);
      printf ("recvfrom returned %d\n", ret);
      if (ret < 0)
	{
	  perror ("error getting data from socket");
	  continue;
	}

      /* Do something with the data. Echo it. */
      ret = sendto (sock, buf, ret, 0, (struct sockaddr *) &client_addr,
len);
      if (ret < 0)
	{
	  perror ("error sending data");
	  continue;
	}

      printf ("Sent %d bytes to client at %x\n", ret,
client_addr.sin_addr.s_addr);
    }

  return 0;
}

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Bug reporting:         http://cygwin.com/bugs.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Bug reporting:         http://cygwin.com/bugs.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/