]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Stricter IO checks in the TCP unit tests and more OOOR tests
authorRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 15 Feb 2021 14:47:56 +0000 (15:47 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 2 Mar 2021 10:39:54 +0000 (11:39 +0100)
pdns/dnsdistdist/test-dnsdisttcp_cc.cc

index 77bad0e33e65401c9110eaad73e206c5f7431e85..e43e00585df3fa0d6861642ff8bf85f9597ebabe 100644 (file)
@@ -99,7 +99,7 @@ BOOST_AUTO_TEST_SUITE(test_dnsdisttcp_cc)
 struct ExpectedStep
 {
 public:
-  enum class ExpectedRequest { handshake, connect, read, write, close };
+  enum class ExpectedRequest { handshakeClient, readFromClient, writeToClient, closeClient, connectToBackend, readFromBackend, writeToBackend, closeBackend };
 
   ExpectedStep(ExpectedRequest r, IOState n, size_t b = 0, std::function<void(int descriptor, const ExpectedStep& step)> fn = nullptr): cb(fn), request(r), nextState(n), bytes(b)
   {
@@ -112,13 +112,6 @@ public:
 };
 
 static std::deque<ExpectedStep> s_steps;
-static ExpectedStep getStep()
-{
-  BOOST_REQUIRE(!s_steps.empty());
-  auto res = s_steps.front();
-  s_steps.pop_front();
-  return res;
-}
 
 static PacketBuffer s_readBuffer;
 static PacketBuffer s_writeBuffer;
@@ -129,7 +122,7 @@ std::ostream& operator<<(std::ostream &os, const ExpectedStep::ExpectedRequest d
 
 std::ostream& operator<<(std::ostream &os, const ExpectedStep::ExpectedRequest d)
 {
-  static const std::vector<std::string> requests = { "handshake", "connect", "read", "write", "close" };
+  static const std::vector<std::string> requests = { "handshake with client", "read from client", "write to client", "close connection to client", "connect to the backend", "read from the backend", "write to the backend", "close connection to backend" };
   os<<requests.at(static_cast<size_t>(d));
   return os;
 }
@@ -146,7 +139,7 @@ public:
   IOState tryHandshake() override
   {
     auto step = getStep();
-    BOOST_REQUIRE_EQUAL(step.request, ExpectedStep::ExpectedRequest::handshake);
+    BOOST_REQUIRE_EQUAL(step.request, ExpectedStep::ExpectedRequest::handshakeClient);
 
     return step.nextState;
   }
@@ -158,7 +151,7 @@ public:
     }
 
     auto step = getStep();
-    BOOST_REQUIRE_EQUAL(step.request, ExpectedStep::ExpectedRequest::write);
+    BOOST_REQUIRE_EQUAL(step.request, !d_client ? ExpectedStep::ExpectedRequest::writeToClient : ExpectedStep::ExpectedRequest::writeToBackend);
 
     if (step.bytes == 0) {
       if (step.nextState == IOState::NeedWrite) {
@@ -188,7 +181,7 @@ public:
     }
 
     auto step = getStep();
-    BOOST_REQUIRE_EQUAL(step.request, ExpectedStep::ExpectedRequest::read);
+    BOOST_REQUIRE_EQUAL(step.request, !d_client ? ExpectedStep::ExpectedRequest::readFromClient : ExpectedStep::ExpectedRequest::readFromBackend);
 
     if (step.bytes == 0) {
       if (step.nextState == IOState::NeedRead) {
@@ -203,6 +196,7 @@ public:
     if (step.bytes < toRead) {
       toRead = step.bytes;
     }
+
     BOOST_REQUIRE_GE(buffer.size(), toRead);
     BOOST_REQUIRE_GE(externalBuffer.size(), toRead);
 
@@ -216,11 +210,7 @@ public:
   IOState tryConnect(bool fastOpen, const ComboAddress& remote) override
   {
     auto step = getStep();
-    BOOST_REQUIRE_EQUAL(step.request, ExpectedStep::ExpectedRequest::connect);
-
-    if (step.cb) {
-      step.cb(d_descriptor, step);
-    }
+    BOOST_REQUIRE_EQUAL(step.request, ExpectedStep::ExpectedRequest::connectToBackend);
 
     return step.nextState;
   }
@@ -228,7 +218,7 @@ public:
   void close() override
   {
     auto step = getStep();
-    BOOST_REQUIRE_EQUAL(step.request, ExpectedStep::ExpectedRequest::close);
+    BOOST_REQUIRE_EQUAL(step.request, !d_client ? ExpectedStep::ExpectedRequest::closeClient : ExpectedStep::ExpectedRequest::closeBackend);
   }
 
   bool hasBufferedData() const override
@@ -270,6 +260,19 @@ public:
     return 0;
   }
 private:
+  ExpectedStep getStep() const
+  {
+    BOOST_REQUIRE(!s_steps.empty());
+    auto step = s_steps.front();
+    s_steps.pop_front();
+
+    if (step.cb) {
+      step.cb(d_descriptor, step);
+    }
+
+    return step;
+  }
+
   const int d_descriptor;
   bool d_client{false};
 };
@@ -318,7 +321,9 @@ public:
 
     gettimeofday(tv, nullptr); // MANDATORY
 
-    for (const auto fd : ready) {
+    /* 'ready' might be altered by a callback while we are iterating */
+    const auto readyFDs = ready;
+    for (const auto fd : readyFDs) {
       {
         const auto& it = d_readCallbacks.find(fd);
 
@@ -408,10 +413,10 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_SelfAnswered)
     s_readBuffer = query;
     s_writeBuffer.clear();
     s_steps = {
-      { ExpectedStep::ExpectedRequest::handshake, IOState::Done },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
     };
     s_processQuery = [](DNSQuestion& dq, ClientState& cs, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
       return ProcessQueryResult::Drop;
@@ -428,12 +433,12 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_SelfAnswered)
     s_readBuffer = query;
     s_writeBuffer.clear();
     s_steps = {
-      { ExpectedStep::ExpectedRequest::handshake, IOState::Done },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, 65537 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 0 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, 65537 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
     };
     s_processQuery = [](DNSQuestion& dq, ClientState& cs, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
       // Would be nicer to actually turn it into a response
@@ -455,17 +460,17 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_SelfAnswered)
     s_readBuffer = query;
     s_writeBuffer.clear();
     s_steps = {
-      { ExpectedStep::ExpectedRequest::handshake, IOState::NeedWrite },
-      { ExpectedStep::ExpectedRequest::handshake, IOState::NeedRead },
-      { ExpectedStep::ExpectedRequest::handshake, IOState::Done },
-      { ExpectedStep::ExpectedRequest::read, IOState::NeedRead, 1 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 1 },
-      { ExpectedStep::ExpectedRequest::read, IOState::NeedRead, query.size() - 3 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 1 },
-      { ExpectedStep::ExpectedRequest::write, IOState::NeedWrite, query.size() - 1},
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, 1 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 0 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::NeedWrite },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::NeedRead },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 1 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 1 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, query.size() - 3 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 1 },
+      { ExpectedStep::ExpectedRequest::writeToClient, IOState::NeedWrite, query.size() - 1},
+      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, 1 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
     };
     s_processQuery = [](DNSQuestion& dq, ClientState& cs, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
       // Would be nicer to actually turn it into a response
@@ -490,10 +495,10 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_SelfAnswered)
     s_readBuffer = query;
     s_writeBuffer.clear();
     s_steps = {
-      { ExpectedStep::ExpectedRequest::handshake, IOState::Done },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
     };
     s_processQuery = [](DNSQuestion& dq, ClientState& cs, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
       throw std::runtime_error("Something unexpected happened");
@@ -512,16 +517,16 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_SelfAnswered)
     size_t count = 10000;
     s_readBuffer.clear();
     s_writeBuffer.clear();
-    s_steps = { { ExpectedStep::ExpectedRequest::handshake, IOState::Done } };
+    s_steps = { { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done } };
 
     for (size_t idx = 0; idx < count; idx++) {
       s_readBuffer.insert(s_readBuffer.end(), query.begin(), query.end());
-      s_steps.push_back({ ExpectedStep::ExpectedRequest::read, IOState::Done, 2 });
-      s_steps.push_back({ ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 });
-      s_steps.push_back({ ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() + 2 });
+      s_steps.push_back({ ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 });
+      s_steps.push_back({ ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 });
+      s_steps.push_back({ ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, query.size() + 2 });
     };
-    s_steps.push_back({ ExpectedStep::ExpectedRequest::read, IOState::Done, 0 });
-    s_steps.push_back({ ExpectedStep::ExpectedRequest::close, IOState::Done });
+    s_steps.push_back({ ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 });
+    s_steps.push_back({ ExpectedStep::ExpectedRequest::closeClient, IOState::Done });
 
     size_t counter = 0;
     s_processQuery = [&counter](DNSQuestion& dq, ClientState& cs, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
@@ -541,10 +546,10 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_SelfAnswered)
     s_readBuffer = query;
     s_writeBuffer.clear();
     s_steps = {
-      { ExpectedStep::ExpectedRequest::handshake, IOState::Done },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::NeedRead, query.size() - 2 - 2 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, query.size() - 2 - 2 },
+      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
     };
     s_processQuery = [](DNSQuestion& dq, ClientState& cs, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
       /* should not be reached */
@@ -578,11 +583,11 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_SelfAnswered)
     s_readBuffer = query;
     s_writeBuffer.clear();
     s_steps = {
-      { ExpectedStep::ExpectedRequest::handshake, IOState::Done },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
-      { ExpectedStep::ExpectedRequest::write, IOState::NeedWrite, 1 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::writeToClient, IOState::NeedWrite, 1 },
+      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
     };
     s_processQuery = [](DNSQuestion& dq, ClientState& cs, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
       return ProcessQueryResult::SendAnswer;
@@ -647,17 +652,17 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionWithProxyProtocol_SelfAnswered)
     s_writeBuffer.clear();
 
     s_steps = {
-      { ExpectedStep::ExpectedRequest::handshake, IOState::Done },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, s_proxyProtocolMinimumHeaderSize },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, proxyPayload.size() - s_proxyProtocolMinimumHeaderSize },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, 65537 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, 65537 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 0 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, s_proxyProtocolMinimumHeaderSize },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, proxyPayload.size() - s_proxyProtocolMinimumHeaderSize },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, 65537 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, 65537 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
     };
     s_processQuery = [](DNSQuestion& dq, ClientState& cs, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
       return ProcessQueryResult::SendAnswer;
@@ -684,9 +689,9 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionWithProxyProtocol_SelfAnswered)
     s_writeBuffer.clear();
 
     s_steps = {
-      { ExpectedStep::ExpectedRequest::handshake, IOState::Done },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, s_proxyProtocolMinimumHeaderSize },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, s_proxyProtocolMinimumHeaderSize },
+      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
     };
     s_processQuery = [](DNSQuestion& dq, ClientState& cs, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
       return ProcessQueryResult::SendAnswer;
@@ -711,10 +716,10 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionWithProxyProtocol_SelfAnswered)
     s_writeBuffer.clear();
 
     s_steps = {
-      { ExpectedStep::ExpectedRequest::handshake, IOState::Done },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, s_proxyProtocolMinimumHeaderSize },
-      { ExpectedStep::ExpectedRequest::read, IOState::NeedRead, proxyPayload.size() - s_proxyProtocolMinimumHeaderSize - 1},
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, s_proxyProtocolMinimumHeaderSize },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, proxyPayload.size() - s_proxyProtocolMinimumHeaderSize - 1},
+      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
     };
     s_processQuery = [](DNSQuestion& dq, ClientState& cs, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
       return ProcessQueryResult::SendAnswer;
@@ -762,8 +767,6 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
   const uint8_t sizeBytes[] = { static_cast<uint8_t>(querySize / 256), static_cast<uint8_t>(querySize % 256) };
   query.insert(query.begin(), sizeBytes, sizeBytes + 2);
 
-  g_verbose = true;
-
   g_proxyProtocolACL.clear();
 
   {
@@ -776,20 +779,20 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
     s_backendWriteBuffer.clear();
 
     s_steps = {
-      { ExpectedStep::ExpectedRequest::handshake, IOState::Done },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
       /* opening a connection to the backend */
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, query.size() },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 },
       /* closing client connection */
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
       /* closing a connection to the backend */
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
     };
     s_processQuery = [tlsCtx](DNSQuestion& dq, ClientState& cs, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
 
@@ -821,18 +824,18 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
     s_backendWriteBuffer.clear();
 
     s_steps = {
-      { ExpectedStep::ExpectedRequest::handshake, IOState::Done },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
       /* opening a connection to the backend */
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, query.size() - 2 },
       /* closing client connection */
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
       /* closing a connection to the backend */
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
     };
     s_processQuery = [tlsCtx](DNSQuestion& dq, ClientState& cs, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
 
@@ -863,18 +866,18 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
     s_backendWriteBuffer.clear();
 
     s_steps = {
-      { ExpectedStep::ExpectedRequest::handshake, IOState::Done },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
       /* opening a connection to the backend */
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, query.size() - 2 },
       /* closing client connection */
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
       /* closing a connection to the backend */
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
     };
     s_processQuery = [tlsCtx](DNSQuestion& dq, ClientState& cs, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
 
@@ -909,18 +912,18 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
     s_backendWriteBuffer.clear();
 
     s_steps = {
-      { ExpectedStep::ExpectedRequest::handshake, IOState::Done },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
       /* opening a connection to the backend */
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, query.size() - 2 },
       /* closing client connection */
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
       /* closing a connection to the backend */
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
     };
     s_processQuery = [tlsCtx](DNSQuestion& dq, ClientState& cs, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
 
@@ -955,42 +958,42 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
     s_backendWriteBuffer.clear();
 
     s_steps = {
-      { ExpectedStep::ExpectedRequest::handshake, IOState::Done },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
       /* connect to backend */
-      { ExpectedStep::ExpectedRequest::connect, IOState::NeedWrite, 0, [&threadData](int desc, const ExpectedStep& step) {
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::NeedWrite, 0, [&threadData](int desc, const ExpectedStep& step) {
           /* set the outgoing descriptor (backend connection) as ready */
           dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(desc);
         }
       },
       /* send query */
-      { ExpectedStep::ExpectedRequest::write, IOState::NeedWrite, 1 },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() - 1 },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::NeedWrite, 1 },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() - 1 },
       /* read response */
