• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PowerDNS / pdns / 13012068652

28 Jan 2025 01:59PM UTC coverage: 64.71% (+0.01%) from 64.699%
13012068652

Pull #14724

github

web-flow
Merge b15562560 into db18c3a17
Pull Request #14724: dnsdist: Add meson support

38328 of 90334 branches covered (42.43%)

Branch coverage included in aggregate %.

361 of 513 new or added lines in 35 files covered. (70.37%)

42 existing lines in 13 files now uncovered.

128150 of 166934 relevant lines covered (76.77%)

4540890.91 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.25
/pdns/dnsdistdist/test-dnsdisttcp_cc.cc
1
/*
2
 * This file is part of PowerDNS or dnsdist.
3
 * Copyright -- PowerDNS.COM B.V. and its contributors
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of version 2 of the GNU General Public License as
7
 * published by the Free Software Foundation.
8
 *
9
 * In addition, for the avoidance of any doubt, permission is granted to
10
 * link this program with OpenSSL and to (re)distribute the binaries
11
 * produced as the result of such linking.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
 */
22
#ifndef BOOST_TEST_DYN_LINK
23
#define BOOST_TEST_DYN_LINK
24
#endif
25

26
#define BOOST_TEST_NO_MAIN
27

28
#include <boost/test/unit_test.hpp>
29

30
#include "dnswriter.hh"
31
#include "dnsdist.hh"
32
#include "dnsdist-proxy-protocol.hh"
33
#include "dnsdist-rings.hh"
34
#include "dnsdist-tcp-downstream.hh"
35
#include "dnsdist-tcp-upstream.hh"
36

37
const bool TCPIOHandler::s_disableConnectForUnitTests = true;
38

39
bool checkDNSCryptQuery(const ClientState& cs, PacketBuffer& query, std::unique_ptr<DNSCryptQuery>& dnsCryptQuery, time_t now, bool tcp)
40
{
20,365✔
41
  (void)cs;
20,365✔
42
  (void)query;
20,365✔
43
  (void)dnsCryptQuery;
20,365✔
44
  (void)now;
20,365✔
45
  (void)tcp;
20,365✔
46
  return false;
20,365✔
47
}
20,365✔
48

49
bool checkQueryHeaders(const struct dnsheader& dnsHeader, ClientState& clientState)
50
{
20,365✔
51
  (void)dnsHeader;
20,365✔
52
  (void)clientState;
20,365✔
53
  return true;
20,365✔
54
}
20,365✔
55

56
uint64_t uptimeOfProcess(const std::string& str)
57
{
×
NEW
58
  (void)str;
×
59
  return 0;
×
60
}
×
61

62
void handleResponseSent(const InternalQueryState& ids, double udiff, const ComboAddress& client, const ComboAddress& backend, unsigned int size, const dnsheader& cleartextDH, dnsdist::Protocol protocol, bool fromBackend)
63
{
20,295✔
64
  (void)ids;
20,295✔
65
  (void)udiff;
20,295✔
66
  (void)client;
20,295✔
67
  (void)backend;
20,295✔
68
  (void)size;
20,295✔
69
  (void)cleartextDH;
20,295✔
70
  (void)protocol;
20,295✔
71
  (void)fromBackend;
20,295✔
72
}
20,295✔
73

74
void handleResponseSent(const DNSName& qname, const QType& qtype, double udiff, const ComboAddress& client, const ComboAddress& backend, unsigned int size, const dnsheader& cleartextDH, dnsdist::Protocol outgoingProtocol, dnsdist::Protocol incomingProtocol, bool fromBackend)
75
{
×
76
}
×
77

78
std::function<ProcessQueryResult(DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend)> s_processQuery;
79

80
ProcessQueryResult processQuery(DNSQuestion& dnsQuestion, std::shared_ptr<DownstreamState>& selectedBackend)
81
{
20,365✔
82
  if (s_processQuery) {
20,365✔
83
    return s_processQuery(dnsQuestion, selectedBackend);
20,364✔
84
  }
20,364✔
85

86
  return ProcessQueryResult::Drop;
1✔
87
}
20,365✔
88

89
bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote, bool allowEmptyResponse)
90
{
288✔
91
  (void)response;
288✔
92
  (void)qname;
288✔
93
  (void)qtype;
288✔
94
  (void)qclass;
288✔
95
  (void)remote;
288✔
96
  (void)allowEmptyResponse;
288✔
97
  return true;
288✔
98
}
288✔
99

100
static std::function<bool(PacketBuffer& response, DNSResponse& dr, bool muted)> s_processResponse;
101

102
bool processResponse(PacketBuffer& response, DNSResponse& dnsResponse, bool muted)
103
{
288✔
104
  if (s_processResponse) {
288!
105
    return s_processResponse(response, dnsResponse, muted);
288✔
106
  }
288✔
107

108
  return false;
×
109
}
288✔
110

111
BOOST_AUTO_TEST_SUITE(test_dnsdisttcp_cc)
112

113
struct ExpectedStep
114
{
115
public:
116
  enum class ExpectedRequest { handshakeClient, readFromClient, writeToClient, closeClient, connectToBackend, readFromBackend, writeToBackend, closeBackend };
117

118
  ExpectedStep(ExpectedRequest r, IOState n, size_t b = 0, std::function<void(int descriptor)> fn = nullptr): cb(fn), request(r), nextState(n), bytes(b)
119
  {
62,674✔
120
  }
62,674✔
121

122
  std::function<void(int descriptor)> cb{nullptr};
123
  ExpectedRequest request;
124
  IOState nextState;
125
  size_t bytes{0};
126
};
127

128
static std::deque<ExpectedStep> s_steps;
129

130
static PacketBuffer s_readBuffer;
131
static PacketBuffer s_writeBuffer;
132
static PacketBuffer s_backendReadBuffer;
133
static PacketBuffer s_backendWriteBuffer;
134

135
std::ostream& operator<<(std::ostream &os, const ExpectedStep::ExpectedRequest d);
136

137
std::ostream& operator<<(std::ostream &os, const ExpectedStep::ExpectedRequest d)
138
{
×
139
  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" };
×
140
  os<<requests.at(static_cast<size_t>(d));
×
141
  return os;
×
142
}
×
143

144
class MockupTLSConnection : public TLSConnection
145
{
146
public:
147
  MockupTLSConnection(int descriptor, bool client = false): d_descriptor(descriptor), d_client(client)
148
  {
230✔
149
  }
230✔
150

151
  ~MockupTLSConnection() { }
×
152

153
  IOState tryHandshake() override
154
  {
96✔
155
    auto step = getStep();
96✔
156
    BOOST_REQUIRE_EQUAL(step.request, ExpectedStep::ExpectedRequest::handshakeClient);
96✔
157

158
    return step.nextState;
96✔
159
  }
96✔
160

161
  IOState tryWrite(const PacketBuffer& buffer, size_t& pos, size_t toWrite) override
162
  {
20,686✔
163
    auto step = getStep();
20,686✔
164
    BOOST_REQUIRE_EQUAL(step.request, !d_client ? ExpectedStep::ExpectedRequest::writeToClient : ExpectedStep::ExpectedRequest::writeToBackend);
20,686✔
165

166
    if (step.bytes == 0) {
20,686✔
167
      if (step.nextState == IOState::NeedWrite) {
32✔
168
        return step.nextState;
6✔
169
      }
6✔
170
      throw std::runtime_error("Remote host closed the connection");
26✔
171
    }
32✔
172

173
    toWrite -= pos;
20,654✔
174
    BOOST_REQUIRE_GE(buffer.size(), pos + toWrite);
20,654✔
175

176
    if (step.bytes < toWrite) {
20,654✔
177
      toWrite = step.bytes;
12✔
178
    }
12✔
179

180
    auto& externalBuffer = d_client ? s_backendWriteBuffer : s_writeBuffer;
20,654✔
181
    externalBuffer.insert(externalBuffer.end(), buffer.begin() + pos, buffer.begin() + pos + toWrite);
20,654✔
182
    pos += toWrite;
20,654✔
183

184
    return step.nextState;
20,654✔
185
  }
20,686✔
186

187
  IOState tryRead(PacketBuffer& buffer, size_t& pos, size_t toRead, bool allowIncomplete=false) override
188
  {
41,524✔
189
    (void)allowIncomplete;
41,524✔
190
    auto step = getStep();
41,524✔
191
    BOOST_REQUIRE_EQUAL(step.request, !d_client ? ExpectedStep::ExpectedRequest::readFromClient : ExpectedStep::ExpectedRequest::readFromBackend);
41,524✔
192

193
    if (step.bytes == 0) {
41,524✔
194
      if (step.nextState == IOState::NeedRead) {
166✔
195
        return step.nextState;
112✔
196
      }
112✔
197
      throw std::runtime_error("Remote host closed the connection");
54✔
198
    }
166✔
199

200
    auto& externalBuffer = d_client ? s_backendReadBuffer : s_readBuffer;
41,358✔
201
    toRead -= pos;
41,358✔
202

203
    if (step.bytes < toRead) {
41,358✔
204
      toRead = step.bytes;
14✔
205
    }
14✔
206

207
    BOOST_REQUIRE_GE(buffer.size(), toRead);
41,358✔
208
    BOOST_REQUIRE_GE(externalBuffer.size(), toRead);
41,358✔
209

210
    std::copy(externalBuffer.begin(), externalBuffer.begin() + toRead, buffer.begin() + pos);
41,358✔
211
    pos += toRead;
41,358✔
212
    externalBuffer.erase(externalBuffer.begin(), externalBuffer.begin() + toRead);
41,358✔
213

214
    return step.nextState;
41,358✔
215
  }
41,524✔
216

217
  IOState tryConnect(bool fastOpen, const ComboAddress& remote) override
218
  {
138✔
219
    (void)fastOpen;
138✔
220
    (void)remote;
138✔
221
    auto step = getStep();
138✔
222
    BOOST_REQUIRE_EQUAL(step.request, ExpectedStep::ExpectedRequest::connectToBackend);
138✔
223

224
    return step.nextState;
138✔
225
  }
138✔
226

227
  void close() override
228
  {
230✔
229
    auto step = getStep();
230✔
230
    BOOST_REQUIRE_EQUAL(step.request, !d_client ? ExpectedStep::ExpectedRequest::closeClient : ExpectedStep::ExpectedRequest::closeBackend);
230✔
231
  }
230✔
232

233
  bool isUsable() const override
234
  {
×
235
    return true;
×
236
  }
×
237

238
  std::string getServerNameIndication() const override
239
  {
20,360✔
240
    return "";
20,360✔
241
  }
20,360✔
242

243
  std::vector<uint8_t> getNextProtocol() const override
244
  {
×
245
    return std::vector<uint8_t>();
×
246
  }
×
247

248
  LibsslTLSVersion getTLSVersion() const override
249
  {
20,360✔
250
    return LibsslTLSVersion::TLS13;
20,360✔
251
  }
20,360✔
252

253
  bool hasSessionBeenResumed() const override
254
  {
202✔
255
    return false;
202✔
256
  }
202✔
257

258
  std::vector<std::unique_ptr<TLSSession>> getSessions() override
259
  {
110✔
260
    return {};
110✔
261
  }
110✔
262

263
  std::vector<int> getAsyncFDs() override
264
  {
70✔
265
    return {};
70✔
266
  }
70✔
267

268
  void setSession(std::unique_ptr<TLSSession>& session) override
269
  {
×
NEW
270
    (void)session;
×
UNCOV
271
  }
×
272

273
  /* unused in that context, don't bother */
274
  void doHandshake() override
275
  {
×
276
  }
×
277

278
  void connect(bool fastOpen, const ComboAddress& remote, const struct timeval& timeout) override
279
  {
×
NEW
280
    (void)fastOpen;
×
NEW
281
    (void)remote;
×
NEW
282
    (void)timeout;
×
UNCOV
283
  }
×
284

285
  size_t read(void* buffer, size_t bufferSize, const struct timeval&readTimeout, const struct timeval& totalTimeout={0,0}, bool allowIncomplete=false) override
286
  {
×
NEW
287
    (void)buffer;
×
NEW
288
    (void)bufferSize;
×
NEW
289
    (void)readTimeout;
×
NEW
290
    (void)totalTimeout;
×
NEW
291
    (void)allowIncomplete;
×
292
    return 0;
×
293
  }
×
294

295
  size_t write(const void* buffer, size_t bufferSize, const struct timeval& writeTimeout) override
296
  {
×
NEW
297
    (void)buffer;
×
NEW
298
    (void)bufferSize;
×
NEW
299
    (void)writeTimeout;
×
300
    return 0;
×
301
  }
×
302
private:
303
  ExpectedStep getStep() const
304
  {
62,674✔
305
    BOOST_REQUIRE(!s_steps.empty());
62,674✔
306
    auto step = s_steps.front();
62,674✔
307
    s_steps.pop_front();
62,674✔
308

309
    if (step.cb) {
62,674✔
310
      step.cb(d_descriptor);
158✔
311
    }
158✔
312

313
    return step;
62,674✔
314
  }
62,674✔
315

316
  const int d_descriptor;
317
  bool d_client{false};
318
};
319

320
class MockupTLSCtx : public TLSCtx
321
{
322
public:
323
  ~MockupTLSCtx()
324
  {
×
325
  }
×
326

327
  std::unique_ptr<TLSConnection> getConnection(int socket, const struct timeval& timeout, time_t now) override
328
  {
92✔
329
    (void)timeout;
92✔
330
    (void)now;
92✔
331
    return std::make_unique<MockupTLSConnection>(socket);
92✔
332
  }
92✔
333

334
  std::unique_ptr<TLSConnection> getClientConnection(const std::string& host, bool hostIsAddr, int socket, const struct timeval& timeout) override
335
  {
138✔
336
    (void)host;
138✔
337
    (void)hostIsAddr;
138✔
338
    (void)timeout;
138✔
339
    return std::make_unique<MockupTLSConnection>(socket, true);
138✔
340
  }
138✔
341

342
  void rotateTicketsKey(time_t now) override
343
  {
×
NEW
344
    (void)now;
×
UNCOV
345
  }
×
346

347
  size_t getTicketsKeysCount() override
348
  {
×
349
    return 0;
×
350
  }
×
351

352
  std::string getName() const override
353
  {
×
354
    return "Mockup TLS";
×
355
  }
×
356
};
357

358
class MockupFDMultiplexer : public FDMultiplexer
359
{
360
public:
361
  MockupFDMultiplexer()
362
  {
102✔
363
  }
102✔
364

365
  ~MockupFDMultiplexer()
366
  {
102✔
367
  }
102✔
368

369
  int run(struct timeval* tv, int timeout=500) override
370
  {
122✔
371
    (void)timeout;
122✔
372
    int ret = 0;
122✔
373

374
    gettimeofday(tv, nullptr); // MANDATORY
122✔
375

376
    /* 'ready' might be altered by a callback while we are iterating */
377
    const auto readyFDs = ready;
122✔
378
    for (const auto fd : readyFDs) {
170✔
379
      {
170✔
380
        const auto& it = d_readCallbacks.find(fd);
170✔
381

382
        if (it != d_readCallbacks.end()) {
170✔
383
          it->d_callback(it->d_fd, it->d_parameter);
104✔
384
          continue; // so we don't refind ourselves as writable!
104✔
385
        }
104✔
386
      }
170✔
387

388
      {
66✔
389
        const auto& it = d_writeCallbacks.find(fd);
66✔
390

391
        if (it != d_writeCallbacks.end()) {
66✔
392
          it->d_callback(it->d_fd, it->d_parameter);
16✔
393
        }
16✔
394
      }
66✔
395
    }
66✔
396

397
    return ret;
122✔
398
  }
122✔
399

400
  void getAvailableFDs(std::vector<int>& fds, int timeout) override
401
  {
×
NEW
402
    (void)fds;
×
NEW
403
    (void)timeout;
×
UNCOV
404
  }
×
405

406
  void addFD(int fd, FDMultiplexer::EventKind kind) override
407
  {
168✔
408
    (void)fd;
168✔
409
    (void)kind;
168✔
410
  }
168✔
411

412
  void removeFD(int fd, FDMultiplexer::EventKind) override
413
  {
168✔
414
    (void)fd;
168✔
415
  }
168✔
416

417
  string getName() const override
418
  {
×
419
    return "mockup";
×
420
  }
×
421

422
  void setReady(int fd)
423
  {
78✔
424
    ready.insert(fd);
78✔
425
  }
78✔
426

427
  void setNotReady(int fd)
428
  {
52✔
429
    ready.erase(fd);
52✔
430
  }
52✔
431

432
private:
433
  std::set<int> ready;
434
};
435

436
static bool isIPv6Supported()
437
{
2✔
438
  try {
2✔
439
    ComboAddress addr("[2001:db8:53::1]:53");
2✔
440
    auto socket = std::make_unique<Socket>(addr.sin4.sin_family, SOCK_STREAM, 0);
2✔
441
    socket->setNonBlocking();
2✔
442
    int res = SConnectWithTimeout(socket->getHandle(), addr, timeval{0, 0});
2✔
443
    if (res == 0 || res == EINPROGRESS) {
2!
444
      return true;
×
445
    }
×
446
    return false;
2✔
447
  }
2✔
448
  catch (const std::exception& e) {
2✔
449
    return false;
2✔
450
  }
2✔
451
}
2✔
452

453
static ComboAddress getBackendAddress(const std::string& lastDigit, uint16_t port)
454
{
124✔
455
  static const bool useV6 = isIPv6Supported();
124✔
456

457
  if (useV6) {
124!
458
    return ComboAddress("2001:db8:53::" + lastDigit, port);
×
459
  }
×
460

461
  return ComboAddress("192.0.2." + lastDigit, port);
124✔
462
}
124✔
463

464
static void appendPayloadEditingID(PacketBuffer& buffer, const PacketBuffer& payload, uint16_t newID)
465
{
590✔
466
  PacketBuffer newPayload(payload);
590✔
467
  dnsheader dh;
590✔
468
  memcpy(&dh, &newPayload.at(sizeof(uint16_t)), sizeof(dh));
590✔
469
  dh.id = htons(newID);
590✔
470
  memcpy(&newPayload.at(sizeof(uint16_t)), &dh, sizeof(dh));
590✔
471
  buffer.insert(buffer.end(), newPayload.begin(), newPayload.end());
590✔
472
}
590✔
473

474
static void prependPayloadEditingID(PacketBuffer& buffer, const PacketBuffer& payload, uint16_t newID)
475
{
10✔
476
  PacketBuffer newPayload(payload);
10✔
477
  dnsheader dh;
10✔
478
  memcpy(&dh, &newPayload.at(sizeof(uint16_t)), sizeof(dh));
10✔
479
  dh.id = htons(newID);
10✔
480
  memcpy(&newPayload.at(sizeof(uint16_t)), &dh, sizeof(dh));
10✔
481
  buffer.insert(buffer.begin(), newPayload.begin(), newPayload.end());
10✔
482
}
10✔
483

484
struct TestFixture
485
{
486
  TestFixture()
487
  {
10✔
488
    reset();
10✔
489
  }
10✔
490
  TestFixture(const TestFixture&) = delete;
491
  TestFixture(TestFixture&&) = delete;
492
  TestFixture& operator=(const TestFixture&) = delete;
493
  TestFixture& operator=(TestFixture&&) = delete;
494
  ~TestFixture()
495
  {
10✔
496
    reset();
10✔
497
  }
10✔
498

499
  static void reset()
500
  {
112✔
501
    s_steps.clear();
112✔
502
    s_readBuffer.clear();
112✔
503
    s_writeBuffer.clear();
112✔
504
    s_backendReadBuffer.clear();
112✔
505
    s_backendWriteBuffer.clear();
112✔
506

507
    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
112✔
508
      config.d_proxyProtocolACL.clear();
112✔
509
    });
112✔
510
    IncomingTCPConnectionState::clearAllDownstreamConnections();
112✔
511

512
    /* we _NEED_ to set this function to empty otherwise we might get what was set
513
       by the last test, and we might not like it at all */
514
    s_processQuery = nullptr;
112✔
515
  }
112✔
516
};
517

518
static void testInit(const std::string& name, TCPClientThreadData& threadData)
519
{
92✔
520
#ifdef DEBUGLOG_ENABLED
521
  cerr<<name<<endl;
522
#else
523
  (void) name;
92✔
524
#endif
92✔
525

526
  TestFixture::reset();
92✔
527
  threadData.mplexer = std::make_unique<MockupFDMultiplexer>();
92✔
528
}
92✔
529

530
#define TEST_INIT(str) testInit(str, threadData)
92✔
531

532
BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_SelfAnswered, TestFixture)
533
{
2✔
534
  const auto tcpRecvTimeout = dnsdist::configuration::getCurrentRuntimeConfiguration().d_tcpRecvTimeout;
2✔
535
  auto local = getBackendAddress("1", 80);
2✔
536
  ClientState localCS(local, true, false, 0, "", {}, true);
2✔
537
  auto tlsCtx = std::make_shared<MockupTLSCtx>();
2✔
538
  localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
2✔
539

540
  TCPClientThreadData threadData;
2✔
541
  threadData.mplexer = std::make_unique<MockupFDMultiplexer>();
2✔
542

543
  struct timeval now;
2✔
544
  gettimeofday(&now, nullptr);
2✔
545

546
  PacketBuffer query;
2✔
547
  GenericDNSPacketWriter<PacketBuffer> pwQ(query, DNSName("powerdns.com."), QType::A, QClass::IN, 0);
2✔
548
  pwQ.getHeader()->rd = 1;
2✔
549

550
  uint16_t querySize = static_cast<uint16_t>(query.size());
2✔
551
  const uint8_t sizeBytes[] = { static_cast<uint8_t>(querySize / 256), static_cast<uint8_t>(querySize % 256) };
2✔
552
  query.insert(query.begin(), sizeBytes, sizeBytes + 2);
2✔
553

554
  {
2✔
555
    /* drop right away */
556
    TEST_INIT("=> drop right away");
2✔
557
    s_readBuffer = query;
2✔
558

559
    s_steps = {
2✔
560
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
561
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
562
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
563
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
564
    };
2✔
565
    s_processQuery = [](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
566
      (void)dq;
2✔
567
      (void)selectedBackend;
2✔
568
      return ProcessQueryResult::Drop;
2✔
569
    };
2✔
570

571
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
572
    state->handleIO();
2✔
573
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
2✔
574
  }
2✔
575

576
  {
2✔
577
    /* self-generated REFUSED, client closes connection right away */
578
    TEST_INIT("=> self-gen");
2✔
579
    s_readBuffer = query;
2✔
580

581
    s_steps = {
2✔
582
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
583
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
584
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
585
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, 65537 },
2✔
586
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 },
2✔
587
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
588
    };
2✔
589
    s_processQuery = [](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
590
      (void)dq;
2✔
591
      (void)selectedBackend;
2✔
592
      // Would be nicer to actually turn it into a response
593
      return ProcessQueryResult::SendAnswer;
2✔
594
    };
2✔
595

596
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
597
    state->handleIO();
2✔
598
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), query.size());
2✔
599
    BOOST_CHECK(s_writeBuffer == query);
2✔
600
  }
2✔
601

