From 3d01ad46b226a3ae2f0a76aa71b26a0dfee36d4b Mon Sep 17 00:00:00 2001 From: Simon Corrodi Date: Fri, 17 Jul 2026 18:38:34 -0500 Subject: [PATCH] TCPTransmitterSocket: handle partial sends and retry on EINTR/EAGAIN ::send() may transmit fewer bytes than requested; loop until the whole buffer is written. Retry instead of throwing on EINTR and EAGAIN (temporary back-pressure), and throw if send() returns 0. --- .../NetworkUtilities/TCPTransmitterSocket.cc | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/otsdaq/NetworkUtilities/TCPTransmitterSocket.cc b/otsdaq/NetworkUtilities/TCPTransmitterSocket.cc index 60b2ed9fe..9963c83d0 100644 --- a/otsdaq/NetworkUtilities/TCPTransmitterSocket.cc +++ b/otsdaq/NetworkUtilities/TCPTransmitterSocket.cc @@ -37,9 +37,22 @@ void TCPTransmitterSocket::send(char const* buffer, << std::endl; return; } - std::size_t sentBytes = ::send(getSocketId(), buffer, size, MSG_NOSIGNAL); - if(sentBytes == static_cast(-1)) + std::size_t totalSent = 0; + while(totalSent < size) { + ssize_t sentBytes = + ::send(getSocketId(), buffer + totalSent, size - totalSent, MSG_NOSIGNAL); + if(sentBytes > 0) + { + totalSent += static_cast(sentBytes); + continue; + } + + if(sentBytes == 0) + { + throw std::runtime_error("Write: returned 0 bytes, connection may be closed"); + } + switch(errno) { // case EINVAL: @@ -62,14 +75,11 @@ void TCPTransmitterSocket::send(char const* buffer, strerror(errno)); } case EINTR: - // TODO: Check for user interrupt flags. - // Beyond the scope of this project - // so continue normal operations. - case EAGAIN: { - // Temporary error. - throw std::runtime_error(std::string("Write: temporary error: ") + - strerror(errno)); - } + // Interrupted by signal; retry send. + continue; + case EAGAIN: + // Temporary back-pressure; retry send. + continue; default: { throw std::runtime_error(std::string("Write: returned -1: ") + strerror(errno));