From 7610a41afe910df6426aa09eae5aad7431d69e36 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 2 Jun 2017 15:02:56 +0200 Subject: TCP output: do not block in the destructor if one connection stalls --- src/TcpSocket.cpp | 22 ++++++++++++++++++++-- src/TcpSocket.h | 5 +++-- src/dabOutput/dabOutputTcp.cpp | 12 +++++++++++- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/TcpSocket.cpp b/src/TcpSocket.cpp index b9824fa..40c1c1a 100644 --- a/src/TcpSocket.cpp +++ b/src/TcpSocket.cpp @@ -2,7 +2,7 @@ Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Copyright (C) 2016 + Copyright (C) 2017 Matthias P. Braendli, matthias.braendli@mpb.li http://www.opendigitalradio.org @@ -132,8 +132,26 @@ ssize_t TcpSocket::recv(void* data, size_t size) } -ssize_t TcpSocket::send(const void* data, size_t size) +ssize_t TcpSocket::send(const void* data, size_t size, int timeout_ms) { + if (timeout_ms) { + struct pollfd fds[1]; + fds[0].fd = m_sock; + fds[0].events = POLLOUT; + + int retval = poll(fds, 1, timeout_ms); + + if (retval == -1) { + stringstream ss; + ss << "TCP Socket send error on poll(): " << strerror(errno); + throw std::runtime_error(ss.str()); + } + else if (retval == 0) { + // Timed out + return 0; + } + } + /* Without MSG_NOSIGNAL the process would receive a SIGPIPE and die */ ssize_t ret = ::send(m_sock, (const char*)data, size, MSG_NOSIGNAL); diff --git a/src/TcpSocket.h b/src/TcpSocket.h index 660515d..9ff09e5 100644 --- a/src/TcpSocket.h +++ b/src/TcpSocket.h @@ -2,7 +2,7 @@ Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Copyright (C) 2016 + Copyright (C) 2017 Matthias P. Braendli, matthias.braendli@mpb.li http://www.opendigitalradio.org @@ -77,9 +77,10 @@ class TcpSocket /** Send data over the TCP connection. * @param data The buffer that will be sent. * @param size Number of bytes to send. + * @param timeout_ms number of milliseconds before timeout * return number of bytes sent or -1 if error */ - ssize_t send(const void* data, size_t size); + ssize_t send(const void* data, size_t size, int timeout_ms=0); /** Receive data from the socket. * @param data The buffer that will receive data. diff --git a/src/dabOutput/dabOutputTcp.cpp b/src/dabOutput/dabOutputTcp.cpp index 2aab48a..f5aebe0 100644 --- a/src/dabOutput/dabOutputTcp.cpp +++ b/src/dabOutput/dabOutputTcp.cpp @@ -89,7 +89,17 @@ class TCPConnection queue.wait_and_pop(data); try { - m_sock.send(&data[0], data.size()); + ssize_t sent = 0; + do { + const int timeout_ms = 10; // Less than one ETI frame + sent = m_sock.send(&data[0], data.size(), timeout_ms); + + if (is_overloaded()) { + m_running = false; + break; + } + } + while (sent == 0); } catch (std::runtime_error& e) { m_running = false; -- cgit v1.2.3