From: Otto Date: Mon, 14 Jun 2021 09:54:05 +0000 (+0200) Subject: Maintain a sseparate inPos and inWanted, this should fix partial reads, X-Git-Tag: dnsdist-1.7.0-alpha1~138^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ea844a86a56ceaa15c0b43eb3ecea50d9ff24969;p=thirdparty%2Fpdns.git Maintain a sseparate inPos and inWanted, this should fix partial reads, make the code more clear and also allow less resizing. --- diff --git a/pdns/pdns_recursor.cc b/pdns/pdns_recursor.cc index bf7a0d4dba..1aeaf0b223 100644 --- a/pdns/pdns_recursor.cc +++ b/pdns/pdns_recursor.cc @@ -485,9 +485,9 @@ LWResult::Result arecvtcp(PacketBuffer& data, const size_t len, shared_ptrtcphandler = handler; pident->tcpsock = handler->getDescriptor(); // We might have a partial result - data.resize(pos); pident->inMSG = data; - pident->inNeeded = len; + pident->inPos = pos; + pident->inWanted = len; pident->inIncompleteOkay = incompleteOkay; pident->highState = TCPAction::DoingRead; @@ -4157,23 +4157,21 @@ static void TCPIOHandlerIO(int fd, FDMultiplexer::funcparam_t& var) // In the code below, we want to update the state of the fd before calling sendEvent // a sendEvent might close the fd, and some poll multiplexers do not like to manipulate a closed fd - + switch (pid->highState) { case TCPAction::DoingRead: TCPLOG("highState: Reading" << endl); + // In arecvtcp, the buffer was resized already so inWanted bytes will fit // try reading try { - size_t pos = pid->inMSG.size(); - pid->inMSG.resize(pos + pid->inNeeded); // make room for what we'll read - newstate = pid->tcphandler->tryRead(pid->inMSG, pos, pid->inNeeded); + newstate = pid->tcphandler->tryRead(pid->inMSG, pid->inPos, pid->inWanted - pid->inPos); switch (newstate) { case IOState::Done: case IOState::NeedRead: - TCPLOG("tryRead: Done or NeedRead " << int(newstate) << ' ' << pos << '/' << pid->inNeeded << endl); - pid->inMSG.resize(pos); // old content (if there) + new bytes read - pid->inNeeded -= pos; - TCPLOG("TCPIOHandlerIO " << pid->inNeeded << ' ' << pid->inIncompleteOkay << endl); - if (pid->inNeeded == 0 || pid->inIncompleteOkay) { + TCPLOG("tryRead: Done or NeedRead " << int(newstate) << ' ' << pid->inPos << '/' << pid->inWanted << endl); + TCPLOG("TCPIOHandlerIO " << pid->inWanted << ' ' << pid->inIncompleteOkay << endl); + if (pid->inPos == pid->inWanted || (pid->inIncompleteOkay && pid->inPos > 0)) { + pid->inMSG.resize(pid->inPos); // old content (if there) + new bytes read, only relevant for the inIncompleteOkay case newstate = IOState::Done; TCPIOHandlerStateChange(pid->lowState, newstate, pid); MT->sendEvent(*pid, &pid->inMSG); @@ -5930,3 +5928,4 @@ int main(int argc, char **argv) return ret; } + diff --git a/pdns/syncres.hh b/pdns/syncres.hh index a67a0ab216..1bcdf712e9 100644 --- a/pdns/syncres.hh +++ b/pdns/syncres.hh @@ -946,7 +946,8 @@ struct PacketID typedef set chain_t; mutable chain_t chain; shared_ptr tcphandler{nullptr}; - size_t inNeeded{0}; // if this is set, we'll read until inNeeded bytes are read + string::size_type inPos{0}; // how for are we along in the inMSG + size_t inWanted{0}; // if this is set, we'll read until inWanted bytes are read string::size_type outPos{0}; // how far we are along in the outMSG mutable uint32_t nearMisses{0}; // number of near misses - host correct, id wrong int fd{-1};