You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@apr.apache.org by Ruediger Pluem <rp...@apache.org> on 2006/08/02 23:06:24 UTC

[Fwd: Re: How to detect is the socket is still open]

Reposting what I sent to Mladen in private. Just missed that
his address was in to and not dev@apr.apache.org :-)

-------- Original Message --------
Subject: Re: How to detect is the socket is still open
Date: Wed, 02 Aug 2006 21:57:36 +0200
From: Ruediger Pluem <rp...@apache.org>
To: Mladen Turk <mt...@apache.org>
References: <44...@apache.org>



On 08/02/2006 01:42 PM, Mladen Turk wrote:

> 
> My question is, if someone is aware of the
> smarter mechanism for checking the socket
> connection, and if we could add the function
> for that inside APR.

What does poll (with timeout zero) return in the case that the socket has been closed?

Regards

Rüdiger



Re: [Fwd: Re: How to detect is the socket is still open]

Posted by Alexander Lazic <al...@none.at>.
On Mit 16.08.2006 08:55, Joe Orton wrote:
>
>POLLERR would only be set for an RST and "exceptional conditions"; the
>same applies to select()+the exceptfds array AFAIK.
>
>There is some inconsistency with handling FIN and sockets across
>platforms: http://www.greenend.org.uk/rjk/2001/06/poll.html but yes
>you'd generally expect POLLIN for "you can read EOF".

On curl-library list there was a similar thread about poll on MacOsX:

'poll & Mac OS X 10.4'
http://curl.haxx.se/mail/lib-2005-05/index.html#118

There was a link to mac develop site:

http://developer.apple.com/technotes/tn2002/tn2071.html

---
.
.
poll

This API is not supported in Mac OS X, instead, the function select is
used. The select function does synchronous I/O multiplexing, similar to
poll. This API is located in the following header files: <sys/types.h>,
<sys/time.h>, <unistd.h> The select API is defined as follow: 

---
int select(int nfds, fd_set *readfds, fd_set *writefds,
       fd_set *exceptfds, struct timeval *timeout);
---

The behavior of select is not exactly the same as poll, so you will have
to alter your code. select gives you a number of macros to manipulate
the file descriptor returned, which is done differently in poll

An alternative to avoid changing your code is to use a wrapper around
select, such as fakepoll.h. Simply include the file fakepoll.h in your
code, and the library does the rest of the work. See
sealiesoftware.com/fakepoll.h for more information about fakepoll.h.

Note: fakepoll.h is a third-party library and not supported by Apple.
.
.
---

regards

Alex

Re: [Fwd: Re: How to detect is the socket is still open]

Posted by Joe Orton <jo...@redhat.com>.
On Wed, Aug 16, 2006 at 06:24:37AM -0700, Justin Erenkrantz wrote:
> Back to our original question: how can we portably detect that the socket is
> still alive?  We can't do a non-blocking read() either...  -- justin

AFAIK the closure of the read direction of the socket is exposed only by
consuming the receive buffer until a read returns EOF.  There is no way
to determine "is the next thing available to read going to be EOF"
except by actually doing the read/recv. (I guess recv/MSG_PEEK will tell
you without having to actually consume the EOF; not sure that makes any
difference though)

joe

Re: [Fwd: Re: How to detect is the socket is still open]

Posted by Davi Arnaut <da...@haxent.com.br>.
Em 16/08/2006, às 14:21, Davi Arnaut escreveu:

>
> Em 16/08/2006, às 12:49, Joe Orton escreveu:
>
>> On Wed, Aug 16, 2006 at 12:36:23PM -0300, Davi Arnaut wrote:
>>> Em 16/08/2006, às 11:00, Justin Erenkrantz escreveu:
>>>> Would a non-blocking read() followed by a poll()/select() be  
>>>> useful?
>>>> We'd still get a 0 back from read() - but if it was the EOF,  
>>>> would the
>>>> state of the socket change to be in the 'exceptional' state then  
>>>> if we
>>>> repoll?  -- justin
>>>
>>> Humm, read returning 0 is a EOF, you could also maybe
>>> getsockopt(SO_ERROR) on the socket to confirm the EOF.
>>
>> SO_ERROR will only give an error in cases where a read or write would
>> fail and set errno; that's not true for EOF.
>
> No, but moving on..
>
>>
>>> Select is a different beast because of the definition of what is
>>> a "exceptional condition" which may be pending error conditions
>>> or oob data. I think the "exception fd" of select is similar to a  
>>> poll
>>> with POLLPRI mask, so it shoud'nt signal a connection reset.
>>
>> It's POLLERR, hopefully; that's how APR maps it anyway ;)
>
> It's POLLPRI, errors are not exceptional conditions.

Just to be clearer, a socket is considered to have an "exceptional  
condition"
if a read would return OOB data without blocking or if there is a OOB  
data mark
on the receive queue. Other exceptional conditions are protocol/ 
implementation
specific. There is no _standard_ way to detect EOF using select().

For example, the Linux select syscall defines/uses the fowling:

#define POLLIN_SET (POLLRDNORM | POLLRDBAND | POLLIN | POLLHUP |  
POLLERR)
#define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR)
#define POLLEX_SET (POLLPRI)

So a socket in the readfds is also watched for a EOF.

--
Davi Arnaut


Re: [Fwd: Re: How to detect is the socket is still open]

Posted by Davi Arnaut <da...@haxent.com.br>.
Em 16/08/2006, às 12:49, Joe Orton escreveu:

> On Wed, Aug 16, 2006 at 12:36:23PM -0300, Davi Arnaut wrote:
>> Em 16/08/2006, às 11:00, Justin Erenkrantz escreveu:
>>> Would a non-blocking read() followed by a poll()/select() be useful?
>>> We'd still get a 0 back from read() - but if it was the EOF,  
>>> would the
>>> state of the socket change to be in the 'exceptional' state then  
>>> if we
>>> repoll?  -- justin
>>
>> Humm, read returning 0 is a EOF, you could also maybe
>> getsockopt(SO_ERROR) on the socket to confirm the EOF.
>
> SO_ERROR will only give an error in cases where a read or write would
> fail and set errno; that's not true for EOF.

No, but moving on..

>
>> Select is a different beast because of the definition of what is
>> a "exceptional condition" which may be pending error conditions
>> or oob data. I think the "exception fd" of select is similar to a  
>> poll
>> with POLLPRI mask, so it shoud'nt signal a connection reset.
>
> It's POLLERR, hopefully; that's how APR maps it anyway ;)

It's POLLPRI, errors are not exceptional conditions.

--
Davi Arnaut


Re: [Fwd: Re: How to detect is the socket is still open]

Posted by Joe Orton <jo...@redhat.com>.
On Wed, Aug 16, 2006 at 12:36:23PM -0300, Davi Arnaut wrote:
> Em 16/08/2006, às 11:00, Justin Erenkrantz escreveu:
> >Would a non-blocking read() followed by a poll()/select() be useful?
> >We'd still get a 0 back from read() - but if it was the EOF, would the
> >state of the socket change to be in the 'exceptional' state then if we
> >repoll?  -- justin
> 
> Humm, read returning 0 is a EOF, you could also maybe
> getsockopt(SO_ERROR) on the socket to confirm the EOF.

SO_ERROR will only give an error in cases where a read or write would
fail and set errno; that's not true for EOF.

> Select is a different beast because of the definition of what is
> a "exceptional condition" which may be pending error conditions
> or oob data. I think the "exception fd" of select is similar to a poll
> with POLLPRI mask, so it shoud'nt signal a connection reset.

It's POLLERR, hopefully; that's how APR maps it anyway ;)

joe

Re: [Fwd: Re: How to detect is the socket is still open]

Posted by Davi Arnaut <da...@haxent.com.br>.
Em 16/08/2006, às 11:00, Justin Erenkrantz escreveu:

> On 8/16/06, Davi Arnaut <da...@haxent.com.br> wrote:
>> The only portable way to "detect" a broken connection is using
>> SO_KEEPALIVE
>> or to write/read "ping" data through the socket -- which is what
>> keepalive does.
>
> How would SO_KEEPALIVE help?  The other end is deliberately closing
> the connection and we need to know that.

