asiolink.h 19.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Copyright (C) 2010  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.

// $Id$

17
18
#ifndef __ASIOLINK_H
#define __ASIOLINK_H 1
19

JINMEI Tatuya's avatar
JINMEI Tatuya committed
20
21
// IMPORTANT NOTE: only very few ASIO headers files can be included in
// this file.  In particular, asio.hpp should never be included here.
JINMEI Tatuya's avatar
JINMEI Tatuya committed
22
// See the description of the namespace below.
23
#include <unistd.h>             // for some network system calls
JINMEI Tatuya's avatar
JINMEI Tatuya committed
24
25
#include <asio/ip/address.hpp>

26
#include <functional>
27
28
#include <string>

29
#include <dns/buffer.h>
30
#include <dns/message.h>
31
#include <dns/question.h>
32

33
34
#include <exceptions/exceptions.h>

35
36
37
38
#include <asiolink/ioaddress.h>
#include <asiolink/ioendpoint.h>
#include <asiolink/iomessage.h>
#include <asiolink/iosocket.h>
39
//#include <asio/io_service.hpp>
40

41
namespace asio {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
42
// forward declaration for IOService::get_io_service() below
43
44
45
class io_service;
}

46
/// \namespace asiolink
JINMEI Tatuya's avatar
JINMEI Tatuya committed
47
48
/// \brief A wrapper interface for the ASIO library.
///
49
/// The \c asiolink namespace is used to define a set of wrapper interfaces
JINMEI Tatuya's avatar
JINMEI Tatuya committed
50
/// for the ASIO library.
Evan Hunt's avatar
Evan Hunt committed
51
52
53
///
/// BIND 10 uses the non-Boost version of ASIO because it's header-only,
/// i.e., does not require a separate library object to be linked, and thus
JINMEI Tatuya's avatar
JINMEI Tatuya committed
54
/// lowers the bar for introduction.
Evan Hunt's avatar
Evan Hunt committed
55
56
///
/// But the advantage comes with its own costs: since the header-only version
JINMEI Tatuya's avatar
JINMEI Tatuya committed
57
58
59
/// includes more definitions in public header files, it tends to trigger
/// more compiler warnings for our own sources, and, depending on the
/// compiler options, may make the build fail.
Evan Hunt's avatar
Evan Hunt committed
60
///
JINMEI Tatuya's avatar
JINMEI Tatuya committed
61
62
/// We also found it may be tricky to use ASIO and standard C++ libraries
/// in a single translation unit, i.e., a .cc file: depending on the order
Evan Hunt's avatar
Evan Hunt committed
63
64
65
/// of including header files, ASIO may or may not work on some platforms.
///
/// This wrapper interface is intended to centralize these
JINMEI Tatuya's avatar
JINMEI Tatuya committed
66
/// problematic issues in a single sub module.  Other BIND 10 modules should
67
/// simply include \c asiolink.h and use the wrapper API instead of
Evan Hunt's avatar
Evan Hunt committed
68
/// including ASIO header files and using ASIO-specific classes directly.
JINMEI Tatuya's avatar
JINMEI Tatuya committed
69
70
71
72
73
74
///
/// This wrapper may be used for other IO libraries if and when we want to
/// switch, but generality for that purpose is not the primary goal of
/// this module.  The resulting interfaces are thus straightforward mapping
/// to the ASIO counterparts.
///
JINMEI Tatuya's avatar
JINMEI Tatuya committed
75
/// Notes to developers:
76
77
78
/// Currently the wrapper interface is fairly specific to use by a
/// DNS server, i.e., b10-auth or b10-recurse.  But the plan is to
/// generalize it and have other modules use it as well.
JINMEI Tatuya's avatar
JINMEI Tatuya committed
79
///
JINMEI Tatuya's avatar
JINMEI Tatuya committed
80
/// One obvious drawback of this approach is performance overhead
JINMEI Tatuya's avatar
JINMEI Tatuya committed
81
/// due to the additional layer.  We should eventually evaluate the cost
Evan Hunt's avatar
Evan Hunt committed
82
83
84
/// of the wrapper abstraction in benchmark tests. Another drawback is
/// that the wrapper interfaces don't provide all features of ASIO
/// (at least for the moment).  We should also re-evaluate the
JINMEI Tatuya's avatar
JINMEI Tatuya committed
85
86
/// maintenance overhead of providing necessary wrappers as we develop
/// more.
JINMEI Tatuya's avatar
JINMEI Tatuya committed
87
88
89
90
///
/// On the other hand, we may be able to exploit the wrapper approach to
/// simplify the interfaces (by limiting the usage) and unify performance
/// optimization points.
Evan Hunt's avatar
Evan Hunt committed
91
///
JINMEI Tatuya's avatar
JINMEI Tatuya committed
92
93
94
/// As for optimization, we may want to provide a custom allocator for
/// the placeholder of callback handlers:
/// http://think-async.com/Asio/asio-1.3.1/doc/asio/reference/asio_handler_allocate.html
JINMEI Tatuya's avatar
JINMEI Tatuya committed
95

