This is the mail archive of the cygwin mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

recvfrom + MSG_PEEK = broken?


I've been tracking down a problem in xinetd. It appears to be an issue
with using MSG_PEEK in recvfrom() on UDP sockets.

The following technique is used by both xinetd, AND libwrap, to
determine the remote address of an incoming UDP packet:

   socket s is non blocking.

   select (on socket as readfd)

   /* sufficient guards, while loop, etc around the select
    * call to guarantee we never get here unless there is
    * actually data waiting to be read */
   char t;
   recvfrom (s, &t, 1, MSG_PEEK,
             (struct sockaddr *)&remote_sa, &addrlen);

   /* do stuff with remote_sa, like validate address
    * against hosts.allow, etc.  Then: */

   recvfrom (s, buf, szbuf, 0,
             (struct sockaddr *)&remote_sa, &addrlen);
   !!! oops. Always returns -1, errno = EAGAIN
   !!! even if I know the packet had more than just the
   !!! one byte we peek'ed into 't'.  IOW, no data.


I've attached a simple (!) test case which isolates the problem. Extract
it and run 'make'. You'll get two servers, and one client.

udp_server1.exe -- works
udp_server2.exe -- broken
udp_client.exe

In two different cygwin windows (same machine is best, so you don't have
to worry about firewall issues).

window #1
$ ./udp_server1 port#

window #2
$ ./udp_client host port# "some text to send"

The client sends the specified text via UDP to the specified host/port.
It then waits for a response from the server, and prints it.

The (working) server will print a hexdump of the data it receives from
the client, and then send back the alphabet to the client.

The (broken) server prints out the "peeked" data -- which should be the
first byte of the text sent by the client. But then, it hits the error
condition after the "real" recvfrom, and complains:
   peeked: t=0x66 (f) rc=1
   Error recieving data from client: Resource temporarily unavailable
The client will try five more times to send the message before giving up
and printing its own error message -- so, you see the pattern above six
times, too.

The only difference between the two servers is the following, in the
middle of the main server loop (after select(), and before the "real"
recvfrom()):

#ifdef DO_PEEK
      {
        char t;
        int rc = recvfrom (s, &t, 1, MSG_PEEK, NULL, 0);
        fprintf (stderr, "peeked: t=0x%02x (%c) rc=%d\n",
                 t, isprint((int)(unsigned char)t) ? t : '.', rc);
      }
#endif

It doesn't matter if I have an actual (struct sockaddr *) in there or not.

I've also attached my cygcheck output (I'm running a self-built snapshot
about two weeks old).

Any ideas?

--
Chuck

Attachment: udp_msg_peek.tar.bz2
Description: Binary data

Attachment: cygcheck.out
Description: Text document

--
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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]