asio_link.h 17.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 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$

#ifndef __ASIO_LINK_H
#define __ASIO_LINK_H 1

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
30
#include <boost/function.hpp>

31
32
33
#include <exceptions/exceptions.h>

namespace asio {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
34
// forward declaration for IOService::get_io_service() below
35
36
37
class io_service;
}

38
39
class AuthSrv;

JINMEI Tatuya's avatar
JINMEI Tatuya committed
40
41
42
43
44
/// \namespace asio_link
/// \brief A wrapper interface for the ASIO library.
///
/// The \c asio_link namespace is used to define a set of wrapper interfaces
/// for the ASIO library.
Evan Hunt's avatar
Evan Hunt committed
45
46
47
///
/// 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
48
/// lowers the bar for introduction.
Evan Hunt's avatar
Evan Hunt committed
49
50
///
/// But the advantage comes with its own costs: since the header-only version
JINMEI Tatuya's avatar
JINMEI Tatuya committed
51
52
53
/// 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
54
///
JINMEI Tatuya's avatar
JINMEI Tatuya committed
55
56
/// 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
57
58
59
/// 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
60
/// problematic issues in a single sub module.  Other BIND 10 modules should
Evan Hunt's avatar
Evan Hunt committed
61
62
/// simply include \c asio_link.h and use the wrapper API instead of
/// including ASIO header files and using ASIO-specific classes directly.
JINMEI Tatuya's avatar
JINMEI Tatuya committed
63
64
65
66
67
68
///
/// 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
69
70
/// Notes to developers:
/// Currently the wrapper interface is specific to the authoritative
JINMEI Tatuya's avatar
JINMEI Tatuya committed
71
72
73
/// server implementation.  But the plan is to generalize it and have
/// other modules use it.
///
JINMEI Tatuya's avatar
JINMEI Tatuya committed
74
/// One obvious drawback of this approach is performance overhead
JINMEI Tatuya's avatar
JINMEI Tatuya committed
75
/// due to the additional layer.  We should eventually evaluate the cost
Evan Hunt's avatar
Evan Hunt committed
76
77
78
/// 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
79
80
/// maintenance overhead of providing necessary wrappers as we develop
/// more.
JINMEI Tatuya's avatar
JINMEI Tatuya committed
81
82
83
84
///
/// 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
85
///
JINMEI Tatuya's avatar
JINMEI Tatuya committed
86
87
88
/// 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
89

90
namespace asio_link {
91
class IOServiceImpl;
92

93
/// \brief An exception that is thrown if an error occurs within the IO
94
95
96
97
98
99
100
101
/// 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) {}
};

JINMEI Tatuya's avatar
JINMEI Tatuya committed
102
103
104
105
/// \brief The \c IOAddress class represents an IP addresses (version
/// agnostic)
///
/// This class is a wrapper for the ASIO \c ip::address class.
106
107
class IOAddress {
public:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
108
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
    ///
    /// \name Constructors and Destructor
    ///
    /// This class is copyable.  We use default versions of copy constructor
    /// and the assignment operator.
    /// We use the default destructor.
    //@{
    /// \brief Constructor from string.
    ///
    /// This constructor converts a textual representation of IPv4 and IPv6
    /// addresses into an IOAddress object.
    /// If \c address_str is not a valid representation of any type of
    /// address, an exception of class \c IOError will be thrown.
    /// This constructor allocates memory for the object, and if that fails
    /// a corresponding standard exception will be thrown.
    ///
    /// \param address_str Textual representation of address.
    IOAddress(const std::string& address_str);

    /// \brief Constructor from an ASIO \c ip::address object.
    ///
    /// This constructor is intended to be used within the wrapper
    /// implementation; user applications of the wrapper API won't use it.
    ///
    /// This constructor never throws an exception.
    ///
    /// \param asio_address The ASIO \c ip::address to be converted.
Jeremy C. Reed's avatar
Jeremy C. Reed committed
135
    IOAddress(const asio::ip::address& asio_address);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
136
137
138
139
140
141
142
143
144
    //@}

    /// \brief Convert the address to a string.
    ///
    /// This method is basically expected to be exception free, but
    /// generating the string will involve resource allocation,
    /// and if it fails the corresponding standard exception will be thrown.
    ///
    /// \return A string representation of the address.
145
146
    std::string toText() const;
private:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
147
    asio::ip::address asio_address_;
148
149
};