96
namespace asiolink {
97
struct DNSServiceImpl;
98
99
struct IOServiceImpl;

100
/// \brief An exception that is thrown if an error occurs within the IO
101
102
103
104
105
106
107
108
/// module.  This is mainly intended to be a wrapper exception class for
/// ASIO specific exceptions.
class IOError : public isc::Exception {
public:
    IOError(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) {}
};

109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/// \brief Forward declarations for classes used below
class SimpleCallback;
class DNSLookup;
class DNSAnswer;

/// \brief The \c IOService class is a wrapper for the ASIO \c io_service
/// class.
///
/// Currently, the interface of this class is very specific to the
/// authoritative/recursive DNS server implementationss in b10-auth
/// and b10-recurse; this is reflected in the constructor signatures.
/// Ultimately the plan is to generalize it so that other BIND 10
/// modules can use this interface, too.
class IOService {
    ///
    /// \name Constructors and Destructor
    ///
    /// These are currently very specific to the authoritative server
    /// implementation.
    ///
    /// Note: The copy constructor and the assignment operator are
    /// intentionally defined as private, making this class non-copyable.
    //@{
private:
    IOService(const IOService& source);
    IOService& operator=(const IOService& source);
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
public:
    /// \brief The constructor
    IOService();
    /// \brief The destructor.
    ~IOService();
    //@}

    /// \brief Start the underlying event loop.
    ///
    /// This method does not return control to the caller until
    /// the \c stop() method is called via some handler.
    void run();

    /// \brief Run the underlying event loop for a single event.
    ///
    /// This method return control to the caller as soon as the
    /// first handler has completed.  (If no handlers are ready when
    /// it is run, it will block until one is.)
    void run_one();

    /// \brief Stop the underlying event loop.
    ///
    /// This will return the control to the caller of the \c run() method.
    void stop();

    /// \brief Return the native \c io_service object used in this wrapper.
    ///
    /// This is a short term work around to support other BIND 10 modules
    /// that share the same \c io_service with the authoritative server.
    /// It will eventually be removed once the wrapper interface is
    /// generalized.
    asio::io_service& get_io_service();

private:
    IOServiceImpl* io_impl_;
};

class DNSService {
    ///
    /// \name Constructors and Destructor
    ///
    /// These are currently very specific to the authoritative server
    /// implementation.
    ///
    /// Note: The copy constructor and the assignment operator are
    /// intentionally defined as private, making this class non-copyable.
    //@{
private:
    DNSService(const DNSService& source);
    DNSService& operator=(const DNSService& source);
185
186
187
public:
    /// \brief The constructor with a specific IP address and port on which
    /// the services listen on.
Jelte Jansen's avatar
Jelte Jansen committed
188
189
190
    DNSService(IOService& io_service, const char& port,
               const char& address, SimpleCallback* checkin,
               DNSLookup* lookup, DNSAnswer* answer);
191
192
193
194
195
196
    /// \brief The constructor with a specific port on which the services
    /// listen on.
    ///
    /// It effectively listens on "any" IPv4 and/or IPv6 addresses.
    /// IPv4/IPv6 services will be available if and only if \c use_ipv4
    /// or \c use_ipv6 is \c true, respectively.
Jelte Jansen's avatar
Jelte Jansen committed
197
198
199
    DNSService(IOService& io_service, const char& port,
               const bool use_ipv4, const bool use_ipv6,
               SimpleCallback* checkin, DNSLookup* lookup,
200
               DNSAnswer* answer);
201
    /// \brief The destructor.
202
    ~DNSService();
203
204
205
206
207
208
209
210
    //@}

