recursive_query_unittest_2.cc 27.2 KB
Newer Older
Stephen Morris's avatar
Stephen Morris committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

#include <algorithm>
#include <cstdlib>
17
#include <iomanip>
Stephen Morris's avatar
Stephen Morris committed
18
#include <iostream>
19
#include <string>
Stephen Morris's avatar
Stephen Morris committed
20
21
22
23
24
25
26
27
28
29
30
31
32

#include <gtest/gtest.h>
#include <boost/bind.hpp>

#include <asio.hpp>

#include <dns/buffer.h>
#include <dns/question.h>
#include <dns/message.h>
#include <dns/messagerenderer.h>
#include <dns/opcode.h>
#include <dns/name.h>
#include <dns/rcode.h>
33
34
35
36
#include <dns/rrtype.h>
#include <dns/rrset.h>
#include <dns/rrttl.h>
#include <dns/rdata.h>
Stephen Morris's avatar
Stephen Morris committed
37
38

#include <asiolink/asiolink_utilities.h>
Stephen Morris's avatar
Stephen Morris committed
39
#include <asiolink/dns_service.h>
Stephen Morris's avatar
Stephen Morris committed
40
41
42
43
#include <asiolink/io_address.h>
#include <asiolink/io_endpoint.h>
#include <asiolink/io_fetch.h>
#include <asiolink/io_service.h>
Jelte Jansen's avatar
Jelte Jansen committed
44
#include <resolve/recursive_query.h>
45
#include <resolve/resolver_interface.h>
Stephen Morris's avatar
Stephen Morris committed
46
47
48

using namespace asio;
using namespace asio::ip;
49
50
51
using namespace isc::dns;
using namespace isc::dns::rdata;
using namespace isc::resolve;
Stephen Morris's avatar
Stephen Morris committed
52
53
54
55
56
57
using namespace std;

/// RecursiveQuery Test - 2
///
/// The second part of the RecursiveQuery unit tests, this attempts to get the
/// RecursiveQuery object to follow a set of referrals for "www.example.org" to
58
59
/// and to invoke TCP fallback on one of the queries.  In particular, we expect
/// that the test will do the following in an attempt to resolve
Stephen Morris's avatar
Stephen Morris committed
60
61
/// www.example.org:
///
62
/// - Send question over UDP to "root" - get referral to "org".
Stephen Morris's avatar
Stephen Morris committed
63
64
65
66
/// - Send question over UDP to "org" - get referral to "example.org" with TC bit set.
/// - Send question over TCP to "org" - get referral to "example.org".
/// - Send question over UDP to "example.org" - get response for www.example.org.
///
67
68
/// (The order of queries is set in this way in order to also test that after a
/// failover to TCP, queries revert to UDP).
Stephen Morris's avatar
Stephen Morris committed
69
70
///
/// By using the "test_server_" element of RecursiveQuery, all queries are
71
72
/// directed to one or other of the "servers" in the RecursiveQueryTest2 class,
/// regardless of the glue returned in referrals.
Stephen Morris's avatar
Stephen Morris committed
73
74
75

