Re: Checking for closed/broken connections

Alwin <[email protected]>
Newsgroups gmane.mail.libetpan.user
Message-ID <[email protected]>
On Wednesday 21 January 2004 10:39, you wrote:
> Alwin a écrit :
> > read from a socket not marked as readable or it ends in a endless read
> > 'cause you have the socket marked as blocking (why?)
>
> you can set a mailstream_delay (or such thing like that) to set the delay.
See remarks below: delay won't work with read/recv or write/send when socket 
is blocking. this is just for select.

> > -tcp/ip file-descriptors I think checking for exceptions is a good idea.
> > There are such a lot of thing can going wrong...
>
> is this an alternative to sigpipe ?
See comment to recv.

>
> For example, when the socket is closed on the other side ?
See remarks below: most important thing is when the low-level connection, eg. 
the interface is closed/broken, we have cable problems and so on. All the 
stuff UNDER the tcp/ip layer.

> > Why not using recv/send on tcp/ip sockets? In most cases it should be
> > have a little better handling for that as pure read/write.
>
> it is the same.
No.
with recv you can switch of "SIGPIPE" ;) see manpage about the flags from recv 
(third parameter). read just implements a standard-call on file-descriptors. 
recv / send gives an interface to the socket specials.

> > of view.... Or is there something I didn't see or not understand the
> > right way?
>
> you can use the delay.
No!
Well, when the interface is remove what ever the reasons are, select will 
mostly go on. 
But when using blocking read, than it will never return. With select you just 
check if there ARE data to read. Or the socket is ready for write. if you 
make a select for read, and ignore the result and make a read on a blocking 
socket even if there are no data, the application hangs forever. means, with 
select you check if the next operation will run into high-level trouble or 
not.
The timeout in the select-call is NOT for read/write! it is just the timeout 
how long select should wait for a result!

In one of my (not-public) applications I made it this way: I'm waiting for a 
response. Socket is non-blocking. best case: select returns that i can read 
data, reading it and ok. sometimes select returns "Ok, socket ready for read" 
but recv returns -1. if errno is set to "EWOULDBLOCK" I retry it after a few 
millisecond up to a most-retry-count. (mostly 10 or 15). If than the socket 
even returns EWOULDBLOCK or EAGAIN something goes real wrong and I'm closing 
it and try to reopen.
If recv returns 0 and select told me that there is something to read, the 
socket is closed on the other side so I'm closing my side, too.

Even before writing data you should make a select on read. Why? when the 
connection is closed on the other side, than the readable flag is set, but 
data returned is 0 -> socket is closed, closing down our socket and stop 
writing. Otherwise it will result in an error. (Of course, if there are real 
data them must be stored into a buffer)

IMHO (and realy IMHO) the recv/send design should be a little bit other then 
now:

- implementing a function "readwrite_socket" this fun will be called from the 
writing and reading part of mailstream_low, not different functions for 
reading and writing.
- mailstream_low_write stores the data to write into a write buffer.
- when calling readwrite_socket (proof of concept taken from a c++ socket 
implementation):

---- snap -----

int readwrite_socket(mailstream_low*st) {
   bool wset = false;
   int closing = 0;

    fd_set in,out,exc;
    FD_ZERO(&in);
    FD_ZERO(&out);
    FD_ZERO(&exc);
    FD_SET(m_Socket,&in);
    if (st->writebufferlength > 0) {
            FD_SET(m_Socket,&out);
            wset = true;
    }
  FD_SET(m_Socket,&exc);
  if (select(FD_SETSIZE,&in,&out,&exc,&tv) < 0) {
    // error handling here
 }
 if (FD_ISSET(m_Socket,&exc)) {
    OnException();
    return -1;
}
if (FD_ISSET(m_Socket,&in)) {
   // reading data with helperfun which will mark the socket closing
   // if it is closed! when reading nonblocked it should retry it for a few
   // milliseconds when int i recv(....) == -1 and errno==EWOULDBLOCK
   // return -1 on failure/close, else amount data read.
   closing = read_data(st);
}
if (closing==-1 && wset && FD_ISSET(m_Socket,&out)) {
   // write out buffer of st with helperfun - same words on
   // blocking/nonblocking sockets. after this operation st holds
   // holds the rest-buffer not yet written or write_data implements a loop 
   // writing out ALL data. 
   if (write_data(st)<0) {
      closing = -1;
   }
}

if (closing==-1) {
  // something goes wrong or other side has closed connection
  // do something here in that case
}

// returns amount data read or -1 if failure
return closing;
}
---- snap ----

- after each write mailstream must check for new arrived data and do something 
  with them (when arrived).

from the manpage of recv:

If no messages are available at the socket, the receive calls wait  for
a message to arrive, unless the socket is nonblocking (see fcntl(2)) in
which case the value -1 is returned and the external variable errno set
to EAGAIN.  The receive calls normally return any data available, up to
the requested amount, rather than  waiting  for  receipt  of  the  full
amount requested.

Means: you MUST check if there are real data to read, this moment you just 
ignore that value -> it results in a neverending block in worst case. (Or 
30-minute-block when imap-server is closing the connection after that time 
and cable isn't broken)
And check for readable set and read-data-length == 0 -> other side has closed.

So, I hope I could explain my ideas a little bit better ( I should learn 
french so the text must not translate so much ;) Please, don't misunderstand: 
them are realy ideas. Your'e code isn't wrong :)

CU

Rajko



-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.