602
  {
2✔
603
    TEST_INIT("=> shorts");
2✔
604
    /* need write then read during handshake,
605
       short read on the size, then on the query itself,
606
       self-generated REFUSED, short write on the response,
607
       client closes connection right away */
608
    s_readBuffer = query;
2✔
609

610
    s_steps = {
2✔
611
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::NeedWrite },
2✔
612
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::NeedRead },
2✔
613
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
614
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 1 },
2✔
615
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 1 },
2✔
616
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, query.size() - 3 },
2✔
617
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 1 },
2✔
618
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::NeedWrite, query.size() - 1},
2✔
619
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, 1 },
2✔
620
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 },
2✔
621
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
622
    };
2✔
623
    s_processQuery = [](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
624
      (void)dq;
2✔
625
      (void)selectedBackend;
2✔
626
      // Would be nicer to actually turn it into a response
627
      return ProcessQueryResult::SendAnswer;
2✔
628
    };
2✔
629

630
    /* mark the incoming FD as always ready */
631
    dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(-1);
2✔
632

633
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
634
    state->handleIO();
2✔
635
    while (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0) {
12✔
636
      threadData.mplexer->run(&now);
10✔
637
    }
10✔
638
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), query.size());
2✔
639
    BOOST_CHECK(s_writeBuffer == query);
2✔
640
  }
2✔
641

642
  {
2✔
643
    TEST_INIT("=> exception while handling the query");
2✔
644
    /* Exception raised while handling the query */
645
    s_readBuffer = query;
2✔
646

647
    s_steps = {
2✔
648
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
649
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
650
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
651
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
652
    };
2✔
653
    s_processQuery = [](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
654
      (void)dq;
2✔
655
      (void)selectedBackend;
2✔
656
      throw std::runtime_error("Something unexpected happened");
2✔
657
    };
2✔
658

659
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
660
    state->handleIO();
2✔
661
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
2✔
662
  }
2✔
663

664
  {
2✔
665
#if 1
2✔
666
    TEST_INIT("=> 10k self-generated pipelined on the same connection");
2✔
667

668
    /* 10k self-generated REFUSED pipelined on the same connection */
669
    size_t count = 10000;
2✔
670

671
    s_steps = { { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done } };
2✔
672

673
    for (size_t idx = 0; idx < count; idx++) {
20,002✔
674
      s_readBuffer.insert(s_readBuffer.end(), query.begin(), query.end());
20,000✔
675
      s_steps.push_back({ ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 });
20,000✔
676
      s_steps.push_back({ ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 });
20,000✔
677
      s_steps.push_back({ ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, query.size() + 2 });
20,000✔
678
    };
20,000✔
679
    s_steps.push_back({ ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 });
2✔
680
    s_steps.push_back({ ExpectedStep::ExpectedRequest::closeClient, IOState::Done });
2✔
681

682
    s_processQuery = [](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
20,000✔
683
      (void)dq;
20,000✔
684
      (void)selectedBackend;
20,000✔
685
      // Would be nicer to actually turn it into a response
686
      return ProcessQueryResult::SendAnswer;
20,000✔
687
    };
20,000✔
688

689
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
690
    state->handleIO();
2✔
691
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), query.size() * count);
2✔
692
#endif
2✔
693
  }
2✔
694

695
  {
2✔
696
    TEST_INIT("=> timeout while reading the query");
2✔
697
    /* timeout while reading the query */
698
    s_readBuffer = query;
2✔
699

700
    s_steps = {
2✔
701
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
702
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
703
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, query.size() - 2 - 2 },
2✔
704
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
705
    };
2✔
706
    s_processQuery = [](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
NEW
707
      (void)dq;
×
NEW
708
      (void)selectedBackend;
×
709
      /* should not be reached */
710
      BOOST_CHECK(false);
×
711
      return ProcessQueryResult::SendAnswer;
×
712
    };
×
713

714
    /* mark the incoming FD as NOT ready */
715
    dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(-1);
2✔
716

717
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
718
    state->handleIO();
2✔
719
    BOOST_CHECK_EQUAL(threadData.mplexer->run(&now), 0);
2✔
720
    struct timeval later = now;
2✔
721
    later.tv_sec += tcpRecvTimeout + 1;
2✔
722
    auto expiredReadConns = threadData.mplexer->getTimeouts(later, false);
2✔
723
    for (const auto& cbData : expiredReadConns) {
2✔
724
      BOOST_CHECK_EQUAL(cbData.first, state->d_handler.getDescriptor());
2✔
725
      if (cbData.second.type() == typeid(std::shared_ptr<IncomingTCPConnectionState>)) {
2!
726
        auto cbState = boost::any_cast<std::shared_ptr<IncomingTCPConnectionState>>(cbData.second);
2✔
727
        BOOST_CHECK_EQUAL(cbData.first, cbState->d_handler.getDescriptor());
2✔
728
        cbState->handleTimeout(cbState, false);
2✔
729
      }
2✔
730
    }
2✔
731
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
2✔
732
  }
2✔
733

734
  {
2✔
735
    TEST_INIT("=> timeout while writing the response");
2✔
736
    /* timeout while writing the response */
737
    s_readBuffer = query;
2✔
738

739
    s_steps = {
2✔
740
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
741
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
742
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
743
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::NeedWrite, 1 },
2✔
744
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
745
    };
2✔
746
    s_processQuery = [](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
747
      (void)dq;
2✔
748
      (void)selectedBackend;
2✔
749
      return ProcessQueryResult::SendAnswer;
2✔
750
    };
2✔
751

752
    /* mark the incoming FD as NOT ready */
753
    dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(-1);
2✔
754

755
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
756
    state->handleIO();
2✔
757
    BOOST_CHECK_EQUAL(threadData.mplexer->run(&now), 0);
2✔
758
    struct timeval later = now;
2✔
759
    later.tv_sec += tcpRecvTimeout + 1;
2✔
760
    auto expiredWriteConns = threadData.mplexer->getTimeouts(later, true);
2✔
761
    for (const auto& cbData : expiredWriteConns) {
2✔
762
      BOOST_CHECK_EQUAL(cbData.first, state->d_handler.getDescriptor());
2✔
763
      if (cbData.second.type() == typeid(std::shared_ptr<IncomingTCPConnectionState>)) {
2!
764
        auto cbState = boost::any_cast<std::shared_ptr<IncomingTCPConnectionState>>(cbData.second);
2✔
765
        BOOST_CHECK_EQUAL(cbData.first, cbState->d_handler.getDescriptor());
2✔
766
        cbState->handleTimeout(cbState, false);
2✔
767
      }
2✔
768
    }
2✔
769
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), 1U);
2✔
770
  }
2✔
771

772
  {
2✔
773
    TEST_INIT("=> Client closes the connection while writing the response (self-answered)");
2✔
774

775
    s_readBuffer = query;
2✔
776

777
    s_steps = {
2✔
778
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
779
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
780
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
781
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, 0 },
2✔
782
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
783
    };
2✔
784
    s_processQuery = [](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
785
      (void)dq;
2✔
786
      (void)selectedBackend;
2✔
787
      return ProcessQueryResult::SendAnswer;
2✔
788
    };
2✔
789

790
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
791
    state->handleIO();
2✔
792
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
2✔
793
  }
2✔
794
}
2✔
795

796
BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionWithProxyProtocol_SelfAnswered, TestFixture)
797
{
2✔
798
  const auto tcpRecvTimeout = dnsdist::configuration::getCurrentRuntimeConfiguration().d_tcpRecvTimeout;
2✔
799
  auto local = getBackendAddress("1", 80);
2✔
800
  ClientState localCS(local, true, false, 0, "", {}, true);
2✔
801
  auto tlsCtx = std::make_shared<MockupTLSCtx>();
2✔
802
  localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
2✔
803

804
  TCPClientThreadData threadData;
2✔
805
  threadData.mplexer = std::make_unique<MockupFDMultiplexer>();
2✔
806

807
  struct timeval now;
2✔
808
  gettimeofday(&now, nullptr);
2✔
809

810
  PacketBuffer query;
2✔
811
  GenericDNSPacketWriter<PacketBuffer> pwQ(query, DNSName("powerdns.com."), QType::A, QClass::IN, 0);
2✔
812
  pwQ.getHeader()->rd = 1;
2✔
813

814
  uint16_t querySize = static_cast<uint16_t>(query.size());
2✔
815
  const uint8_t sizeBytes[] = { static_cast<uint8_t>(querySize / 256), static_cast<uint8_t>(querySize % 256) };
2✔
816
  query.insert(query.begin(), sizeBytes, sizeBytes + 2);
2✔
817

818
  {
2✔
819
    TEST_INIT("=> reading PP");
2✔
820

821
    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
2✔
822
      config.d_proxyProtocolACL.addMask("0.0.0.0/0");
2✔
823
      config.d_proxyProtocolACL.addMask("::0/0");
2✔
824
    });
2✔
825

826
    auto proxyPayload = makeProxyHeader(true, ComboAddress("192.0.2.1"), ComboAddress("192.0.2.2"), {});
2✔
827
    BOOST_REQUIRE_GT(proxyPayload.size(), s_proxyProtocolMinimumHeaderSize);
2✔
828
    s_readBuffer = query;
2✔
829
    // preprend the proxy protocol payload
830
    s_readBuffer.insert(s_readBuffer.begin(), proxyPayload.begin(), proxyPayload.end());
2✔
831
    // append a second query
832
    s_readBuffer.insert(s_readBuffer.end(), query.begin(), query.end());
2✔
833

834
    s_steps = {
2✔
835
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
836
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, s_proxyProtocolMinimumHeaderSize },
2✔
837
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, proxyPayload.size() - s_proxyProtocolMinimumHeaderSize },
2✔
838
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
839
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
840
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, 65537 },
2✔
841
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
842
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
843
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, 65537 },
2✔
844
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 },
2✔
845
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
846
    };
2✔
847
    s_processQuery = [](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
4✔
848
      (void)dq;
4✔
849
      (void)selectedBackend;
4✔
850
      return ProcessQueryResult::SendAnswer;
4✔
851
    };
4✔
852

853
    /* mark the incoming FD as NOT ready */
854
    dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(-1);
2✔
855

856
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
857
    state->handleIO();
2✔
858
    BOOST_CHECK_EQUAL(threadData.mplexer->run(&now), 0);
2✔
859
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), query.size() * 2U);
2✔
860
  }
2✔
861

862
  {
2✔
863
    TEST_INIT("=> Invalid PP");
2✔
864

865
    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
2✔
866
      config.d_proxyProtocolACL.addMask("0.0.0.0/0");
2✔
867
      config.d_proxyProtocolACL.addMask("::0/0");
2✔
868
    });
2✔
869

870
    auto proxyPayload = std::vector<uint8_t>(s_proxyProtocolMinimumHeaderSize);
2✔
871
    std::fill(proxyPayload.begin(), proxyPayload.end(), 0);
2✔
872

873
    s_readBuffer = query;
2✔
874
    // preprend the proxy protocol payload
875
    s_readBuffer.insert(s_readBuffer.begin(), proxyPayload.begin(), proxyPayload.end());
2✔
876

877
    s_steps = {
2✔
878
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
879
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, s_proxyProtocolMinimumHeaderSize },
2✔
880
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
881
    };
2✔
882
    s_processQuery = [](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
NEW
883
      (void)dq;
×
NEW
884
      (void)selectedBackend;
×
885
      return ProcessQueryResult::SendAnswer;
×
886
    };
×
887

888
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
889
    state->handleIO();
2✔
890

891
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
2✔
892
  }
2✔
893

894
  {
2✔
895
    TEST_INIT("=> timeout while reading PP");
2✔
896

897
    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
2✔
898
      config.d_proxyProtocolACL.addMask("0.0.0.0/0");
2✔
899
      config.d_proxyProtocolACL.addMask("::0/0");
2✔
900
    });
2✔
901

902
    auto proxyPayload = makeProxyHeader(true, ComboAddress("192.0.2.1"), ComboAddress("192.0.2.2"), {});
2✔
903
    BOOST_REQUIRE_GT(proxyPayload.size(), s_proxyProtocolMinimumHeaderSize);
2✔
904
    s_readBuffer = query;
2✔
905
    // preprend the proxy protocol payload
906
    s_readBuffer.insert(s_readBuffer.begin(), proxyPayload.begin(), proxyPayload.end());
2✔
907

908
    s_steps = {
2✔
909
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
910
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, s_proxyProtocolMinimumHeaderSize },
2✔
911
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, proxyPayload.size() - s_proxyProtocolMinimumHeaderSize - 1},
2✔
912
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
913
    };
2✔
914
    s_processQuery = [](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
NEW
915
      (void)dq;
×
NEW
916
      (void)selectedBackend;
×
917
      return ProcessQueryResult::SendAnswer;
×
918
    };
×
919

920
    /* mark the incoming FD as NOT ready */
921
    dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(-1);
2✔
922

923
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
924
    state->handleIO();
2✔
925
    BOOST_CHECK_EQUAL(threadData.mplexer->run(&now), 0);
2✔
926
    struct timeval later = now;
2✔
927
    later.tv_sec += tcpRecvTimeout + 1;
2✔
928
    auto expiredReadConns = threadData.mplexer->getTimeouts(later, false);
2✔
929
    for (const auto& cbData : expiredReadConns) {
2✔
930
      BOOST_CHECK_EQUAL(cbData.first, state->d_handler.getDescriptor());
2✔
931
      if (cbData.second.type() == typeid(std::shared_ptr<IncomingTCPConnectionState>)) {
2!
932
        auto cbState = boost::any_cast<std::shared_ptr<IncomingTCPConnectionState>>(cbData.second);
2✔
933
        BOOST_CHECK_EQUAL(cbData.first, cbState->d_handler.getDescriptor());
2✔
934
        cbState->handleTimeout(cbState, false);
2✔
935
      }
2✔
936
    }
2✔
937
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
2✔
938
  }
2✔
939
}
2✔
940

941
BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_BackendNoOOOR, TestFixture)
942
{
2✔
943
  auto local = getBackendAddress("1", 80);
2✔
944
  ClientState localCS(local, true, false, 0, "", {}, true);
2✔
945
  auto tlsCtx = std::make_shared<MockupTLSCtx>();
2✔
946
  localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
2✔
947

948
  TCPClientThreadData threadData;
2✔
949
  threadData.mplexer = std::make_unique<MockupFDMultiplexer>();
2✔
950

951
  struct timeval now;
2✔
952
  gettimeofday(&now, nullptr);
2✔
953

954
  PacketBuffer query;
2✔
955
  GenericDNSPacketWriter<PacketBuffer> pwQ(query, DNSName("powerdns.com."), QType::A, QClass::IN, 0);
2✔
956
  pwQ.getHeader()->rd = 1;
2✔
957
  pwQ.getHeader()->id = 0;
2✔
958

959
  auto shortQuery = query;
2✔
960
  shortQuery.resize(sizeof(dnsheader) - 1);
2✔
961
  uint16_t shortQuerySize = static_cast<uint16_t>(shortQuery.size());
2✔
962
  const uint8_t shortSizeBytes[] = { static_cast<uint8_t>(shortQuerySize / 256), static_cast<uint8_t>(shortQuerySize % 256) };
2✔
963
  shortQuery.insert(shortQuery.begin(), shortSizeBytes, shortSizeBytes + 2);
2✔
964

965
  uint16_t querySize = static_cast<uint16_t>(query.size());
2✔
966
  const uint8_t sizeBytes[] = { static_cast<uint8_t>(querySize / 256), static_cast<uint8_t>(querySize % 256) };
2✔
967
  query.insert(query.begin(), sizeBytes, sizeBytes + 2);
2✔
968

969
  auto backend = std::make_shared<DownstreamState>(getBackendAddress("42", 53));
2✔
970
  backend->d_tlsCtx = tlsCtx;
2✔
971

972
  {
2✔
973
    /* pass to backend, backend answers right away, client closes the connection */
974
    TEST_INIT("=> Query to backend, backend answers right away");
2✔
975
    s_readBuffer = query;
2✔
976

977
    s_backendReadBuffer = query;
2✔
978

979
    s_steps = {
2✔
980
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
981
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
982
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
983
      /* opening a connection to the backend */
984
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
985
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
2✔
986
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
987
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, query.size() - 2 },
2✔
988
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, query.size() },
2✔
989
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 },
2✔
990
      /* closing client connection */
991
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
992
      /* closing a connection to the backend */
993
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
994
    };
2✔
995
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
996
      (void)dq;
2✔
997
      selectedBackend = backend;
2✔
998
      return ProcessQueryResult::PassToBackend;
2✔
999
    };
2✔
1000
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
2✔
1001
      (void)response;
2✔
1002
      (void)dr;
2✔
1003
      (void)muted;
2✔
1004
      return true;
2✔
1005
    };
2✔
1006

1007
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
1008
    state->handleIO();
2✔
1009
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), query.size());
2✔
1010
    BOOST_CHECK(s_writeBuffer == query);
2✔
1011
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), query.size());
2✔
1012
    BOOST_CHECK(s_backendWriteBuffer == query);
2✔
1013
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
1014
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
1015
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
1016
  }
2✔
1017

1018
  {
2✔
1019
    /* pass to backend, backend answers right away, exception while handling the response */
1020
    TEST_INIT("=> Exception while handling the response sent by the backend");
2✔
1021
    s_readBuffer = query;
2✔
1022

1023
    s_backendReadBuffer = query;
2✔
1024

1025
    s_steps = {
2✔
1026
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
1027
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
1028
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
1029
      /* opening a connection to the backend */
1030
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1031
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
2✔
1032
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
1033
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, query.size() - 2 },
2✔
1034
      /* closing client connection */
1035
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
1036
      /* closing a connection to the backend */
1037
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1038
    };
2✔
1039
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
1040
      (void)dq;
2✔
1041
      selectedBackend = backend;
2✔
1042
      return ProcessQueryResult::PassToBackend;
2✔
1043
    };
2✔
1044
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
2✔
1045
      (void)response;
2✔
1046
      (void)dr;
2✔
1047
      (void)muted;
2✔
1048
      throw std::runtime_error("Unexpected error while processing the response");
2✔
1049
    };
2✔
1050

1051
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
1052
    state->handleIO();
2✔
1053
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
2✔
1054
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), query.size());
2✔
1055
    BOOST_CHECK(s_backendWriteBuffer == query);
2✔
1056
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
1057
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
1058
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
1059
  }
2✔
1060

1061
  {
2✔
1062
    /* pass to backend, backend answers right away, processResponse() fails */
1063
    TEST_INIT("=> Response processing fails ");
2✔
1064
    s_readBuffer = query;
2✔
1065

1066
    s_backendReadBuffer = query;
2✔
1067

1068
    s_steps = {
2✔
1069
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
1070
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
1071
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
1072
      /* opening a connection to the backend */
1073
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1074
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
2✔
1075
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
1076
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, query.size() - 2 },
2✔
1077
      /* closing client connection */
1078
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
1079
      /* closing a connection to the backend */
1080
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1081
    };
2✔
1082
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
1083
      (void)dq;
2✔
1084
      selectedBackend = backend;
2✔
1085
      return ProcessQueryResult::PassToBackend;
2✔
1086
    };
2✔
1087
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
2✔
1088
      (void)response;
2✔
1089
      (void)dr;
2✔
1090
      (void)muted;
2✔
1091
      return false;
2✔
1092
    };
2✔
1093

1094
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
1095
    state->handleIO();
2✔
1096
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
2✔
1097
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), query.size());
2✔
1098
    BOOST_CHECK(s_backendWriteBuffer == query);
2✔
1099
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
1100
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
1101
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
1102
  }
2✔
1103

1104
  {
2✔
1105
    /* pass to backend, backend answers right away, ID matching fails */
1106
    TEST_INIT("=> ID matching fails ");
2✔
1107
    s_readBuffer = query;
2✔
1108

1109
    auto responsePacket = query;
2✔
1110
    /* mess with the transaction ID */
1111
    responsePacket.at(3) ^= 42;
2✔
1112

1113
    s_backendReadBuffer = responsePacket;
2✔
1114

1115
    s_steps = {
2✔
1116
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
1117
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
1118
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
1119
      /* opening a connection to the backend */
1120
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1121
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
2✔
1122
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
1123
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, query.size() - 2 },
2✔
1124
      /* closing client connection */
1125
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
1126
      /* closing a connection to the backend */
1127
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1128
    };
2✔
1129
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
1130
      (void)dq;
2✔
1131
      selectedBackend = backend;
2✔
1132
      return ProcessQueryResult::PassToBackend;
2✔
1133
    };
2✔
1134
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
2✔
NEW
1135
      (void)response;
×
NEW
1136
      (void)dr;
×
NEW
1137
      (void)muted;
×
1138
      return true;
×
1139
    };
×
1140

1141
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
1142
    state->handleIO();
2✔
1143
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
2✔
1144
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), query.size());
2✔
1145
    BOOST_CHECK(s_backendWriteBuffer == query);
2✔
1146
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
1147
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
1148
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
1149
  }
2✔
1150

1151
  {
2✔
1152
    TEST_INIT("=> Short (too short) query");
2✔
1153
    s_readBuffer = shortQuery;
2✔
1154

1155
    s_steps = {
2✔
1156
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
1157
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
1158
      /* closing client connection */
1159
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
1160
    };
2✔
1161
    s_processQuery = [](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
NEW
1162
      (void)dq;
×
NEW
1163
      (void)selectedBackend;
×
1164
      return ProcessQueryResult::SendAnswer;
×
1165
    };
×
1166
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
2✔
NEW
1167
      (void)response;
×
NEW
1168
      (void)dr;
×
NEW
1169
      (void)muted;
×
1170
      return true;
×
1171
    };
×
1172

1173
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
1174
    state->handleIO();
2✔
1175
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
2✔
1176
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), 0U);
2✔
1177
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
1178

1179
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
1180
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
1181
  }
2✔
1182

1183
  {
2✔
1184
    TEST_INIT("=> Short (too short) response from backend");
2✔
1185
    s_readBuffer = query;
2✔
1186

1187
    s_backendReadBuffer = shortQuery;
2✔
1188

1189
    s_steps = {
2✔
1190
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
1191
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
1192
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() },
2✔
1193
      /* opening a connection to the backend */
1194
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1195
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
2✔
1196
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
1197
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, query.size() - 2 },
2✔
1198
      /* closing client connection */
1199
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
1200
      /* closing backend connection */
1201
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1202
    };
2✔
1203
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
1204
      (void)dq;
2✔
1205
      selectedBackend = backend;
2✔
1206
      return ProcessQueryResult::PassToBackend;
2✔
1207
    };
2✔
1208
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
2✔
NEW
1209
      (void)response;
×
NEW
1210
      (void)dr;
×
NEW
1211
      (void)muted;
×
1212
      return true;
×
1213
    };
×
1214

1215
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
1216
    state->handleIO();
2✔
1217
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
2✔
1218
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), query.size());
2✔
1219
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
1220

1221
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
1222
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
1223
  }
2✔
1224

1225
  {
2✔
1226
    /* connect in progress, short write to the backend, short read from the backend, client */
1227
    TEST_INIT("=> Short read and write to backend");
2✔
1228
    s_readBuffer = query;
2✔
1229
    // append a second query
1230
    appendPayloadEditingID(s_readBuffer, query, 1);
2✔
1231

1232
    s_backendReadBuffer = query;
2✔
1233
    // append a second query
1234
    appendPayloadEditingID(s_backendReadBuffer, query, 1);
2✔
1235

1236
    s_steps = {
2✔
1237
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
1238
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
1239
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
1240
      /* connect to backend */
1241
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::NeedWrite, 0, [&threadData](int desc) {
2✔
1242
          /* set the outgoing descriptor (backend connection) as ready */
1243
          dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(desc);
2✔
1244
        }
2✔
1245
      },
2✔
1246
      /* send query */
1247
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::NeedWrite, 1 },
2✔
1248
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() - 1 },
2✔
1249
      /* read response */