JINMEI Tatuya's avatar
JINMEI Tatuya committed
150
151
152
153
154
155
156
157
158
/// \brief The \c IOEndpoint class is an abstract base class to represent
/// a communication endpoint.
///
/// This class is a wrapper for the ASIO endpoint classes such as
/// \c ip::tcp::endpoint and \c ip::udp::endpoint.
///
/// Derived class implementations are completely hidden within the
/// implementation.  User applications only get access to concrete
/// \c IOEndpoint objects via the abstract interfaces.
JINMEI Tatuya's avatar
JINMEI Tatuya committed
159
class IOEndpoint {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
160
161
162
163
164
165
    ///
    /// \name Constructors and Destructor
    ///
    /// Note: The copy constructor and the assignment operator are
    /// intentionally defined as private, making this class non-copyable.
    //@{
JINMEI Tatuya's avatar
JINMEI Tatuya committed
166
167
168
169
private:
    IOEndpoint(const IOEndpoint& source);
    IOEndpoint& operator=(const IOEndpoint& source);
protected:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
170
171
172
173
    /// \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).
JINMEI Tatuya's avatar
JINMEI Tatuya committed
174
175
    IOEndpoint() {}
public:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
176
    /// The destructor.
JINMEI Tatuya's avatar
JINMEI Tatuya committed
177
    virtual ~IOEndpoint() {}
JINMEI Tatuya's avatar
JINMEI Tatuya committed
178
179
180
181
182
183
    //@}

    /// \brief Returns the address of the endpoint.
    ///
    /// This method returns an IOAddress object corresponding to \c this
    /// endpoint.
Evan Hunt's avatar
Evan Hunt committed
184
    /// Note that the return value is a real object, not a reference or
JINMEI Tatuya's avatar
JINMEI Tatuya committed
185
186
187
188
189
190
191
192
193
194
195
196
    /// a pointer.
    /// This is aligned with the interface of the ASIO counterpart:
    /// the \c address() method of \c ip::xxx::endpoint classes returns
    /// an \c ip::address object.
    /// This also means handling the address of an endpoint using this method
    /// can be expensive.  If the address information is necessary in a
    /// performance sensitive context and there's a more efficient interface
    /// for that purpose, it's probably better to avoid using this method.
    ///
    /// This method never throws an exception.
    ///
    /// \return A copy of \c IOAddress object corresponding to the endpoint.
JINMEI Tatuya's avatar
JINMEI Tatuya committed
197
    virtual IOAddress getAddress() const = 0;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
198
199
200
201
202
203
204
205
206
207
208
209

    /// \brief A polymorphic factory of endpoint from address and port.
    ///
    /// This method creates a new instance of (a derived class of)
    /// \c IOEndpoint object that identifies the pair of given address
    /// and port.
    /// The appropriate derived class is chosen based on the specified
    /// transport protocol.  If the \c protocol doesn't specify a protocol
    /// supported in this implementation, an exception of class \c IOError
    /// will be thrown.
    ///
    /// Memory for the created object will be dynamically allocated.  It's
Jeremy C. Reed's avatar
Jeremy C. Reed committed
210
    /// the caller's responsibility to \c delete it later.
JINMEI Tatuya's avatar
JINMEI Tatuya committed
211
212
213
214
215
216
217
218
    /// If resource allocation for the new object fails, a corresponding
    /// standard exception will be thrown.
    ///
    /// \param protocol The transport protocol used for the endpoint.
    /// Currently, only \c IPPROTO_UDP and \c IPPROTO_TCP can be specified.
    /// \param address The (IP) address of the endpoint.
    /// \param port The transport port number of the endpoint
    /// \return A pointer to a newly created \c IOEndpoint object.
219
    static const IOEndpoint* create(const int protocol,
JINMEI Tatuya's avatar
JINMEI Tatuya committed
220
                                    const IOAddress& address,
221
                                    const unsigned short port);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
222
223
224
225
226
227
228
229
};

/// \brief The \c IOSocket class is an abstract base class to represent
/// various types of network sockets.
///
/// This class is a wrapper for the ASIO socket classes such as
/// \c ip::tcp::socket and \c ip::udp::socket.
///
JINMEI Tatuya's avatar
JINMEI Tatuya committed
230
/// Derived class implementations are completely hidden within the
JINMEI Tatuya's avatar
JINMEI Tatuya committed
231
232
/// implementation.  User applications only get access to concrete
/// \c IOSocket objects via the abstract interfaces.
233
234
235
236
/// We may revisit this decision when we generalize the wrapper and more
/// modules use it.  Also, at that point we may define a separate (visible)
/// derived class for testing purposes rather than providing factory methods
/// (i.e., getDummy variants below).
237
class IOSocket {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
238
239
240
241
242
243
    ///
    /// \name Constructors and Destructor
    ///
    /// Note: The copy constructor and the assignment operator are
    /// intentionally defined as private, making this class non-copyable.
    //@{
244
245
246
247
private:
    IOSocket(const IOSocket& source);
    IOSocket& operator=(const IOSocket& source);
protected:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
248
249
250
251
    /// \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).
252
253
    IOSocket() {}
public:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
254
    /// The destructor.
255
    virtual ~IOSocket() {}
JINMEI Tatuya's avatar
JINMEI Tatuya committed
256
257
258
259
260
261
262
263
264
265
266
    //@}