    /// \brief Return the native \c io_service object used in this wrapper.
    ///
    /// This is a short term work around to support other BIND 10 modules
    /// that share the same \c io_service with the authoritative server.
    /// It will eventually be removed once the wrapper interface is
    /// generalized.
211
    asio::io_service& get_io_service() { return io_service_.get_io_service(); };
212
private:
213
214
    DNSServiceImpl* impl_;
    IOService& io_service_;
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
};

/// \brief The \c DNSServer class is a wrapper (and base class) for
/// classes which provide DNS server functionality.
/// 
/// The classes derived from this one, \c TCPServer and \c UDPServer,
/// act as the interface layer between clients sending queries, and
/// functions defined elsewhere that provide answers to those queries.
/// Those functions are described in more detail below under
/// \c SimpleCallback, \c DNSLookup, and \c DNSAnswer.
///
/// Notes to developers:
/// When constructed, this class (and its derived classes) will have its
/// "self_" member set to point to "this".  Calls to methods in the base
/// class are then rerouted via this pointer to methods in the derived
/// class.  This allows code from outside asiolink, with no specific
/// knowledge of \c TCPServer or \c UDPServer, to access their methods.
///
/// This class is both assignable and copy-constructable.  Its subclasses
/// use the "stackless coroutine" pattern, meaning that it will copy itself
/// when "forking", and that instances will be posted as ASIO handler
/// objects, which are always copied.
///
/// Because these objects are frequently copied, it is recommended 
/// that derived classes be kept small to reduce copy overhead.
class DNSServer {
protected: 
    ///
    /// \name Constructors and destructors
    ///
    /// This is intentionally defined as \c protected, as this base class
    /// should never be instantiated except as part of a derived class.
    //@{
    DNSServer() : self_(this) {}
249
public:
250
251
252
    /// \brief The destructor
    virtual ~DNSServer() {}
    //@}
253

254
255
256
257
258
    ///
    /// \name Class methods
    ///
    /// These methods all make their calls indirectly via the "self_"
    /// pointer, ensuring that the functions ultimately invoked will be
259
260
261
262
    /// the ones in the derived class.  This makes it possible to pass
    /// instances of derived classes as references to this base class
    /// without losing access to derived class data.
    /// 
263
264
    //@{
    /// \brief The funtion operator
265
266
267
    virtual void operator()(asio::error_code ec = asio::error_code(),
                            size_t length = 0)
    {
268
        (*self_)(ec, length);
269
270
    }

271
272
273
    /// \brief Resume processing of the server coroutine after an 
    /// asynchronous call (e.g., to the DNS Lookup provider) has completed.
    virtual inline void resume(const bool done) { self_->resume(done); }
274

275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
    /// \brief Indicate whether the server is able to send an answer
    /// to a query.
    /// 
    /// This is presently used only for testing purposes.
    virtual inline bool hasAnswer() { return (self_->hasAnswer()); }

    /// \brief Returns the current value of the 'coroutine' object
    ///
    /// This is a temporary method, intended to be used for debugging
    /// purposes during development and removed later.  It allows
    /// callers from outside the coroutine object to retrieve information
    /// about its current state.
    virtual inline int value() { return (self_->value()); }