namespace asiolink {

76
77
78
const std::string TEST_ADDRESS = "127.0.0.1";   ///< Servers are on this address
const uint16_t TEST_PORT = 5301;                ///< ... and this port
const size_t BUFFER_SIZE = 1024;                ///< For all buffers
79
const char* WWW_EXAMPLE_ORG = "192.0.2.254";    ///< Address of www.example.org
Stephen Morris's avatar
Stephen Morris committed
80

81
82
83
// As the test is fairly long and complex, debugging "print" statements have
// been left in although they are disabled.  Set the following to "true" to
// enable them.
84
const bool DEBUG_PRINT = false;
Stephen Morris's avatar
Stephen Morris committed
85

Jelte Jansen's avatar
Jelte Jansen committed
86
87
88
89
90
91
92
93
class MockResolver : public isc::resolve::ResolverInterface {
    void resolve(const QuestionPtr& question,
                 const ResolverInterface::CallbackPtr& callback) {
    }
};



94
95
/// \brief Test fixture for the RecursiveQuery Test
class RecursiveQueryTest2 : public virtual ::testing::Test
Stephen Morris's avatar
Stephen Morris committed
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
{
public:

    /// \brief Status of query
    ///
    /// Set before the query and then by each "server" when responding.
    enum QueryStatus {
        NONE = 0,                   ///< Default
        UDP_ROOT = 1,               ///< Query root server over UDP
        UDP_ORG = 2,                ///< Query ORG server over UDP
        TCP_ORG = 3,                ///< Query ORG server over TCP
        UDP_EXAMPLE_ORG = 4,        ///< Query EXAMPLE.ORG server over UDP
        COMPLETE = 5                ///< Query is complete
    };

Stephen Morris's avatar
Stephen Morris committed
111
    // Common stuff
112
    bool            debug_;                     ///< Set true for debug print
Stephen Morris's avatar
Stephen Morris committed
113
    IOService       service_;                   ///< Service to run everything
Stephen Morris's avatar
Stephen Morris committed
114
    DNSService      dns_service_;               ///< Resolver is part of "server"
115
116
    QuestionPtr     question_;                  ///< What to ask
    QueryStatus     last_;                      ///< What was the last state
Stephen Morris's avatar
Stephen Morris committed
117
118
    QueryStatus     expected_;                  ///< Expected next state
    OutputBufferPtr question_buffer_;           ///< Question we expect to receive
Jelte Jansen's avatar
Jelte Jansen committed
119
120
    isc::nsas::NameserverAddressStore* nsas_;
    isc::cache::ResolverCache cache_;
Stephen Morris's avatar
Stephen Morris committed
121

Stephen Morris's avatar
Stephen Morris committed
122
    // Data for TCP Server
Stephen Morris's avatar
Stephen Morris committed
123
124
125
    size_t          tcp_cumulative_;            ///< Cumulative TCP data received
    tcp::endpoint   tcp_endpoint_;              ///< Endpoint for TCP receives
    size_t          tcp_length_;                ///< Expected length value
126
    uint8_t         tcp_receive_buffer_[BUFFER_SIZE];   ///< Receive buffer for TCP I/O
Stephen Morris's avatar
Stephen Morris committed
127
128
129
130
    OutputBufferPtr tcp_send_buffer_;           ///< Send buffer for TCP I/O
    tcp::socket     tcp_socket_;                ///< Socket used by TCP server

    /// Data for UDP
131
    udp::endpoint   udp_remote_;                ///< Endpoint for UDP receives
Stephen Morris's avatar
Stephen Morris committed
132
    size_t          udp_length_;                ///< Expected length value
133
    uint8_t         udp_receive_buffer_[BUFFER_SIZE];   ///< Receive buffer for UDP I/O
Stephen Morris's avatar
Stephen Morris committed
134
135
136
137
138
    OutputBufferPtr udp_send_buffer_;           ///< Send buffer for UDP I/O
    udp::socket     udp_socket_;                ///< Socket used by UDP server

    /// \brief Constructor
    RecursiveQueryTest2() :
139
        debug_(DEBUG_PRINT),
Stephen Morris's avatar
Stephen Morris committed
140
        service_(),
141
142
        dns_service_(service_, NULL, NULL, NULL),
        question_(new Question(Name("www.example.org"), RRClass::IN(), RRType::A())),
Stephen Morris's avatar
Stephen Morris committed
143
144
        last_(NONE),
        expected_(NONE),
145
        question_buffer_(new OutputBuffer(BUFFER_SIZE)),
Stephen Morris's avatar
Stephen Morris committed
146
        tcp_cumulative_(0),
147
        tcp_endpoint_(asio::ip::address::from_string(TEST_ADDRESS), TEST_PORT),
Stephen Morris's avatar
Stephen Morris committed
148
149
        tcp_length_(0),
        tcp_receive_buffer_(),
150
        tcp_send_buffer_(new OutputBuffer(BUFFER_SIZE)),
Stephen Morris's avatar
Stephen Morris committed
151
        tcp_socket_(service_.get_io_service()),
152
        udp_remote_(),
Stephen Morris's avatar
Stephen Morris committed
153
154
        udp_length_(0),
        udp_receive_buffer_(),
155
        udp_send_buffer_(new OutputBuffer(BUFFER_SIZE)),
Stephen Morris's avatar
Stephen Morris committed
156
        udp_socket_(service_.get_io_service(), udp::v4())
Jelte Jansen's avatar
Jelte Jansen committed
157
158
159
160
    {
        boost::shared_ptr<MockResolver>mock_resolver(new MockResolver());
        nsas_ = new isc::nsas::NameserverAddressStore(mock_resolver);
    }
Stephen Morris's avatar
Stephen Morris committed
161
162
163
164
165
166
167
168
169
170
171
172
173

    /// \brief Set Common Message Bits
    ///
    /// Sets up the common bits of a response message returned by the handlers.
    ///
    /// \param msg Message buffer in RENDER mode.
    /// \param qid QIT to set the message to
    void setCommonMessage(isc::dns::Message& msg, uint16_t qid = 0) {
        msg.setQid(qid);
        msg.setHeaderFlag(Message::HEADERFLAG_QR);
        msg.setOpcode(Opcode::QUERY());
        msg.setHeaderFlag(Message::HEADERFLAG_AA);
        msg.setRcode(Rcode::NOERROR());
174
        msg.addQuestion(*question_);
Stephen Morris's avatar
Stephen Morris committed
175
176
177
178
179
180
181
182
183
    }

    /// \brief Set Referral to "org"
    ///
    /// Sets up the passed-in message (expected to be in "RENDER" mode to
    /// indicate a referral to fictitious .org nameservers.
    ///
    /// \param msg Message to update with referral information.
    void setReferralOrg(isc::dns::Message& msg) {
184
185
186
        if (debug_) {
            cout << "setReferralOrg(): creating referral to .org nameservers" << endl;
        }
Stephen Morris's avatar
Stephen Morris committed
187
188

        // Do a referral to org.  We'll define all NS records as "in-zone"
189
190
191
        // nameservers (and supply glue) to avoid the possibility of the
        // resolver starting another recursive query to resolve the address of
        // a nameserver.
192
193
194
        RRsetPtr org_ns(new RRset(Name("org."), RRClass::IN(), RRType::NS(), RRTTL(300)));
        org_ns->addRdata(createRdata(RRType::NS(), RRClass::IN(), "ns1.org."));
        org_ns->addRdata(createRdata(RRType::NS(), RRClass::IN(), "ns2.org."));
Stephen Morris's avatar
Stephen Morris committed
195
196
        msg.addRRset(Message::SECTION_AUTHORITY, org_ns);

197
198
        RRsetPtr org_ns1(new RRset(Name("ns1.org."), RRClass::IN(), RRType::A(), RRTTL(300)));
        org_ns1->addRdata(createRdata(RRType::A(), RRClass::IN(), "192.0.2.1"));
Stephen Morris's avatar
Stephen Morris committed
199
200
        msg.addRRset(Message::SECTION_ADDITIONAL, org_ns1);

201
202
        RRsetPtr org_ns2(new RRset(Name("ns2.org."), RRClass::IN(), RRType::A(), RRTTL(300)));
        org_ns2->addRdata(createRdata(RRType::A(), RRClass::IN(), "192.0.2.2"));
Stephen Morris's avatar
Stephen Morris committed
203
204
205
206
207
208
209
210
211
212
        msg.addRRset(Message::SECTION_ADDITIONAL, org_ns2);
    }

    /// \brief Set Referral to "example.org"
    ///
    /// Sets up the passed-in message (expected to be in "RENDER" mode to
    /// indicate a referral to fictitious example.org nameservers.
    ///
    /// \param msg Message to update with referral information.
    void setReferralExampleOrg(isc::dns::Message& msg) {
213
214
215
        if (debug_) {
            cout << "setReferralExampleOrg(): creating referral to example.org nameservers" << endl;
        }
Stephen Morris's avatar
Stephen Morris committed
216
217

        // Do a referral to example.org.  As before, we'll define all NS
218
219
220
        // records as "in-zone" nameservers (and supply glue) to avoid the
        // possibility of the resolver starting another recursive query to look
        // up the address of the nameserver.
221
222
223
        RRsetPtr example_org_ns(new RRset(Name("example.org."), RRClass::IN(), RRType::NS(), RRTTL(300)));
        example_org_ns->addRdata(createRdata(RRType::NS(), RRClass::IN(), "ns1.example.org."));
        example_org_ns->addRdata(createRdata(RRType::NS(), RRClass::IN(), "ns2.example.org."));
Stephen Morris's avatar
Stephen Morris committed
224
225
        msg.addRRset(Message::SECTION_AUTHORITY, example_org_ns);

226
227
        RRsetPtr example_org_ns1(new RRset(Name("ns1.example.org."), RRClass::IN(), RRType::A(), RRTTL(300)));
        example_org_ns1->addRdata(createRdata(RRType::A(), RRClass::IN(), "192.0.2.11"));
Stephen Morris's avatar
Stephen Morris committed
228
229
        msg.addRRset(Message::SECTION_ADDITIONAL, example_org_ns1);

230
231
        RRsetPtr example_org_ns2(new RRset(Name("ns2.example.org."), RRClass::IN(), RRType::A(), RRTTL(300)));
        example_org_ns2->addRdata(createRdata(RRType::A(), RRClass::IN(), "192.0.2.21"));
Stephen Morris's avatar
Stephen Morris committed
232
233
234
235
236
        msg.addRRset(Message::SECTION_ADDITIONAL, example_org_ns2);
    }

    /// \brief Set Answer to "www.example.org"
    ///
237
    /// Sets up the passed-in message (expected to be in "RENDER" mode) to
Stephen Morris's avatar
Stephen Morris committed
238
239
240
241
    /// indicate an authoritative answer to www.example.org.
    ///
    /// \param msg Message to update with referral information.
    void setAnswerWwwExampleOrg(isc::dns::Message& msg) {
242
243
244
        if (debug_) {
            cout << "setAnswerWwwExampleOrg(): creating answer for www.example.org" << endl;
        }
Stephen Morris's avatar
Stephen Morris committed
245
246

        // Give a response for www.example.org.
247
248
249
        RRsetPtr www_example_org_a(new RRset(Name("www.example.org."), RRClass::IN(), RRType::A(), RRTTL(300)));
        www_example_org_a->addRdata(createRdata(RRType::A(), RRClass::IN(), WWW_EXAMPLE_ORG));
        msg.addRRset(Message::SECTION_ANSWER, www_example_org_a);
Stephen Morris's avatar
Stephen Morris committed
250
251
252
253
254
255
256
257

        // ... and add the Authority and Additional sections. (These are the
        // same as in the referral to example.org from the .org nameserver.)
        setReferralExampleOrg(msg);
    }

    /// \brief UDP Receive Handler
    ///
258
259
260
261
    /// This is invoked when a message is received over UDP from the
    /// RecursiveQuery object under test.  It formats an answer and sends it
    /// asynchronously, with the UdpSendHandler method being specified as the
    /// completion handler.
Stephen Morris's avatar
Stephen Morris committed
262
263
264
265
266
    ///
    /// \param ec ASIO error code, completion code of asynchronous I/O issued
    ///        by the "server" to receive data.
    /// \param length Amount of data received.
    void udpReceiveHandler(error_code ec = error_code(), size_t length = 0) {
267
268
269
270
271
        if (debug_) {
            cout << "udpReceiveHandler(): error = " << ec.value() <<
                    ", length = " << length << ", last state = " << last_ <<
                    ", expected state = " << expected_ << endl;
        }
Stephen Morris's avatar
Stephen Morris committed
272
273
274
275
276
277
278
279
280
281
282

        // Expected state should be one greater than the last state.
        EXPECT_EQ(static_cast<int>(expected_), static_cast<int>(last_) + 1);
        last_ = expected_;

        // The QID in the incoming data is random so set it to 0 for the
        // data comparison check. (It is set to 0 in the buffer containing
        // the expected data.)
        uint16_t qid = readUint16(udp_receive_buffer_);
        udp_receive_buffer_[0] = udp_receive_buffer_[1] = 0;

283
        // Check that question we received is what was expected.
284
        checkReceivedPacket(udp_receive_buffer_, length);
Stephen Morris's avatar
Stephen Morris committed
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303

        // The message returned depends on what state we are in.  Set up
        // common stuff first: bits not mentioned are set to 0.
        Message msg(Message::RENDER);
        setCommonMessage(msg, qid);

        // Set up state-dependent bits:
        switch (expected_) {
        case UDP_ROOT:
            // Return a referral to org.  We then expect to query the "org"
            // nameservers over UDP next.
            setReferralOrg(msg);
            expected_ = UDP_ORG;
            break;

         case UDP_ORG:
            // Return a referral to example.org.  We explicitly set the TC bit to
            // force a repeat query to the .org nameservers over TCP.
            setReferralExampleOrg(msg);
304
305
306
            if (debug_) {
                cout << "udpReceiveHandler(): setting TC bit" << endl;
            }
Stephen Morris's avatar
Stephen Morris committed
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
            msg.setHeaderFlag(Message::HEADERFLAG_TC);
            expected_ = TCP_ORG;
            break;

         case UDP_EXAMPLE_ORG:
            // Return the answer to the question.
            setAnswerWwwExampleOrg(msg);
            expected_ = COMPLETE;
            break;

         default:
            FAIL() << "UdpReceiveHandler called with unknown state";
        }

        // Convert to wire format
322
        udp_send_buffer_->clear();
Stephen Morris's avatar
Stephen Morris committed
323
324
325
        MessageRenderer renderer(*udp_send_buffer_);
        msg.toWire(renderer);

326
327
328
        // Return a message back to the IOFetch object (after setting the
        // expected length of data for the check in the send handler).
        udp_length_ = udp_send_buffer_->getLength();
329
330
331
332
333
        udp_socket_.async_send_to(asio::buffer(udp_send_buffer_->getData(),
                                               udp_send_buffer_->getLength()),
                                  udp_remote_,
                                  boost::bind(&RecursiveQueryTest2::udpSendHandler,
                                              this, _1, _2));
Stephen Morris's avatar
Stephen Morris committed
334
335
336
337
338
339
340
    }

    /// \brief UDP Send Handler
    ///
    /// Called when a send operation of the UDP server (i.e. a response
    /// being sent to the RecursiveQuery) has completed, this re-issues
    /// a read call.
341
342
343
    ///
    /// \param ec Completion error code of the send.
    /// \param length Actual number of bytes sent.
Stephen Morris's avatar
Stephen Morris committed
344
    void udpSendHandler(error_code ec = error_code(), size_t length = 0) {
345
346
347
348
        if (debug_) {
            cout << "udpSendHandler(): error = " << ec.value() <<
                    ", length = " << length << endl;
        }
Stephen Morris's avatar
Stephen Morris committed
349
350
351
352
353

        // Check send was OK
        EXPECT_EQ(0, ec.value());
        EXPECT_EQ(udp_length_, length);

354
        // Reissue the receive call to await the next message.
Stephen Morris's avatar
Stephen Morris committed
355
356
        udp_socket_.async_receive_from(
            asio::buffer(udp_receive_buffer_, sizeof(udp_receive_buffer_)),
357
358
            udp_remote_,
            boost::bind(&RecursiveQueryTest2::udpReceiveHandler, this, _1, _2));
Stephen Morris's avatar
Stephen Morris committed
359
360
361
362
    }

    /// \brief Completion Handler for Accepting TCP Data
    ///
363
    /// Called when the remote system connects to the "TCP server".  It issues
Stephen Morris's avatar
Stephen Morris committed
364
365
366
367
    /// an asynchronous read on the socket to read data.
    ///
    /// \param socket Socket on which data will be received
    /// \param ec Boost error code, value should be zero.
368
369
370
371
372
373
    void tcpAcceptHandler(error_code ec = error_code(), size_t length = 0) {
        if (debug_) {
            cout << "tcpAcceptHandler(): error = " << ec.value() <<
                    ", length = " << length << endl;
        }

Stephen Morris's avatar
Stephen Morris committed
374
375
376
377
378
379
380
381
        // Expect that the accept completed without a problem.
        EXPECT_EQ(0, ec.value());

        // Initiate a read on the socket, indicating that nothing has yet been
        // received.
        tcp_cumulative_ = 0;
        tcp_socket_.async_receive(
            asio::buffer(tcp_receive_buffer_, sizeof(tcp_receive_buffer_)),
382
            boost::bind(&RecursiveQueryTest2::tcpReceiveHandler, this, _1, _2));
Stephen Morris's avatar
Stephen Morris committed
383
384
385
386
387
    }

    /// \brief Completion Handler for Receiving TCP Data
    ///
    /// Reads data from the RecursiveQuery object and loops, reissuing reads,
388
389
    /// until all the message has been read.  It then returns an appropriate
    /// response.
Stephen Morris's avatar
Stephen Morris committed
390
391
392
393
394
    ///
    /// \param socket Socket to use to send the answer
    /// \param ec ASIO error code, completion code of asynchronous I/O issued
    ///        by the "server" to receive data.
    /// \param length Amount of data received.
395
396
397
398
399
400
401
    void tcpReceiveHandler(error_code ec = error_code(), size_t length = 0) {
        if (debug_) {
            cout << "tcpReceiveHandler(): error = " << ec.value() <<
                    ", length = " << length <<
                    ", cumulative = " << tcp_cumulative_ << endl;
        }

Stephen Morris's avatar
Stephen Morris committed
402
403
404
405
406
407
408
409
410
411
412
413
414
        // Expect that the receive completed without a problem.
        EXPECT_EQ(0, ec.value());

        // Have we received all the data?  We know this by checking if the two-
        // byte length count in the message is equal to the data received.
        tcp_cumulative_ += length;
        bool complete = false;
        if (tcp_cumulative_ > 2) {
            uint16_t dns_length = readUint16(tcp_receive_buffer_);
            complete = ((dns_length + 2) == tcp_cumulative_);
        }

        if (!complete) {
415
416
417
418
            if (debug_) {
                cout << "tcpReceiveHandler(): read not complete, " <<
                        "issuing another read" << endl;
            }
Stephen Morris's avatar
Stephen Morris committed
419
420
421
422
423

            // Not complete yet, issue another read.
            tcp_socket_.async_receive(
                asio::buffer(tcp_receive_buffer_ + tcp_cumulative_,
                             sizeof(tcp_receive_buffer_) - tcp_cumulative_),
424
                boost::bind(&RecursiveQueryTest2::tcpReceiveHandler, this, _1, _2));
Stephen Morris's avatar
Stephen Morris committed
425
426
427
428
429
430
431
432
            return;
        }

        // Have received a TCP message.  Expected state should be one greater
        // than the last state.
        EXPECT_EQ(static_cast<int>(expected_), static_cast<int>(last_) + 1);
        last_ = expected_;

433
434
        // Check that question we received is what was expected.  Note that we
        // have to ignore the two-byte header in order to parse the message.
435
        checkReceivedPacket(tcp_receive_buffer_ + 2, length - 2);
Stephen Morris's avatar
Stephen Morris committed
436
437

        // Return a message back.  This is a referral to example.org, which
438
439
        // should result in another query over UDP.  Note the setting of the
        // QID in the returned message with what was in the received message.
Stephen Morris's avatar
Stephen Morris committed
440
        Message msg(Message::RENDER);
441
        setCommonMessage(msg, readUint16(tcp_receive_buffer_));
Stephen Morris's avatar
Stephen Morris committed
442
443
444
        setReferralExampleOrg(msg);

        // Convert to wire format
445
446
447
448
        // Use a temporary buffer for the dns wire data (we copy it
        // to the 'real' buffer below)
        OutputBuffer msg_buf(BUFFER_SIZE);
        MessageRenderer renderer(msg_buf);
Stephen Morris's avatar
Stephen Morris committed
449
        msg.toWire(renderer);
450

Stephen Morris's avatar
Stephen Morris committed
451
        // Expected next state (when checked) is the UDP query to example.org.
452
453
        // Also, take this opportunity to clear the accumulated read count in
        // readiness for the next read. (If any - at present, there is only
454
        // one read in the test, although extensions to this test suite could
455
        // change that.)
Stephen Morris's avatar
Stephen Morris committed
456
        expected_ = UDP_EXAMPLE_ORG;
457
        tcp_cumulative_ = 0;
458

459
460
461
462
463
464
465
        // Unless we go through a callback loop we cannot simply use
        // async_send() multiple times, so we cannot send the size first
        // followed by the actual data. We copy them to a new buffer
        // first
        tcp_send_buffer_->clear();
        tcp_send_buffer_->writeUint16(msg_buf.getLength());
        tcp_send_buffer_->writeData(msg_buf.getData(), msg_buf.getLength());
466
467
468
469
        tcp_socket_.async_send(asio::buffer(tcp_send_buffer_->getData(),
                                            tcp_send_buffer_->getLength()),
                               boost::bind(&RecursiveQueryTest2::tcpSendHandler, this,
                                           tcp_send_buffer_->getLength(), _1, _2));
Stephen Morris's avatar
Stephen Morris committed
470
471
472
473
474
475
476
477
478
    }

    /// \brief Completion Handler for Sending TCP data
    ///
    /// Called when the asynchronous send of data back to the RecursiveQuery
    /// by the TCP "server" in this class has completed.  (This send has to
    /// be asynchronous because control needs to return to the caller in order
    /// for the IOService "run()" method to be called to run the handlers.)
    ///
479
    /// \param expected_length Number of bytes that were expected to have been sent.
Stephen Morris's avatar
Stephen Morris committed
480
481
    /// \param ec Boost error code, value should be zero.
    /// \param length Number of bytes sent.
482
    void tcpSendHandler(size_t expected_length = 0, error_code ec = error_code(),
Stephen Morris's avatar
Stephen Morris committed
483
484
                        size_t length = 0)
    {
485
486
487
488
489
        if (debug_) {
            cout << "tcpSendHandler(): error = " << ec.value() <<
                    ", length = " << length <<
                    ", (expected length = " << expected_length << ")" << endl;
        }
Stephen Morris's avatar
Stephen Morris committed
490
        EXPECT_EQ(0, ec.value());       // Expect no error
491
        EXPECT_EQ(expected_length, length);    // And that amount sent is as expected
Stephen Morris's avatar
Stephen Morris committed
492
493
    }

494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
    /// \brief Check Received Packet
    ///
    /// Checks the packet received from the RecursiveQuery object to ensure
    /// that the question is what is expected.
    ///
    /// \param data Start of data.  This is the start of the received buffer in
    ///        the case of UDP data, and an offset into the buffer past the
    ///        count field for TCP data.
    /// \param length Length of data.
    void checkReceivedPacket(uint8_t* data, size_t length) {

        // Decode the received buffer.
        InputBuffer buffer(data, length);
        Message message(Message::PARSE);
        message.fromWire(buffer);

        // Check the packet.
        EXPECT_FALSE(message.getHeaderFlag(Message::HEADERFLAG_QR));

        Question question = **(message.beginQuestion());
        EXPECT_TRUE(question == *question_);
    }
Stephen Morris's avatar
Stephen Morris committed
516
517
518
519
520
};

/// \brief Resolver Callback Object
///
/// Holds the success and failure callback methods for the resolver
521
class ResolverCallback : public isc::resolve::ResolverInterface::Callback {
Stephen Morris's avatar
Stephen Morris committed
522
523
public:
    /// \brief Constructor
524
525
    ResolverCallback(IOService& service) :
        service_(service), run_(false), status_(false), debug_(DEBUG_PRINT)
Stephen Morris's avatar
Stephen Morris committed
526
527
528
529
530
531
532
    {}

