From 62e08d084c9a49effce5ac246e6e6f786d1a8b92 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 17 Dec 2024 12:12:35 -0500 Subject: [PATCH] Don't Error when sendto() errors with ENETUNREACH or EHOSTUNREACH Don't latch for transient TX errors (eg. routing change when NIC unplugged). Eliminate SocketBusy since SOCK_EWOULDBLOCK is no longer quite such a special case. --- src/driver/device.cpp | 22 +++++++++++++++++----- src/util/utils.cpp | 4 ---- src/util/utils.h | 6 ------ 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/driver/device.cpp b/src/driver/device.cpp index 1289ea1..c851553 100644 --- a/src/driver/device.cpp +++ b/src/driver/device.cpp @@ -449,9 +449,17 @@ void Device::handle_send(Guard& G) // non-blocking sendto(), so we don't unlock here sock.sendto(peer_addr, (const char*)&msg.buf[0], msg.buf.size()*4); cnt_sent++; - }catch(SocketBusy&){ - want_to_send = true; - return; + }catch(SocketError& e){ + if(e.code==SOCK_EWOULDBLOCK) { + want_to_send = true; + return; + } else if(e.code==ENETUNREACH || e.code==EHOSTUNREACH) { + IFDBG(1, "Unable to send to %s : (%d) %s", peer_name.c_str(), e.code, e.what()); + // Don't throw (and latch into Error state) what is probably + // a transient error. Will timeout since packet wasn't sent + } else { + throw; + } } IFDBG(1, "Send seq=%08x %zu bytes", (unsigned)msg.seq, msg.buf.size()*4u); @@ -952,8 +960,12 @@ void Device::run() doProcess[i] = true; cnt_recv++; cnt_recv_bytes += unsigned(feedUDPHeaderSize) + bufs[i].size(); - }catch(SocketBusy&){ - break; + }catch(SocketError& e){ + if(e.code==SOCK_EWOULDBLOCK) { + break; + } else { + throw; + } } if(!doProcess[i]) { diff --git a/src/util/utils.cpp b/src/util/utils.cpp index f3b1459..c3e5c47 100644 --- a/src/util/utils.cpp +++ b/src/util/utils.cpp @@ -106,8 +106,6 @@ void Socket::sendto(const osiSockAddr& dest, const char* buf, size_t buflen) con ssize_t ret = ::sendto(sock, buf, buflen, 0, &dest.sa, sizeof(dest)); if(ret<0) { int code = SOCKERRNO; - if(code==SOCK_EWOULDBLOCK) - throw SocketBusy(); throw SocketError(code); } else if(size_t(ret)!=buflen) throw std::runtime_error("Incomplete sendto()"); @@ -119,8 +117,6 @@ size_t Socket::recvfrom(osiSockAddr& src, char* buf, size_t buflen) const ssize_t ret = ::recvfrom(sock, buf, buflen, 0, &src.sa, &len); if(ret<0) { int code = SOCKERRNO; - if(code==SOCK_EWOULDBLOCK) - throw SocketBusy(); throw SocketError(code); } return size_t(ret); diff --git a/src/util/utils.h b/src/util/utils.h index 5973b4d..e1a1beb 100644 --- a/src/util/utils.h +++ b/src/util/utils.h @@ -59,12 +59,6 @@ struct epicsShareClass SocketError : public std::exception const char *what() const throw(); }; -struct epicsShareClass SocketBusy : public SocketError -{ - SocketBusy() :SocketError(SOCK_EWOULDBLOCK) {} - virtual ~SocketBusy() throw() {} -}; - // RAII handle to ensure that sockets aren't leaked // and helper to make socket calls throw SocketError struct Socket