    /// \brief Return the "native" representation of the socket.
    ///
    /// In practice, this is the file descriptor of the socket for
    /// UNIX-like systems so the current implementation simply uses
    /// \c int as the type of the return value.
    /// We may have to need revisit this decision later.
    ///
    /// In general, the application should avoid using this method;
    /// it essentially discloses an implementation specific "handle" that
JINMEI Tatuya's avatar
JINMEI Tatuya committed
267
    /// can change the internal state of the socket (consider the
JINMEI Tatuya's avatar
JINMEI Tatuya committed
268
269
270
271
272
273
274
275
276
277
    /// application closes it, for example).
    /// But we sometimes need to perform very low-level operations that
    /// requires the native representation.  Passing the file descriptor
    /// to a different process is one example.
    /// This method is provided as a necessary evil for such limited purposes.
    ///
    /// This method never throws an exception.
    ///
    /// \return The native representation of the socket.  This is the socket
    /// file descriptor for UNIX-like systems.
278
    virtual int getNative() const = 0;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
279
280
281
282
283
284
285
286
287
288

    /// \brief Return the transport protocol of the socket.
    ///
    /// Currently, it returns \c IPPROTO_UDP for UDP sockets, and
    /// \c IPPROTO_TCP for TCP sockets.
    ///
    /// This method never throws an exception.
    ///
    /// \return IPPROTO_UDP for UDP sockets
    /// \return IPPROTO_TCP for TCP sockets
289
    virtual int getProtocol() const = 0;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
290
291
292
293
294
295
296
297
298
299
300
301
302
303

    /// \brief Return a non-usable "dummy" UDP socket for testing.
    ///
    /// This is a class method that returns a "mock" of UDP socket.
    /// This is not associated with any actual socket, and its only
    /// responsibility is to return \c IPPROTO_UDP from \c getProtocol().
    /// The only feasible usage of this socket is for testing so that
    /// the test code can prepare some "UDP data" even without opening any
    /// actual socket.
    ///
    /// This method never throws an exception.
    ///
    /// \return A reference to an \c IOSocket object whose \c getProtocol()
    /// returns \c IPPROTO_UDP.
304
    static IOSocket& getDummyUDPSocket();
JINMEI Tatuya's avatar
JINMEI Tatuya committed
305
306
307
308
309
310
311

    /// \brief Return a non-usable "dummy" TCP socket for testing.
    ///
    /// See \c getDummyUDPSocket().  This method is its TCP version.
    ///
    /// \return A reference to an \c IOSocket object whose \c getProtocol()
    /// returns \c IPPROTO_TCP.
312
    static IOSocket& getDummyTCPSocket();
313
314
};

JINMEI Tatuya's avatar
JINMEI Tatuya committed
315
316
/// \brief The \c IOMessage class encapsulates an incoming message received
/// on a socket.
JINMEI Tatuya's avatar
JINMEI Tatuya committed
317
318
319
320
321
322
323
324
325
///
/// An \c IOMessage object represents a tuple of a chunk of data
/// (a UDP packet or some segment of TCP stream), the socket over which the
/// data is passed, the information about the other end point of the
/// communication, and perhaps more.
///
/// The current design and interfaces of this class is tentative.
/// It only provides a minimal level of support that is necessary for
/// the current implementation of the authoritative server.
JINMEI Tatuya's avatar
JINMEI Tatuya committed
326
/// A future version of this class will definitely support more.
327
class IOMessage {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
328
329
330
331
332
333
    ///
    /// \name Constructors and Destructor
    ///
    /// Note: The copy constructor and the assignment operator are
    /// intentionally defined as private, making this class non-copyable.
    //@{
334
335
336
private:
    IOMessage(const IOMessage& source);
    IOMessage& operator=(const IOMessage& source);
337
public:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
338
339
340
341
342
343
344
345
346
347
348
349
350
    /// \brief Constructor from message information.
    ///
    /// This constructor needs to handle the ASIO \c ip::address class,
    /// and is intended to be used within this wrapper implementation.
    /// Once the \c IOMessage object is created, the application can
    /// get access to the information via the wrapper interface such as
    /// \c getRemoteAddress().
    ///
    /// This constructor never throws an exception.
    ///
    /// \param data A pointer to the message data.
    /// \param data_size The size of the message data in bytes.
    /// \param io_socket The socket over which the data is given.
JINMEI Tatuya's avatar
JINMEI Tatuya committed
351
352
    /// \param remote_endpoint The other endpoint of the socket, that is,
    /// the sender of the message.
353
    IOMessage(const void* data, const size_t data_size, IOSocket& io_socket,
JINMEI Tatuya's avatar
JINMEI Tatuya committed
354
355
              const IOEndpoint& remote_endpoint);
    //@}
JINMEI Tatuya's avatar
JINMEI Tatuya committed
356
357

    /// \brief Returns a pointer to the received data.
358
    const void* getData() const { return (data_); }
JINMEI Tatuya's avatar
JINMEI Tatuya committed
359
360

    /// \brief Returns the size of the received data in bytes.
361
    size_t getDataSize() const { return (data_size_); }
JINMEI Tatuya's avatar
JINMEI Tatuya committed
362
363

    /// \brief Returns the socket on which the message arrives.
364
    const IOSocket& getSocket() const { return (io_socket_); }
JINMEI Tatuya's avatar
JINMEI Tatuya committed
365
366

    /// \brief Returns the endpoint that sends the message.
JINMEI Tatuya's avatar
JINMEI Tatuya committed
367
    const IOEndpoint& getRemoteEndpoint() const { return (remote_endpoint_); }
368
private:
369
370
371
    const void* data_;
    const size_t data_size_;
    IOSocket& io_socket_;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
372
    const IOEndpoint& remote_endpoint_;
373
374
};

JINMEI Tatuya's avatar
JINMEI Tatuya committed
375
376
377
378
379
380
381
/// \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 server implementation as indicated in the signature of
/// the constructor, but the plan is to generalize it so that other BIND 10
/// modules can use this interface, too.
382
class IOService {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
383
384
385
    ///
    /// \name Constructors and Destructor
    ///
386
387
388
    /// These are currently very specific to the authoritative server
    /// implementation.
    ///
JINMEI Tatuya's avatar
JINMEI Tatuya committed
389
390
391
    /// Note: The copy constructor and the assignment operator are
    /// intentionally defined as private, making this class non-copyable.
    //@{
JINMEI Tatuya's avatar
JINMEI Tatuya committed
392
393
394
private:
    IOService(const IOService& source);
    IOService& operator=(const IOService& source);
395
public:
396
397
398
399
400
401
402
403
404
    /// \brief The constructor with a specific IP address and port on which
    /// the services listen on.
    IOService(AuthSrv* auth_server, const char& port, const char& address);
    /// \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.
405
406
    IOService(AuthSrv* auth_server, const char& port,
              const bool use_ipv4, const bool use_ipv6);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
407
    /// \brief The destructor.
408
    ~IOService();
JINMEI Tatuya's avatar
JINMEI Tatuya committed
409
    //@}
JINMEI Tatuya's avatar
JINMEI Tatuya committed
410
411
412

    /// \brief Start the underlying event loop.
    ///
Evan Hunt's avatar
Evan Hunt committed
413
414
    /// This method does not return control to the caller until
    /// the \c stop() method is called via some handler.
415
    void run();
JINMEI Tatuya's avatar
JINMEI Tatuya committed
416
417
418
419

    /// \brief Stop the underlying event loop.
    ///
    /// This will return the control to the caller of the \c run() method.
420
    void stop();
JINMEI Tatuya's avatar
JINMEI Tatuya committed
421
422
423
424

    /// \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
JINMEI Tatuya's avatar
JINMEI Tatuya committed
425
    /// that share the same \c io_service with the authoritative server.
JINMEI Tatuya's avatar
JINMEI Tatuya committed
426
427
    /// It will eventually be removed once the wrapper interface is
    /// generalized.
428
    asio::io_service& get_io_service();
JINMEI Tatuya's avatar
JINMEI Tatuya committed
429
430
431
432
433
434
435
436
437
438
439
440

    /// \brief A functor(-like) class that specifies a custom call back
    /// invoked from the event loop instead of the embedded authoritative
    /// server callbacks.
    ///
    /// Currently, the callback is intended to be used only for testing
    /// purposes.  But we'll need a generic callback type like this to
    /// generalize the wrapper interface.
    typedef boost::function<void(const IOMessage& io_message)> IOCallBack;

    /// \brief Set the custom call back invoked from the event loop.
    ///
441
442
443
    /// Right now this method is only for testing, but will eventually be
    /// generalized.
    void setCallBack(IOCallBack callback);
444
445
446
447
448
449
450
451
452
private:
    IOServiceImpl* impl_;
};
}      // asio_link
#endif // __ASIO_LINK_H

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