>
>
>This does not actually *say* that the appropriate behavior after EINTR
>is to retry, but reading between the lines one might infer that it will
>work like the nonblocking case, wherein a retry of connect tries to link
>to the existing connection attempt, not start a new one.
>
>What's more important is that a retry will expose the possibility of
>getting EALREADY or EISCONN.  EALREADY certainly must be treated as
>success the same as EINPROGRESS (if it exists on a given platform ---
>better #ifdef it I think).  Not so sure about EISCONN; does that imply
>"you moron, this socket's been open forever", or does it get returned on
>the first iteration that doesn't return EALREADY?
>

Not to worry.  EINPROGRESS, etc, are normally used for select() and 
return the current state of the connection attempt.  connect() in 
blocking mode will normally only return when it is interrupted or 
complete.  In non-blocking mode, it will return immediately with errno 
set to EALREADY, in which case you should spin on the socket connection 
attempt and wait until it returns a good status, i.e. return value=0, or 
if you happen to make a mistake and drop that iteration, EISCONN.

Those of you who are interested in socket operations would probably 
enjoy reading TCP/IP Illustrated, I believe the most recent version is 
#3, sorry I don't have the ISBN handy but most libraries should have v2.

As to your last concern Tom, the cycle should be: return=-1 [repeats 
until connection fails or succeeds], return=0 on success, or -1 on 
failure w/ errno set to appropriate fault, and afterwards, either return 
-1 with errno=EISCONN (already connected with prior success), or 
appropriate fault.

The important part is that if the socket successfully connects, it will 
return a 0.  That should be the last iteration of your spin on that 
connect call.  If you have a mistake in your code and you keep spinning 
on a successfully connected socket, yes you will get EISCONN, i.e. 
"hello..the socket is still connected" :)

Thus a simplified loop should look like this:

do {
    int r;

    r=connect(...);
    if(!r)    /* we're connected, r=0.  exit the loop */
        break;
   
    switch(errno) {    /* connect returns 0 or -1, so this must be -1 */
        case EINTR:    /* we were interrupted by a signal */
            continue;
        default:
            error_log(logfd, "Error connecting, kernel said: %s", 
strerror(errno));
            r=-2;    /* jump out of the loop */
            break;
        }

    } while(r==-1):

This will continue trying the connect call as long as it hasn't returned 
a failure message and the errno is EINTR.  All other -1 return values 
will exit the loop.  As soon as it has connected properly it will also 
exit the loop.

David



Fri, 26 Oct 2001 15:57:01 -0400
David Ford <david@blue-labs.org>
Re: [patch] helps fe-connect.c handle -EINTR more gracefully
David Ford <david@blue-labs.org> writes:
> Thus a simplified loop should look like this:

No, it should *not* look like that.  The fe-connect.c code is designed
to move on as soon as it's convinced that the kernel has accepted the
connection request.  We use a non-blocking connect() call and later
wait for connection complete by probing the select() status.  Looping
on the connect() itself would be a busy-wait, which would be antisocial.

Certainly we can move on as soon as we see EINPROGRESS or EALREADY.
What I'm wondering at the moment is whether we could take EINTR to be
also an indication that the kernel has accepted the connection request,
and proceed forward to the select(), rather than trying the connect()
again.

Although Brent didn't say so very clearly, I think his real concern is
"why are you getting EINTR from a non-blocking connect, and what does
that mean anyway?"  The HPUX man page certainly makes it sound like
this is not distinct from the EINPROGRESS return, and that there's
no need to retry the connect() per se.

			regards, tom lane

Fri, 26 Oct 2001 17:29:09 -0400
Tom Lane <tgl@sss.pgh.pa.us>
Re: [patch] helps fe-connect.c handle -EINTR more gracefully