    /// \brief Destructor
    virtual ~ResolverCallback()
    {}

    /// \brief Resolver Callback Success
Stephen Morris's avatar
Stephen Morris committed
533
    ///
Stephen Morris's avatar
Stephen Morris committed
534
    /// Called if the resolver detects that the call has succeeded.
Stephen Morris's avatar
Stephen Morris committed
535
    ///
Stephen Morris's avatar
Stephen Morris committed
536
537
    /// \param response Answer to the question.
    virtual void success(const isc::dns::MessagePtr response) {
538
539
        if (debug_) {
            cout << "ResolverCallback::success(): answer received" << endl;
540
            cout << response->toText() << endl;
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
        }

        // There should be one RR each  in the question and answer sections, and
        // two RRs in each of the the authority and additional sections.
        EXPECT_EQ(1, response->getRRCount(Message::SECTION_QUESTION));
        EXPECT_EQ(1, response->getRRCount(Message::SECTION_ANSWER));
        EXPECT_EQ(2, response->getRRCount(Message::SECTION_AUTHORITY));
        EXPECT_EQ(2, response->getRRCount(Message::SECTION_ADDITIONAL));

        // Check the answer - that the RRset is there...
        EXPECT_TRUE(response->hasRRset(Message::SECTION_ANSWER,
                                       RRsetPtr(new RRset(Name("www.example.org."),
                                                RRClass::IN(),
                                                RRType::A(),
                                                RRTTL(300)))));
        const RRsetIterator rrset_i = response->beginSection(Message::SECTION_ANSWER);

        // ... get iterator into the Rdata of this RRset and point to first
        // element...
        const RdataIteratorPtr rdata_i = (*rrset_i)->getRdataIterator();
        rdata_i->first();

        // ... and check it is what we expect.
        EXPECT_EQ(string(WWW_EXAMPLE_ORG), rdata_i->getCurrent().toText());

        // Flag completion
        run_ = true;
        status_ = true;

Stephen Morris's avatar
Stephen Morris committed
570
571
        service_.stop();    // Cause run() to exit.
    }
Stephen Morris's avatar
Stephen Morris committed
572

Stephen Morris's avatar
Stephen Morris committed
573
574
    /// \brief Resolver Failure Completion
    ///
575
    /// Called if the resolver detects that the resolution has failed.
Stephen Morris's avatar
Stephen Morris committed
576
    virtual void failure() {
577
578
579
580
581
582
583
584
585
        if (debug_) {
            cout << "ResolverCallback::success(): resolution failure" << endl;
        }
        FAIL() << "Resolver reported completion failure";

        // Flag completion
        run_ = true;
        status_ = false;

Stephen Morris's avatar
Stephen Morris committed
586
        service_.stop();    // Cause run() to exit.
Stephen Morris's avatar
Stephen Morris committed
587
588
    }

589
590
591
592
593
594
595
596
597
598
    /// \brief Return status of "run" flag
    bool getRun() const {
        return (run_);
    }

    /// \brief Return "status" flag
    bool getStatus() const {
        return (status_);
    }

Stephen Morris's avatar
Stephen Morris committed
599
600
private:
    IOService&      service_;       ///< Service handling the run queue
601
602
603
    bool            run_;           ///< Set true when completion handler run
    bool            status_;        ///< Set true for success, false on error
    bool            debug_;         ///< Debug flag
Stephen Morris's avatar
Stephen Morris committed
604
605
};

Stephen Morris's avatar
Stephen Morris committed
606
607
608
// Sets up the UDP and TCP "servers", then tries a resolution.

TEST_F(RecursiveQueryTest2, Resolve) {
609
610
611
    // Set up the UDP server and issue the first read.  The endpoint from which
    // the query is sent is put in udp_endpoint_ when the read completes, which
    // is referenced in the callback as the place to which the response is sent.
Stephen Morris's avatar
Stephen Morris committed
612
    udp_socket_.set_option(socket_base::reuse_address(true));
613
614
615
616
617
618
    udp_socket_.bind(udp::endpoint(address::from_string(TEST_ADDRESS), TEST_PORT));
    udp_socket_.async_receive_from(asio::buffer(udp_receive_buffer_,
                                                sizeof(udp_receive_buffer_)),
                                   udp_remote_,
                                   boost::bind(&RecursiveQueryTest2::udpReceiveHandler,
                                               this, _1, _2));
Stephen Morris's avatar
Stephen Morris committed
619

Stephen Morris's avatar
Stephen Morris committed
620
621
622
623
    // Set up the TCP server and issue the accept.  Acceptance will cause the
    // read to be issued.
    tcp::acceptor acceptor(service_.get_io_service(),
                           tcp::endpoint(tcp::v4(), TEST_PORT));
624
625
626
    acceptor.async_accept(tcp_socket_,
                          boost::bind(&RecursiveQueryTest2::tcpAcceptHandler,
                                      this, _1, 0));
Stephen Morris's avatar
Stephen Morris committed
627
628
629
630

    // Set up the RecursiveQuery object.
    std::vector<std::pair<std::string, uint16_t> > upstream;         // Empty
    std::vector<std::pair<std::string, uint16_t> > upstream_root;    // Empty
Jelte Jansen's avatar
Jelte Jansen committed
631
632
    RecursiveQuery query(dns_service_, *nsas_, cache_,
                         upstream, upstream_root);
633
    query.setTestServer(TEST_ADDRESS, TEST_PORT);
Stephen Morris's avatar
Stephen Morris committed
634

635
636
    // Set up callback for the tor eceive notification that the query has
    // completed.
Jelte Jansen's avatar
Jelte Jansen committed
637
    isc::resolve::ResolverInterface::CallbackPtr
638
        resolver_callback(new ResolverCallback(service_));
Stephen Morris's avatar
Stephen Morris committed
639

640
641
642
643
    // Kick off the resolution process.  We expect the first question to go to
    // "root".
    expected_ = UDP_ROOT;
    query.resolve(question_, resolver_callback);
Stephen Morris's avatar
Stephen Morris committed
644
645
    service_.run();

646
647
648
649
650
651
    // Check what ran. (We have to cast the callback to ResolverCallback as we
    // lost the information on the derived class when we used a
    // ResolverInterface::CallbackPtr to store a pointer to it.)
    ResolverCallback* rc = static_cast<ResolverCallback*>(resolver_callback.get());
    EXPECT_TRUE(rc->getRun());
    EXPECT_TRUE(rc->getStatus());
Stephen Morris's avatar
Stephen Morris committed
652
653
654
}

} // namespace asiolink