-      { ExpectedStep::ExpectedRequest::read, IOState::NeedRead, 1 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 1 },
-      { ExpectedStep::ExpectedRequest::read, IOState::NeedRead, query.size() - 3 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 1 },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 1 },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 1 },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, query.size() - 3 },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 1 },
       /* write response to client */
-      { ExpectedStep::ExpectedRequest::write, IOState::NeedWrite, query.size() - 1 },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, 1 },
+      { ExpectedStep::ExpectedRequest::writeToClient, IOState::NeedWrite, query.size() - 1 },
+      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, 1 },
       /* read second query */
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
       /* write second query to backend */
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
       /* read second response */
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, query.size() - 2 },
       /* write second response */
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() },
+      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, query.size() },
       /* read from client */
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 },
       /* close connection to client */
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
       /* close connection to the backend, eventually */
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
     };
 
     auto backend = std::make_shared<DownstreamState>(ComboAddress("192.0.2.42:53"), ComboAddress("0.0.0.0:0"), 0, std::string(), 1, false);
@@ -1027,37 +1030,37 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
     s_backendWriteBuffer.clear();
 
     s_steps = {
-      { ExpectedStep::ExpectedRequest::handshake, IOState::Done },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
       /* opening a connection to the backend (5 tries by default) */
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done, 0, [](int descriptor, const ExpectedStep& step) {
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done, 0, [](int descriptor, const ExpectedStep& step) {
           throw NetworkError("Connection refused by the backend");
         }
       },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done, 0, [](int descriptor, const ExpectedStep& step) {
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done, 0, [](int descriptor, const ExpectedStep& step) {
           throw NetworkError("Connection refused by the backend");
         }
       },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done, 0, [](int descriptor, const ExpectedStep& step) {
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done, 0, [](int descriptor, const ExpectedStep& step) {
           throw NetworkError("Connection refused by the backend");
         }
       },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done, 0, [](int descriptor, const ExpectedStep& step) {
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done, 0, [](int descriptor, const ExpectedStep& step) {
           throw NetworkError("Connection refused by the backend");
         }
       },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done, 0, [](int descriptor, const ExpectedStep& step) {
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done, 0, [](int descriptor, const ExpectedStep& step) {
           throw NetworkError("Connection refused by the backend");
         }
       },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
       /* closing client connection */
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
     };
     auto backend = std::make_shared<DownstreamState>(ComboAddress("192.0.2.42:53"), ComboAddress("0.0.0.0:0"), 0, std::string(), 1, false);
     backend->d_tlsCtx = tlsCtx;