1250
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 1 },
2✔
1251
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 1 },
2✔
1252
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, query.size() - 3 },
2✔
1253
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 1 },
2✔
1254
      /* write response to client */
1255
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::NeedWrite, query.size() - 1 },
2✔
1256
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, 1 },
2✔
1257
      /* read second query */
1258
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
1259
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
1260
      /* write second query to backend */
1261
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
2✔
1262
      /* read second response */
1263
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
1264
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, query.size() - 2 },
2✔
1265
      /* write second response */
1266
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, query.size() },
2✔
1267
      /* read from client */
1268
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 },
2✔
1269
      /* close connection to client */
1270
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
1271
      /* close connection to the backend, eventually */
1272
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1273
    };
2✔
1274

1275
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
4✔
1276
      (void)dq;
4✔
1277
      selectedBackend = backend;
4✔
1278
      return ProcessQueryResult::PassToBackend;
4✔
1279
    };
4✔
1280
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
4✔
1281
      (void)response;
4✔
1282
      (void)dr;
4✔
1283
      (void)muted;
4✔
1284
      return true;
4✔
1285
    };
4✔
1286

1287
    /* set the incoming descriptor as ready! */
1288
    dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(-1);
2✔
1289
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
1290
    state->handleIO();
2✔
1291
    while (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0) {
10✔
1292
      threadData.mplexer->run(&now);
8✔
1293
    }
8✔
1294
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), query.size() * 2U);
2✔
1295
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), query.size() * 2U);
2✔
1296
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
1297

1298
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
1299
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
1300
  }
2✔
1301

1302
  {
2✔
1303
    /* connection refused by the backend */
1304
    TEST_INIT("=> Connection refused by the backend ");
2✔
1305
    s_readBuffer = query;
2✔
1306

1307
    s_steps = {
2✔
1308
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
1309
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
1310
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
1311
      /* opening a connection to the backend (5 tries by default) */
1312
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done, 0, [](int descriptor) {
2✔
1313
          (void)descriptor;
2✔
1314
          throw NetworkError("Connection refused by the backend");
2✔
1315
        }
2✔
1316
      },
2✔
1317
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1318
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done, 0, [](int descriptor) {
2✔
1319
          (void)descriptor;
2✔
1320
          throw NetworkError("Connection refused by the backend");
2✔
1321
        }
2✔
1322
      },
2✔
1323
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1324
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done, 0, [](int descriptor) {
2✔
1325
          (void)descriptor;
2✔
1326
          throw NetworkError("Connection refused by the backend");
2✔
1327
        }
2✔
1328
      },
2✔
1329
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1330
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done, 0, [](int descriptor) {
2✔
1331
          (void)descriptor;
2✔
1332
          throw NetworkError("Connection refused by the backend");
2✔
1333
        }
2✔
1334
      },
2✔
1335
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1336
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done, 0, [](int descriptor) {
2✔
1337
          (void)descriptor;
2✔
1338
          throw NetworkError("Connection refused by the backend");
2✔
1339
        }
2✔
1340
      },
2✔
1341
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1342
      /* closing client connection */
1343
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
1344
    };
2✔
1345

1346
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
1347
      (void)dq;
2✔
1348
      selectedBackend = backend;
2✔
1349
      return ProcessQueryResult::PassToBackend;
2✔
1350
    };
2✔
1351
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
2✔
NEW
1352
      (void)response;
×
NEW
1353
      (void)dr;
×
NEW
1354
      (void)muted;
×
1355
      return true;
×
1356
    };
×
1357

1358
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
1359
    state->handleIO();
2✔
1360
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
2✔
1361
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), 0U);
2✔
1362
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
1363

1364
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
1365
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
1366
  }
2✔
1367

1368
  {
2✔
1369
    /* timeout from the backend (write) */
1370
    TEST_INIT("=> Timeout from the backend (write) ");
2✔
1371
    s_readBuffer = query;
2✔
1372

1373
    s_steps = {
2✔
1374
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
1375
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
1376
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
1377
      /* opening a connection to the backend (retrying 5 times) */
1378
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1379
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::NeedWrite },
2✔
1380
      /* closing client connection */
1381
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
1382
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1383
    };
2✔
1384

1385
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
1386
      (void)dq;
2✔
1387
      selectedBackend = backend;
2✔
1388
      return ProcessQueryResult::PassToBackend;
2✔
1389
    };
2✔
1390
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
2✔
NEW
1391
      (void)response;
×
NEW
1392
      (void)dr;
×
NEW
1393
      (void)muted;
×
1394
      return true;
×
1395
    };
×
1396

1397
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
1398
    state->handleIO();
2✔
1399
    struct timeval later = now;
2✔
1400
    later.tv_sec += backend->d_config.tcpSendTimeout + 1;
2✔
1401
    auto expiredWriteConns = threadData.mplexer->getTimeouts(later, true);
2✔
1402
    BOOST_CHECK_EQUAL(expiredWriteConns.size(), 1U);
2✔
1403
    for (const auto& cbData : expiredWriteConns) {
2✔
1404
      if (cbData.second.type() == typeid(std::shared_ptr<TCPConnectionToBackend>)) {
2!
1405
        auto cbState = boost::any_cast<std::shared_ptr<TCPConnectionToBackend>>(cbData.second);
2✔
1406
        cbState->handleTimeout(later, true);
2✔
1407
      }
2✔
1408
    }
2✔
1409
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
2✔
1410
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), 0U);
2✔
1411
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
1412

1413
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
1414
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
1415
  }
2✔
1416

1417
  {
2✔
1418
    /* timeout from the backend (read) */
1419
    TEST_INIT("=> Timeout from the backend (read) ");
2✔
1420
    s_readBuffer = query;
2✔
1421

1422
    s_steps = {
2✔
1423
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
1424
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
1425
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
1426
      /* opening a connection to the backend */
1427
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1428
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
2✔
1429
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
1430
      /* closing client connection */
1431
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
1432
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1433
    };
2✔
1434

1435
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
1436
      (void)dq;
2✔
1437
      selectedBackend = backend;
2✔
1438
      return ProcessQueryResult::PassToBackend;
2✔
1439
    };
2✔
1440
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
2✔
NEW
1441
      (void)response;
×
NEW
1442
      (void)dr;
×
NEW
1443
      (void)muted;
×
1444
      return true;
×
1445
    };
×
1446

1447
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
1448
    state->handleIO();
2✔
1449
    struct timeval later = now;
2✔
1450
    later.tv_sec += backend->d_config.tcpRecvTimeout + 1;
2✔
1451
    auto expiredConns = threadData.mplexer->getTimeouts(later, false);
2✔
1452
    BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
2✔
1453
    for (const auto& cbData : expiredConns) {
2✔
1454
      if (cbData.second.type() == typeid(std::shared_ptr<TCPConnectionToBackend>)) {
2!
1455
        auto cbState = boost::any_cast<std::shared_ptr<TCPConnectionToBackend>>(cbData.second);
2✔
1456
        cbState->handleTimeout(later, false);
2✔
1457
      }
2✔
1458
    }
2✔
1459
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
2✔
1460
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), query.size());
2✔
1461
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
1462

1463
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
1464
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
1465
  }
2✔
1466

1467
  {
2✔
1468
    /* connection closed from the backend (write) */
1469
    TEST_INIT("=> Connection closed from the backend (write) ");
2✔
1470
    s_readBuffer = query;
2✔
1471

1472
    s_steps = {
2✔
1473
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
1474
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
1475
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
1476
      /* opening a connection to the backend, connection closed on first write (5 attempts) */
1477
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1478
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, 0 },
2✔
1479
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1480
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1481
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, 0 },
2✔
1482
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1483
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1484
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, 0 },
2✔
1485
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1486
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1487
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, 0 },
2✔
1488
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1489
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1490
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, 0 },
2✔
1491
      /* closing client connection */
1492
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
1493
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1494
    };
2✔
1495

1496
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
1497
      (void)dq;
2✔
1498
      selectedBackend = backend;
2✔
1499
      return ProcessQueryResult::PassToBackend;
2✔
1500
    };
2✔
1501
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
2✔
NEW
1502
      (void)response;
×
NEW
1503
      (void)dr;
×
NEW
1504
      (void)muted;
×
1505
      return true;
×
1506
    };
×
1507

1508
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
1509
    state->handleIO();
2✔
1510
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
2✔
1511
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), 0U);
2✔
1512
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
1513

1514
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
1515
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
1516
  }
2✔
1517

1518
  {
2✔
1519
    /* connection closed from the backend (write) 4 times then succeeds */
1520
    TEST_INIT("=> Connection closed from the backend (write) 4 times then succeeds");
2✔
1521
    s_readBuffer = query;
2✔
1522
    s_backendReadBuffer = query;
2✔
1523

1524
    s_steps = {
2✔
1525
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
1526
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
1527
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
1528
      /* opening a connection to the backend, connection closed on first write (5 attempts) */
1529
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1530
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, 0 },
2✔
1531
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1532
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1533
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, 0 },
2✔
1534
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1535
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1536
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, 0 },
2✔
1537
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1538
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1539
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, 0 },
2✔
1540
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1541
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1542
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
2✔
1543
      /* reading the response */
1544
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
1545
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, query.size() - 2 },
2✔
1546
      /* send the response to the client */
1547
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, query.size() },
2✔
1548
      /* client closes the connection */
1549
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 },
2✔
1550
      /* closing client connection */
1551
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
1552
      /* then eventually the backend one */
1553
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1554
    };
2✔
1555

1556
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
1557
      (void)dq;
2✔
1558
      selectedBackend = backend;
2✔
1559
      return ProcessQueryResult::PassToBackend;
2✔
1560
    };
2✔
1561
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
2✔
1562
      (void)response;
2✔
1563
      (void)dr;
2✔
1564
      (void)muted;
2✔
1565
      return true;
2✔
1566
    };
2✔
1567

1568
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
1569
    state->handleIO();
2✔
1570
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), query.size());
2✔
1571
    BOOST_CHECK(s_writeBuffer == query);
2✔
1572
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), query.size());
2✔
1573
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
1574

1575
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
1576
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
1577
  }
2✔
1578

1579
  {
2✔
1580
    TEST_INIT("=> connection closed by the backend on write, then refused");
2✔
1581
    s_readBuffer = query;
2✔
1582

1583
    s_steps = {
2✔
1584
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
1585
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
1586
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
1587
      /* opening a connection to the backend, connection closed on first write */
1588
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1589
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, 0 },
2✔
1590
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1591
      /* and now reconnection fails (1) */
1592
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done, 0, [](int descriptor) {
2✔
1593
          (void)descriptor;
2✔
1594
          throw NetworkError("Connection refused by the backend");
2✔
1595
        }
2✔
1596
      },
2✔
1597
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1598
      /* 2 */
1599
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done, 0, [](int descriptor) {
2✔
1600
          (void)descriptor;
2✔
1601
          throw NetworkError("Connection refused by the backend");
2✔
1602
        }
2✔
1603
      },
2✔
1604
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1605
      /* 3 */
1606
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done, 0, [](int descriptor) {
2✔
1607
          (void)descriptor;
2✔
1608
          throw NetworkError("Connection refused by the backend");
2✔
1609
        }
2✔
1610
      },
2✔
1611
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1612
      /* 4 */
1613
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done, 0, [](int descriptor) {
2✔
1614
          (void)descriptor;
2✔
1615
          throw NetworkError("Connection refused by the backend");
2✔
1616
        }
2✔
1617
      },
2✔
1618
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1619
      /* closing client connection */
1620
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
1621
    };
2✔
1622

1623
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
1624
      (void)dq;
2✔
1625
      selectedBackend = backend;
2✔
1626
      return ProcessQueryResult::PassToBackend;
2✔
1627
    };
2✔
1628
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
2✔
NEW
1629
      (void)response;
×
NEW
1630
      (void)dr;
×
NEW
1631
      (void)muted;
×
1632
      return true;
×
1633
    };
×
1634

1635
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
1636
    state->handleIO();
2✔
1637
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
2✔
1638
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), 0U);
2✔
1639
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
1640

1641
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
1642
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
1643
  }
2✔
1644

1645
  {
2✔
1646
    /* connection closed from the backend (read) */
1647
    TEST_INIT("=> Connection closed from the backend (read) ");
2✔
1648
    s_readBuffer = query;
2✔
1649

1650
    s_steps = {
2✔
1651
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
1652
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
1653
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
1654
      /* opening a connection to the backend, connection closed on read, 5 attempts, last one succeeds */
1655
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1656
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
2✔
1657
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 0 },
2✔
1658
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1659
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1660
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
2✔
1661
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 0 },
2✔
1662
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1663
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1664
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
2✔
1665
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 0 },
2✔
1666
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1667
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1668
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
2✔
1669
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 0 },
2✔
1670
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1671
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1672
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
2✔
1673
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 0 },
2✔
1674
      /* closing client connection */
1675
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
1676
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1677
    };
2✔
1678

1679
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
1680
      (void)dq;
2✔
1681
      selectedBackend = backend;
2✔
1682
      return ProcessQueryResult::PassToBackend;
2✔
1683
    };
2✔
1684
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
2✔
NEW
1685
      (void)response;
×
NEW
1686
      (void)dr;
×
NEW
1687
      (void)muted;
×
1688
      return true;
×
1689
    };
×
1690

1691
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
1692
    state->handleIO();
2✔
1693
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
2✔
1694
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), query.size() * backend->d_config.d_retries);
2✔
1695
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
1696

1697
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
1698
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
1699
  }
2✔
1700

1701
  {
2✔
1702
    /* connection closed from the backend (read) 4 times then succeeds */
1703
    TEST_INIT("=> Connection closed from the backend (read) 4 times then succeeds ");
2✔
1704
    s_readBuffer = query;
2✔
1705
    s_backendReadBuffer = query;
2✔
1706

1707
    s_steps = {
2✔
1708
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
1709
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
1710
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
1711
      /* opening a connection to the backend, connection closed on read, 5 attempts, last one succeeds */
1712
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1713
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
2✔
1714
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 0 },
2✔
1715
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1716
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1717
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
2✔
1718
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 0 },
2✔
1719
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1720
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1721
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
2✔
1722
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 0 },
2✔
1723
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1724
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1725
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
2✔
1726
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 0 },
2✔
1727
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1728
      /* this time it works */
1729
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1730
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
2✔
1731
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
1732
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, query.size() - 2 },
2✔
1733
      /* sending the response to the client */
1734
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, query.size() },
2✔
1735
      /* client closes the connection */
1736
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 },
2✔
1737
      /* closing client connection */
1738
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
1739
      /* the eventually the backend one */
1740
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1741
    };
2✔
1742

1743
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
1744
      (void)dq;
2✔
1745
      selectedBackend = backend;
2✔
1746
      return ProcessQueryResult::PassToBackend;
2✔
1747
    };
2✔
1748
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
2✔
1749
      (void)response;
2✔
1750
      (void)dr;
2✔
1751
      (void)muted;
2✔
1752
      return true;
2✔
1753
    };
2✔
1754

1755
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
1756
    state->handleIO();
2✔
1757
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), query.size());
2✔
1758
    BOOST_CHECK(s_writeBuffer == query);
2✔
1759
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), query.size() * backend->d_config.d_retries);
2✔
1760
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
1761

1762
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
1763
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
1764
  }
2✔
1765

1766
  {
2✔
1767
    TEST_INIT("=> Connection closed by the client when trying to send the response received from the backend");
2✔
1768
    s_readBuffer = query;
2✔
1769
    s_backendReadBuffer = query;
2✔
1770

1771
    s_steps = {
2✔
1772
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
1773
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
1774
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
1775
      /* opening a connection to the backend */
1776
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1777
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() },
2✔
1778
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
1779
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, query.size() - 2 },
2✔
1780
      /* sending the response to the client, the connection has been closed */
1781
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, 0 },
2✔
1782
      /* closing client connection */
1783
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
1784
      /* and eventually the backend one */
1785
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
1786
    };
2✔
1787

1788
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
1789
      (void)dq;
2✔
1790
      selectedBackend = backend;
2✔
1791
      return ProcessQueryResult::PassToBackend;
2✔
1792
    };
2✔
1793
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
2✔
1794
      (void)response;
2✔
1795
      (void)dr;
2✔
1796
      (void)muted;
2✔
1797
      return true;
2✔
1798
    };
2✔
1799

1800
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
1801
    state->handleIO();
2✔
1802
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
2✔
1803
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), query.size());
2✔
1804
    BOOST_CHECK(s_backendWriteBuffer == query);
2✔
1805
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
1806

1807
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
1808
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
1809
  }
2✔
1810

1811
  {
2✔
1812
#if 1
2✔
1813
    /* 101 queries on the same connection, check that the maximum number of queries kicks in */
1814
    TEST_INIT("=> 101 queries on the same connection");
2✔
1815

1816
    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
2✔
1817
      config.d_maxTCPQueriesPerConn = 100;
2✔
1818
    });
2✔
1819

1820
    size_t count = 101;
2✔
1821

1822
    s_readBuffer = query;
2✔
1823

1824
    for (size_t idx = 0; idx < count; idx++) {
204✔
1825
      appendPayloadEditingID(s_readBuffer, query, idx);
202✔
1826
      appendPayloadEditingID(s_backendReadBuffer, query, idx);
202✔
1827
    }
202✔
1828

1829
    s_steps = { { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
1830
                { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
1831
                { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
1832
                /* opening a connection to the backend */
1833
                { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
1834
                { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() + 2 },
2✔
1835
                { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
1836
                { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, query.size() - 2 },
2✔
1837
                { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, query.size() + 2 }
2✔
1838
    };
2✔
1839

1840
    for (size_t idx = 0; idx < count - 1; idx++) {
202✔
1841
      /* read a new query */
1842
      s_steps.push_back({ ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 });
200✔
1843
      s_steps.push_back({ ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 });
200✔
1844
      /* pass it to the backend */
1845
      s_steps.push_back({ ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, query.size() + 2 });
200✔
1846
      s_steps.push_back({ ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 });
200✔
1847
      s_steps.push_back({ ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, query.size() - 2 });
200✔
1848
      /* send the response */
1849
      s_steps.push_back({ ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, query.size() + 2 });
200✔
1850
    };
200✔
1851
    /* close the connection with the backend */
1852
    s_steps.push_back({ ExpectedStep::ExpectedRequest::closeBackend, IOState::Done });
2✔
1853
    /* close the connection with the client */
1854
    s_steps.push_back({ ExpectedStep::ExpectedRequest::closeClient, IOState::Done });
2✔
1855

1856
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
202✔
1857
      (void)dq;
202✔
1858
      selectedBackend = backend;
202✔
1859
      return ProcessQueryResult::PassToBackend;
202✔
1860
    };
202✔
1861
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
202✔
1862
      (void)response;
202✔
1863
      (void)dr;
202✔
1864
      (void)muted;
202✔
1865
      return true;
202✔
1866
    };
202✔
1867

1868
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
1869
    state->handleIO();
2✔
1870
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), query.size() * count);
2✔
1871
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
1872

1873
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
1874
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
1875

1876
    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
2✔
1877
      config.d_maxTCPQueriesPerConn = 0;
2✔
1878
    });
2✔
1879
#endif
2✔
1880
  }
2✔
1881

1882
  {
2✔
1883
    /* 2 queries on the same connection, asynchronously handled, check that we only read the first one (no OOOR as maxInFlight is 0) */
1884
    TEST_INIT("=> 2 queries on the same connection, async");
2✔
1885

1886
    size_t count = 2;
2✔
1887

1888
    s_readBuffer = query;
2✔
1889

1890
    for (size_t idx = 0; idx < count; idx++) {
6✔
1891
      appendPayloadEditingID(s_readBuffer, query, idx);
4✔
1892
      appendPayloadEditingID(s_backendReadBuffer, query, idx);
4✔
1893
    }
4✔
1894

1895
    s_steps = { { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
1896
                { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
1897
                { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, query.size() - 2 },
2✔
1898
                /* close the connection with the client */
1899
                { ExpectedStep::ExpectedRequest::closeClient, IOState::Done }
2✔
1900
    };
2✔
1901

1902
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
1903
      (void)dq;
2✔
1904
      selectedBackend = backend;
2✔
1905
      dq.asynchronous = true;
2✔
1906
      /* note that we do nothing with the query, we just tell the frontend it was dealt with */
1907
      return ProcessQueryResult::Asynchronous;
2✔
1908
    };
2✔
1909
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
2✔
NEW
1910
      (void)response;
×
NEW
1911
      (void)dr;
×
NEW
1912
      (void)muted;
×
1913
      return true;
×
1914
    };
×
1915

1916
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
1917
    state->handleIO();
2✔
1918
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
1919

1920
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
1921
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
1922
  }
2✔
1923
}
2✔
1924

