// 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. #ifndef __ASIOLINK_DNS_SERVER_H #define __ASIOLINK_DNS_SERVER_H 1 #include namespace asiolink { /// \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". Objects of this class (as /// instantiated through a base class) are sometimes passed by /// reference (as this superclass); 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) {} public: /// \brief The destructor virtual ~DNSServer() {} //@} /// /// \name Class methods /// /// These methods all make their calls indirectly via the "self_" /// pointer, ensuring that the functions ultimately invoked will be /// 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. /// //@{ /// \brief The funtion operator virtual void operator()(asio::error_code ec = asio::error_code(), size_t length = 0) { (*self_)(ec, length); } /// \brief Stop current running server virtual void stop() { self_->stop();} /// \brief Resume processing of the server coroutine after an /// asynchronous call (e.g., to the DNS Lookup provider) has completed. /// /// \param done If true, this signals the system there is an answer /// to return. virtual void resume(const bool done) { self_->resume(done); } /// \brief Indicate whether the server is able to send an answer /// to a query. /// /// This is presently used only for testing purposes. virtual 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. /// /// \return The value of the 'coroutine' object virtual 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. /// /// \return A deep copy of this DNSServer object virtual DNSServer* clone() { return (self_->clone()); } //@} protected: /// \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 class AsyncLookup { public: AsyncLookup(T& caller) : caller_(caller) {} 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 void asyncLookup() { self_->asyncLookup(); } private: DNSServer* self_; }; } // asiolink #endif // __ASIOLINK_DNS_SERVER_H