From 5fc89ddc7a74d3b88abcbe324fb85f45bc03d34d Mon Sep 17 00:00:00 2001 From: Otto Date: Mon, 8 Nov 2021 13:32:50 +0100 Subject: [PATCH] Use a global timeout for the various recv's we're doing to get a control message --- pdns/rec_channel.cc | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/pdns/rec_channel.cc b/pdns/rec_channel.cc index b288abe832..41faffddb6 100644 --- a/pdns/rec_channel.cc +++ b/pdns/rec_channel.cc @@ -152,16 +152,30 @@ void RecursorControlChannel::send(int fd, const Answer& msg, unsigned int timeou } } -RecursorControlChannel::Answer RecursorControlChannel::recv(int fd, unsigned int timeout) +static void waitForRead(int fd, unsigned int timeout, time_t start) { - int ret = waitForData(fd, timeout, 0); + time_t elapsed = time(nullptr) - start; + if (elapsed >= timeout) { + throw PDNSException("Timeout waiting for control channel data"); + } + int ret = waitForData(fd, timeout - elapsed, 0); if (ret == 0) { - throw PDNSException("Timeout waiting for answer from control channel"); + throw PDNSException("Timeout waiting for control channel data"); } +} + +RecursorControlChannel::Answer RecursorControlChannel::recv(int fd, unsigned int timeout) +{ + // timeout covers the operation of all read ops combined + const time_t start = time(nullptr); + + waitForRead(fd, timeout, start); int err; if (::recv(fd, &err, sizeof(err), 0) != sizeof(err)) { throw PDNSException("Unable to receive return status over control channel: " + stringerror()); } + + waitForRead(fd, timeout, start); size_t len; if (::recv(fd, &len, sizeof(len), 0) != sizeof(len)) { throw PDNSException("Unable to receive length over control channel: " + stringerror()); @@ -171,6 +185,7 @@ RecursorControlChannel::Answer RecursorControlChannel::recv(int fd, unsigned int str.reserve(len); while (str.length() < len) { char buffer[1024]; + waitForRead(fd, timeout, start); size_t toRead = std::min(len - str.length(), sizeof(buffer)); ssize_t recvd = ::recv(fd, buffer, toRead, 0); if (recvd <= 0) { -- 2.47.2