1925
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
1926
BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture)
1927
{
2✔
1928
  const auto tcpRecvTimeout = dnsdist::configuration::getCurrentRuntimeConfiguration().d_tcpRecvTimeout;
2✔
1929
  auto local = getBackendAddress("1", 80);
2✔
1930
  ClientState localCS(local, true, false, 0, "", {}, true);
2✔
1931
  /* enable out-of-order on the front side */
1932
  localCS.d_maxInFlightQueriesPerConn = 65536;
2✔
1933

1934
  auto tlsCtx = std::make_shared<MockupTLSCtx>();
2✔
1935
  localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
2✔
1936

1937
  ConnectionInfo connInfo(&localCS);
2✔
1938
  connInfo.remote = getBackendAddress("84", 4242);
2✔
1939

1940
  auto backend = std::make_shared<DownstreamState>(getBackendAddress("42", 53));
2✔
1941
  backend->d_tlsCtx = tlsCtx;
2✔
1942
  /* enable out-of-order on the backend side as well */
1943
  backend->d_config.d_maxInFlightQueriesPerConn = 65536;
2✔
1944
  /* shorter than the client one */
1945
  backend->d_config.tcpRecvTimeout = 1;
2✔
1946

1947
  TCPClientThreadData threadData;
2✔
1948
  threadData.mplexer = std::make_unique<MockupFDMultiplexer>();
2✔
1949

1950
  struct timeval now;
2✔
1951
  gettimeofday(&now, nullptr);
2✔
1952

1953
  std::vector<PacketBuffer> queries(5);
2✔
1954
  std::vector<PacketBuffer> responses(5);
2✔
1955

1956
  size_t counter = 0;
2✔
1957
  size_t totalQueriesSize = 0;
2✔
1958
  for (auto& query : queries) {
10✔
1959
    GenericDNSPacketWriter<PacketBuffer> pwQ(query, DNSName("powerdns" + std::to_string(counter) + ".com."), QType::A, QClass::IN, 0);
10✔
1960
    pwQ.getHeader()->rd = 1;
10✔
1961
    pwQ.getHeader()->id = htons(counter);
10✔
1962
    uint16_t querySize = static_cast<uint16_t>(query.size());
10✔
1963
    const uint8_t sizeBytes[] = { static_cast<uint8_t>(querySize / 256), static_cast<uint8_t>(querySize % 256) };
10✔
1964
    query.insert(query.begin(), sizeBytes, sizeBytes + 2);
10✔
1965
    totalQueriesSize += query.size();
10✔
1966
    ++counter;
10✔
1967
  }
10✔
1968

1969
  counter = 0;
2✔
1970
  size_t totalResponsesSize = 0;
2✔
1971
  for (auto& response : responses) {
10✔
1972
    DNSName name("powerdns" + std::to_string(counter) + ".com.");
10✔
1973
    GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
10✔
1974
    pwR.getHeader()->qr = 1;
10✔
1975
    pwR.getHeader()->rd = 1;
10✔
1976
    pwR.getHeader()->ra = 1;
10✔
1977
    pwR.getHeader()->id = htons(counter);
10✔
1978
    pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
10✔
1979
    pwR.xfr32BitInt(0x01020304);
10✔
1980
    pwR.commit();
10✔
1981

1982
    uint16_t responseSize = static_cast<uint16_t>(response.size());
10✔
1983
    const uint8_t sizeBytes[] = { static_cast<uint8_t>(responseSize / 256), static_cast<uint8_t>(responseSize % 256) };
10✔
1984
    response.insert(response.begin(), sizeBytes, sizeBytes + 2);
10✔
1985
    totalResponsesSize += response.size();
10✔
1986
    ++counter;
10✔
1987
  }
10✔
1988

1989
  {
2✔
1990
    TEST_INIT("=> 5 OOOR queries to the backend, backend responds in reverse order");
2✔
1991
    PacketBuffer expectedWriteBuffer;
2✔
1992
    PacketBuffer expectedBackendWriteBuffer;
2✔
1993

1994
    uint16_t backendCounter = 0;
2✔
1995
    for (const auto& query : queries) {
10✔
1996
      s_readBuffer.insert(s_readBuffer.end(), query.begin(), query.end());
10✔
1997
      appendPayloadEditingID(expectedBackendWriteBuffer, query, backendCounter++);
10✔
1998
    }
10✔
1999

2000
    backendCounter = 0;
2✔
2001
    for (const auto& response : responses) {
10✔
2002
      /* reverse order */
2003
      prependPayloadEditingID(s_backendReadBuffer, response, backendCounter++);
10✔
2004
      expectedWriteBuffer.insert(expectedWriteBuffer.begin(), response.begin(), response.end());
10✔
2005
    }
10✔
2006

2007
    s_steps = {
2✔
2008
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
2009
      /* reading a query from the client (1) */
2010
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2011
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(0).size() - 2 },
2✔
2012
      /* opening a connection to the backend */
2013
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
2014
      /* sending query to the backend */
2015
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(0).size() },
2✔
2016
      /* no response ready yet */
2017
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
2018
      /* reading a query from the client (2) */
2019
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2020
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(1).size() - 2 },
2✔
2021
      /* sending query to the backend */
2022
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(1).size() },
2✔
2023
      /* no response ready yet */
2024
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
2025
      /* reading a query from the client (3) */
2026
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2027
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(2).size() - 2 },
2✔
2028
      /* sending query to the backend */
2029
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(2).size() },
2✔
2030
      /* no response ready yet */
2031
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
2032
      /* reading a query from the client (4) */
2033
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2034
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(3).size() - 2 },
2✔
2035
      /* sending query to the backend */
2036
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(3).size() },
2✔
2037
      /* no response ready yet */
2038
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
2039
      /* reading a query from the client (5) */
2040
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2041
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(4).size() - 2 },
2✔
2042
      /* sending query to the backend */
2043
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(4).size() },
2✔
2044
      /* no response ready yet, but the backend becomes ready */
2045
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0, [&threadData](int desc) {
2✔
2046
        /* set the outgoing descriptor (backend connection) as ready */
2047
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(desc);
2✔
2048
      } },
2✔
2049

2050
      /* no more queries from the client */
2051
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 0 },
2✔
2052

2053
      /* reading a response from the backend */
2054
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(4).size() - 2 },
2✔
2055
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(4).size() },
2✔
2056
      /* sending it to the client */
2057
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(4).size() },
2✔
2058

2059
      /* reading a response from the backend */
2060
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(3).size() - 2 },
2✔
2061
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(3).size() },
2✔
2062
      /* sending it to the client */
2063
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(3).size() },
2✔
2064

2065
      /* reading a response from the backend */
2066
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(2).size() - 2 },
2✔
2067
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(2).size() },
2✔
2068
      /* sending it to the client */
2069
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(2).size() },
2✔
2070

2071
      /* reading a response from the backend */
2072
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(1).size() - 2 },
2✔
2073
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(1).size() },
2✔
2074
      /* sending it to the client */
2075
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(1).size() },
2✔
2076

2077
      /* reading a response from the backend */
2078
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(0).size() - 2 },
2✔
2079
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(0).size() },
2✔
2080
      /* sending it to the client, the client descriptor becomes ready */
2081
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(0).size(), [&threadData](int desc) {
2✔
2082
        /* set the incoming descriptor (client connection) as ready */
2083
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(desc);
2✔
2084
      } },
2✔
2085

2086
      /* client is closing the connection */
2087
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 },
2✔
2088
      /* closing client connection */
2089
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
2090
      /* closing a connection to the backend */
2091
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
2092
    };
2✔
2093

2094
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
10✔
2095
      (void)dq;
10✔
2096
      selectedBackend = backend;
10✔
2097
      return ProcessQueryResult::PassToBackend;
10✔
2098
    };
10✔
2099
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
10✔
2100
      (void)response;
10✔
2101
      (void)dr;
10✔
2102
      (void)muted;
10✔
2103
      return true;
10✔
2104
    };
10✔
2105

2106
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
2107
    state->handleIO();
2✔
2108
    while (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0) {
14!
2109
      threadData.mplexer->run(&now);
12✔
2110
    }
12✔
2111

2112
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), totalResponsesSize);
2✔
2113
    BOOST_CHECK(s_writeBuffer == expectedWriteBuffer);
2✔
2114
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), totalQueriesSize);
2✔
2115
    BOOST_CHECK(s_backendWriteBuffer == expectedBackendWriteBuffer);
2✔
2116
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
2117

2118
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
2119
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
2120
  }
2✔
2121

2122
  {
2✔
2123
    TEST_INIT("=> 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");
2✔
2124

2125
    // increase the client timeout for that test, we want the backend to timeout first
2126
    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
2✔
2127
      config.d_tcpRecvTimeout = 5;
2✔
2128
    });
2✔
2129

2130
    PacketBuffer expectedWriteBuffer;
2✔
2131
    PacketBuffer expectedBackendWriteBuffer;
2✔
2132

2133
    for (const auto& query : queries) {
10✔
2134
      s_readBuffer.insert(s_readBuffer.end(), query.begin(), query.end());
10✔
2135
    }
10✔
2136

2137
    uint16_t backendCounter = 0;
2✔
2138
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(0), backendCounter++);
2✔
2139
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(1), backendCounter++);
2✔
2140
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(2), backendCounter++);
2✔
2141
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(4), backendCounter++);
2✔
2142

2143
    appendPayloadEditingID(s_backendReadBuffer, responses.at(0), 0);
2✔
2144
    appendPayloadEditingID(s_backendReadBuffer, responses.at(4), 3);
2✔
2145

2146
    /* self-answered */
2147
    expectedWriteBuffer.insert(expectedWriteBuffer.end(), responses.at(3).begin(), responses.at(3).end());
2✔
2148
    /* from backend */
2149
    expectedWriteBuffer.insert(expectedWriteBuffer.end(), responses.at(0).begin(), responses.at(0).end());
2✔
2150
    expectedWriteBuffer.insert(expectedWriteBuffer.end(), responses.at(4).begin(), responses.at(4).end());
2✔
2151

2152
    bool timeout = false;
2✔
2153
    s_steps = {
2✔
2154
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
2155
      /* reading a query from the client (1) */
2156
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2157
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(0).size() - 2 },
2✔
2158
      /* opening a connection to the backend */
2159
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
2160
      /* sending query to the backend */
2161
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(0).size() },
2✔
2162
      /* no response ready yet */
2163
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
2164
      /* reading a query from the client (2) */
2165
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2166
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(1).size() - 2 },
2✔
2167
      /* sending query to the backend */
2168
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(1).size() },
2✔
2169
      /* no response ready yet */
2170
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
2171
      /* reading a query from the client (3) */
2172
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2173
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(2).size() - 2 },
2✔
2174
      /* sending query to the backend */
2175
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(2).size() },
2✔
2176
      /* no response ready yet */
2177
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
2178
      /* reading a query from the client (4) */
2179
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2180
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(3).size() - 2 },
2✔
2181
      /* sending the response right away (self-answered)  */
2182
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(3).size() },
2✔
2183
      /* reading a query from the client (5) */
2184
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2185
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(4).size() - 2 },
2✔
2186
      /* sending query to the backend (5) */
2187
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(4).size() },
2✔
2188
      /* reading a response from the backend (1) */
2189
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(0).size() - 2 },
2✔
2190
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(0).size(), [&threadData](int desc) {
2✔
2191
        /* set the backend descriptor as ready */
2192
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(desc);
2✔
2193
      } },
2✔
2194
      /* sending it to the client (1) */
2195
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(0).size(), [&threadData](int desc) {
2✔
2196
        /* set the client descriptor as NOT ready */
2197
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(desc);
2✔
2198
      } },
2✔
2199
      /* reading from the client (not ready) */
2200
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 0 },
2✔
2201
      /* reading a response from the backend (5) */
2202
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(4).size() - 2 },
2✔
2203
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(4).size() },
2✔
2204
      /* sending it to the client (5) */
2205
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(4).size() },
2✔
2206

2207
      /* try to read from the backend but there is no answer ready yet */
2208
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0, [&threadData, &timeout](int desc) {
2✔
2209
        /* set the backend descriptor as NOT ready */
2210
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(desc);
2✔
2211
        timeout = true;
2✔
2212
      } },
2✔
2213

2214
      /* A timeout occurs */
2215

2216
      /* closing client connection */
2217
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
2218

2219
      /* closing a connection to the backend */
2220
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
2221
    };
2✔
2222

2223
    s_processQuery = [backend,&responses](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
10✔
2224
      static size_t count = 0;
10✔
2225
      if (count++ == 3) {
10✔
2226
        /* self answered */
2227
        dq.getMutableData() = responses.at(3);
2✔
2228
        /* remove the length */
2229
        dq.getMutableData().erase(dq.getMutableData().begin(), dq.getMutableData().begin() + 2);
2✔
2230

2231
        return ProcessQueryResult::SendAnswer;
2✔
2232
      }
2✔
2233
      selectedBackend = backend;
8✔
2234
      return ProcessQueryResult::PassToBackend;
8✔
2235
    };
10✔
2236
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
4✔
2237
      (void)response;
4✔
2238
      (void)dr;
4✔
2239
      (void)muted;
4✔
2240
      return true;
4✔
2241
    };
4✔
2242

2243
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
2244
    state->handleIO();
2✔
2245

2246
    while (!timeout && (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
6!
2247
      threadData.mplexer->run(&now);
4✔
2248
    }
4✔
2249

2250
    struct timeval later = now;
2✔
2251
    later.tv_sec += backend->d_config.tcpRecvTimeout + 1;
2✔
2252
    auto expiredConns = threadData.mplexer->getTimeouts(later, false);
2✔
2253
    BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
2✔
2254
    for (const auto& cbData : expiredConns) {
2✔
2255
      if (cbData.second.type() == typeid(std::shared_ptr<TCPConnectionToBackend>)) {
2!
2256
        auto cbState = boost::any_cast<std::shared_ptr<TCPConnectionToBackend>>(cbData.second);
2✔
2257
        cbState->handleTimeout(later, false);
2✔
2258
      }
2✔
2259
    }
2✔
2260

2261
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), expectedWriteBuffer.size());
2✔
2262
    BOOST_CHECK(s_writeBuffer == expectedWriteBuffer);
2✔
2263
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), expectedBackendWriteBuffer.size());
2✔
2264
    BOOST_CHECK(s_backendWriteBuffer == expectedBackendWriteBuffer);
2✔
2265
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
2266

2267
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
2268
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
2269

2270
    // restore the client timeout
2271
    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
2✔
2272
      config.d_tcpRecvTimeout = 2;
2✔
2273
    });
2✔
2274
  }
2✔
2275

2276
  {
2✔
2277
    TEST_INIT("=> 1 query sent to the backend, short read from the backend, 1 new query arrives in the meantime, the first answer is sent to the client, then the second query is handled, a new one arrives but the connection to the backend dies on us, short write on a new connection, the last query arrives and both are answered");
2✔
2278

2279
    PacketBuffer expectedWriteBuffer;
2✔
2280
    PacketBuffer expectedBackendWriteBuffer;
2✔
2281

2282
    for (const auto& query : queries) {
10✔
2283
      s_readBuffer.insert(s_readBuffer.end(), query.begin(), query.end());
10✔
2284
    }
10✔
2285
    for (const auto& response : responses) {
10✔
2286
      expectedWriteBuffer.insert(expectedWriteBuffer.end(), response.begin(), response.end());
10✔
2287
    }
10✔
2288

2289
    uint16_t backendCounter = 0;
2✔
2290
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(0), backendCounter);
2✔
2291
    appendPayloadEditingID(s_backendReadBuffer, responses.at(0), backendCounter++);
2✔
2292
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(1), backendCounter);
2✔
2293
    appendPayloadEditingID(s_backendReadBuffer, responses.at(1), backendCounter++);
2✔
2294

2295
    // new connection
2296
    backendCounter = 0;
2✔
2297
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(2), backendCounter);
2✔
2298
    appendPayloadEditingID(s_backendReadBuffer, responses.at(2), backendCounter++);
2✔
2299
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(3), backendCounter);
2✔
2300
    appendPayloadEditingID(s_backendReadBuffer, responses.at(3), backendCounter++);
2✔
2301
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(4), backendCounter);
2✔
2302
    appendPayloadEditingID(s_backendReadBuffer, responses.at(4), backendCounter++);
2✔
2303

2304
    bool timeout = false;
2✔
2305
    int backendDesc;
2✔
2306
    s_steps = {
2✔
2307
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
2308
      /* reading a query from the client (1) */
2309
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2310
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(0).size() - 2 },
2✔
2311
      /* opening a connection to the backend */
2312
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
2313
      /* sending query to the backend */
2314
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(0).size() },
2✔
2315
      /* read response size and the beginning of the response (1) from the backend */
2316
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
2317
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 1, [&threadData](int desc) {
2✔
2318
        /* set the backend descriptor as ready */
2319
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(desc);
2✔
2320
      } },
2✔
2321
      /* reading a query from the client (2) */
2322
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2323
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(1).size() - 2 },
2✔
2324
      /* trying to read an additional query, if any */
2325
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 0, [&threadData](int desc) {
2✔
2326
        /* set the client descriptor as NOT ready */
2327
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(desc);
2✔
2328
      } },
2✔
2329
      /* reading the remaining bytes of response (1) from the backend */
2330
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(0).size() - 3 },
2✔
2331
      /* sending response (1) to the client */
2332
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(0).size() },
2✔
2333
      /* sending query (2) to the backend */
2334
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(1).size() },
2✔
2335
      /* the response (2) is already there */
2336
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
2337
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(1).size() - 2 },
2✔
2338
      /* sending response (2) to the client */
2339
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(1).size(), [&threadData](int desc) {
2✔
2340
        /* set the client descriptor as ready */
2341
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(desc);
2✔
2342
      } },
2✔
2343
      /* reading a query from the client (3) */
2344
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2345
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(2).size() - 2 },
2✔
2346
      /* sending query to the backend */
2347
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, 0 },
2✔
2348
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
2349
      /* opening a connection to the backend */
2350
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
2351
      /* sending query (3) to the backend, short write */
2352
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::NeedWrite, 1, [&threadData,&backendDesc](int desc) {
2✔
2353
        /* set the backend descriptor as NOT ready */
2354
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(desc);
2✔
2355
        backendDesc = desc;
2✔
2356
        /* but client is ready */
2357
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(-1);
2✔
2358
      } },
2✔
2359
      /* reading a query from the client (4) */
2360
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2361
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(3).size() - 2 },
2✔
2362
      /* reading a query from the client (5) */
2363
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2364
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(4).size() - 2, [&threadData,&backendDesc](int desc) {
2✔
2365
        (void)desc;
2✔
2366
        /* set the backend descriptor as ready now */
2367
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(backendDesc);
2✔
2368
      } },
2✔
2369
      /* nothing else to read from the client for now */
2370
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 0, [&threadData](int desc) {
2✔
2371
        /* set the client descriptor as NOT ready */
2372
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(desc);
2✔
2373
      } },
2✔
2374
      /* finishing sending the query (3) to the backend */
2375
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(2).size() - 1 },
2✔
2376
      /* sending the query (4) to the backend */
2377
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(3).size() },
2✔
2378
      /* sending the query (5) to the backend */
2379
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(4).size() },
2✔
2380
      /* reading a response from the backend (3) */
2381
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
2382
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(2).size() - 2 },
2✔
2383
      /* sending it to the client (3) */
2384
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(2).size() },
2✔
2385
      /* reading a response from the backend (4) */
2386
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
2387
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(3).size() - 2 },
2✔
2388
      /* sending it to the client (4) but short write */
2389
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::NeedWrite, responses.at(3).size() - 1, [&threadData](int desc) {
2✔
2390
        /* set the client descriptor as NOT ready */
2391
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(desc);
2✔
2392
      } },
2✔
2393
      /* reading a response from the backend (5) */
2394
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
2395
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(4).size() - 2, [&threadData](int desc) {
2✔
2396
        (void)desc;
2✔
2397
        /* set the client descriptor as ready to resume sending */
2398
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(-1);
2✔
2399
      } },
2✔
2400
      /* resume sending it to the client (4) */
2401
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, 1 },
2✔
2402
      /* sending it to the client (5) */
2403
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(4).size() },
2✔
2404

2405
      /* nothing to read from the client, then timeout later */
2406
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 0, [&threadData,&timeout](int desc) {
2✔
2407
        /* set the client descriptor as NOT ready */
2408
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(desc);
2✔
2409
        timeout = true;
2✔
2410
      } },
2✔
2411

2412
      /* closing a connection to the backend */
2413
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
2414

2415
      /* closing client connection */
2416
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
2417
    };
2✔
2418

2419
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
10✔
2420
      (void)dq;
10✔
2421
      selectedBackend = backend;
10✔
2422
      return ProcessQueryResult::PassToBackend;
10✔
2423
    };
10✔
2424
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
10✔
2425
      (void)response;
10✔
2426
      (void)dr;
10✔
2427
      (void)muted;
10✔
2428
      return true;
10✔
2429
    };
10✔
2430

2431
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
2432
    state->handleIO();
2✔
2433

2434
    while (!timeout && (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
14!
2435
      threadData.mplexer->run(&now);
12✔
2436
    }
12✔
2437

2438
    struct timeval later = now;
2✔
2439
    later.tv_sec += tcpRecvTimeout + 1;
2✔
2440
    auto expiredConns = threadData.mplexer->getTimeouts(later, false);
2✔
2441
    BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
2✔
2442
    for (const auto& cbData : expiredConns) {
2✔
2443
      if (cbData.second.type() == typeid(std::shared_ptr<IncomingTCPConnectionState>)) {
2!
2444
        auto cbState = boost::any_cast<std::shared_ptr<IncomingTCPConnectionState>>(cbData.second);
2✔
2445
        cbState->handleTimeout(cbState, false);
2✔
2446
      }
2✔
2447
    }
2✔
2448

2449
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), expectedWriteBuffer.size());
2✔
2450
    BOOST_CHECK(s_writeBuffer == expectedWriteBuffer);
2✔
2451
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), expectedBackendWriteBuffer.size());
2✔
2452
    BOOST_CHECK(s_backendWriteBuffer == expectedBackendWriteBuffer);
2✔
2453
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
2454

2455
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
2456
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
2457
  }
2✔
2458

2459
  {
2✔
2460
    TEST_INIT("=> 1 query to the backend, second query from the client is dropped, backend times out");
2✔
2461
    // useful to tests that we check that the client connection is alive in notifyAllQueriesFailed()
2462
    PacketBuffer expectedWriteBuffer;
2✔
2463
    PacketBuffer expectedBackendWriteBuffer;
2✔
2464

2465
    s_readBuffer.insert(s_readBuffer.end(), queries.at(0).begin(), queries.at(0).end());
2✔
2466
    s_readBuffer.insert(s_readBuffer.end(), queries.at(1).begin(), queries.at(1).end());
2✔
2467

2468
    // only the first query is passed to the backend
2469
    expectedBackendWriteBuffer.insert(expectedBackendWriteBuffer.end(), queries.at(0).begin(), queries.at(0).end());
2✔
2470

2471
    bool timeout = false;
2✔
2472
    s_steps = {
2✔
2473
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
2474
      /* reading a query from the client (1) */
2475
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2476
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(0).size() - 2 },
2✔
2477
      /* opening a connection to the backend */
2478
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
2479
      /* sending query to the backend */
2480
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(0).size() },
2✔
2481
      /* no response ready yet */
2482
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
2483
      /* reading a second query from the client */
2484
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2485
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(1).size() - 2 },
2✔
2486
      /* query is dropped, closing the connection to the client */
2487
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done, 0, [&timeout](int desc) {
2✔
2488
        (void)desc;
2✔
2489
        timeout = true;
2✔
2490
      } },
2✔
2491
      /* closing a connection to the backend after a timeout */
2492
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
2493
    };
2✔
2494

2495
    counter = 0;
2✔
2496
    s_processQuery = [backend,&counter](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
4✔
2497
      (void)dq;
4✔
2498
      if (counter == 0) {
4✔
2499
        ++counter;
2✔
2500
        selectedBackend = backend;
2✔
2501
        return ProcessQueryResult::PassToBackend;
2✔
2502
      }
2✔
2503
      return ProcessQueryResult::Drop;
2✔
2504
    };
4✔
2505
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
2✔
NEW
2506
      (void)response;
×
NEW
2507
      (void)dr;
×
NEW
2508
      (void)muted;
×
2509
      return true;
×
2510
    };
×
2511

2512
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
2513
    state->handleIO();
2✔
2514
    while (!timeout && (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
2!
2515
      threadData.mplexer->run(&now);
×
2516
    }
×
2517

2518
    struct timeval later = now;
2✔
2519
    later.tv_sec += backend->d_config.tcpRecvTimeout + 1;
2✔
2520
    auto expiredConns = threadData.mplexer->getTimeouts(later, false);
2✔
2521
    BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
2✔
2522
    for (const auto& cbData : expiredConns) {
2✔
2523
      if (cbData.second.type() == typeid(std::shared_ptr<TCPConnectionToBackend>)) {
2!
2524
        auto cbState = boost::any_cast<std::shared_ptr<TCPConnectionToBackend>>(cbData.second);
2✔
2525
        cbState->handleTimeout(later, false);
2✔
2526
      }
2✔
2527
    }
2✔
2528

2529
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), expectedWriteBuffer.size());
2✔
2530
    BOOST_CHECK(s_writeBuffer == expectedWriteBuffer);