It would help detect a broken connection, not a RST state.

> Would a non-blocking read() followed by a poll()/select() be useful?
> We'd still get a 0 back from read() - but if it was the EOF, would the
> state of the socket change to be in the 'exceptional' state then if we
> repoll?  -- justin

Humm, read returning 0 is a EOF, you could also maybe
getsockopt(SO_ERROR) on the socket to confirm the EOF.

Upon receive of a RST the socket should move to the closed
state, and poll should return immediately if the POLLHUP mask
was passed for that socket, and SO_ERROR should be one of
ECONNREFUSED (syn sent)/EPIPE (close wait)/ECONNRESET
or none if the socket was already closed.

Select is a different beast because of the definition of what is
a "exceptional condition" which may be pending error conditions
or oob data. I think the "exception fd" of select is similar to a poll
with POLLPRI mask, so it shoud'nt signal a connection reset.

--
Davi Arnaut




Re: [Fwd: Re: How to detect is the socket is still open]

Posted by Justin Erenkrantz <ju...@erenkrantz.com>.
On 8/16/06, Davi Arnaut <da...@haxent.com.br> wrote:
> The only portable way to "detect" a broken connection is using
> SO_KEEPALIVE
> or to write/read "ping" data through the socket -- which is what
> keepalive does.

How would SO_KEEPALIVE help?  The other end is deliberately closing
the connection and we need to know that.

Would a non-blocking read() followed by a poll()/select() be useful?
We'd still get a 0 back from read() - but if it was the EOF, would the
state of the socket change to be in the 'exceptional' state then if we
repoll?  -- justin

Re: [Fwd: Re: How to detect is the socket is still open]

Posted by Davi Arnaut <da...@haxent.com.br>.
Em 16/08/2006, às 10:24, Justin Erenkrantz escreveu:

> On Wed, Aug 16, 2006 at 08:55:44AM +0100, Joe Orton wrote:
>> POLLERR would only be set for an RST and "exceptional conditions";  
>> the
>> same applies to select()+the exceptfds array AFAIK.
>>
>> There is some inconsistency with handling FIN and sockets across
>> platforms: http://www.greenend.org.uk/rjk/2001/06/poll.html but yes
>> you'd generally expect POLLIN for "you can read EOF".
>
> Back to our original question: how can we portably detect that the  
> socket is
> still alive?  We can't do a non-blocking read() either...  -- justin

Hi,

The only portable way to "detect" a broken connection is using  
SO_KEEPALIVE
or to write/read "ping" data through the socket -- which is what  
keepalive does.

There is no other way around this, most network protocols are timeout  
based.

--
Davi Arnaut

Re: [Fwd: Re: How to detect is the socket is still open]

Posted by Justin Erenkrantz <ju...@erenkrantz.com>.
On Wed, Aug 16, 2006 at 08:55:44AM +0100, Joe Orton wrote:
> POLLERR would only be set for an RST and "exceptional conditions"; the
> same applies to select()+the exceptfds array AFAIK.
> 
> There is some inconsistency with handling FIN and sockets across
> platforms: http://www.greenend.org.uk/rjk/2001/06/poll.html but yes
> you'd generally expect POLLIN for "you can read EOF".

Back to our original question: how can we portably detect that the socket is
still alive?  We can't do a non-blocking read() either...  -- justin

Re: [Fwd: Re: How to detect is the socket is still open]

Posted by Joe Orton <jo...@redhat.com>.
On Wed, Aug 16, 2006 at 12:01:34AM -0700, Justin Erenkrantz wrote:
> On that second update, there are often 15+ second pauses from svn.a.o
> that causes httpd to close the connection as its idle.  But, when we
> want to reuse that connection later, serf does a pollset_poll() and it
> says that the connection is good to go.  But, it's not and we get an 0
> from read().  This leads to a 'Premature EOF seen from server' error.
> 
> Shouldn't select() be returning POLLERR in this case?  Or, am I nuts?
> Are we hitting some type of stupidity in Darwin?  -- justin

POLLERR would only be set for an RST and "exceptional conditions"; the
same applies to select()+the exceptfds array AFAIK.

There is some inconsistency with handling FIN and sockets across
platforms: http://www.greenend.org.uk/rjk/2001/06/poll.html but yes
you'd generally expect POLLIN for "you can read EOF".

joe

Re: [Fwd: Re: How to detect is the socket is still open]

Posted by Justin Erenkrantz <ju...@erenkrantz.com>.
On 8/3/06, Gonzalo Paniagua Javier <go...@gmail.com> wrote:
> > > It reports that the socket is readable.
> >
> > And when you read it, it returns EOF?
>
> Yes, it returns a 0.

Are you on Mac OS X by any chance?

I'm seeing this same thing with serf via apr_pollset_poll().

select() returns 5 (POLLIN & POLLOUT I think) - but by this point, the
local end has already received a remote FIN.

My repro case (ra_serf / serf / apr trunk) is:

% svn co -r300000 http://svn.apache.org/repos/asf/httpd/httpd/trunk
% svn up -rHEAD trunk

On that second update, there are often 15+ second pauses from svn.a.o
that causes httpd to close the connection as its idle.  But, when we
want to reuse that connection later, serf does a pollset_poll() and it
says that the connection is good to go.  But, it's not and we get an 0
from read().  This leads to a 'Premature EOF seen from server' error.

Shouldn't select() be returning POLLERR in this case?  Or, am I nuts?
Are we hitting some type of stupidity in Darwin?  -- justin

Re: [Fwd: Re: How to detect is the socket is still open]

Posted by Gonzalo Paniagua Javier <go...@gmail.com>.
On 8/3/06, Ruediger Pluem <rp...@apache.org> wrote:
>
>
> On 08/03/2006 02:47 AM, Gonzalo Paniagua Javier wrote:
> >>
> >> What does poll (with timeout zero) return in the case that the socket
> >> has been closed?
> >
> >
> > It reports that the socket is readable.
>
> And when you read it, it returns EOF?

Yes, it returns a 0.

-Gonzalo

Re: [Fwd: Re: How to detect is the socket is still open]

Posted by Ruediger Pluem <rp...@apache.org>.

On 08/03/2006 02:47 AM, Gonzalo Paniagua Javier wrote:
>>
>> What does poll (with timeout zero) return in the case that the socket
>> has been closed?
> 
> 
> It reports that the socket is readable.

And when you read it, it returns EOF?

Regards

Rüdiger


Re: [Fwd: Re: How to detect is the socket is still open]

Posted by Gonzalo Paniagua Javier <go...@gmail.com>.
>
> What does poll (with timeout zero) return in the case that the socket has been closed?

It reports that the socket is readable.

-Gonzalo

Re: [Fwd: Re: How to detect is the socket is still open]

Posted by Mladen Turk <mt...@apache.org>.
Ruediger Pluem wrote:
> Reposting what I sent to Mladen in private. Just missed that
> his address was in to and not dev@apr.apache.org :-)
> 

OK. Here is the new code used in mod_jk
It works for the selected set of platforms
(windows, linux, solaris)

Any comments about other platforms?

int jk_is_socket_connected(jk_sock_t sock)
{
     fd_set fd;
     struct timeval tv;
     int rc;

     FD_ZERO(&fd);
     FD_SET(sock, &fd);

     /* Wait one microsecond */
     tv.tv_sec  = 0;
     tv.tv_usec = 1;

     do {
         rc = select((int)sock + 1, &fd, NULL, NULL, &tv);
#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
         errno = WSAGetLastError() - WSABASEERR;
#endif
     } while (rc == -1 && errno == EINTR);

     if (rc == 0) {
         /* If we get a timeout, then we are still connected */
         return 1;
     }
     else if (rc == 1) {
#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
         u_long nr;
         if (ioctlsocket(sock, FIONREAD, &nr) == 0) {
             return nr == 0 ? 0 : 1;
         }
#else
         int nr;
         if (ioctl(sock, FIONREAD, (void*)&nr) == 0) {
             return nr == 0 ? 0 : 1;
         }
#endif
     }

     return 0;
}