@@ -1089,15 +1092,15 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
     s_backendWriteBuffer.clear();
 
     s_steps = {
-      { ExpectedStep::ExpectedRequest::handshake, IOState::Done },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
       /* opening a connection to the backend (retrying 5 times) */
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::NeedWrite },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::NeedWrite },
       /* closing client connection */
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
     };
     auto backend = std::make_shared<DownstreamState>(ComboAddress("192.0.2.42:53"), ComboAddress("0.0.0.0:0"), 0, std::string(), 1, false);;
     backend->d_tlsCtx = tlsCtx;
@@ -1139,16 +1142,16 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
     s_backendWriteBuffer.clear();
 
     s_steps = {
-      { ExpectedStep::ExpectedRequest::handshake, IOState::Done },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
       /* opening a connection to the backend */
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() },
-      { ExpectedStep::ExpectedRequest::read, IOState::NeedRead, 0 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
       /* closing client connection */
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
     };
     auto backend = std::make_shared<DownstreamState>(ComboAddress("192.0.2.42:53"), ComboAddress("0.0.0.0:0"), 0, std::string(), 1, false);;
     backend->d_tlsCtx = tlsCtx;
@@ -1190,27 +1193,27 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
     s_backendWriteBuffer.clear();
 
     s_steps = {
-      { ExpectedStep::ExpectedRequest::handshake, IOState::Done },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
       /* opening a connection to the backend, connection closed on first write (5 attempts) */
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, 0 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, 0 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, 0 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, 0 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, 0 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, 0 },
       /* closing client connection */
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
     };
     auto backend = std::make_shared<DownstreamState>(ComboAddress("192.0.2.42:53"), ComboAddress("0.0.0.0:0"), 0, std::string(), 1, false);;
     backend->d_tlsCtx = tlsCtx;
@@ -1242,35 +1245,35 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
     s_backendWriteBuffer.clear();
 
     s_steps = {
-      { ExpectedStep::ExpectedRequest::handshake, IOState::Done },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
       /* opening a connection to the backend, connection closed on first write (5 attempts) */
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, 0 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, 0 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, 0 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, 0 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
       /* reading the response */
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, query.size() - 2 },
       /* send the response to the client */
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() },
+      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, query.size() },
       /* client closes the connection */
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 },
       /* closing client connection */
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
       /* then eventually the backend one */
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
     };
     auto backend = std::make_shared<DownstreamState>(ComboAddress("192.0.2.42:53"), ComboAddress("0.0.0.0:0"), 0, std::string(), 1, false);;
     backend->d_tlsCtx = tlsCtx;
@@ -1303,32 +1306,32 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
     s_backendWriteBuffer.clear();
 
     s_steps = {
-      { ExpectedStep::ExpectedRequest::handshake, IOState::Done },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
       /* opening a connection to the backend, connection closed on read, 5 attempts, last one succeeds */
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 0 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 0 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 0 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 0 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 0 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 0 },
       /* closing client connection */
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
     };
     auto backend = std::make_shared<DownstreamState>(ComboAddress("192.0.2.42:53"), ComboAddress("0.0.0.0:0"), 0, std::string(), 1, false);;
     backend->d_tlsCtx = tlsCtx;
@@ -1360,39 +1363,39 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
     s_backendWriteBuffer.clear();
 
     s_steps = {
-      { ExpectedStep::ExpectedRequest::handshake, IOState::Done },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
       /* opening a connection to the backend, connection closed on read, 5 attempts, last one succeeds */
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 0 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 0 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 0 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 0 },
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
       /* this time it works */
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, query.size() - 2 },
       /* sending the response to the client */
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() },
+      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, query.size() },
       /* client closes the connection */
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 },
       /* closing client connection */
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
       /* the eventually the backend one */
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
     };
     auto backend = std::make_shared<DownstreamState>(ComboAddress("192.0.2.42:53"), ComboAddress("0.0.0.0:0"), 0, std::string(), 1, false);;
     backend->d_tlsCtx = tlsCtx;
@@ -1438,32 +1441,32 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
       s_backendReadBuffer.insert(s_backendReadBuffer.end(), query.begin(), query.end());
     }
 
-    s_steps = { { ExpectedStep::ExpectedRequest::handshake, IOState::Done },
-                { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-                { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
+    s_steps = { { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+                { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+                { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
                 /* opening a connection to the backend */
-                { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-                { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() + 2 },
-                { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-                { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
-                { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() + 2 }
+                { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+                { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() + 2 },
+                { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
+                { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, query.size() - 2 },
+                { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, query.size() + 2 }
     };
 
     for (size_t idx = 0; idx < count - 1; idx++) {
       /* read a new query */
-      s_steps.push_back({ ExpectedStep::ExpectedRequest::read, IOState::Done, 2 });
-      s_steps.push_back({ ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 });
+      s_steps.push_back({ ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 });
+      s_steps.push_back({ ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 });
       /* pass it to the backend */
-      s_steps.push_back({ ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() + 2 });
-      s_steps.push_back({ ExpectedStep::ExpectedRequest::read, IOState::Done, 2 });
-      s_steps.push_back({ ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 });
+      s_steps.push_back({ ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() + 2 });
+      s_steps.push_back({ ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 });
+      s_steps.push_back({ ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, query.size() - 2 });
       /* send the response */
-      s_steps.push_back({ ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() + 2 });
+      s_steps.push_back({ ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, query.size() + 2 });
     };
     /* close the connection with the client */
-    s_steps.push_back({ ExpectedStep::ExpectedRequest::close, IOState::Done });
+    s_steps.push_back({ ExpectedStep::ExpectedRequest::closeClient, IOState::Done });
     /* eventually with the backend as well */
-    s_steps.push_back({ ExpectedStep::ExpectedRequest::close, IOState::Done });
+    s_steps.push_back({ ExpectedStep::ExpectedRequest::closeBackend, IOState::Done });
 
     auto backend = std::make_shared<DownstreamState>(ComboAddress("192.0.2.42:53"), ComboAddress("0.0.0.0:0"), 0, std::string(), 1, false);;
     backend->d_tlsCtx = tlsCtx;
@@ -1504,6 +1507,8 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR)
   backend->d_tlsCtx = tlsCtx;
   /* enable out-of-order on the backend side as well */
   backend->d_maxInFlightQueriesPerConn = 65536;
+  /* shorter than the client one */
+  backend->tcpRecvTimeout = 1;
 
   TCPClientThreadData threadData;
   threadData.mplexer = std::make_unique<MockupFDMultiplexer>();
@@ -1511,41 +1516,151 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR)
   struct timeval now;
   gettimeofday(&now, nullptr);
 
-  PacketBuffer query;
-  GenericDNSPacketWriter<PacketBuffer> pwQ(query, DNSName("powerdns.com."), QType::A, QClass::IN, 0);
-  pwQ.getHeader()->rd = 1;
+  std::vector<PacketBuffer> queries(5);
+  std::vector<PacketBuffer> responses(5);
+
+  size_t counter = 0;
+  size_t totalQueriesSize = 0;
+  for (auto& query : queries) {
+    GenericDNSPacketWriter<PacketBuffer> pwQ(query, DNSName("powerdns" + std::to_string(counter) + ".com."), QType::A, QClass::IN, 0);
+    pwQ.getHeader()->rd = 1;
+    pwQ.getHeader()->id = counter;
+    uint16_t querySize = static_cast<uint16_t>(query.size());
+    const uint8_t sizeBytes[] = { static_cast<uint8_t>(querySize / 256), static_cast<uint8_t>(querySize % 256) };
+    query.insert(query.begin(), sizeBytes, sizeBytes + 2);
+    totalQueriesSize += query.size();
+    ++counter;
+  }
 
-  uint16_t querySize = static_cast<uint16_t>(query.size());
-  const uint8_t sizeBytes[] = { static_cast<uint8_t>(querySize / 256), static_cast<uint8_t>(querySize % 256) };
-  query.insert(query.begin(), sizeBytes, sizeBytes + 2);
+  counter = 0;
+  size_t totalResponsesSize = 0;
+  for (auto& response : responses) {
+    DNSName name("powerdns" + std::to_string(counter) + ".com.");
+    GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
+    pwR.getHeader()->qr = 1;
+    pwR.getHeader()->rd = 1;
+    pwR.getHeader()->ra = 1;
+    pwR.getHeader()->id = counter;
+    pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
+    pwR.xfr32BitInt(0x01020304);
+    pwR.commit();
+
+    uint16_t responseSize = static_cast<uint16_t>(response.size());
+    const uint8_t sizeBytes[] = { static_cast<uint8_t>(responseSize / 256), static_cast<uint8_t>(responseSize % 256) };
+    response.insert(response.begin(), sizeBytes, sizeBytes + 2);
+    totalResponsesSize += response.size();
+    ++counter;
+  }
 
   g_verbose = true;
 
   g_proxyProtocolACL.clear();
 
   {
-    cerr<<"=> 5 OOOR queries to the backend, backend responds out of order"<<endl;
-    s_readBuffer = query;
+    cerr<<"=> 5 OOOR queries to the backend, backend responds in reverse order"<<endl;
+    PacketBuffer expectedWriteBuffer;
+    PacketBuffer expectedBackendWriteBuffer;
+
+    s_readBuffer.clear();
+    for (const auto& query : queries) {
+      s_readBuffer.insert(s_readBuffer.end(), query.begin(), query.end());
+    }
+    expectedBackendWriteBuffer = s_readBuffer;
     s_writeBuffer.clear();
-#warning TODOOOOOOOOOO
-    s_backendReadBuffer = query;
+
+    s_backendReadBuffer.clear();
+    for (const auto& response : responses) {
+      /* reverse order */
+      s_backendReadBuffer.insert(s_backendReadBuffer.begin(), response.begin(), response.end());
+    }
+    expectedWriteBuffer = s_backendReadBuffer;
     s_backendWriteBuffer.clear();
 
     s_steps = {
-      { ExpectedStep::ExpectedRequest::handshake, IOState::Done },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+      /* reading a query from the client (1) */
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(0).size() - 2 },
       /* opening a connection to the backend */
-      { ExpectedStep::ExpectedRequest::connect, IOState::Done },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 2 },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, query.size() - 2 },
-      { ExpectedStep::ExpectedRequest::write, IOState::Done, query.size() },
-      { ExpectedStep::ExpectedRequest::read, IOState::Done, 0 },
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      /* sending query to the backend */
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(0).size() },
+      /* no response ready yet */
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
+      /* reading a query from the client (2) */
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(1).size() - 2 },
+      /* sending query to the backend */
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(1).size() },
+      /* no response ready yet */
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
+      /* reading a query from the client (3) */
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(2).size() - 2 },
+      /* sending query to the backend */
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(2).size() },
+      /* no response ready yet */
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
+      /* reading a query from the client (4) */
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(3).size() - 2 },
+      /* sending query to the backend */
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(3).size() },
+      /* no response ready yet */
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
+      /* reading a query from the client (5) */
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(4).size() - 2 },
+      /* sending query to the backend */
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(4).size() },
+      /* no response ready yet, but the backend becomes ready */
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0, [&threadData](int desc, const ExpectedStep& step) {
+        /* set the outgoing descriptor (backend connection) as ready */
+        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(desc);
+      } },
+
+      /* no more queries from the client */
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 0 },
+
+      /* reading a response from the backend */
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(4).size() - 2 },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(4).size() },
+      /* sending it to the client */
+      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(4).size() },
+
+      /* reading a response from the backend */
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(3).size() - 2 },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(3).size() },
+      /* sending it to the client */
+      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(3).size() },
+
+      /* reading a response from the backend */
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(2).size() - 2 },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(2).size() },
+      /* sending it to the client */
+      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(2).size() },
+
+      /* reading a response from the backend */
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(1).size() - 2 },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(1).size() },
+      /* sending it to the client */
+      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(1).size() },
+
+      /* reading a response from the backend */
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(0).size() - 2 },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(0).size() },
+      /* sending it to the client, the client descriptor becomes ready */
+      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(0).size(), [&threadData](int desc, const ExpectedStep& step) {
+        /* set the incoming descriptor (client connection) as ready */
+        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(desc);
+      } },
+
+      /* client is closing the connection */
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 },
       /* closing client connection */
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
       /* closing a connection to the backend */
-      { ExpectedStep::ExpectedRequest::close, IOState::Done },
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
     };
 
     s_processQuery = [backend](DNSQuestion& dq, ClientState& cs, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
@@ -1558,19 +1673,173 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR)
 
     auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS), threadData, now);
     IncomingTCPConnectionState::handleIO(state, now);
-    BOOST_CHECK_EQUAL(s_writeBuffer.size(), query.size());
-    BOOST_CHECK(s_writeBuffer == query);
-    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), query.size());
-    BOOST_CHECK(s_backendWriteBuffer == query);
+    while (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0) {
+      threadData.mplexer->run(&now);
+    }
+
+    BOOST_CHECK_EQUAL(s_writeBuffer.size(), totalResponsesSize);
+    BOOST_CHECK(s_writeBuffer == expectedWriteBuffer);
+    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), totalQueriesSize);
+    BOOST_CHECK(s_backendWriteBuffer == expectedBackendWriteBuffer);
+
+    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
+    IncomingTCPConnectionState::clearAllDownstreamConnections();
+  }
+
+  {
+    cerr<<"=> 3 queries sent to the backend, 1 self-answered, 1 new query sent to the backend which responds to the first query right away, then to the last one, then the connection to the backend times out"<<endl;
+
+    // increase the client timeout for that test, we want the backend to timeout first
+    g_tcpRecvTimeout = 5;
+
+    PacketBuffer expectedWriteBuffer;
+    PacketBuffer expectedBackendWriteBuffer;
+
+    s_readBuffer.clear();
+    for (const auto& query : queries) {
+      s_readBuffer.insert(s_readBuffer.end(), query.begin(), query.end());
+    }
+    s_writeBuffer.clear();
+
+    s_backendReadBuffer.clear();
+    s_backendReadBuffer.insert(s_backendReadBuffer.end(), responses.at(0).begin(), responses.at(0).end());
+    s_backendReadBuffer.insert(s_backendReadBuffer.end(), responses.at(4).begin(), responses.at(4).end());
+
+    /* self-answered */
+    expectedWriteBuffer.insert(expectedWriteBuffer.end(), responses.at(3).begin(), responses.at(3).end());
+    /* from backend */
+    expectedWriteBuffer.insert(expectedWriteBuffer.end(), responses.at(0).begin(), responses.at(0).end());
+    expectedWriteBuffer.insert(expectedWriteBuffer.end(), responses.at(4).begin(), responses.at(4).end());
+
+    s_backendWriteBuffer.clear();
+
+    expectedBackendWriteBuffer.insert(expectedBackendWriteBuffer.end(), queries.at(0).begin(), queries.at(0).end());
+    expectedBackendWriteBuffer.insert(expectedBackendWriteBuffer.end(), queries.at(1).begin(), queries.at(1).end());
+    expectedBackendWriteBuffer.insert(expectedBackendWriteBuffer.end(), queries.at(2).begin(), queries.at(2).end());
+    expectedBackendWriteBuffer.insert(expectedBackendWriteBuffer.end(), queries.at(4).begin(), queries.at(4).end());
+
+
+    bool timeout = false;
+    s_steps = {
+      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
+      /* reading a query from the client (1) */
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(0).size() - 2 },
+      /* opening a connection to the backend */
+      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
+      /* sending query to the backend */
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(0).size() },
+      /* no response ready yet */
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
+      /* reading a query from the client (2) */
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(1).size() - 2 },
+      /* sending query to the backend */
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(1).size() },
+      /* no response ready yet */
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
+      /* reading a query from the client (3) */
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(2).size() - 2 },
+      /* sending query to the backend */
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(2).size() },
+      /* no response ready yet */
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
+      /* reading a query from the client (4) */
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(3).size() - 2 },
+      /* sending the response right away (self-answered)  */
+      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(3).size() },
+      /* reading a query from the client (5) */
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(4).size() - 2 },
+      /* sending query to the backend (5) */
+      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(4).size() },
+      /* reading a response from the backend (1) */
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(0).size() - 2 },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(0).size(), [&threadData](int desc, const ExpectedStep& step) {
+        /* set the backend descriptor as ready */
+        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(desc);
+      } },
+      /* sending it to the client (1) */
+      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(0).size(), [&threadData](int desc, const ExpectedStep& step) {
+        /* set the client descriptor as NOT ready */
+        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(desc);
+      } },
+      /* reading from the client (not ready) */
+      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 0 },
+      /* reading a response from the backend (5) */
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(4).size() - 2 },
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(4).size() },
+      /* sending it to the client (5) */
+      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(4).size() },
+
+      /* try to read from the backend but there is no answer ready yet */
+      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0, [&threadData, &timeout](int desc, const ExpectedStep& step) {
+        /* set the backend descriptor as NOT ready */
+        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(desc);
+        timeout = true;
+      } },
+
+      /* A timeout occurs */
+
+      /* closing client connection */
+      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
+
+      /* closing a connection to the backend */
+      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
+    };
+
+    s_processQuery = [backend,&responses](DNSQuestion& dq, ClientState& cs, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
+      static size_t count = 0;
+      if (count++ == 3) {
+        /* self answered */
+        dq.getMutableData() = responses.at(3);
+        /* remove the length */
+        dq.getMutableData().erase(dq.getMutableData().begin(), dq.getMutableData().begin() + 2);
+
+        return ProcessQueryResult::SendAnswer;
+      }
+      selectedBackend = backend;
+      return ProcessQueryResult::PassToBackend;
+    };
+    s_processResponse = [](PacketBuffer& response, LocalStateHolder<vector<DNSDistResponseRuleAction> >& localRespRulactions, DNSResponse& dr, bool muted) -> bool {
+      return true;
+    };
+
+    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS), threadData, now);
+    IncomingTCPConnectionState::handleIO(state, now);
+
+    while (!timeout && (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
+      threadData.mplexer->run(&now);
+    }
+
+    struct timeval later = now;
+    later.tv_sec += backend->tcpRecvTimeout + 1;
+    auto expiredConns = threadData.mplexer->getTimeouts(later, false);
+    BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
+    for (const auto& cbData : expiredConns) {
+      if (cbData.second.type() == typeid(std::shared_ptr<TCPConnectionToBackend>)) {
+        auto cbState = boost::any_cast<std::shared_ptr<TCPConnectionToBackend>>(cbData.second);
+        cbState->handleTimeout(later, false);
+      }
+    }
+
+    BOOST_CHECK_EQUAL(s_writeBuffer.size(), expectedWriteBuffer.size());
+    BOOST_CHECK(s_writeBuffer == expectedWriteBuffer);
+    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), expectedBackendWriteBuffer.size());
+    BOOST_CHECK(s_backendWriteBuffer == expectedBackendWriteBuffer);
+
     /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
     IncomingTCPConnectionState::clearAllDownstreamConnections();
+
+    // restore the client timeout
+    g_tcpRecvTimeout = 2;
   }
 }
 
 #warning TODO:
 
-// proxy protocol to backend?
-
 // OOOR: OOOR enabled but packet cache hit
 // OOOR: OOOR enabled but backend answers very fast
 // OOOR: OOOR, get 10 queries before the backend can answer. backend doesn't support OOOR, we should get 10 connections. Check that we do reuse them on two subsequent queries