2002-10-14 14:51:35

by Jogchem de Groot

[permalink] [raw]
Subject: poll() incompatability with POSIX.1-2001

Hello,

There's an incompatability with the poll() implementation in the
linux-2.4 kernel. (Tried 2.4.18).

According to the POSIX.1-2001 standard select() and poll() should
return writability (POLLOUT) when connect() initated on a non-blocking
socket asynchronously completes.

http://www.opengroup.org/onlinepubs/007904975/functions/connect.html

"If the connection cannot be established immediately and O_NONBLOCK is set
for the file descriptor for the socket, connect() shall fail and set errno to
[EINPROGRESS], but the connection request shall not be aborted, and the
connection shall be established asynchronously. Subsequent calls to connect()
for the same socket, before the connection is established, shall fail and set
errno to [EALREADY].

When the connection has been established asynchronously, select() and poll()
shall indicate that the file descriptor for the socket is ready for writing."

On linux-2.4 i noticed the following behaviour:

On connect() success select() returns writability for the socket.
On connect() failure select() returns readability and writability for the
socket.

This behaviour is according to the specification.

However with poll() (with events=POLLIN|POLLOUT) i get the following
behaviour:

On connect() success poll() returns POLLOUT in revents.
On connect() failure poll() returns POLLIN|POLLHUP|POLLERR in revents.

It does not set the POLLOUT bit here..

I hope somebody will take a closer look at this. It doesnt seem to require a
big fix at all..

Thank you,
bighawk


2002-10-14 15:06:11

by Richard B. Johnson

[permalink] [raw]
Subject: Re: poll() incompatability with POSIX.1-2001

On Mon, 14 Oct 2002, Jogchem de Groot wrote:

> Hello,
>
> There's an incompatability with the poll() implementation in the
> linux-2.4 kernel. (Tried 2.4.18).
>
> According to the POSIX.1-2001 standard select() and poll() should
> return writability (POLLOUT) when connect() initated on a non-blocking
> socket asynchronously completes.
>
> http://www.opengroup.org/onlinepubs/007904975/functions/connect.html
>
> "If the connection cannot be established immediately and O_NONBLOCK is set
> for the file descriptor for the socket, connect() shall fail and set errno to
> [EINPROGRESS], but the connection request shall not be aborted, and the
> connection shall be established asynchronously. Subsequent calls to connect()
> for the same socket, before the connection is established, shall fail and set
> errno to [EALREADY].
>
> When the connection has been established asynchronously, select() and poll()
> shall indicate that the file descriptor for the socket is ready for writing."
>
> On linux-2.4 i noticed the following behaviour:
>
> On connect() success select() returns writability for the socket.
> On connect() failure select() returns readability and writability for the
> socket.
>
> This behaviour is according to the specification.
>
> However with poll() (with events=POLLIN|POLLOUT) i get the following
> behaviour:
>
> On connect() success poll() returns POLLOUT in revents.
> On connect() failure poll() returns POLLIN|POLLHUP|POLLERR in revents.
>
> It does not set the POLLOUT bit here..

This is a failure to connect! The socket is therefore not ready for
writing or reading -ever. This behavior may not be correct, not
because of a failure to set the POLLOUT bit, but because the POLLIN
bit is set. Check if this is really true. I can't duplicate this
on 2.4.18 here because it's hard to get a deferred connect with my
setup.

Cheers,
Dick Johnson
Penguin : Linux version 2.4.18 on an i686 machine (797.90 BogoMips).
The US military has given us many words, FUBAR, SNAFU, now ENRON.
Yes, top management were graduates of West Point and Annapolis.

2002-10-14 17:07:12

by Jogchem de Groot

[permalink] [raw]
Subject: Re: poll() incompatability with POSIX.1-2001

Hello,

This is a failure to connect! The socket is therefore not ready for
writing or reading -ever. This behavior may not be correct, not
because of a failure to set the POLLOUT bit, but because the POLLIN
bit is set. Check if this is really true. I can't duplicate this
on 2.4.18 here because it's hard to get a deferred connect with my
setup.

It's really true:..

Here is some strace output:

Case where connect() succeeds:

connect(3, {sin_family=AF_INET, sin_port=htons(111),
sin_addr=inet_addr("127.0.0.1")}}, 16) = -1 EINPROGRESS (Operation now in
progress)
poll([{fd=3, events=POLLIN|POLLOUT, revents=POLLOUT}], 1, -1) = 1
getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0

As you can see SO_ERROR returns '0', connection succeeded.

Case where connect() fails:

connect(3, {sin_family=AF_INET, sin_port=htons(110),
sin_addr=inet_addr("127.0.0.1")}}, 16) = -1 EINPROGRESS (Operation now in
progress)
poll([{fd=3, events=POLLIN|POLLOUT, revents=POLLIN|POLLERR|POLLHUP}], 1, -1)
= 1
getsockopt(3, SOL_SOCKET, SO_ERROR, [111], [4]) = 0

As you can see SO_ERROR returns '111', connection failed.

bighawk

2002-10-15 03:37:17

by Geoffrey Lee

[permalink] [raw]
Subject: Re: poll() incompatability with POSIX.1-2001

> >
> > When the connection has been established asynchronously, select() and poll()
> > shall indicate that the file descriptor for the socket is ready for writing."
> >
> > On linux-2.4 i noticed the following behaviour:
> >
> > On connect() success select() returns writability for the socket.
> > On connect() failure select() returns readability and writability for the
> > socket.
> >
> > This behaviour is according to the specification.
> >
> > However with poll() (with events=POLLIN|POLLOUT) i get the following
> > behaviour:
> >
> > On connect() success poll() returns POLLOUT in revents.
> > On connect() failure poll() returns POLLIN|POLLHUP|POLLERR in revents.
> >
> > It does not set the POLLOUT bit here..
>
> This is a failure to connect! The socket is therefore not ready for
> writing or reading -ever. This behavior may not be correct, not
> because of a failure to set the POLLOUT bit, but because the POLLIN
> bit is set. Check if this is really true. I can't duplicate this
> on 2.4.18 here because it's hard to get a deferred connect with my
> setup.
>


Hello!



I have done some experimentation.


First I used telnet to verify that the host xx.xx.xx.xx on port 80 is
up and listening. We verify that this is true.

Then, we run a test program.

The test program creates a TCP socket which will connect to a given host
on a given port then use the fcntl() call to set the non-blocking bit.

We then use connect() to connect to the host. We verify that the errno
is indeed EINPROGRESS.

We then use poll with an events member set to POLLIN | POLLOUT.


This is the result on a return from poll().

glee@orion ~/tmp $ ./poll-new -h xx.xx.xx.xx -p 80
connect
connect: INPROGRESS
poll: POLLOUT is set
terminating
glee@orion ~/tmp $


So, POLLOUT is set.


Now, we try to connect to an invalid port.

n ~/tmp $ ./poll-new -h xx.xx.xx.xx -p 4
connect
connect: INPROGRESS
poll: POLLERR set
poll: POLLHUP set
poll: POLLOUT is set
terminating
glee@orion ~/tmp $


So, POLLOUT is set.

By the way, what constants should be defined when you do a #include <poll.h>?


A lot of them are not defined, those listed in the poll() document on
the opengroup website, only POLLPRI and POLLIN, POLLOUT, POLLNVAL,
POLLHUP and POLLERR are defined.


POLLRDNORM, POLLRDBAND, POLLWRBAND, POLLWRNORM are not defined.


-- G.

2002-10-15 07:40:25

by Jogchem de Groot

[permalink] [raw]
Subject: Re: poll() incompatability with POSIX.1-2001

On Tuesday 15 October 2002 05:36, you wrote:

> This is the result on a return from poll().
>
> glee@orion ~/tmp $ ./poll-new -h xx.xx.xx.xx -p 80
> connect
> connect: INPROGRESS
> poll: POLLOUT is set
> terminating
> glee@orion ~/tmp $
>
>
> So, POLLOUT is set.
>
>
> Now, we try to connect to an invalid port.
>
> n ~/tmp $ ./poll-new -h xx.xx.xx.xx -p 4
> connect
> connect: INPROGRESS
> poll: POLLERR set
> poll: POLLHUP set
> poll: POLLOUT is set
> terminating
> glee@orion ~/tmp $
>
>
> So, POLLOUT is set.

Hello, on what version did you try this? I've tried this now on
Linux-2.4.18 and Linux-2.4.19 and both give the behaviour i described
previously (No POLLOUT set).

The simple test program i used is as follows:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <sys/select.h>
#include <errno.h>

main(int argc, char **argv) {
int sd,flags,stat,len=sizeof(int);
struct sockaddr_in sin;
struct pollfd pfd;

memset(&sin, 0, sizeof(sin));

sd = socket(AF_INET, SOCK_STREAM, 0);
fcntl(sd, F_SETFL, fcntl(sd, F_GETFL, 0) | O_NONBLOCK);

sin.sin_addr.s_addr = htonl(0x7f000001);
sin.sin_port = htons(atoi(argv[1]));
sin.sin_family = AF_INET;

if(connect(sd, (struct sockaddr *)&sin, sizeof(sin)) == -1 && errno ==
EINPROGRESS)
printf("connect returned EINPROGRESS\n");

pfd.fd = sd;
pfd.events = POLLIN | POLLOUT;
pfd.revents = 0;

poll(&pfd, 1, -1);
getsockopt(sd, SOL_SOCKET, SO_ERROR, &stat, &len);
printf("%s\n", stat ? "failed" : "succeeded");
printf("returned events: %hd\n", pfd.revents);
}

bighawk

2002-10-15 13:54:12

by Geoffrey Lee

[permalink] [raw]
Subject: Re: poll() incompatability with POSIX.1-2001

> Hello, on what version did you try this? I've tried this now on
> Linux-2.4.18 and Linux-2.4.19 and both give the behaviour i described
> previously (No POLLOUT set).
>


Ah, you are indeed right. I had a typo in my test code (trailing semi
colon).

So POLLIN | POLLERR | POLLHUP flags are for the revents member.



-- G.