    /// \brief Returns a pointer to a clone of this DNSServer object.
    ///
    /// When a \c DNSServer object is copied or assigned, the result will
    /// normally be another \c DNSServer object containing a copy
    /// of the original "self_" pointer.  Calling clone() guarantees
    /// that the underlying object is also correctly copied.
    virtual inline DNSServer* clone() { return (self_->clone()); }
    //@}
297
298

protected:
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
    /// \brief Lookup handler object.
    ///
    /// This is a protected class; it can only be instantiated
    /// from within a derived class of \c DNSServer.
    ///
    /// A server object that has received a query creates an instance
    /// of this class and scheudles it on the ASIO service queue
    /// using asio::io_service::post().  When the handler executes, it
    /// calls the asyncLookup() method in the server object to start a
    /// DNS lookup.  When the lookup is complete, the server object is
    /// scheduled to resume, again using io_service::post().
    ///
    /// Note that the calling object is copied into the handler object,
    /// not referenced.  This is because, once the calling object yields
    /// control to the handler, it falls out of scope and may disappear
    template <typename T>
    class AsyncLookup {
    public:
        AsyncLookup(T caller) : caller_(caller) {}
        inline void operator()() { caller_.asyncLookup(); }
    private:
        T caller_;
    };

    /// \brief Carries out a DNS lookup.
    ///
    /// This function calls the \c DNSLookup object specified by the
    /// DNS server when the \c IOService was created, passing along
    /// the details of the query and a pointer back to the current
    /// server object.  It is called asynchronously via the AsyncLookup
    /// handler class.
    virtual inline void asyncLookup() { self_->asyncLookup(); }
331
332

private:
333
    DNSServer* self_;
334
335
336
};

/// \brief The \c DNSLookup class is an abstract base class for a DNS
337
/// Lookup provider function.
338
339
340
341
342
343
///
/// Specific derived class implementations are hidden within the
/// implementation.  Instances of the derived classes can be called
/// as functions via the operator() interface.  Pointers to these
/// instances can then be provided to the \c IOService class
/// via its constructor.
344
345
346
347
348
///
/// A DNS Lookup provider function obtains the data needed to answer
/// a DNS query (e.g., from authoritative data source, cache, or upstream
/// query).  After it has run, the OutputBuffer object passed to it
/// should contain the answer to the query, in an internal representation.
349
class DNSLookup {
350
351
352
353
354
355
356
    ///
    /// \name Constructors and Destructor
    ///
    /// Note: The copy constructor and the assignment operator are
    /// intentionally defined as private, making this class non-copyable.
    //@{
private:
357
358
    DNSLookup(const DNSLookup& source);
    DNSLookup& operator=(const DNSLookup& source);
359
360
361
362
363
protected:
    /// \brief The default constructor.
    ///
    /// This is intentionally defined as \c protected as this base class
    /// should never be instantiated (except as part of a derived class).
364
    DNSLookup() : self_(this) {}
365
366
public:
    /// \brief The destructor
367
    virtual ~DNSLookup() {}
368
    //@}
369
370
371
372
373
374
    /// \brief The function operator
    ///
    /// This makes its call indirectly via the "self" pointer, ensuring
    /// that the function ultimately invoked will be the one in the derived
    /// class.
    virtual void operator()(const IOMessage& io_message,
375
376
                            isc::dns::MessagePtr message,
                            isc::dns::OutputBufferPtr buffer,
377
                            DNSServer* server) const
378
    {
379
        (*self_)(io_message, message, buffer, server);
380
381
    }
private:
382
    DNSLookup* self_;
383
384
385
};

/// \brief The \c DNSAnswer class is an abstract base class for a DNS
386
/// Answer provider function.
387
388
389
390
391
392
///
/// Specific derived class implementations are hidden within the
/// implementation.  Instances of the derived classes can be called
/// as functions via the operator() interface.  Pointers to these
/// instances can then be provided to the \c IOService class
/// via its constructor.
393
394
395
396
397
///
/// A DNS Answer provider function takes answer data that has been obtained
/// from a DNS Lookup provider functon and readies it to be sent to the
/// client.  After it has run, the OutputBuffer object passed to it should
/// contain the answer to the query rendered into wire format.
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
class DNSAnswer {
    ///
    /// \name Constructors and Destructor
    ///
    /// Note: The copy constructor and the assignment operator are
    /// intentionally defined as private, making this class non-copyable.
    //@{
private:
    DNSAnswer(const DNSAnswer& source);
    DNSAnswer& operator=(const DNSAnswer& source);
protected:
    /// \brief The default constructor.
    ///
    /// This is intentionally defined as \c protected as this base class
    /// should never be instantiated (except as part of a derived class).
    DNSAnswer() {}
public:
    /// \brief The destructor
    virtual ~DNSAnswer() {}
417
    //@}
418
419
    /// \brief The function operator
    virtual void operator()(const IOMessage& io_message,
420
421
                            isc::dns::MessagePtr message,
                            isc::dns::OutputBufferPtr buffer) const = 0;
422
423
};

424
/// \brief The \c SimpleCallback class is an abstract base class for a
425
/// simple callback function with the signature:
426
427
428
429
430
431
///
/// Specific derived class implementations are hidden within the
/// implementation.  Instances of the derived classes can be called
/// as functions via the operator() interface.  Pointers to these
/// instances can then be provided to the \c IOService class
/// via its constructor.
432
433
434
435
436
///
/// The \c SimpleCallback is expected to be used for basic, generic
/// tasks such as checking for configuration changes.  It may also be
/// used for testing purposes.
class SimpleCallback {
437
438
439
440
441
442
443
    ///
    /// \name Constructors and Destructor
    ///
    /// Note: The copy constructor and the assignment operator are
    /// intentionally defined as private, making this class non-copyable.
    //@{
private:
444
445
    SimpleCallback(const SimpleCallback& source);
    SimpleCallback& operator=(const SimpleCallback& source);
446
447
448
449
450
protected:
    /// \brief The default constructor.
    ///
    /// This is intentionally defined as \c protected as this base class
    /// should never be instantiated (except as part of a derived class).
451
    SimpleCallback() : self_(this) {}
452
453
public:
    /// \brief The destructor
454
    virtual ~SimpleCallback() {}
455
    /// \brief The function operator
456
    //@}
457
458
459
460
461
    ///
    /// This makes its call indirectly via the "self" pointer, ensuring
    /// that the function ultimately invoked will be the one in the derived
    /// class.
    virtual void operator()(const IOMessage& io_message) const {
462
        (*self_)(io_message);
463
464
    }
private:
465
    SimpleCallback* self_;
466
467
};

468
469
/// \brief The \c RecursiveQuery class provides a layer of abstraction around
/// the ASIO code that carries out an upstream query.
JINMEI Tatuya's avatar
JINMEI Tatuya committed
470
///
471
472
473
/// This design is very preliminary; currently it is only capable of
/// handling simple forward requests to a single resolver.
class RecursiveQuery {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
474
    ///
475
    /// \name Constructors
476
    ///
JINMEI Tatuya's avatar
JINMEI Tatuya committed
477
    //@{
478
public:
479
    /// \brief Constructor for use when acting as a forwarder
480
    ///
481
482
483
    /// This is currently the only way to construct \c RecursiveQuery
    /// object.  The address of the forward nameserver is specified,
    /// and all upstream queries will be sent to that one address.
484
    RecursiveQuery(DNSService& dns_service, const char& forward,
485
                   uint16_t port = 53);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
486
    //@}
JINMEI Tatuya's avatar
JINMEI Tatuya committed
487

488
    /// \brief Initiates an upstream query in the \c RecursiveQuery object.
JINMEI Tatuya's avatar
JINMEI Tatuya committed
489
    ///
490
491
492
    /// \param question The question being answered <qname/qclass/qtype>
    /// \param buffer An output buffer into which the response can be copied
    /// \param server A pointer to the \c DNSServer object handling the client
JINMEI Tatuya's avatar
JINMEI Tatuya committed
493
    ///
494
495
496
497
    /// When sendQuery() is called, a message is sent asynchronously to
    /// the upstream name server.  When a reply arrives, 'server'
    /// is placed on the ASIO service queue via io_service::post(), so
    /// that the original \c DNSServer objct can resume processing.
498
    void sendQuery(const isc::dns::Question& question,
499
                   isc::dns::OutputBufferPtr buffer,
500
                   DNSServer* server);
501
private:
502
    DNSService& dns_service_;
503
    IOAddress ns_addr_;
504
    uint16_t port_;
505
506
};

507
508
}      // asiolink
#endif // __ASIOLINK_H
509
510
511
512

// Local Variables: 
// mode: c++
// End: