LCOV - code coverage report
Current view: top level - asiodns - sync_udp_server.cc (source / functions) Hit Total Coverage
Test: report.info Lines: 53 60 88.3 %
Date: 2012-05-15 Functions: 8 9 88.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 52 96 54.2 %

           Branch data     Line data    Source code
       1                 :            : // Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
       2                 :            : //
       3                 :            : // Permission to use, copy, modify, and/or distribute this software for any
       4                 :            : // purpose with or without fee is hereby granted, provided that the above
       5                 :            : // copyright notice and this permission notice appear in all copies.
       6                 :            : //
       7                 :            : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
       8                 :            : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
       9                 :            : // AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
      10                 :            : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
      11                 :            : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
      12                 :            : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
      13                 :            : // PERFORMANCE OF THIS SOFTWARE.
      14                 :            : 
      15                 :            : #include <config.h>
      16                 :            : 
      17                 :            : #include <asio.hpp>
      18                 :            : #include <asio/error.hpp>
      19                 :            : 
      20                 :            : #include "sync_udp_server.h"
      21                 :            : #include "logger.h"
      22                 :            : 
      23                 :            : #include <asiolink/dummy_io_cb.h>
      24                 :            : #include <asiolink/udp_endpoint.h>
      25                 :            : #include <asiolink/udp_socket.h>
      26                 :            : 
      27                 :            : #include <boost/bind.hpp>
      28                 :            : 
      29                 :            : #include <sys/types.h>
      30                 :            : #include <netinet/in.h>
      31                 :            : #include <sys/socket.h>
      32                 :            : #include <unistd.h>             // for some IPC/network system calls
      33                 :            : #include <errno.h>
      34                 :            : 
      35                 :            : using namespace std;
      36                 :            : using namespace isc::asiolink;
      37                 :            : 
      38                 :            : namespace isc {
      39                 :            : namespace asiodns {
      40                 :            : 
      41                 :         16 : SyncUDPServer::SyncUDPServer(asio::io_service& io_service, const int fd,
      42                 :            :                              const int af, asiolink::SimpleCallback* checkin,
      43                 :            :                              DNSLookup* lookup, DNSAnswer* answer) :
      44                 :            :     output_buffer_(new isc::util::OutputBuffer(0)),
      45         [ +  - ]:         16 :     query_(new isc::dns::Message(isc::dns::Message::PARSE)),
      46         [ +  - ]:         16 :     answer_(new isc::dns::Message(isc::dns::Message::RENDER)),
      47                 :            :     io_(io_service), checkin_callback_(checkin), lookup_callback_(lookup),
      48 [ +  - ][ +  - ]:         64 :     answer_callback_(answer), stopped_(false)
         [ +  - ][ +  - ]
                 [ +  - ]
      49                 :            : {
      50         [ +  + ]:         16 :     if (af != AF_INET && af != AF_INET6) {
      51 [ +  - ][ +  - ]:          2 :         isc_throw(InvalidParameter, "Address family must be either AF_INET "
                 [ +  - ]
      52                 :            :                   "or AF_INET6, not " << af);
      53                 :            :     }
      54 [ +  - ][ +  - ]:         15 :     LOG_DEBUG(logger, DBGLVL_TRACE_BASIC, ASIODNS_FD_ADD_UDP).arg(fd);
         [ +  - ][ +  - ]
                 [ +  - ]
      55                 :            :     try {
      56         [ +  - ]:         15 :         socket_.reset(new asio::ip::udp::socket(io_service));
      57                 :         15 :         socket_->assign(af == AF_INET6 ? asio::ip::udp::v6() :
      58         [ +  - ]:         15 :                         asio::ip::udp::v4(), fd);
      59         [ #  # ]:          0 :     } catch (const std::exception& exception) {
      60                 :            :         // Whatever the thing throws, it is something from ASIO and we
      61                 :            :         // convert it
      62 [ #  # ][ #  # ]:          0 :         isc_throw(IOError, exception.what());
      63                 :            :     }
      64                 :         15 : }
      65                 :            : 
      66                 :            : void
      67                 :         11 : SyncUDPServer::scheduleRead() {
      68                 :         11 :     socket_->async_receive_from(asio::buffer(data_, MAX_LENGTH), sender_,
      69                 :            :                                 boost::bind(&SyncUDPServer::handleRead, this,
      70                 :         11 :                                             _1, _2));
      71                 :         11 : }
      72                 :            : 
      73                 :            : void
      74                 :         11 : SyncUDPServer::handleRead(const asio::error_code& ec, const size_t length) {
      75                 :            :     // Abort on fatal errors
      76         [ +  + ]:         11 :     if (ec) {
      77                 :            :         using namespace asio::error;
      78 [ +  - ][ +  - ]:          3 :         if (ec.value() != would_block && ec.value() != try_again &&
         [ -  + ][ -  + ]
      79                 :            :             ec.value() != interrupted) {
      80                 :            :             return;
      81                 :            :         }
      82                 :            :     }
      83                 :            :     // Some kind of interrupt, spurious wakeup, or like that. Just try reading
      84                 :            :     // again.
      85 [ +  - ][ +  - ]:          8 :     if (ec || length == 0) {
                 [ -  + ]
      86                 :          0 :         scheduleRead();
      87                 :          0 :         return;
      88                 :            :     }
      89                 :            :     // OK, we have a real packet of data. Let's dig into it!
      90                 :            : 
      91                 :            :     // XXX: This is taken (and ported) from UDPSocket class. What the hell does
      92                 :            :     // it really mean?
      93                 :            : 
      94                 :            :     // The UDP socket class has been extended with asynchronous functions
      95                 :            :     // and takes as a template parameter a completion callback class.  As
      96                 :            :     // UDPServer does not use these extended functions (only those defined
      97                 :            :     // in the IOSocket base class) - but needs a UDPSocket to get hold of
      98                 :            :     // the underlying Boost UDP socket - DummyIOCallback is used.  This
      99                 :            :     // provides the appropriate operator() but is otherwise functionless.
     100                 :         11 :     UDPSocket<DummyIOCallback> socket(*socket_);
     101                 :          8 :     UDPEndpoint endpoint(sender_);
     102                 :          8 :     IOMessage message(data_, length, socket, endpoint);
     103         [ +  + ]:          8 :     if (checkin_callback_ != NULL) {
     104         [ +  - ]:          6 :         (*checkin_callback_)(message);
     105         [ +  + ]:          6 :         if (stopped_) {
     106                 :            :             return;
     107                 :            :         }
     108                 :            :     }
     109                 :            : 
     110                 :            :     // If we don't have a DNS Lookup provider, there's no point in
     111                 :            :     // continuing; we exit the coroutine permanently.
     112         [ -  + ]:          7 :     if (lookup_callback_ == NULL) {
     113         [ #  # ]:          0 :         scheduleRead();
     114                 :            :         return;
     115                 :            :     }
     116                 :            : 
     117                 :            :     // Make sure the buffers are fresh
     118                 :          7 :     output_buffer_->clear();
     119         [ +  - ]:          7 :     query_->clear(isc::dns::Message::PARSE);
     120         [ +  - ]:          7 :     answer_->clear(isc::dns::Message::RENDER);
     121                 :            : 
     122                 :            :     // Mark that we don't have an answer yet.
     123                 :          7 :     done_ = false;
     124                 :          7 :     resume_called_ = false;
     125                 :            : 
     126                 :            :     // Call the actual lookup
     127         [ +  - ]:          7 :     (*lookup_callback_)(message, query_, answer_, output_buffer_, this);
     128                 :            : 
     129         [ +  + ]:          7 :     if (!resume_called_) {
     130 [ +  - ][ +  - ]:          2 :         isc_throw(isc::Unexpected,
     131                 :            :                   "No resume called from the lookup callback");
     132                 :            :     }
     133                 :            : 
     134         [ +  + ]:          6 :     if (stopped_) {
     135                 :            :         return;
     136                 :            :     }
     137                 :            : 
     138         [ +  + ]:          4 :     if (done_) {
     139                 :            :         // Good, there's an answer.
     140                 :            :         // Call the answer callback to render it.
     141         [ +  - ]:          3 :         (*answer_callback_)(message, query_, answer_, output_buffer_);
     142                 :            : 
     143         [ +  + ]:          3 :         if (stopped_) {
     144                 :            :             return;
     145                 :            :         }
     146                 :            : 
     147                 :            :         socket_->send_to(asio::buffer(output_buffer_->getData(),
     148                 :          2 :                                       output_buffer_->getLength()),
     149         [ +  - ]:          2 :                          sender_);
     150                 :            :     }
     151                 :            : 
     152                 :            :     // And schedule handling another socket.
     153         [ +  - ]:          3 :     scheduleRead();
     154                 :            : }
     155                 :            : 
     156                 :            : void
     157                 :          8 : SyncUDPServer::operator()(asio::error_code, size_t) {
     158                 :            :     // To start the server, we just schedule reading of data when they
     159                 :            :     // arrive.
     160                 :          8 :     scheduleRead();
     161                 :          8 : }
     162                 :            : 
     163                 :            : /// Stop the UDPServer
     164                 :            : void
     165                 :         26 : SyncUDPServer::stop() {
     166                 :            :     /// Using close instead of cancel, because cancel
     167                 :            :     /// will only cancel the asynchornized event already submitted
     168                 :            :     /// to io service, the events post to io service after
     169                 :            :     /// cancel still can be scheduled by io service, if
     170                 :            :     /// the socket is cloesed, all the asynchronized event
     171                 :            :     /// for it won't be scheduled by io service not matter it is
     172                 :            :     /// submit to io serice before or after close call. And we will
     173                 :            :     //. get bad_descriptor error
     174                 :         26 :     socket_->close();
     175                 :         26 :     stopped_ = true;
     176                 :         26 : }
     177                 :            : 
     178                 :            : /// Post this coroutine on the ASIO service queue so that it will
     179                 :            : /// resume processing where it left off.  The 'done' parameter indicates
     180                 :            : /// whether there is an answer to return to the client.
     181                 :            : void
     182                 :          6 : SyncUDPServer::resume(const bool done) {
     183                 :          6 :     resume_called_ = true;
     184                 :          6 :     done_ = done;
     185                 :          6 : }
     186                 :            : 
     187                 :            : bool
     188                 :          0 : SyncUDPServer::hasAnswer() {
     189                 :          0 :     return (done_);
     190                 :            : }
     191                 :            : 
     192                 :            : } // namespace asiodns
     193 [ +  - ][ +  - ]:          9 : } // namespace isc

Generated by: LCOV version 1.9