It is currently Tue, 14 Jul 2020 00:42:17 GMT



 
Author Message
 kernel 2.4.18 - select() returning strange value
Hello everyone.

Please CC: me on replies

Summary: when calling select() on a set of file descriptors containing
only the descriptor of a non-connected stream socket, select() returns
1 and marks the FD set as if data were waiting on the socket.

Details: I first noticed, when trying to install the perl module
Net::Telnet, that the select test was failing. Running strace on the
test program, I determined that select() was returning an unexpected
value.
I wrote a simple C program to duplicate this behavior, and got the
same results.

sock = socket(AF_INET, SOCK_STREAM, 6);
FD_ZERO(&rfds);
FD_SET(sock, &rfds);
tv.tv_sec = 0; tv.tv_usec = 0;
retval = select(sock+1, &rfds, NULL, NULL, &tv);

Produced these strace lines:

socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
select(4, [3], NULL, NULL, {0, 0}) = 1 (in [3], left {0, 0})

According to what I've read in the man pages for select() and
socket(), a nonconnected socket should be unreadable, and therefore
select() should timeout and return 0. I cannot figure out why it is
returning 1.

I've gotten this result on kernel 2.4.18, and someone confirmed the
same result on 2.4.19-pre7. A user with 2.2.19 ran my test program and
got a return value of 0, which is what I would expect the return value
to be.

Has something changed in the kernel or the way the select() syscall
behaves on a nonconnected socket that I should be aware of? I cannot
find anything relevant in the recent change logs, but I am probably
missing something.

Any insight into this would be much appreciated. Thanks in advance.

--
Regards,
Jake                          mailto:co...@rafb.net

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at   http://www.**-**.com/
Please read the FAQ at   http://www.**-**.com/



 Wed, 24 Nov 2004 07:01:30 GMT   
 kernel 2.4.18 - select() returning strange value

        This seems correct to me. A read or write will not block and there is
nothing to wait for.

        Because the socket is ready for read. If a read were attempted immediately,
it would not block. If a read would result in an error other than
'EWOULDBLOCK', the socket is ready to be read.

        I'm guessing the previous erroneous behavior was fixed. When you 'select' on
an unconnected socket, what do you expect 'select' to wait for?

        DS

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/



 Thu, 25 Nov 2004 10:00:09 GMT   
 kernel 2.4.18 - select() returning strange value
[I am replying off web archive; please Cc any response to me. Thank you]

So I am not the only one who noticed it. Good.

Unfortunately, _any_ attempt to read or write on socket in this state is
meaningless and undefined (see below). For this reason return value of
select is misleading and wrong.

No. It is not. That's the whole point.

Currently 'read' does not result in any error. That is exactly the problem.
It is not only 'select' that is misbehaving but 'read' as well.

Nobody expects 'select' to wait. As said above 'select should timeout and
return nothing to read/write'.

The problem stems from the fact that Linux does not make distinction between
'not yet connected' and 'already closed' states.

What you say is true and correct for 'already closed' state. In this case
select _must_ return 'ready to read' at least once so that application can
properly sense EOF condition. What happens on subsequent select's/read's is
strictly speaking implementation defined (access to a file after EOF has
been seen is undefined) but natural implementation is "sticky EOF" that
always returns EOF after socket has been closed.

For 'not yet connected' socket situation is different. The problem is not
would operation block or not - the problem is 'read' in this case returns
EOF thus effectively telling application "you must not touch this file any
more" and preventing further access to socket.

Here is test program from dante SOCKS server configure and output on Linux
and another Unix for comparison. Note that this test program signals error
on Linux ...

========================
/*
 * ftp.inet.no:/pub/home/michaels/stuff/unconnectedsocket-select.c
 * $ cc unconnectedsocket-select.c && uname -a && ./a.out
 * Modified by Eric Anderson <ande...@hpl.hp.com>
 */

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

#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>

static int
selectcheck(int s);

int
main(void)
{
        char foo[5];
        int s, p;
        struct sigaction act;
        int res;

        act.sa_handler = SIG_IGN;
        sigaction(SIGPIPE,&act,NULL);
        fprintf(stderr, "testing with a normal, unconnected socket:\n");
        if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
                perror("socket()");
                exit(1);
        }
        fprintf(stderr, "  created socket, select() returned %d\n",
               selectcheck(s));
        p = read(s, NULL, 0);
        fprintf(stderr, "  read() returned %d, errno = %d (%s)\n", p, errno,
(strerror(errno)));
        p = write(s, foo, 5);
        fprintf(stderr, "  write() returned %d, errno = %d (%s)\n", p,
errno, (strerror(errno)));

        fprintf(stderr, "testing with a non-blocking, unconnected
socket:\n");
        if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
                perror("socket()");
                exit(1);
        }
        if ((p = fcntl(s, F_GETFL, 0)) == -1
            || fcntl(s, F_SETFL, p | O_NONBLOCK) == -1) {
                perror("fcntl()");
                exit(1);
        }
        res = selectcheck(s);
        fprintf(stderr, "  socket nonblocking, select() returned %d\n",
res);

        p = read(s, NULL, 0);
        fprintf(stderr, "  read() returned %d, errno = %d (%s)\n", p, errno,
(strerror(errno)));
        p = write(s, &foo, 5);
        fprintf(stderr, "  write() returned %d, errno = %d (%s)\n", p,
errno, (strerror(errno)));

        if (res == 0)
                return 0; /* correct behaviour */
        else
                return 1; /* incorrect behaviour */

static int
selectcheck(s)
        int s;
{
        fd_set rset, wset, xset;
        struct timeval timeout;
        int ret,i;

        FD_ZERO(&rset);
        FD_SET(s, &rset);
        wset = xset = rset;

        timeout.tv_sec  = 0;
        timeout.tv_usec         = 0;

        errno = 0;
        ret = select(s + 1, &rset, &wset, &xset, &timeout);
        if (FD_ISSET(s,&rset)) {
            fprintf(stderr, "  socket is readable\n");
        }
        if (FD_ISSET(s,&wset)) {
            fprintf(stderr, "  socket is writeable\n");
        }
        if (FD_ISSET(s,&xset)) {
            fprintf(stderr, "  socket has an exception\n");
        }
        return ret;
====================

Linux runs:

bor@cooker% ./a.out
testing with a normal, unconnected socket:
  socket is readable
  socket is writeable
  created socket, select() returned 2
  read() returned 0, errno = 0 (Success)
  write() returned -1, errno = 32 (Broken pipe)
testing with a non-blocking, unconnected socket:
  socket is readable
  socket is writeable
  socket nonblocking, select() returned 2
  read() returned 0, errno = 0 (Success)
  write() returned -1, errno = 32 (Broken pipe)

"Other UNIX" runs:

bor@itsrm2% /tmp/a.out
testing with a normal, unconnected socket:
  created socket, select() returned 0
  read() returned -1, errno = 134 (Transport endpoint is not connected)
  write() returned -1, errno = 134 (Transport endpoint is not connected)
testing with a non-blocking, unconnected socket:
  socket nonblocking, select() returned 0
  read() returned -1, errno = 134 (Transport endpoint is not connected)
  write() returned -1, errno = 134 (Transport endpoint is not connected)

-andrej
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/



 Fri, 26 Nov 2004 14:20:06 GMT   
 
   [ 3 post ] 

Similar Threads

1. Strange problems with kernels >= 2.4.18

2. Kernel 2.4.18 and strange OOM Killer behaveness

3. select return value

4. Q. regarding to select() and its return value

5. Return value of select() on socket error

6. Select() returns an erroneous value ?


 
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software