2✔
2531
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), expectedBackendWriteBuffer.size());
2✔
2532
    BOOST_CHECK(s_backendWriteBuffer == expectedBackendWriteBuffer);
2✔
2533
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
2534

2535
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
2536
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
2537
  }
2✔
2538

2539
  {
2✔
2540
    TEST_INIT("=> 1 query to the backend, second query from the client is dropped, backend sends the answer");
2✔
2541
    // useful to tests that we check that the client connection is alive in handleResponse()
2542
    PacketBuffer expectedWriteBuffer;
2✔
2543
    PacketBuffer expectedBackendWriteBuffer;
2✔
2544

2545
    s_readBuffer.insert(s_readBuffer.end(), queries.at(0).begin(), queries.at(0).end());
2✔
2546
    s_readBuffer.insert(s_readBuffer.end(), queries.at(1).begin(), queries.at(1).end());
2✔
2547

2548
    // only the first query is passed to the backend
2549
    expectedBackendWriteBuffer.insert(expectedBackendWriteBuffer.end(), queries.at(0).begin(), queries.at(0).end());
2✔
2550

2551
    s_backendReadBuffer.insert(s_backendReadBuffer.end(), responses.at(0).begin(), responses.at(0).end());
2✔
2552

2553
    int backendDescriptor = -1;
2✔
2554
    s_steps = {
2✔
2555
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
2556
      /* reading a query from the client (1) */
2557
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2558
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(0).size() - 2 },
2✔
2559
      /* opening a connection to the backend */
2560
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done, 0, [&backendDescriptor](int desc) {
2✔
2561
        backendDescriptor = desc;
2✔
2562
      } },
2✔
2563
      /* sending query to the backend */
2564
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(0).size() },
2✔
2565
      /* no response ready yet */
2566
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
2567
      /* reading a second query from the client */
2568
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2569
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(1).size() - 2 },
2✔
2570
      /* query is dropped, closing the connection to the client */
2571
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done, 0, [&threadData,&backendDescriptor](int desc) {
2✔
2572
        (void)desc;
2✔
2573
        /* the backend descriptor becomes ready */
2574
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(backendDescriptor);
2✔
2575
      } },
2✔
2576
      /* reading the response to the first query from the backend */
2577
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
2578
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(0).size() - 2 },
2✔
2579
      /* closing a connection to the backend */
2580
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
2581
    };
2✔
2582

2583
    counter = 0;
2✔
2584
    s_processQuery = [backend,&counter](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
4✔
2585
      (void)dq;
4✔
2586
      if (counter == 0) {
4✔
2587
        ++counter;
2✔
2588
        selectedBackend = backend;
2✔
2589
        return ProcessQueryResult::PassToBackend;
2✔
2590
      }
2✔
2591
      return ProcessQueryResult::Drop;
2✔
2592
    };
4✔
2593
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
2✔
NEW
2594
      (void)response;
×
NEW
2595
      (void)dr;
×
NEW
2596
      (void)muted;
×
2597
      return true;
×
2598
    };
×
2599

2600
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
2601
    state->handleIO();
2✔
2602
    while ((threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
4!
2603
      threadData.mplexer->run(&now);
2✔
2604
    }
2✔
2605

2606
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), expectedWriteBuffer.size());
2✔
2607
    BOOST_CHECK(s_writeBuffer == expectedWriteBuffer);
2✔
2608
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), expectedBackendWriteBuffer.size());
2✔
2609
    BOOST_CHECK(s_backendWriteBuffer == expectedBackendWriteBuffer);
2✔
2610
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
2611

2612
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
2613
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
2614
  }
2✔
2615

2616
  {
2✔
2617
    TEST_INIT("=> 2 queries to the backend, client times out, responses arrive and are delivered, we start reading from the client again");
2✔
2618

2619
    PacketBuffer expectedWriteBuffer;
2✔
2620
    PacketBuffer expectedBackendWriteBuffer;
2✔
2621

2622
    s_readBuffer.insert(s_readBuffer.end(), queries.at(0).begin(), queries.at(0).end());
2✔
2623
    s_readBuffer.insert(s_readBuffer.end(), queries.at(1).begin(), queries.at(1).end());
2✔
2624
    s_readBuffer.insert(s_readBuffer.end(), queries.at(4).begin(), queries.at(4).end());
2✔
2625

2626
    uint16_t backendCounter = 0;
2✔
2627
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(0), backendCounter++);
2✔
2628
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(1), backendCounter++);
2✔
2629
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(4), backendCounter++);
2✔
2630

2631
    appendPayloadEditingID(s_backendReadBuffer, responses.at(1), 1);
2✔
2632
    appendPayloadEditingID(s_backendReadBuffer, responses.at(0), 0);
2✔
2633
    appendPayloadEditingID(s_backendReadBuffer, responses.at(4), 2);
2✔
2634

2635
    appendPayloadEditingID(expectedWriteBuffer, responses.at(1), 1);
2✔
2636
    appendPayloadEditingID(expectedWriteBuffer, responses.at(0), 0);
2✔
2637
    appendPayloadEditingID(expectedWriteBuffer, responses.at(4), 4);
2✔
2638

2639
    /* make sure that the backend's timeout is longer than the client's */
2640
    backend->d_config.tcpRecvTimeout = 30;
2✔
2641

2642
    bool timeout = false;
2✔
2643
    int backendDescriptor = -1;
2✔
2644
    s_steps = {
2✔
2645
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
2646
      /* reading a query from the client (1) */
2647
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2648
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(0).size() - 2 },
2✔
2649
      /* opening a connection to the backend */
2650
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
2651
      /* sending query (1) to the backend */
2652
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(0).size() },
2✔
2653
      /* no response ready yet */
2654
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
2655
      /* reading a second query from the client */
2656
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2657
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(1).size() - 2 },
2✔
2658
      /* sending query (2) to the backend */
2659
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(1).size() },
2✔
2660
      /* no response ready yet */
2661
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0, [&timeout,&backendDescriptor](int desc) {
2✔
2662
        backendDescriptor = desc;
2✔
2663
        timeout = true;
2✔
2664
      } },
2✔
2665
      /* nothing from the client either */
2666
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 0 },
2✔
2667
      /* the client times out, and we will set the backend descriptor to ready at that point */
2668
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
2669
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(1).size() - 2 },
2✔
2670
      /* sending response (2) to the client */
2671
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(1).size() },
2✔
2672
      /* reading the response (1) from the backend */
2673
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
2674
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(0).size() - 2 },
2✔
2675
      /* sending response (1) to the client */
2676
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(0).size(), [&threadData](int desc) {
2✔
2677
        /* setting the client descriptor ready */
2678
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(desc);
2✔
2679
      } },
2✔
2680
      /* try to read from the client again, get query (3) */
2681
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2682
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(4).size() - 2 },
2✔
2683
      /* sending query (3) to the backend */
2684
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(4).size() },
2✔
2685
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0, [&threadData](int desc) {
2✔
2686
        /* setting the backend descriptor NOT ready */
2687
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(desc);
2✔
2688
      } },
2✔
2689
      /* try to read from the client again, nothing yet */
2690
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 0, [&threadData,&backendDescriptor](int desc) {
2✔
2691
        /* the client descriptor becomes NOT ready */
2692
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(desc);
2✔
2693
        /* the backend one is ready, though */
2694
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(backendDescriptor);
2✔
2695
      } },
2✔
2696
      /* reading the response (3) from the backend */
2697
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
2698
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(4).size() - 2 },
2✔
2699
      /* sending response (3) to the client */
2700
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(4).size(), [&timeout](int desc) {
2✔
2701
        (void)desc;
2✔
2702
        timeout = true;
2✔
2703
      } },
2✔
2704
      /* closing a connection to the backend */
2705
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
2706
      /* client times out again, this time we close the connection */
2707
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done, 0 },
2✔
2708
    };
2✔
2709

2710
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
6✔
2711
      (void)dq;
6✔
2712
      selectedBackend = backend;
6✔
2713
      return ProcessQueryResult::PassToBackend;
6✔
2714
    };
6✔
2715
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
6✔
2716
      (void)response;
6✔
2717
      (void)dr;
6✔
2718
      (void)muted;
6✔
2719
      return true;
6✔
2720
    };
6✔
2721

2722
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
2723
    state->handleIO();
2✔
2724
    while (!timeout && (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
2!
2725
      threadData.mplexer->run(&now);
×
2726
    }
×
2727

2728
    struct timeval later = now;
2✔
2729
    later.tv_sec += tcpRecvTimeout + 1;
2✔
2730
    auto expiredConns = threadData.mplexer->getTimeouts(later, false);
2✔
2731
    BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
2✔
2732
    for (const auto& cbData : expiredConns) {
2✔
2733
      if (cbData.second.type() == typeid(std::shared_ptr<IncomingTCPConnectionState>)) {
2!
2734
        auto cbState = boost::any_cast<std::shared_ptr<IncomingTCPConnectionState>>(cbData.second);
2✔
2735
        cbState->handleTimeout(cbState, false);
2✔
2736
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(backendDescriptor);
2✔
2737
      }
2✔
2738
    }
2✔
2739
    timeout = false;
2✔
2740
    while (!timeout && (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
8!
2741
      threadData.mplexer->run(&now);
6✔
2742
    }
6✔
2743

2744
    later = now;
2✔
2745
    later.tv_sec += tcpRecvTimeout + 1;
2✔
2746
    expiredConns = threadData.mplexer->getTimeouts(later, false);
2✔
2747
    BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
2✔
2748
    for (const auto& cbData : expiredConns) {
2✔
2749
      if (cbData.second.type() == typeid(std::shared_ptr<IncomingTCPConnectionState>)) {
2!
2750
        auto cbState = boost::any_cast<std::shared_ptr<IncomingTCPConnectionState>>(cbData.second);
2✔
2751
        cbState->handleTimeout(cbState, false);
2✔
2752
      }
2✔
2753
    }
2✔
2754

2755
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), expectedWriteBuffer.size());
2✔
2756
    BOOST_CHECK(s_writeBuffer == expectedWriteBuffer);
2✔
2757
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), expectedBackendWriteBuffer.size());
2✔
2758
    BOOST_CHECK(s_backendWriteBuffer == expectedBackendWriteBuffer);
2✔
2759
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
2760

2761
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
2762
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
2763
  }
2✔
2764

2765
  {
2✔
2766
    TEST_INIT("=> 3 queries to the backend, the first 2 responses arrive and are queued (client write blocks), and the backend closes the connection before sending the last one");
2✔
2767

2768
    PacketBuffer expectedWriteBuffer;
2✔
2769
    PacketBuffer expectedBackendWriteBuffer;
2✔
2770

2771
    s_readBuffer.insert(s_readBuffer.end(), queries.at(0).begin(), queries.at(0).end());
2✔
2772
    s_readBuffer.insert(s_readBuffer.end(), queries.at(1).begin(), queries.at(1).end());
2✔
2773
    s_readBuffer.insert(s_readBuffer.end(), queries.at(2).begin(), queries.at(2).end());
2✔
2774

2775
    expectedBackendWriteBuffer.insert(expectedBackendWriteBuffer.end(), queries.at(0).begin(), queries.at(0).end());
2✔
2776
    expectedBackendWriteBuffer.insert(expectedBackendWriteBuffer.end(), queries.at(1).begin(), queries.at(1).end());
2✔
2777
    expectedBackendWriteBuffer.insert(expectedBackendWriteBuffer.end(), queries.at(2).begin(), queries.at(2).end());
2✔
2778

2779
    s_backendReadBuffer.insert(s_backendReadBuffer.end(), responses.at(1).begin(), responses.at(1).end());
2✔
2780
    s_backendReadBuffer.insert(s_backendReadBuffer.end(), responses.at(0).begin(), responses.at(0).end());
2✔
2781

2782
    expectedWriteBuffer = s_backendReadBuffer;
2✔
2783

2784
    s_steps = {
2✔
2785
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
2786
      /* reading a query from the client (1) */
2787
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2788
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(0).size() - 2 },
2✔
2789
      /* opening a connection to the backend */
2790
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
2791
      /* sending query (1) to the backend */
2792
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(0).size() },
2✔
2793
      /* no response ready yet */
2794
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
2795
      /* reading a second query from the client */
2796
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2797
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(1).size() - 2 },
2✔
2798
      /* sending query (2) to the backend */
2799
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(1).size() },
2✔
2800
      /* no response ready yet */
2801
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
2802
      /* reading a third query from the client */
2803
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
2804
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(2).size() - 2 },
2✔
2805
      /* sending query (3) to the backend */
2806
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(2).size() },
2✔
2807
      /* no response ready yet but the backend descriptor becomes ready */
2808
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0, [&threadData](int desc) {
2✔
2809
        /* the backend descriptor becomes ready */
2810
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(desc);
2✔
2811
      } },
2✔
2812
      /* nothing from the client either */
2813
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 0, [&threadData](int desc) {
2✔
2814
        /* the client descriptor is NOT ready */
2815
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(desc);
2✔
2816
      } },
2✔
2817
      /* read the response (2) from the backend  */
2818
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
2819
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(1).size() - 2 },
2✔
2820
      /* trying to send response (2) to the client but blocking */
2821
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::NeedWrite, 0 },
2✔
2822
      /* reading the response (1) from the backend */
2823
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
2824
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(0).size() - 2 },
2✔
2825
      /* trying to read from the backend again, connection closes on us */
2826
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 0 },
2✔
2827
      /* so we close the connection */
2828
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
2829
      /* try opening a new connection to the backend, it fails (5) times */
2830
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done, 0, [](int desc) {
2✔
2831
        (void)desc;
2✔
2832
        throw NetworkError("Connection refused by the backend");
2✔
2833
      } },
2✔
2834
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
2835
      /* try opening a new connection to the backend, it fails (5) times */
2836
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done,0, [](int desc) {
2✔
2837
        (void)desc;
2✔
2838
        throw NetworkError("Connection refused by the backend");
2✔
2839
      } },
2✔
2840
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
2841
      /* try opening a new connection to the backend, it fails (5) times */
2842
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done,0, [](int desc) {
2✔
2843
        (void)desc;
2✔
2844
        throw NetworkError("Connection refused by the backend");
2✔
2845
      } },
2✔
2846
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
2847
      /* try opening a new connection to the backend, it fails (5) times */
2848
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done,0, [](int desc) {
2✔
2849
        (void)desc;
2✔
2850
        throw NetworkError("Connection refused by the backend");
2✔
2851
      } },
2✔
2852
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
2853
      /* try opening a new connection to the backend, it fails (5) times */
2854
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done,0, [](int desc) {
2✔
2855
        (void)desc;
2✔
2856
        throw NetworkError("Connection refused by the backend");
2✔
2857
      } },
2✔
2858
      /* closing a connection to the backend, client becomes ready */
2859
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done, 0, [&threadData](int desc) {
2✔
2860
        (void)desc;
2✔
2861
        /* the client descriptor is ready */
2862
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(-1);
2✔
2863
      } },
2✔
2864
      /* sending response (2) to the client */
2865
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(1).size() },
2✔
2866
      /* sending response (1) to the client */
2867
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(0).size() },
2✔
2868
      /* closing the client connection */
2869
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done, 0 },
2✔
2870
    };
2✔
2871

2872
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
6✔
2873
      (void)dq;
6✔
2874
      selectedBackend = backend;
6✔
2875
      return ProcessQueryResult::PassToBackend;
6✔
2876
    };
6✔
2877
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
4✔
2878
      (void)response;
4✔
2879
      (void)dr;
4✔
2880
      (void)muted;
4✔
2881
      return true;
4✔
2882
    };
4✔
2883

2884
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
2885
    state->handleIO();
2✔
2886
    while (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0) {
10✔
2887
      threadData.mplexer->run(&now);
8✔
2888
    }
8✔
2889

2890
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), expectedWriteBuffer.size());
2✔
2891
    BOOST_CHECK(s_writeBuffer == expectedWriteBuffer);
2✔
2892
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), expectedBackendWriteBuffer.size());
2✔
2893
    BOOST_CHECK(s_backendWriteBuffer == expectedBackendWriteBuffer);
2✔
2894
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
2895

2896
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
2897
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
2898
  }
2✔
2899

2900
  {
2✔
2901
    TEST_INIT("=> AXFR");
2✔
2902

2903
    PacketBuffer axfrQuery;
2✔
2904
    PacketBuffer secondQuery;
2✔
2905
    std::vector<PacketBuffer> axfrResponses(3);
2✔
2906
    PacketBuffer secondResponse;
2✔
2907

2908
    GenericDNSPacketWriter<PacketBuffer> pwAXFRQuery(axfrQuery, DNSName("powerdns.com."), QType::AXFR, QClass::IN, 0);
2✔
2909
    pwAXFRQuery.getHeader()->rd = 0;
2✔
2910
    pwAXFRQuery.getHeader()->id = 42;
2✔
2911
    uint16_t axfrQuerySize = static_cast<uint16_t>(axfrQuery.size());
2✔
2912
    const uint8_t axfrQuerySizeBytes[] = { static_cast<uint8_t>(axfrQuerySize / 256), static_cast<uint8_t>(axfrQuerySize % 256) };
2✔
2913
    axfrQuery.insert(axfrQuery.begin(), axfrQuerySizeBytes, axfrQuerySizeBytes + 2);
2✔
2914

2915
    const DNSName name("powerdns.com.");
2✔
2916
    {
2✔
2917
      /* first message */
2918
      auto& response = axfrResponses.at(0);
2✔
2919
      GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
2✔
2920
      pwR.getHeader()->qr = 1;
2✔
2921
      pwR.getHeader()->id = 42;
2✔
2922

2923
      /* insert SOA */
2924
      pwR.startRecord(name, QType::SOA, 3600, QClass::IN, DNSResourceRecord::ANSWER);
2✔
2925
      pwR.xfrName(g_rootdnsname, true);
2✔
2926
      pwR.xfrName(g_rootdnsname, true);
2✔
2927
      pwR.xfr32BitInt(1 /* serial */);
2✔
2928
      pwR.xfr32BitInt(0);
2✔
2929
      pwR.xfr32BitInt(0);
2✔
2930
      pwR.xfr32BitInt(0);
2✔
2931
      pwR.xfr32BitInt(0);
2✔
2932
      pwR.commit();
2✔
2933

2934
      /* A record */
2935
      pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
2✔
2936
      pwR.xfr32BitInt(0x01020304);
2✔
2937
      pwR.commit();
2✔
2938

2939
      uint16_t responseSize = static_cast<uint16_t>(response.size());
2✔
2940
      const uint8_t sizeBytes[] = { static_cast<uint8_t>(responseSize / 256), static_cast<uint8_t>(responseSize % 256) };
2✔
2941
      response.insert(response.begin(), sizeBytes, sizeBytes + 2);
2✔
2942
    }
2✔
2943
    {
2✔
2944
      /* second message */
2945
      auto& response = axfrResponses.at(1);
2✔
2946
      GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
2✔
2947
      pwR.getHeader()->qr = 1;
2✔
2948
      pwR.getHeader()->id = 42;
2✔
2949

2950
      /* A record */
2951
      pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
2✔
2952
      pwR.xfr32BitInt(0x01020304);
2✔
2953
      pwR.commit();
2✔
2954

2955
      uint16_t responseSize = static_cast<uint16_t>(response.size());
2✔
2956
      const uint8_t sizeBytes[] = { static_cast<uint8_t>(responseSize / 256), static_cast<uint8_t>(responseSize % 256) };
2✔
2957
      response.insert(response.begin(), sizeBytes, sizeBytes + 2);
2✔
2958
    }
2✔
2959
    {
2✔
2960
      /* third message */
2961
      auto& response = axfrResponses.at(2);
2✔
2962
      GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
2✔
2963
      pwR.getHeader()->qr = 1;
2✔
2964
      pwR.getHeader()->id = 42;
2✔
2965

2966
      /* A record */
2967
      pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
2✔
2968
      pwR.xfr32BitInt(0x01020304);
2✔
2969
      pwR.commit();
2✔
2970

2971
      /* final SOA */
2972
      pwR.startRecord(name, QType::SOA, 3600, QClass::IN, DNSResourceRecord::ANSWER);
2✔
2973
      pwR.xfrName(g_rootdnsname, true);
2✔
2974
      pwR.xfrName(g_rootdnsname, true);
2✔
2975
      pwR.xfr32BitInt(1 /* serial */);
2✔
2976
      pwR.xfr32BitInt(0);
2✔
2977
      pwR.xfr32BitInt(0);
2✔
2978
      pwR.xfr32BitInt(0);
2✔
2979
      pwR.xfr32BitInt(0);
2✔
2980
      pwR.commit();
2✔
2981

2982
      uint16_t responseSize = static_cast<uint16_t>(response.size());
2✔
2983
      const uint8_t sizeBytes[] = { static_cast<uint8_t>(responseSize / 256), static_cast<uint8_t>(responseSize % 256) };
2✔
2984
      response.insert(response.begin(), sizeBytes, sizeBytes + 2);
2✔
2985
    }
2✔
2986

2987
    {
2✔
2988
      GenericDNSPacketWriter<PacketBuffer> pwSecondQuery(secondQuery, DNSName("powerdns.com."), QType::A, QClass::IN, 0);
2✔
2989
      pwSecondQuery.getHeader()->rd = 1;
2✔
2990
      pwSecondQuery.getHeader()->id = 84;
2✔
2991
      uint16_t secondQuerySize = static_cast<uint16_t>(secondQuery.size());
2✔
2992
      const uint8_t secondQuerySizeBytes[] = { static_cast<uint8_t>(secondQuerySize / 256), static_cast<uint8_t>(secondQuerySize % 256) };
2✔
2993
      secondQuery.insert(secondQuery.begin(), secondQuerySizeBytes, secondQuerySizeBytes + 2);
2✔
2994
    }
2✔
2995

2996
    {
2✔
2997
      GenericDNSPacketWriter<PacketBuffer> pwSecondResponse(secondResponse, DNSName("powerdns.com."), QType::A, QClass::IN, 0);
2✔
2998
      pwSecondResponse.getHeader()->qr = 1;
2✔
2999
      pwSecondResponse.getHeader()->rd = 1;
2✔
3000
      pwSecondResponse.getHeader()->ra = 1;
2✔
3001
      pwSecondResponse.getHeader()->id = 84;
2✔
3002
      pwSecondResponse.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
2✔
3003
      pwSecondResponse.xfr32BitInt(0x01020304);
2✔
3004
      pwSecondResponse.commit();
2✔
3005
      uint16_t responseSize = static_cast<uint16_t>(secondResponse.size());
2✔
3006
      const uint8_t sizeBytes[] = { static_cast<uint8_t>(responseSize / 256), static_cast<uint8_t>(responseSize % 256) };
2✔
3007
      secondResponse.insert(secondResponse.begin(), sizeBytes, sizeBytes + 2);
2✔
3008
    }
2✔
3009

3010
    PacketBuffer expectedWriteBuffer;
2✔
3011
    PacketBuffer expectedBackendWriteBuffer;
2✔
3012

3013
    s_readBuffer = axfrQuery;
2✔
3014
    s_readBuffer.insert(s_readBuffer.end(), secondQuery.begin(), secondQuery.end());
2✔
3015

3016
    uint16_t backendCounter = 0;
2✔
3017
    appendPayloadEditingID(expectedBackendWriteBuffer, axfrQuery, backendCounter++);
2✔
3018
    appendPayloadEditingID(expectedBackendWriteBuffer, secondQuery, backendCounter++);
2✔
3019

3020
    for (const auto& response : axfrResponses) {
6✔
3021
      appendPayloadEditingID(s_backendReadBuffer, response, 0);
6✔
3022
      expectedWriteBuffer.insert(expectedWriteBuffer.end(), response.begin(), response.end());
6✔
3023
    }
6✔
3024
    appendPayloadEditingID(s_backendReadBuffer, secondResponse, 1);
2✔
3025
    expectedWriteBuffer.insert(expectedWriteBuffer.end(), secondResponse.begin(), secondResponse.end());
2✔
3026

3027
    bool timeout = false;
2✔
3028
    s_steps = {
2✔
3029
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
3030
      /* reading a query from the client (1) */
3031
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
3032
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, axfrQuery.size() - 2 },
2✔
3033
      /* opening a connection to the backend */
3034
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
3035
      /* sending query (1) to the backend */
3036
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, axfrQuery.size() },
2✔
3037
      /* no response ready yet, but setting the backend descriptor readable */
3038
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0, [&threadData](int desc) {
2✔
3039
        /* the backend descriptor becomes ready */
3040
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(desc);
2✔
3041
      } },
2✔
3042
      /* no more query from the client for now */
3043
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 0 , [&threadData](int desc) {
2✔
3044
        (void)desc;
2✔
3045
        /* the client descriptor becomes NOT ready */
3046
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(-1);
2✔
3047
      } },
2✔
3048
      /* read the response (1) from the backend  */
3049
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
3050
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, axfrResponses.at(0).size() - 2 },
2✔
3051
      /* sending response (1) to the client */
3052
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, axfrResponses.at(0).size() },
2✔
3053
      /* reading the response (2) from the backend */
3054
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
3055
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, axfrResponses.at(1).size() - 2 },
2✔
3056
      /* sending response (2) to the client */
3057
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, axfrResponses.at(1).size() },
2✔
3058
      /* reading the response (3) from the backend */
3059
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
3060
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, axfrResponses.at(2).size() - 2 },
2✔
3061
      /* sending response (3) to the client */
3062
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, axfrResponses.at(2).size(), [&threadData](int desc) {
2✔
3063
        (void)desc;
2✔
3064
        /* the client descriptor becomes ready */
3065
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(-1);
2✔
3066
      } },
2✔
3067
      /* trying to read from the client, getting a second query */
3068
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
3069
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, secondQuery.size() - 2 },
2✔
3070
      /* sending query (2) to the backend */
3071
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, secondQuery.size() },
2✔
3072
      /* reading the response (4) from the backend */
3073
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
3074
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, secondResponse.size() - 2 },
2✔
3075
      /* sending response (4) to the client */
3076
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, secondResponse.size() },
2✔
3077
      /* trying to read from the client, getting EOF */
3078
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 },
2✔
3079
      /* closing the client connection */
3080
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
3081
      /* closing the backend connection */
3082
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
3083
    };
2✔
3084

3085
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
4✔
3086
      (void)dq;
4✔
3087
      selectedBackend = backend;
4✔
3088
      return ProcessQueryResult::PassToBackend;
4✔
3089
    };
4✔
3090
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
2✔
3091
      (void)response;
2✔
3092
      (void)dr;
2✔
3093
      (void)muted;
2✔
3094
      return true;
2✔
3095
    };
2✔
3096

3097
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
3098
    state->handleIO();
2✔
3099
    while (!timeout && (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
10!
3100
      threadData.mplexer->run(&now);
8✔
3101
    }
8✔
3102

3103
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), expectedWriteBuffer.size());
2✔
3104
    BOOST_CHECK(s_writeBuffer == expectedWriteBuffer);
2✔
3105
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), expectedBackendWriteBuffer.size());
2✔
3106
    BOOST_CHECK(s_backendWriteBuffer == expectedBackendWriteBuffer);
2✔
3107

3108
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
3109
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
3110
  }
2✔
3111

3112
  {
2✔
3113
    TEST_INIT("=> Interrupted AXFR");
2✔
3114

3115
    PacketBuffer axfrQuery;
2✔
3116
    PacketBuffer secondQuery;
2✔
3117
    std::vector<PacketBuffer> axfrResponses(3);
2✔
3118
    PacketBuffer secondResponse;
2✔
3119

3120
    auto proxyPayload = makeProxyHeader(true, getBackendAddress("84", 4242), local, {});
2✔
3121
    BOOST_REQUIRE_GT(proxyPayload.size(), s_proxyProtocolMinimumHeaderSize);
2✔
3122

3123
    auto proxyEnabledBackend = std::make_shared<DownstreamState>(getBackendAddress("42", 53));
2✔
3124
    proxyEnabledBackend->d_tlsCtx = tlsCtx;
2✔
3125
    proxyEnabledBackend->d_config.useProxyProtocol = true;
2✔
3126

3127
    GenericDNSPacketWriter<PacketBuffer> pwAXFRQuery(axfrQuery, DNSName("powerdns.com."), QType::AXFR, QClass::IN, 0);
2✔
3128
    pwAXFRQuery.getHeader()->rd = 0;
2✔
3129
    pwAXFRQuery.getHeader()->id = 42;
2✔
3130
    uint16_t axfrQuerySize = static_cast<uint16_t>(axfrQuery.size());
2✔
3131
    const uint8_t axfrQuerySizeBytes[] = { static_cast<uint8_t>(axfrQuerySize / 256), static_cast<uint8_t>(axfrQuerySize % 256) };
2✔
3132
    axfrQuery.insert(axfrQuery.begin(), axfrQuerySizeBytes, axfrQuerySizeBytes + 2);
2✔
3133

3134
    const DNSName name("powerdns.com.");
2✔
3135
    {
2✔
3136
      /* first message */
3137
      auto& response = axfrResponses.at(0);
2✔
3138
      GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
2✔
3139
      pwR.getHeader()->qr = 1;
2✔
3140
      pwR.getHeader()->id = 42;
2✔
3141

3142
      /* insert SOA */
3143
      pwR.startRecord(name, QType::SOA, 3600, QClass::IN, DNSResourceRecord::ANSWER);
2✔
3144
      pwR.xfrName(g_rootdnsname, true);
2✔
3145
      pwR.xfrName(g_rootdnsname, true);
2✔
3146
      pwR.xfr32BitInt(1 /* serial */);
2✔
3147
      pwR.xfr32BitInt(0);
2✔
3148
      pwR.xfr32BitInt(0);
2✔
3149
      pwR.xfr32BitInt(0);
2✔
3150
      pwR.xfr32BitInt(0);
2✔
3151
      pwR.commit();
2✔
3152

3153
      /* A record */
3154
      pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
2✔
3155
      pwR.xfr32BitInt(0x01020304);
2✔
3156
      pwR.commit();
2✔
3157

3158
      uint16_t responseSize = static_cast<uint16_t>(response.size());
2✔
3159
      const uint8_t sizeBytes[] = { static_cast<uint8_t>(responseSize / 256), static_cast<uint8_t>(responseSize % 256) };
2✔
3160
      response.insert(response.begin(), sizeBytes, sizeBytes + 2);
2✔
3161
    }
2✔
3162
    {
2✔
3163
      /* second message */
3164
      auto& response = axfrResponses.at(1);
2✔
3165
      GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
2✔
3166
      pwR.getHeader()->qr = 1;
2✔
3167
      pwR.getHeader()->id = 42;
2✔
3168

3169
      /* A record */
3170
      pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
2✔
3171
      pwR.xfr32BitInt(0x01020304);
2✔
3172
      pwR.commit();
2✔
3173

3174
      uint16_t responseSize = static_cast<uint16_t>(response.size());
2✔
3175
      const uint8_t sizeBytes[] = { static_cast<uint8_t>(responseSize / 256), static_cast<uint8_t>(responseSize % 256) };
2✔
3176
      response.insert(response.begin(), sizeBytes, sizeBytes + 2);
2✔
3177
    }
2✔
3178
    {
2✔
3179
      /* third message */
3180
      auto& response = axfrResponses.at(2);
2✔
3181
      GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
2✔
3182
      pwR.getHeader()->qr = 1;
2✔
3183
      pwR.getHeader()->id = 42;
2✔
3184

3185
      /* A record */
3186
      pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
2✔
3187
      pwR.xfr32BitInt(0x01020304);
2✔
3188
      pwR.commit();
2✔
3189

3190
      /* final SOA */
3191
      pwR.startRecord(name, QType::SOA, 3600, QClass::IN, DNSResourceRecord::ANSWER);
2✔
3192
      pwR.xfrName(g_rootdnsname, true);
2✔
3193
      pwR.xfrName(g_rootdnsname, true);
2✔
3194
      pwR.xfr32BitInt(1 /* serial */);
2✔
3195
      pwR.xfr32BitInt(0);
2✔
3196
      pwR.xfr32BitInt(0);
2✔
3197
      pwR.xfr32BitInt(0);
2✔
3198
      pwR.xfr32BitInt(0);
2✔
3199
      pwR.commit();
2✔
3200

3201
      uint16_t responseSize = static_cast<uint16_t>(response.size());
2✔
3202
      const uint8_t sizeBytes[] = { static_cast<uint8_t>(responseSize / 256), static_cast<uint8_t>(responseSize % 256) };
2✔
3203
      response.insert(response.begin(), sizeBytes, sizeBytes + 2);
2✔
3204
    }
2✔
3205

3206
    PacketBuffer expectedWriteBuffer;
2✔
3207
    PacketBuffer expectedBackendWriteBuffer;
2✔
3208

3209
    s_readBuffer = axfrQuery;
2✔
3210

3211
    uint16_t backendCounter = 0;
2✔
3212
    expectedBackendWriteBuffer.insert(expectedBackendWriteBuffer.end(), proxyPayload.begin(), proxyPayload.end());
2✔
3213
    appendPayloadEditingID(expectedBackendWriteBuffer, axfrQuery, backendCounter++);
2✔
3214

3215
    for (const auto& response : axfrResponses) {
6✔
3216
      appendPayloadEditingID(s_backendReadBuffer, response, 0);
6✔
3217
    }
6✔
3218
    expectedWriteBuffer.insert(expectedWriteBuffer.end(), axfrResponses.at(0).begin(), axfrResponses.at(0).end());
2✔
3219
    expectedWriteBuffer.insert(expectedWriteBuffer.end(), axfrResponses.at(1).begin(), axfrResponses.at(1).end());
2✔
3220

3221
    bool timeout = false;
2✔
3222
    s_steps = {
2✔
3223
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
3224
      /* reading a query from the client (1) */
3225
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
3226
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, axfrQuery.size() - 2 },
2✔
3227
      /* opening a connection to the backend */
3228
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
3229
      /* sending query (1) to the backend */
3230
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, proxyPayload.size() + axfrQuery.size() },
2✔
3231
      /* no response ready yet, but setting the backend descriptor readable */
3232
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0, [&threadData](int desc) {
2✔
3233
        /* the backend descriptor becomes ready */
3234
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(desc);
2✔
3235
      } },
2✔
3236
      /* no more query from the client for now */
3237
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 0 , [&threadData](int desc) {
2✔
3238
        (void)desc;
2✔
3239
        /* the client descriptor becomes NOT ready */
3240
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(-1);
2✔
3241
      } },
2✔
3242
      /* read the response (1) from the backend  */
3243
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
3244
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, axfrResponses.at(0).size() - 2 },
2✔
3245
      /* sending response (1) to the client */
3246
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, axfrResponses.at(0).size() },
2✔
3247
      /* reading the response (2) from the backend */
3248
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
3249
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, axfrResponses.at(1).size() - 2 },
2✔
3250
      /* sending response (2) to the client */
3251
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, axfrResponses.at(1).size() },
2✔
3252
      /* reading the response (3) from the backend, get EOF!! */
3253
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 0 },
2✔
3254
      /* closing the backend connection */
3255
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
3256
      /* opening a connection to the backend */
3257
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
3258
      /* closing the client connection */
3259
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
3260
      /* closing the backend connection */
3261
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
3262
    };
2✔
3263

3264
    s_processQuery = [proxyEnabledBackend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
2✔
3265
      (void)dq;
2✔
3266
      selectedBackend = proxyEnabledBackend;
2✔
3267
      return ProcessQueryResult::PassToBackend;
2✔
3268
    };
2✔
3269
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
2✔
NEW
3270
      (void)response;
×
NEW
3271
      (void)dr;
×
NEW
3272
      (void)muted;
×
3273
      return true;
×
3274
    };
×
3275

3276
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
3277
    state->handleIO();
2✔
3278
    while (!timeout && (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
8!
3279
      threadData.mplexer->run(&now);
6✔
3280
    }
6✔
3281

3282
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), expectedWriteBuffer.size());
2✔
3283
    BOOST_CHECK(s_writeBuffer == expectedWriteBuffer);
2✔
3284
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), expectedBackendWriteBuffer.size());
2✔
3285
    BOOST_CHECK(s_backendWriteBuffer == expectedBackendWriteBuffer);
2✔
3286

3287
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
3288
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
3289
  }
2✔
3290

3291
  {
2✔
3292
    TEST_INIT("=> IXFR");
2✔
3293

3294
    PacketBuffer firstQuery;
2✔
3295
    PacketBuffer ixfrQuery;
2✔
3296
    PacketBuffer secondQuery;
2✔
3297
    PacketBuffer firstResponse;
2✔
3298
    std::vector<PacketBuffer> ixfrResponses(1);
2✔
3299
    PacketBuffer secondResponse;
2✔
3300

3301
    {
2✔
3302
      GenericDNSPacketWriter<PacketBuffer> pwFirstQuery(firstQuery, DNSName("powerdns.com."), QType::SOA, QClass::IN, 0);
2✔
3303
      pwFirstQuery.getHeader()->rd = 1;
2✔
3304
      pwFirstQuery.getHeader()->id = 84;
2✔
3305
      uint16_t firstQuerySize = static_cast<uint16_t>(firstQuery.size());
2✔
3306
      const uint8_t firstQuerySizeBytes[] = { static_cast<uint8_t>(firstQuerySize / 256), static_cast<uint8_t>(firstQuerySize % 256) };
2✔
3307
      firstQuery.insert(firstQuery.begin(), firstQuerySizeBytes, firstQuerySizeBytes + 2);
2✔
3308
    }
2✔
3309

3310
    {
2✔
3311
      GenericDNSPacketWriter<PacketBuffer> pwFirstResponse(firstResponse, DNSName("powerdns.com."), QType::SOA, QClass::IN, 0);
2✔
3312
      pwFirstResponse.getHeader()->qr = 1;
2✔
3313
      pwFirstResponse.getHeader()->rd = 1;
2✔
3314
      pwFirstResponse.getHeader()->ra = 1;
2✔
3315
      pwFirstResponse.getHeader()->id = 84;
2✔
3316
      pwFirstResponse.startRecord(DNSName("powerdns.com."), QType::SOA, 3600, QClass::IN, DNSResourceRecord::ANSWER);
2✔
3317
      pwFirstResponse.xfrName(g_rootdnsname, true);
2✔
3318
      pwFirstResponse.xfrName(g_rootdnsname, true);
2✔
3319
      pwFirstResponse.xfr32BitInt(3 /* serial */);
2✔
3320
      pwFirstResponse.xfr32BitInt(0);
2✔
3321
      pwFirstResponse.xfr32BitInt(0);
2✔
3322
      pwFirstResponse.xfr32BitInt(0);
2✔
3323
      pwFirstResponse.xfr32BitInt(0);
2✔
3324
      pwFirstResponse.commit();
2✔
3325

3326
      uint16_t responseSize = static_cast<uint16_t>(firstResponse.size());
2✔
3327
      const uint8_t sizeBytes[] = { static_cast<uint8_t>(responseSize / 256), static_cast<uint8_t>(responseSize % 256) };
2✔
3328
      firstResponse.insert(firstResponse.begin(), sizeBytes, sizeBytes + 2);
2✔
3329
    }
2✔
3330

3331
    {
2✔
3332
      GenericDNSPacketWriter<PacketBuffer> pwIXFRQuery(ixfrQuery, DNSName("powerdns.com."), QType::IXFR, QClass::IN, 0);
2✔
3333
      pwIXFRQuery.getHeader()->rd = 0;
2✔
3334
      pwIXFRQuery.getHeader()->id = 42;
2✔
3335
      uint16_t ixfrQuerySize = static_cast<uint16_t>(ixfrQuery.size());
2✔
3336
      const uint8_t ixfrQuerySizeBytes[] = { static_cast<uint8_t>(ixfrQuerySize / 256), static_cast<uint8_t>(ixfrQuerySize % 256) };
2✔
3337
      ixfrQuery.insert(ixfrQuery.begin(), ixfrQuerySizeBytes, ixfrQuerySizeBytes + 2);
2✔
3338
    }
2✔
3339

3340
    const DNSName name("powerdns.com.");
2✔
3341
    {
2✔
3342
      /* first message */
3343
      auto& response = ixfrResponses.at(0);
2✔
3344
      GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
2✔
3345
      pwR.getHeader()->qr = 1;
2✔
3346
      pwR.getHeader()->id = 42;
2✔
3347

3348
      /* insert final SOA */
3349
      pwR.startRecord(name, QType::SOA, 3600, QClass::IN, DNSResourceRecord::ANSWER);
2✔
3350
      pwR.xfrName(g_rootdnsname, true);
2✔
3351
      pwR.xfrName(g_rootdnsname, true);
2✔
3352
      pwR.xfr32BitInt(3 /* serial */);
2✔
3353
      pwR.xfr32BitInt(0);
2✔
3354
      pwR.xfr32BitInt(0);
2✔
3355
      pwR.xfr32BitInt(0);
2✔
3356
      pwR.xfr32BitInt(0);
2✔
3357
      pwR.commit();
2✔
3358

3359
      /* insert first SOA */
3360
      pwR.startRecord(name, QType::SOA, 3600, QClass::IN, DNSResourceRecord::ANSWER);
2✔
3361
      pwR.xfrName(g_rootdnsname, true);
2✔
3362
      pwR.xfrName(g_rootdnsname, true);
2✔
3363
      pwR.xfr32BitInt(1 /* serial */);
2✔
3364
      pwR.xfr32BitInt(0);
2✔
3365
      pwR.xfr32BitInt(0);
2✔
3366
      pwR.xfr32BitInt(0);
2✔
3367
      pwR.xfr32BitInt(0);
2✔
3368
      pwR.commit();
2✔
3369

3370
      /* removals */
3371
      /* A record */
3372
      pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
2✔
3373
      pwR.xfr32BitInt(0x01020304);
2✔
3374
      pwR.commit();
2✔
3375

3376
      /* additions */
3377
      /* insert second SOA */
3378
      pwR.startRecord(name, QType::SOA, 3600, QClass::IN, DNSResourceRecord::ANSWER);
2✔
3379
      pwR.xfrName(g_rootdnsname, true);
2✔
3380
      pwR.xfrName(g_rootdnsname, true);
2✔
3381
      pwR.xfr32BitInt(2 /* serial */);
2✔
3382
      pwR.xfr32BitInt(0);
2✔
3383
      pwR.xfr32BitInt(0);
2✔
3384
      pwR.xfr32BitInt(0);
2✔
3385
      pwR.xfr32BitInt(0);
2✔
3386
      pwR.commit();
2✔
3387
      /* A record */
3388
      pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
2✔
3389
      pwR.xfr32BitInt(0x01020305);
2✔
3390
      pwR.commit();
2✔
3391
      /* done with 1 -> 2 */
3392
      pwR.startRecord(name, QType::SOA, 3600, QClass::IN, DNSResourceRecord::ANSWER);
2✔
3393
      pwR.xfrName(g_rootdnsname, true);
2✔
3394
      pwR.xfrName(g_rootdnsname, true);
2✔
3395
      pwR.xfr32BitInt(2 /* serial */);
2✔
3396
      pwR.xfr32BitInt(0);
2✔
3397
      pwR.xfr32BitInt(0);
2✔
3398
      pwR.xfr32BitInt(0);
2✔
3399
      pwR.xfr32BitInt(0);
2✔
3400
      pwR.commit();
2✔
3401

3402
      /* no removal */
3403

3404
      /* additions */
3405
      /* insert second SOA */
3406
      pwR.startRecord(name, QType::SOA, 3600, QClass::IN, DNSResourceRecord::ANSWER);
2✔
3407
      pwR.xfrName(g_rootdnsname, true);
2✔
3408
      pwR.xfrName(g_rootdnsname, true);
2✔
3409
      pwR.xfr32BitInt(3 /* serial */);
2✔
3410
      pwR.xfr32BitInt(0);
2✔
3411
      pwR.xfr32BitInt(0);
2✔
3412
      pwR.xfr32BitInt(0);
2✔
3413
      pwR.xfr32BitInt(0);
2✔
3414
      pwR.commit();
2✔
3415

3416
      /* actually no addition either */
3417
      /* done */
3418
      pwR.startRecord(name, QType::SOA, 3600, QClass::IN, DNSResourceRecord::ANSWER);
2✔
3419
      pwR.xfrName(g_rootdnsname, true);
2✔
3420
      pwR.xfrName(g_rootdnsname, true);
2✔
3421
      pwR.xfr32BitInt(3 /* serial */);
2✔
3422
      pwR.xfr32BitInt(0);
2✔
3423
      pwR.xfr32BitInt(0);
2✔
3424
      pwR.xfr32BitInt(0);
2✔
3425
      pwR.xfr32BitInt(0);
2✔
3426
      pwR.commit();
2✔
3427

3428
      uint16_t responseSize = static_cast<uint16_t>(response.size());
2✔
3429
      const uint8_t sizeBytes[] = { static_cast<uint8_t>(responseSize / 256), static_cast<uint8_t>(responseSize % 256) };
2✔
3430
      response.insert(response.begin(), sizeBytes, sizeBytes + 2);
2✔
3431
    }
2✔
3432

3433
    {
2✔
3434
      GenericDNSPacketWriter<PacketBuffer> pwSecondQuery(secondQuery, DNSName("powerdns.com."), QType::A, QClass::IN, 0);
2✔
3435
      pwSecondQuery.getHeader()->rd = 1;
2✔
3436
      pwSecondQuery.getHeader()->id = 84;
2✔
3437
      uint16_t secondQuerySize = static_cast<uint16_t>(secondQuery.size());
2✔
3438
      const uint8_t secondQuerySizeBytes[] = { static_cast<uint8_t>(secondQuerySize / 256), static_cast<uint8_t>(secondQuerySize % 256) };
2✔
3439
      secondQuery.insert(secondQuery.begin(), secondQuerySizeBytes, secondQuerySizeBytes + 2);
2✔
3440
    }
2✔
3441

3442
    {
2✔
3443
      GenericDNSPacketWriter<PacketBuffer> pwSecondResponse(secondResponse, DNSName("powerdns.com."), QType::A, QClass::IN, 0);
2✔
3444
      pwSecondResponse.getHeader()->qr = 1;
2✔
3445
      pwSecondResponse.getHeader()->rd = 1;
2✔
3446
      pwSecondResponse.getHeader()->ra = 1;
2✔
3447
      pwSecondResponse.getHeader()->id = 84;
2✔
3448
      pwSecondResponse.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
2✔
3449
      pwSecondResponse.xfr32BitInt(0x01020304);
2✔
3450
      pwSecondResponse.commit();
2✔
3451
      uint16_t responseSize = static_cast<uint16_t>(secondResponse.size());
2✔
3452
      const uint8_t sizeBytes[] = { static_cast<uint8_t>(responseSize / 256), static_cast<uint8_t>(responseSize % 256) };
2✔
3453
      secondResponse.insert(secondResponse.begin(), sizeBytes, sizeBytes + 2);
2✔
3454
    }
2✔
3455

3456
    PacketBuffer expectedWriteBuffer;
2✔
3457
    PacketBuffer expectedBackendWriteBuffer;
2✔
3458

3459
    s_readBuffer = firstQuery;
2✔
3460
    s_readBuffer.insert(s_readBuffer.end(), ixfrQuery.begin(), ixfrQuery.end());
2✔
3461
    s_readBuffer.insert(s_readBuffer.end(), secondQuery.begin(), secondQuery.end());
2✔
3462

3463
    appendPayloadEditingID(expectedBackendWriteBuffer, firstQuery, 0);
2✔
3464
    appendPayloadEditingID(expectedBackendWriteBuffer, ixfrQuery, 1);
2✔
3465
    appendPayloadEditingID(expectedBackendWriteBuffer, secondQuery, 2);
2✔
3466

3467
    appendPayloadEditingID(s_backendReadBuffer, firstResponse, 0);
2✔
3468
    expectedWriteBuffer.insert(expectedWriteBuffer.begin(), firstResponse.begin(), firstResponse.end());
2✔
3469
    for (const auto& response : ixfrResponses) {
2✔
3470
      appendPayloadEditingID(s_backendReadBuffer, response, 1);
2✔
3471
      expectedWriteBuffer.insert(expectedWriteBuffer.end(), response.begin(), response.end());
2✔
3472
    }
2✔
3473
    appendPayloadEditingID(s_backendReadBuffer, secondResponse, 2);
2✔
3474
    expectedWriteBuffer.insert(expectedWriteBuffer.end(), secondResponse.begin(), secondResponse.end());
2✔
3475

3476
    bool timeout = false;
2✔
3477
    s_steps = {
2✔
3478
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
3479
      /* reading a query from the client (1) */
3480
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
3481
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, firstQuery.size() - 2 },
2✔
3482
      /* opening a connection to the backend */
3483
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
3484
      /* sending query (1) to the backend */
3485
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, firstQuery.size() },
2✔
3486
      /* no response ready yet, but setting the backend descriptor readable */
3487
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0, [&threadData](int desc) {
2✔
3488
        /* the backend descriptor becomes ready */
3489
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(desc);
2✔
3490
      } },
2✔
3491
      /* try to read a second query from the client, none yet */
3492
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 0 },
2✔
3493
      /* read the response (1) from the backend  */
3494
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
3495
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, firstResponse.size() - 2 },
2✔
3496
      /* sending response (1) to the client */
3497
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, firstResponse.size(), [&threadData](int desc) {
2✔
3498
        (void)desc;
2✔
3499
        /* client descriptor becomes ready */
3500
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(-1);
2✔
3501
      } },
2✔
3502
      /* reading a query from the client (2) */
3503
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
3504
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, ixfrQuery.size() - 2 },
2✔
3505
      /* sending query (2) to the backend */
3506
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, ixfrQuery.size() },
2✔
3507
      /* read the response (ixfr 1) from the backend  */
3508
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
3509
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, ixfrResponses.at(0).size() - 2 },
2✔
3510
      /* sending response (ixfr 1) to the client */
3511
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, ixfrResponses.at(0).size(), [&threadData](int desc) {
2✔
3512
        (void)desc;
2✔
3513
        /* the client descriptor becomes ready */
3514
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(-1);
2✔
3515
      } },
2✔
3516
      /* trying to read from the client, getting a second query */
3517
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
3518
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, secondQuery.size() - 2 },
2✔
3519
      /* sending query (2) to the backend */
3520
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, secondQuery.size() },
2✔
3521
      /* reading the response (4) from the backend */
3522
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
3523
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, secondResponse.size() - 2 },
2✔
3524
      /* sending response (4) to the client */
3525
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, secondResponse.size() },
2✔
3526
      /* trying to read from the client, getting EOF */
3527
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 },
2✔
3528
      /* closing the client connection */
3529
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
3530
      /* closing the backend connection */
3531
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
3532
    };
2✔
3533

3534
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
6✔
3535
      (void)dq;
6✔
3536
      selectedBackend = backend;
6✔
3537
      return ProcessQueryResult::PassToBackend;
6✔
3538
    };
6✔
3539
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
4✔
3540
      (void)response;
4✔
3541
      (void)dr;
4✔
3542
      (void)muted;
4✔
3543
      return true;
4✔
3544
    };
4✔
3545

3546
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
3547
    state->handleIO();
2✔
3548
    while (!timeout && (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
6!
3549
      threadData.mplexer->run(&now);
4✔
3550
    }
4✔
3551

3552
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), expectedWriteBuffer.size());
2✔
3553
    BOOST_CHECK(s_writeBuffer == expectedWriteBuffer);
2✔
3554
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), expectedBackendWriteBuffer.size());
2✔
3555
    BOOST_CHECK(s_backendWriteBuffer == expectedBackendWriteBuffer);
2✔
3556
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
3557

3558
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
3559
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
3560
  }
2✔
3561

3562
  {
2✔
3563
    TEST_INIT("=> Outgoing proxy protocol, 3 queries to the backend, first response is sent, connection closed while reading the second one");
2✔
3564

3565
    PacketBuffer expectedWriteBuffer;
2✔
3566
    PacketBuffer expectedBackendWriteBuffer;
2✔
3567

3568
    auto proxyPayload = makeProxyHeader(true, getBackendAddress("84", 4242), local, {});
2✔
3569
    BOOST_REQUIRE_GT(proxyPayload.size(), s_proxyProtocolMinimumHeaderSize);
2✔
3570

3571
    s_readBuffer.insert(s_readBuffer.end(), queries.at(0).begin(), queries.at(0).end());
2✔
3572
    s_readBuffer.insert(s_readBuffer.end(), queries.at(1).begin(), queries.at(1).end());
2✔
3573
    s_readBuffer.insert(s_readBuffer.end(), queries.at(2).begin(), queries.at(2).end());
2✔
3574

3575
    auto proxyEnabledBackend = std::make_shared<DownstreamState>(getBackendAddress("42", 53));
2✔
3576
    proxyEnabledBackend->d_tlsCtx = tlsCtx;
2✔
3577
    /* enable out-of-order on the backend side as well */
3578
    proxyEnabledBackend->d_config.d_maxInFlightQueriesPerConn = 65536;
2✔
3579
    proxyEnabledBackend->d_config.useProxyProtocol = true;
2✔
3580

3581
    expectedBackendWriteBuffer.insert(expectedBackendWriteBuffer.end(), proxyPayload.begin(), proxyPayload.end());
2✔
3582
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(0), 0);
2✔
3583
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(1), 1);
2✔
3584
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(2), 2);
2✔
3585
    expectedBackendWriteBuffer.insert(expectedBackendWriteBuffer.end(), proxyPayload.begin(), proxyPayload.end());
2✔
3586
    /* we are using an unordered_map, so all bets are off here :-/ */
3587
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(2), 0);
2✔
3588
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(1), 1);
2✔
3589

3590
    appendPayloadEditingID(s_backendReadBuffer, responses.at(0), 0);
2✔
3591
    /* after the reconnection */
3592
    appendPayloadEditingID(s_backendReadBuffer, responses.at(1), 1);
2✔
3593
    appendPayloadEditingID(s_backendReadBuffer, responses.at(2), 0);
2✔
3594

3595
    expectedWriteBuffer.insert(expectedWriteBuffer.end(), responses.at(0).begin(), responses.at(0).end());
2✔
3596
    expectedWriteBuffer.insert(expectedWriteBuffer.end(), responses.at(1).begin(), responses.at(1).end());
2✔
3597
    expectedWriteBuffer.insert(expectedWriteBuffer.end(), responses.at(2).begin(), responses.at(2).end());
2✔
3598

3599
    s_steps = {
2✔
3600
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
3601
      /* reading a query from the client (1) */
3602
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
3603
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(0).size() - 2 },
2✔
3604
      /* opening a connection to the backend */
3605
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
3606
      /* sending query (1) to the backend */
3607
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, proxyPayload.size() + queries.at(0).size() },
2✔
3608
      /* got the response */
3609
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
3610
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(0).size() },
2✔
3611
      /* sending the response (1) to the client */
3612
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(0).size() },
2✔
3613
      /* reading a second query from the client */
3614
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
3615
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(1).size() - 2 },
2✔
3616
      /* sending query (2) to the backend */
3617
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(1).size() },
2✔
3618
      /* backend is not ready yet */
3619
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
3620
      /* reading a third query from the client */
3621
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
3622
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(2).size() - 2 },
2✔
3623
      /* sending query (3) to the backend */
3624
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(2).size() },
2✔
3625
      /* backend is not ready yet, but the descriptor becomes ready */
3626
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0, [&threadData](int desc) {
2✔
3627
        /* the backend descriptor becomes ready */
3628
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(desc);
2✔
3629
      }},
2✔
3630
      /* nothing from the client */
3631
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 0, [&threadData](int desc) {
2✔
3632
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(desc);
2✔
3633
      } },
2✔
3634
      /* backend closes the connection on us */
3635
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 0 },
2✔
3636
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
3637
      /* opening a new connection to the backend */
3638
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
3639
      /* sending query (2) to the backend */
3640
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, proxyPayload.size() + queries.at(1).size() },
2✔
3641
      /* sending query (3) to the backend */
3642
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(2).size() },
2✔
3643
      /* got the response for 2 */
3644
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
3645
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(1).size() },
2✔
3646
      /* sending the response (2) to the client */
3647
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(1).size() },
2✔
3648
      /* got the response for 3 */
3649
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
3650
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(2).size() },
2✔
3651
      /* sending the response (3) to the client */
3652
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(2).size(), [&threadData](int desc) {
2✔
3653
        /* the client descriptor becomes ready */
3654
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(desc);
2✔
3655
      } },
2✔
3656
      /* client closes the connection */
3657
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 },
2✔
3658
      /* closing the backend connection */
3659
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done, 0 },
2✔
3660
      /* closing the client connection */
3661
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done, 0 },
2✔
3662
    };
2✔
3663

3664
    s_processQuery = [proxyEnabledBackend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
6✔
3665
      (void)dq;
6✔
3666
      selectedBackend = proxyEnabledBackend;
6✔
3667
      return ProcessQueryResult::PassToBackend;
6✔
3668
    };
6✔
3669
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
6✔
3670
      (void)response;
6✔
3671
      (void)dr;
6✔
3672
      (void)muted;
6✔
3673
      return true;
6✔
3674
    };
6✔
3675

3676
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
3677
    state->handleIO();
2✔
3678
    while (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0) {
8!
3679
      threadData.mplexer->run(&now);
6✔
3680
    }
6✔
3681

3682
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), expectedWriteBuffer.size());
2✔
3683
    BOOST_CHECK(s_writeBuffer == expectedWriteBuffer);
2✔
3684
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), expectedBackendWriteBuffer.size());
2✔
3685
    BOOST_CHECK(s_backendWriteBuffer == expectedBackendWriteBuffer);
2✔
3686
    BOOST_CHECK_EQUAL(proxyEnabledBackend->outstanding.load(), 0U);
2✔
3687

3688
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
3689
    /* we should have nothing to clear since the connection cannot be reused due to the Proxy Protocol payload */
3690
    BOOST_CHECK_EQUAL(IncomingTCPConnectionState::clearAllDownstreamConnections(), 0U);
2✔
3691
  }
2✔
3692

3693
  {
2✔
3694
    TEST_INIT("=> Outgoing proxy protocol, 3 queries to the backend, the client closes while sending the first response");
2✔
3695

3696
    PacketBuffer expectedWriteBuffer;
2✔
3697
    PacketBuffer expectedBackendWriteBuffer;
2✔
3698

3699
    auto proxyPayload = makeProxyHeader(true, getBackendAddress("84", 4242), local, {});
2✔
3700
    BOOST_REQUIRE_GT(proxyPayload.size(), s_proxyProtocolMinimumHeaderSize);
2✔
3701

3702
    s_readBuffer.insert(s_readBuffer.end(), queries.at(0).begin(), queries.at(0).end());
2✔
3703
    s_readBuffer.insert(s_readBuffer.end(), queries.at(1).begin(), queries.at(1).end());
2✔
3704
    s_readBuffer.insert(s_readBuffer.end(), queries.at(2).begin(), queries.at(2).end());
2✔
3705

3706
    auto proxyEnabledBackend = std::make_shared<DownstreamState>(getBackendAddress("42", 53));
2✔
3707
    proxyEnabledBackend->d_tlsCtx = tlsCtx;
2✔
3708
    /* enable out-of-order on the backend side as well */
3709
    proxyEnabledBackend->d_config.d_maxInFlightQueriesPerConn = 65536;
2✔
3710
    proxyEnabledBackend->d_config.useProxyProtocol = true;
2✔
3711

3712
    expectedBackendWriteBuffer.insert(expectedBackendWriteBuffer.end(), proxyPayload.begin(), proxyPayload.end());
2✔
3713
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(0), 0);
2✔
3714
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(1), 1);
2✔
3715
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(2), 2);
2✔
3716

3717
    s_steps = {
2✔
3718
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
3719
      /* reading a query from the client (1) */
3720
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
3721
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(0).size() - 2 },
2✔
3722
      /* opening a connection to the backend */
3723
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
3724
      /* sending query (1) to the backend */
3725
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, proxyPayload.size() + queries.at(0).size() },
2✔
3726
      /* we try to read the response, not ready yet */
3727
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
3728
      /* reading a second query from the client */
3729
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
3730
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(1).size() - 2 },
2✔
3731
      /* sending query (2) to the backend */
3732
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(1).size() },
2✔
3733
      /* backend is not ready yet */
3734
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
3735
      /* reading a third query from the client */
3736
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
3737
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(2).size() - 2 },
2✔
3738
      /* sending query (3) to the backend */
3739
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(2).size() },
2✔
3740
      /* backend is not ready yet, but the descriptor becomes ready */
3741
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0, [&threadData](int desc) {
2✔
3742
        /* the backend descriptor becomes ready */
3743
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(desc);
2✔
3744
      }},
2✔
3745
      /* client closes the connection */
3746
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 },
2✔
3747
      /* closing the backend connection */
3748
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done, 0 },
2✔
3749
      /* closing the client connection */
3750
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done, 0 },
2✔
3751
    };
2✔
3752

3753
    s_processQuery = [proxyEnabledBackend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
6✔
3754
      (void)dq;
6✔
3755
      selectedBackend = proxyEnabledBackend;
6✔
3756
      return ProcessQueryResult::PassToBackend;
6✔
3757
    };
6✔
3758
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
2✔
NEW
3759
      (void)response;
×
NEW
3760
      (void)dr;
×
NEW
3761
      (void)muted;
×
3762
      return true;
×
3763
    };
×
3764

3765
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
3766
    state->handleIO();
2✔
3767
    while (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0) {
2!
3768
      threadData.mplexer->run(&now);
×
3769
    }
×
3770

3771
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), expectedWriteBuffer.size());
2✔
3772
    BOOST_CHECK(s_writeBuffer == expectedWriteBuffer);
2✔
3773
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), expectedBackendWriteBuffer.size());
2✔
3774
    BOOST_CHECK(s_backendWriteBuffer == expectedBackendWriteBuffer);
2✔
3775
    BOOST_CHECK_EQUAL(proxyEnabledBackend->outstanding.load(), 0U);
2✔
3776

3777
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
3778
    /* we should have nothing to clear since the connection cannot be reused due to the Proxy Protocol payload */
3779
    BOOST_CHECK_EQUAL(IncomingTCPConnectionState::clearAllDownstreamConnections(), 0U);
2✔
3780
  }
2✔
3781

3782
  {
2✔
3783
    TEST_INIT("=> I/O error with the backend with queries not sent to the backend yet");
2✔
3784

3785
    PacketBuffer expectedWriteBuffer;
2✔
3786
    PacketBuffer expectedBackendWriteBuffer;
2✔
3787

3788
    s_readBuffer.insert(s_readBuffer.end(), queries.at(0).begin(), queries.at(0).end());
2✔
3789
    s_readBuffer.insert(s_readBuffer.end(), queries.at(1).begin(), queries.at(1).end());
2✔
3790
    s_readBuffer.insert(s_readBuffer.end(), queries.at(2).begin(), queries.at(2).end());
2✔
3791

3792
    /* make sure that the backend's timeout is shorter than the client's */
3793
    backend->d_config.tcpConnectTimeout = 1;
2✔
3794
    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
2✔
3795
      config.d_tcpRecvTimeout = 5;
2✔
3796
    });
2✔
3797

3798
    bool timeout = false;
2✔
3799
    s_steps = {
2✔
3800
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
3801
      /* reading a query from the client (1) */
3802
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
3803
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(0).size() - 2 },
2✔
3804
      /* opening a connection to the backend */
3805
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
3806
      /* backend is not ready yet */
3807
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::NeedWrite, 0 },
2✔
3808
      /* reading a second query from the client */
3809
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
3810
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(1).size() - 2 },
2✔
3811
      /* reading a third query from the client */
3812
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
3813
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(2).size() - 2, [&timeout](int desc) {
2✔
3814
        (void)desc;
2✔
3815
        timeout = true;
2✔
3816
      } },
2✔
3817
      /* trying to read more from the client but nothing to read */
3818
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 0 },
2✔
3819
      /* closing the client connection */
3820
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done, 0 },
2✔
3821
      /* closing the backend connection */
3822
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done, 0 },
2✔
3823
    };
2✔
3824

3825
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
6✔
3826
      (void)dq;
6✔
3827
      selectedBackend = backend;
6✔
3828
      return ProcessQueryResult::PassToBackend;
6✔
3829
    };
6✔
3830
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
2✔
NEW
3831
      (void)response;
×
NEW
3832
      (void)dr;
×
NEW
3833
      (void)muted;
×
3834
      return true;
×
3835
    };
×
3836

3837
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
3838
    state->handleIO();
2✔
3839
    while (!timeout && (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
2!
3840
      threadData.mplexer->run(&now);
×
3841
    }
×
3842

3843
    struct timeval later = now;
2✔
3844
    later.tv_sec += backend->d_config.tcpConnectTimeout + 1;
2✔
3845
    auto expiredConns = threadData.mplexer->getTimeouts(later, true);
2✔
3846
    BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
2✔
3847
    for (const auto& cbData : expiredConns) {
2✔
3848
      if (cbData.second.type() == typeid(std::shared_ptr<TCPConnectionToBackend>)) {
2!
3849
        auto cbState = boost::any_cast<std::shared_ptr<TCPConnectionToBackend>>(cbData.second);
2✔
3850
        cbState->handleTimeout(later, true);
2✔
3851
      }
2✔
3852
    }
2✔
3853

3854
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
2✔
3855
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), 0U);
2✔
3856
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
3857

3858
    /* restore */
3859
    backend->d_config.tcpSendTimeout = 30;
2✔
3860
    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
2✔
3861
      config.d_tcpRecvTimeout = 2;
2✔
3862
    });
2✔
3863

3864
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
3865
    /* we have no connection to clear, because there was a timeout! */
3866
    BOOST_CHECK_EQUAL(IncomingTCPConnectionState::clearAllDownstreamConnections(), 0U);
2✔
3867
  }
2✔
3868

3869
  {
2✔
3870
    TEST_INIT("=> 5 OOOR queries, backend only accepts two at a time");
2✔
3871
    PacketBuffer expectedWriteBuffer;
2✔
3872
    PacketBuffer expectedBackendWriteBuffer;
2✔
3873

3874
    for (const auto& query : queries) {
10✔
3875
      s_readBuffer.insert(s_readBuffer.end(), query.begin(), query.end());
10✔
3876
    }
10✔
3877

3878
    /* queries 0, 1 and 4 are sent to the first backend, 2 and 3 to the second */
3879
    uint16_t firstBackendCounter = 0;
2✔
3880
    uint16_t secondBackendCounter = 0;
2✔
3881
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(0), firstBackendCounter++);
2✔
3882
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(1), firstBackendCounter++);
2✔
3883
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(2), secondBackendCounter++);
2✔
3884
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(3), secondBackendCounter++);
2✔
3885
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(4), firstBackendCounter++);
2✔
3886

3887
    firstBackendCounter = 0;
2✔
3888
    secondBackendCounter = 0;
2✔
3889
    appendPayloadEditingID(s_backendReadBuffer, responses.at(0), firstBackendCounter++);
2✔
3890
    appendPayloadEditingID(s_backendReadBuffer, responses.at(1), firstBackendCounter++);
2✔
3891
    appendPayloadEditingID(s_backendReadBuffer, responses.at(2), secondBackendCounter++);
2✔
3892
    appendPayloadEditingID(s_backendReadBuffer, responses.at(4), firstBackendCounter++);
2✔
3893
    appendPayloadEditingID(s_backendReadBuffer, responses.at(3), secondBackendCounter++);
2✔
3894

3895
    expectedWriteBuffer.insert(expectedWriteBuffer.end(), responses.at(0).begin(), responses.at(0).end());
2✔
3896
    expectedWriteBuffer.insert(expectedWriteBuffer.end(), responses.at(1).begin(), responses.at(1).end());
2✔
3897
    expectedWriteBuffer.insert(expectedWriteBuffer.end(), responses.at(2).begin(), responses.at(2).end());
2✔
3898
    expectedWriteBuffer.insert(expectedWriteBuffer.end(), responses.at(4).begin(), responses.at(4).end());
2✔
3899
    expectedWriteBuffer.insert(expectedWriteBuffer.end(), responses.at(3).begin(), responses.at(3).end());
2✔
3900

3901
    auto backend1 = std::make_shared<DownstreamState>(getBackendAddress("42", 53));
2✔
3902
    backend1->d_tlsCtx = tlsCtx;
2✔
3903
    /* only two queries in flight! */
3904
    backend1->d_config.d_maxInFlightQueriesPerConn = 2;
2✔
3905

3906
    int backend1Desc = -1;
2✔
3907
    int backend2Desc = -1;
2✔
3908

3909
    s_steps = {
2✔
3910
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
3911
      /* reading a query from the client (1) */
3912
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
3913
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(0).size() - 2 },
2✔
3914
      /* opening a connection to the backend (1) */
3915
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done, 0, [&backend1Desc](int desc) {
2✔
3916
        backend1Desc = desc;
2✔
3917
      } },
2✔
3918
      /* sending query (1) to the backend */
3919
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(0).size() },
2✔
3920
      /* no response ready yet */
3921
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
3922
      /* reading a query from the client (2) */
3923
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
3924
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(1).size() - 2 },
2✔
3925
      /* sending query (2) to the backend */
3926
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(1).size() },
2✔
3927
      /* no response ready yet */
3928
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
3929
      /* reading a query from the client (3) */
3930
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
3931
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(2).size() - 2 },
2✔
3932
      /* opening a connection to the SECOND backend (2) */
3933
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done, 0, [&backend2Desc](int desc) {
2✔
3934
        backend2Desc = desc;
2✔
3935
      } },
