3

The basic code sequence I'm interesting for is (pseudocode)

sendto(some host); // host may be unreachable for now which is normal
...
if(select(readfs, timeout)) // there are some data to read
  recvfrom();

Since Win2000, ICMP packet, which is sent back after sending UDP datagram to unreachable port, triggers select, after that recvfrom fails with WSAECONNRESET. Such behaviour isn't desirable for me, because I want select to finish with timeout in this case (there are no data to read). On Windows this can be solved with WSAIoctl SIO_UDP_CONNRESET ( http://support.microsoft.com/kb/263823 ).

My questions are:

  1. Is SIO_UDP_CONNRESET the best way in this situation?
  2. Are there some other methods to ignore ICMP for "select" or to filter it for recvfrom (maybe, ignoring WSAECONNRESET error on Windows treating it like timeout, can this error be triggered in some other case)?
  3. Are there similar issues on Linux and Unix (Solaris, OpenBSD)?
Yury
  • 3,000
  • 2
  • 24
  • 24
  • Will you only be using the connection once? If not, how will you know when to close the connection if you never get an error telling you the connection is no longer active and should be closed? – Some programmer dude Dec 05 '11 at 09:27
  • I want to continue sending datagrams until remote host (actually it is some embedded system) will be up or user terminate this action. – Yury Dec 05 '11 at 11:42
  • I hit this error when porting an application from Linux. In my case it is a non-blocking broadcast of UDP datagrams and I do not want to close the connection at all, if client dies I start getting WSAECONNRESET errors on recv on the server! It seems error does not clear. Fixed by that SIO_UDP_CONNRESET but seems to me like a bug in Winsock. – dashesy Oct 23 '12 at 00:13

1 Answers1

2

select()'s readfds set really just reports that a read() on the socket won't block -- it doesn't promise anything about whether or not there is actual data available to read.

I don't know what specifically you're trying to accomplish with the two-second timeout rather than just sleeping forever -- nor why you can't just add an if block to check for WSAECONNRESET from recvfrom() -- but it feels like you've got an overly-complicated design if it doesn't handle this case well.

The select_tut(2) manpage on many Linux systems has some guidelines for properly using select(). Here's several rules that seem most apropos to your situation:

   1.  You should always try to use select() without a timeout.
       Your program should have nothing to do if there is no
       data available.  Code that depends on timeouts is not
       usually portable and is difficult to debug.

   ...

   3.  No file descriptor must be added to any set if you do not
       intend to check its result after the select() call, and
       respond appropriately.  See next rule.

   4.  After select() returns, all file descriptors in all sets
       should be checked to see if they are ready.
sarnold
  • 102,305
  • 22
  • 181
  • 238
  • I want to support gentle user interrupt (actually this module is an only small part of the software), so I periodically call select with some timeout and recvfrom, if there are data. I want to read data, if available, with minimum possible timeout, so I can't use sleep; on the other hand, if there are no data there shouldn't be any overhead. Thanks much for reply, I will look into. – Yury Dec 05 '11 at 11:46
  • If the user "interrupt" is delivered via a socket, you can add it to your `select` call... – sarnold Dec 05 '11 at 11:48
  • No, I mean interrupt (=terminate) from the UI. This code runs in a special thread, and this thread is controlled from another module. Sure, it is possible to hard-terminate thread, but I need careful and controlled exit (for mutexes etc.). – Yury Dec 05 '11 at 12:20
  • That's excellent! Set up a socket between the UI and the module; when the UI wants to terminate, send the terminate command down the socket. That way you can respond to terminate commands immediately rather than waiting two seconds _and_ you can remove the timeout that is complicating the `select` code. – sarnold Dec 05 '11 at 12:25
  • Thanks much, very interesting idea. Could you point me to realization for Linux and Windows (I'v read [another SOF topic](http://stackoverflow.com/questions/7117958/trying-to-exit-from-a-blocking-udp-socket-read) and it's not quite clear for me). – Yury Dec 06 '11 at 05:49
  • On the POSIX systems, you can use `pipe(2)` to create a unidirectional pipe. When your application starts, create a `pipe(2)`, `fork(2)`, hand the read-end of the pipe to the module and let the UI keep the write end of the pipe. The UI will `write(2)` commands into the pipe and your module will `select(2)` on its end in addition to all the other sockets it needs to listen to. – sarnold Dec 06 '11 at 06:58
  • OK! Moreover, to get cross-platform solution, one could create another socket bound to any available port (port==0), and GUI, knowing that port, could send any data through loopback to trigger infinite `select`, which includes "main" work socket and this "auxiliary" one. – Yury Dec 06 '11 at 07:16
  • That's it exactly! Involving TCP for this seemed a bit much, but you're right, if cross-platform is your goal, that's just fine. – sarnold Dec 06 '11 at 07:18
  • I've just realized that this improves GUI<->thread interaction design, but lefts the main question open (select will return on ICMP, causing recvfrom fail with WSAECONNRESET). – Yury Dec 06 '11 at 09:38
  • Sure -- can't you just handle the reset connection? Connections can be reset anywhere, and if you don't handle the reset immediately after whichever `select()` reported it, your application might get very confused. – sarnold Dec 06 '11 at 09:42
  • Yes, I've make automatic reset for connections, which becomes disconnected due to an error. However, such behaviour isn't very transparent for me. Moreover, I get such packets for one host, and miss then for another one, while both are down. – Yury Dec 07 '11 at 06:53
  • UDP provides _no_ guarantees that you will get any notification when a host is down. It is a kindness from some system in the middle when you are notified that a host is down. :) – sarnold Dec 07 '11 at 06:55