]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Do not add request to a wait chain that's already processed or being processed. 9707/head
authorOtto Moerbeek <otto@drijf.net>
Wed, 11 Nov 2020 11:02:50 +0000 (12:02 +0100)
committerOtto Moerbeek <otto@drijf.net>
Wed, 11 Nov 2020 11:18:06 +0000 (12:18 +0100)
The following scenario can occur. Multiple concurrent clients doing the same query A
are needed to trigger it:

1. Incoming request A, which has a need for request X
2. Add request X to chain because we already have an identical outstanding request
3. We receive the reply for X
4. We process the chain
5. In the meantime a new request for X that's identical is added to the chain
6. The added id in step 5 is not being processed anymore -> timeout

This can happen if request X has TTL 0, otherwise the record cache would have a hit.

pdns/mtasker.hh
pdns/pdns_recursor.cc
pdns/syncres.hh

index ed6b02d0c59ca23b3c763a58a97c8ed8bfabb48f..2b9301d9a17942382a6a3cc4a7c8c7be7163cd7f 100644 (file)
@@ -81,7 +81,7 @@ public:
     EventKey key;
     std::shared_ptr<pdns_ucontext_t> context;
     struct timeval ttd;
-    int tid;    
+    int tid;
   };
 
   typedef multi_index_container<
index d22c8e9843ad6311c419aa58586af6da95405221..49cf2c463cb8ae34d6973be8e0b4698f2222ff4a 100644 (file)
@@ -653,7 +653,7 @@ LWResult::Result asendto(const char *data, size_t len, int flags,
   pair<MT_t::waiters_t::iterator, MT_t::waiters_t::iterator> chain=MT->d_waiters.equal_range(pident, PacketIDBirthdayCompare());
 
   for(; chain.first != chain.second; chain.first++) {
-    if(chain.first->key.fd > -1) { // don't chain onto existing chained waiter!
+    if(chain.first->key.fd > -1 && !chain.first->key.closed) { // don't chain onto existing chained waiter or a chain already processed
       /*
       cerr<<"Orig: "<<pident.domain<<", "<<pident.remote.toString()<<", id="<<id<<endl;
       cerr<<"Had hit: "<< chain.first->key.domain<<", "<<chain.first->key.remote.toString()<<", id="<<chain.first->key.id
@@ -3814,6 +3814,9 @@ static void handleTCPClientWritable(int fd, FDMultiplexer::funcparam_t& var)
 // resend event to everybody chained onto it
 static void doResends(MT_t::waiters_t::iterator& iter, PacketID resend, const string& content)
 {
+  // We close the chain for new entries, since they won't be processed anyway
+  iter->key.closed = true;
+
   if(iter->key.chain.empty())
     return;
   //  cerr<<"doResends called!\n";
index b38203bada4df1a6dca38973aec9573f716e9a2f..ccb6cfd47b9cc8a1e0a9d289f449e0ec7ac89656 100644 (file)
@@ -908,7 +908,7 @@ LWResult::Result arecvtcp(string& data, size_t len, Socket* sock, bool incomplet
 
 struct PacketID
 {
-  PacketID() : id(0), type(0), sock(0), inNeeded(0), inIncompleteOkay(false), outPos(0), nearMisses(0), fd(-1)
+  PacketID() : id(0), type(0), sock(0), inNeeded(0), inIncompleteOkay(false), outPos(0), nearMisses(0), fd(-1), closed(false)
   {
     remote.reset();
   }
@@ -930,6 +930,7 @@ struct PacketID
   mutable chain_t chain;
   mutable uint32_t nearMisses; // number of near misses - host correct, id wrong
   int fd;
+  mutable bool closed; // Processing already started, don't accept new chained ids
 
   bool operator<(const PacketID& b) const
   {