2✔
3936
      /* sending query (3) to backend 2 */
3937
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(2).size() },
2✔
3938
      /* no response ready yet */
3939
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
3940
      /* reading a query from the client (4) */
3941
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
3942
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(3).size() - 2 },
2✔
3943
      /* sending query to the second backend */
3944
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(3).size() },
2✔
3945
      /* no response ready yet */
3946
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
3947
      /* nothing more to read from the client at that moment */
3948
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 0, [&threadData, &backend1Desc](int desc) {
2✔
3949
        (void)desc;
2✔
3950
        /* but the first backend becomes readable */
3951
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(backend1Desc);
2✔
3952
      } },
2✔
3953
      /* reading response (1) from the first backend (1) */
3954
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
3955
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(0).size() - 2 },
2✔
3956
      /* sending it to the client */
3957
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(0).size(), [&threadData](int desc) {
2✔
3958
        /* client becomes readable */
3959
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(desc);
2✔
3960
      } },
2✔
3961
      /* reading a query from the client (5) */
3962
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
3963
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(4).size() - 2, [&threadData](int desc) {
2✔
3964
        /* client is not ready anymore */
3965
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(desc);
2✔
3966
      }  },
2✔
3967
      /* sending query (5) to the first backend (1) */
3968
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(4).size() },
2✔
3969
      /* no response ready yet, but the first backend becomes ready */
3970
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0, [&threadData](int desc) {
2✔
3971
        /* set the outgoing descriptor (backend connection) as ready */
3972
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(desc);
2✔
3973
      } },
2✔
3974
      /* trying to read from client, nothing yet */
3975
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 0 },
2✔
3976
      /* reading response (2) from the first backend (1) */
3977
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
3978
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(1).size() - 2 },
2✔
3979
      /* sending it to the client */
3980
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(1).size(), [&threadData,&backend1Desc,&backend2Desc](int desc) {
2✔
3981
        /* client is NOT readable, backend1 is not readable, backend 2 becomes readable */
3982
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(desc);
2✔
3983
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(backend1Desc);
2✔
3984
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(backend2Desc);
2✔
3985
      } },
2✔
3986
      /* reading response (3) from the second backend (2) */
3987
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
3988
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(2).size() - 2 },
2✔
3989
      /* sending it to the client */
3990
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(2).size(), [&threadData,&backend1Desc,&backend2Desc](int desc) {
2✔
3991
        (void)desc;
2✔
3992
        /* backend 2 is no longer readable, backend 1 becomes readable */
3993
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(backend2Desc);
2✔
3994
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(backend1Desc);
2✔
3995
      } },
2✔
3996
      /* reading response (5) from the first backend (1) */
3997
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
3998
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(4).size() - 2 },
2✔
3999
      /* sending it to the client */
4000
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(4).size(), [&threadData,&backend1Desc,&backend2Desc](int desc) {
2✔
4001
        (void)desc;
2✔
4002
        /* backend 1 is no longer readable, backend 2 becomes readable */
4003
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(backend1Desc);
2✔
4004
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(backend2Desc);
2✔
4005
      } },
2✔
4006
      /* reading response (4) from the second backend (2) */
4007
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
4008
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(3).size() - 2 },
2✔
4009
      /* sending it to the client */
4010
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(3).size(), [&threadData,&backend2Desc](int desc) {
2✔
4011
        (void)desc;
2✔
4012
        /* backend 2 is no longer readable */
4013
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(backend2Desc);
2✔
4014
        /* client becomes readable */
4015
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(-1);
2✔
4016
      } },
2✔
4017
      /* client closes the connection */
4018
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 },
2✔
4019
      /* closing client connection */
4020
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
4021
      /* closing a connection to the backends */
4022
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
4023
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
4024
    };
2✔
4025

4026
    s_processQuery = [backend1](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
10✔
4027
      (void)dq;
10✔
4028
      selectedBackend = backend1;
10✔
4029
      return ProcessQueryResult::PassToBackend;
10✔
4030
    };
10✔
4031
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
10✔
4032
      (void)response;
10✔
4033
      (void)dr;
10✔
4034
      (void)muted;
10✔
4035
      return true;
10✔
4036
    };
10✔
4037

4038
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
4039
    state->handleIO();
2✔
4040
    while (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0) {
14!
4041
      threadData.mplexer->run(&now);
12✔
4042
    }
12✔
4043

4044
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), totalResponsesSize);
2✔
4045
    BOOST_CHECK(s_writeBuffer == expectedWriteBuffer);
2✔
4046
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), totalQueriesSize);
2✔
4047
    BOOST_CHECK(s_backendWriteBuffer == expectedBackendWriteBuffer);
2✔
4048
    BOOST_CHECK_EQUAL(backend1->outstanding.load(), 0U);
2✔
4049

4050
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
4051
    BOOST_CHECK_EQUAL(IncomingTCPConnectionState::clearAllDownstreamConnections(), 2U);
2✔
4052
  }
2✔
4053

4054
  {
2✔
4055
    TEST_INIT("=> 2 OOOR queries to the backend with duplicated IDs");
2✔
4056
    PacketBuffer expectedWriteBuffer;
2✔
4057
    PacketBuffer expectedBackendWriteBuffer;
2✔
4058

4059
    s_readBuffer.insert(s_readBuffer.end(), queries.at(0).begin(), queries.at(0).end());
2✔
4060
    s_readBuffer.insert(s_readBuffer.end(), queries.at(0).begin(), queries.at(0).end());
2✔
4061

4062
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(0), 0);
2✔
4063
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(0), 1);
2✔
4064

4065
    appendPayloadEditingID(s_backendReadBuffer, responses.at(0), 0);
2✔
4066
    appendPayloadEditingID(s_backendReadBuffer, responses.at(0), 1);
2✔
4067

4068
    appendPayloadEditingID(expectedWriteBuffer, responses.at(0), 0);
2✔
4069
    appendPayloadEditingID(expectedWriteBuffer, responses.at(0), 0);
2✔
4070

4071
    bool timeout = false;
2✔
4072
    s_steps = {
2✔
4073
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
4074
      /* reading a query from the client (1) */
4075
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
4076
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(0).size() - 2 },
2✔
4077
      /* opening a connection to the backend */
4078
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done },
2✔
4079
      /* sending query to the backend */
4080
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(0).size() },
2✔
4081
      /* no response ready yet */
4082
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
4083
      /* reading a query from the client (2) */
4084
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
4085
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(1).size() - 2 },
2✔
4086
      /* sending query to the backend */
4087
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(1).size() },
2✔
4088
      /* no response ready yet, but mark the descriptor as ready */
4089
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0, [&threadData](int desc) {
2✔
4090
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(desc);
2✔
4091
      } },
2✔
4092
      /* nothing more from the client either */
4093
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 0 },
2✔
4094

4095
      /* reading response (1) from the backend */
4096
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(0).size() - 2 },
2✔
4097
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(0).size()},
2✔
4098
      /* sending it to the client */
4099
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(0).size()},
2✔
4100
      /* reading response (2) from the backend */
4101
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(0).size() - 2 },
2✔
4102
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(0).size(), [&threadData](int desc) {
2✔
4103
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(desc);
2✔
4104
      } },
2✔
4105
      /* sending it to the client. we don't have anything else to send to the client, no new query from it either, until we time out */
4106
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(0).size(), [&timeout](int desc) {
2✔
4107
        (void)desc;
2✔
4108
        timeout = true;
2✔
4109
      } },
2✔
4110
      /* closing a connection to the backend */
4111
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
4112
      /* closing client connection */
4113
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
4114
    };
2✔
4115

4116
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
4✔
4117
      (void)dq;
4✔
4118
      selectedBackend = backend;
4✔
4119
      return ProcessQueryResult::PassToBackend;
4✔
4120
    };
4✔
4121
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
4✔
4122
      (void)response;
4✔
4123
      (void)dr;
4✔
4124
      (void)muted;
4✔
4125
      return true;
4✔
4126
    };
4✔
4127

4128
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
4129
    state->handleIO();
2✔
4130
    while (!timeout && (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
6!
4131
      threadData.mplexer->run(&now);
4✔
4132
    }
4✔
4133

4134
    struct timeval later = now;
2✔
4135
    later.tv_sec += tcpRecvTimeout + 1;
2✔
4136
    auto expiredConns = threadData.mplexer->getTimeouts(later);
2✔
4137
    BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
2✔
4138
    for (const auto& cbData : expiredConns) {
2✔
4139
      if (cbData.second.type() == typeid(std::shared_ptr<IncomingTCPConnectionState>)) {
2!
4140
        auto cbState = boost::any_cast<std::shared_ptr<IncomingTCPConnectionState>>(cbData.second);
2✔
4141
        cbState->handleTimeout(cbState, false);
2✔
4142
      }
2✔
4143
    }
2✔
4144

4145
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), expectedWriteBuffer.size());
2✔
4146
    BOOST_CHECK(s_writeBuffer == expectedWriteBuffer);
2✔
4147
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), expectedBackendWriteBuffer.size());
2✔
4148
    BOOST_CHECK(s_backendWriteBuffer == expectedBackendWriteBuffer);
2✔
4149
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
4150

4151
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
4152
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
4153
  }
2✔
4154
}
2✔
4155

4156
BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendNotOOOR, TestFixture)
4157
{
2✔
4158
  const auto tcpRecvTimeout = dnsdist::configuration::getCurrentRuntimeConfiguration().d_tcpRecvTimeout;
2✔
4159
  auto local = getBackendAddress("1", 80);
2✔
4160
  ClientState localCS(local, true, false, 0, "", {}, true);
2✔
4161
  /* enable out-of-order on the front side */
4162
  localCS.d_maxInFlightQueriesPerConn = 65536;
2✔
4163

4164
  auto tlsCtx = std::make_shared<MockupTLSCtx>();
2✔
4165
  localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
2✔
4166

4167
  auto backend = std::make_shared<DownstreamState>(getBackendAddress("42", 53));
2✔
4168
  backend->d_tlsCtx = tlsCtx;
2✔
4169
  /* shorter than the client one */
4170
  backend->d_config.tcpRecvTimeout = 1;
2✔
4171

4172
  TCPClientThreadData threadData;
2✔
4173
  threadData.mplexer = std::make_unique<MockupFDMultiplexer>();
2✔
4174

4175
  struct timeval now;
2✔
4176
  gettimeofday(&now, nullptr);
2✔
4177

4178
  std::vector<PacketBuffer> queries(5);
2✔
4179
  std::vector<PacketBuffer> responses(5);
2✔
4180

4181
  size_t counter = 0;
2✔
4182
  size_t totalQueriesSize = 0;
2✔
4183
  for (auto& query : queries) {
10✔
4184
    GenericDNSPacketWriter<PacketBuffer> pwQ(query, DNSName("powerdns" + std::to_string(counter) + ".com."), QType::A, QClass::IN, 0);
10✔
4185
    pwQ.getHeader()->rd = 1;
10✔
4186
    pwQ.getHeader()->id = counter;
10✔
4187
    uint16_t querySize = static_cast<uint16_t>(query.size());
10✔
4188
    const uint8_t sizeBytes[] = { static_cast<uint8_t>(querySize / 256), static_cast<uint8_t>(querySize % 256) };
10✔
4189
    query.insert(query.begin(), sizeBytes, sizeBytes + 2);
10✔
4190
    totalQueriesSize += query.size();
10✔
4191
    ++counter;
10✔
4192
  }
10✔
4193

4194
  counter = 0;
2✔
4195
  size_t totalResponsesSize = 0;
2✔
4196
  for (auto& response : responses) {
10✔
4197
    DNSName name("powerdns" + std::to_string(counter) + ".com.");
10✔
4198
    GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
10✔
4199
    pwR.getHeader()->qr = 1;
10✔
4200
    pwR.getHeader()->rd = 1;
10✔
4201
    pwR.getHeader()->ra = 1;
10✔
4202
    pwR.getHeader()->id = counter;
10✔
4203
    pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
10✔
4204
    pwR.xfr32BitInt(0x01020304);
10✔
4205
    pwR.commit();
10✔
4206

4207
    uint16_t responseSize = static_cast<uint16_t>(response.size());
10✔
4208
    const uint8_t sizeBytes[] = { static_cast<uint8_t>(responseSize / 256), static_cast<uint8_t>(responseSize % 256) };
10✔
4209
    response.insert(response.begin(), sizeBytes, sizeBytes + 2);
10✔
4210
    totalResponsesSize += response.size();
10✔
4211
    ++counter;
10✔
4212
  }
10✔
4213

4214
  {
2✔
4215
    TEST_INIT("=> 5 OOOR queries, we will need to open 5 backend connections");
2✔
4216
    PacketBuffer expectedWriteBuffer;
2✔
4217
    PacketBuffer expectedBackendWriteBuffer;
2✔
4218

4219
    for (const auto& query : queries) {
10✔
4220
      s_readBuffer.insert(s_readBuffer.end(), query.begin(), query.end());
10✔
4221
    }
10✔
4222

4223
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(0), 0);
2✔
4224
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(1), 0);
2✔
4225
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(2), 0);
2✔
4226
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(3), 0);
2✔
4227
    appendPayloadEditingID(expectedBackendWriteBuffer, queries.at(4), 0);
2✔
4228

4229
    appendPayloadEditingID(s_backendReadBuffer, responses.at(0), 0);
2✔
4230
    appendPayloadEditingID(s_backendReadBuffer, responses.at(2), 0);
2✔
4231
    appendPayloadEditingID(s_backendReadBuffer, responses.at(1), 0);
2✔
4232
    appendPayloadEditingID(s_backendReadBuffer, responses.at(4), 0);
2✔
4233
    appendPayloadEditingID(s_backendReadBuffer, responses.at(3), 0);
2✔
4234

4235
    expectedWriteBuffer.insert(expectedWriteBuffer.end(), responses.at(0).begin(), responses.at(0).end());
2✔
4236
    expectedWriteBuffer.insert(expectedWriteBuffer.end(), responses.at(2).begin(), responses.at(2).end());
2✔
4237
    expectedWriteBuffer.insert(expectedWriteBuffer.end(), responses.at(1).begin(), responses.at(1).end());
2✔
4238
    expectedWriteBuffer.insert(expectedWriteBuffer.end(), responses.at(4).begin(), responses.at(4).end());
2✔
4239
    expectedWriteBuffer.insert(expectedWriteBuffer.end(), responses.at(3).begin(), responses.at(3).end());
2✔
4240

4241
    std::vector<int> backendDescriptors = { -1, -1, -1, -1, -1 };
2✔
4242

4243
    s_steps = {
2✔
4244
      { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
4245
      /* reading a query from the client (1) */
4246
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
4247
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(0).size() - 2 },
2✔
4248
      /* opening a connection to the backend (1) */
4249
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done, 0, [&backendDescriptors](int desc) {
2✔
4250
        backendDescriptors.at(0) = desc;
2✔
4251
      } },
2✔
4252
      /* sending query (1) to the backend */
4253
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(0).size() },
2✔
4254
      /* no response ready yet */
4255
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
4256
      /* reading a query from the client (2) */
4257
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
4258
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(1).size() - 2 },
2✔
4259
      /* opening a connection to the backend (2) */
4260
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done, 0, [&backendDescriptors](int desc) {
2✔
4261
        backendDescriptors.at(1) = desc;
2✔
4262
      } },
2✔
4263
      /* sending query (2) to the backend */
4264
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(1).size() },
2✔
4265
      /* no response ready yet */
4266
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
4267
      /* reading a query from the client (3) */
4268
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
4269
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(2).size() - 2 },
2✔
4270
      /* opening a connection to the backend (3) */
4271
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done, 0, [&backendDescriptors](int desc) {
2✔
4272
        backendDescriptors.at(2) = desc;
2✔
4273
      } },
2✔
4274
      /* sending query (3) to the backend */
4275
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(2).size() },
2✔
4276
      /* no response ready yet */
4277
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
4278
      /* reading a query from the client (4) */
4279
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
4280
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(3).size() - 2 },
2✔
4281
      /* opening a connection to the backend (4) */
4282
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done, 0, [&backendDescriptors](int desc) {
2✔
4283
        backendDescriptors.at(3) = desc;
2✔
4284
      } },
2✔
4285
      /* sending query (3) to the backend */
4286
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(3).size() },
2✔
4287
      /* no response ready yet */
4288
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0 },
2✔
4289
      /* reading a query from the client (5) */
4290
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
4291
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(4).size() - 2 },
2✔
4292
      /* opening a connection to the backend (5) */
4293
      { ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done, 0, [&backendDescriptors](int desc) {
2✔
4294
        backendDescriptors.at(4) = desc;
2✔
4295
      } },
2✔
4296
      /* sending query (5) to the backend */
4297
      { ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, queries.at(4).size() },
2✔
4298
      /* no response ready yet, client stops being readable, first backend has a response */
4299
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0, [&threadData,&backendDescriptors](int desc) {
2✔
4300
        (void)desc;
2✔
4301
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(backendDescriptors.at(0));
2✔
4302
      } },
2✔
4303
      /* trying to read from the client but nothing yet */
4304
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 0 , [&threadData](int desc) {
2✔
4305
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(desc);
2✔
4306
      } },
2✔
4307
      /* reading response (1) from the first backend (1) */
4308
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
4309
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(0).size() - 2 },
2✔
4310
      /* sending it to the client */
4311
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(0).size(), [&threadData,&backendDescriptors](int desc) {
2✔
4312
        (void)desc;
2✔
4313
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(backendDescriptors.at(2));
2✔
4314
      } },
2✔
4315
      /* reading response (3) from the third backend (3) */
4316
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
4317
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(2).size() - 2 },
2✔
4318
      /* sending it to the client */
4319
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(2).size(), [&threadData,&backendDescriptors](int desc) {
2✔
4320
        (void)desc;
2✔
4321
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(backendDescriptors.at(1));
2✔
4322
      } },
2✔
4323
      /* reading response (2) from the second backend (2) */
4324
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
4325
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(1).size() - 2 },
2✔
4326
      /* sending it to the client */
4327
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(1).size(), [&threadData,&backendDescriptors](int desc) {
2✔
4328
        (void)desc;
2✔
4329
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(backendDescriptors.at(4));
2✔
4330
      } },
2✔
4331
      /* reading response (5) from the fifth backend (5) */
4332
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
4333
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(4).size() - 2 },
2✔
4334
      /* sending it to the client */
4335
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(4).size(), [&threadData,&backendDescriptors](int desc) {
2✔
4336
        (void)desc;
2✔
4337
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(backendDescriptors.at(3));
2✔
4338
      } },
2✔
4339
      /* reading response (4) from the fourth backend (4) */
4340
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 2 },
2✔
4341
      { ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, responses.at(3).size() - 2 },
2✔
4342
      /* sending it to the client */
4343
      { ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, responses.at(3).size(), [&threadData](int desc) {
2✔
4344
        (void)desc;
2✔
4345
        dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(-1);
2✔
4346
      } },
2✔
4347
      /* client closes the connection */
4348
      { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0 },
2✔
4349
      /* closing client connection */
4350
      { ExpectedStep::ExpectedRequest::closeClient, IOState::Done },
2✔
4351
      /* closing a connection to the backends */
4352
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
4353
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
4354
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
4355
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
4356
      { ExpectedStep::ExpectedRequest::closeBackend, IOState::Done },
2✔
4357
    };
2✔
4358

4359
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
10✔
4360
      (void)dq;
10✔
4361
      selectedBackend = backend;
10✔
4362
      return ProcessQueryResult::PassToBackend;
10✔
4363
    };
10✔
4364
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
10✔
4365
      (void)response;
10✔
4366
      (void)dr;
10✔
4367
      (void)muted;
10✔
4368
      return true;
10✔
4369
    };
10✔
4370

4371
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
4372
    state->handleIO();
2✔
4373
    while (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0) {
14!
4374
      threadData.mplexer->run(&now);
12✔
4375
    }
12✔
4376

4377
    BOOST_CHECK_EQUAL(s_writeBuffer.size(), totalResponsesSize);
2✔
4378
    BOOST_CHECK(s_writeBuffer == expectedWriteBuffer);
2✔
4379
    BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), totalQueriesSize);
2✔
4380
    BOOST_CHECK(s_backendWriteBuffer == expectedBackendWriteBuffer);
2✔
4381
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
4382

4383
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
4384
    BOOST_CHECK_EQUAL(IncomingTCPConnectionState::clearAllDownstreamConnections(), 5U);
2✔
4385
  }
2✔
4386

4387
  {
2✔
4388
    /* 2 queries on the same connection, asynchronously handled, check that we only read all of them (OOOR as maxInFlight is 65535) */
4389
    TEST_INIT("=> 2 queries on the same connection, async with OOOR");
2✔
4390

4391
    size_t count = 2;
2✔
4392

4393
    s_readBuffer = queries.at(0);
2✔
4394

4395
    for (size_t idx = 0; idx < count; idx++) {
6✔
4396
      appendPayloadEditingID(s_readBuffer, queries.at(idx), idx);
4✔
4397
      appendPayloadEditingID(s_backendReadBuffer, queries.at(idx), idx);
4✔
4398
    }
4✔
4399

4400
    bool timeout = false;
2✔
4401
    s_steps = { { ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done },
2✔
4402
                { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
4403
                { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(0).size() - 2 },
2✔
4404
                { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 2 },
2✔
4405
                { ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, queries.at(1).size() - 2 },
2✔
4406
                { ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 0, [&timeout](int desc) {
2✔
4407
                  (void)desc;
2✔
4408
                  timeout = true;
2✔
4409
                }},
2✔
4410
                /* close the connection with the client */
4411
                { ExpectedStep::ExpectedRequest::closeClient, IOState::Done }
2✔
4412
    };
2✔
4413

4414
    s_processQuery = [backend](DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
4✔
4415
      selectedBackend = backend;
4✔
4416
      dq.asynchronous = true;
4✔
4417
      /* note that we do nothing with the query, we just tell the frontend it was dealt with */
4418
      return ProcessQueryResult::Asynchronous;
4✔
4419
    };
4✔
4420
    s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool {
2✔
NEW
4421
      (void)response;
×
NEW
4422
      (void)dr;
×
NEW
4423
      (void)muted;
×
4424
      return true;
×
4425
    };
×
4426

4427
    auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
2✔
4428
    state->handleIO();
2✔
4429
    while (!timeout && (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
2!
4430
      threadData.mplexer->run(&now);
×
4431
    }
×
4432

4433
    struct timeval later = now;
2✔
4434
    later.tv_sec += tcpRecvTimeout + 1;
2✔
4435
    auto expiredConns = threadData.mplexer->getTimeouts(later);
2✔
4436
    BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
2✔
4437
    for (const auto& cbData : expiredConns) {
2✔
4438
      if (cbData.second.type() == typeid(std::shared_ptr<IncomingTCPConnectionState>)) {
2!
4439
        auto cbState = boost::any_cast<std::shared_ptr<IncomingTCPConnectionState>>(cbData.second);
2✔
4440
        cbState->handleTimeout(cbState, false);
2✔
4441
      }
2✔
4442
    }
2✔
4443

4444
    BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
2✔
4445

4446
    /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
4447
    IncomingTCPConnectionState::clearAllDownstreamConnections();
2✔
4448
  }
2✔
4449
}
2✔
4450

4451
BOOST_AUTO_TEST_SUITE_END();
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc