LCOV - code coverage report
Current view: top level - eventdispatcher - udp_server_message_connection.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1 44 2.3 %
Date: 2019-08-10 01:48:51 Functions: 2 5 40.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2012-2019  Made to Order Software Corp.  All Rights Reserved
       2             : //
       3             : // https://snapwebsites.org/project/eventdispatcher
       4             : // contact@m2osw.com
       5             : //
       6             : // This program is free software; you can redistribute it and/or modify
       7             : // it under the terms of the GNU General Public License as published by
       8             : // the Free Software Foundation; either version 2 of the License, or
       9             : // (at your option) any later version.
      10             : //
      11             : // This program is distributed in the hope that it will be useful,
      12             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             : // GNU General Public License for more details.
      15             : //
      16             : // You should have received a copy of the GNU General Public License
      17             : // along with this program; if not, write to the Free Software
      18             : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      19             : 
      20             : /** \file
      21             :  * \brief Implementation of the Snap Communicator class.
      22             :  *
      23             :  * This class wraps the C poll() interface in a C++ object with many types
      24             :  * of objects:
      25             :  *
      26             :  * \li Server Connections; for software that want to offer a port to
      27             :  *     which clients can connect to; the server will call accept()
      28             :  *     once a new client connection is ready; this results in a
      29             :  *     Server/Client connection object
      30             :  * \li Client Connections; for software that want to connect to
      31             :  *     a server; these expect the IP address and port to connect to
      32             :  * \li Server/Client Connections; for the server when it accepts a new
      33             :  *     connection; in this case the server gets a socket from accept()
      34             :  *     and creates one of these objects to handle the connection
      35             :  *
      36             :  * Using the poll() function is the easiest and allows us to listen
      37             :  * on pretty much any number of sockets (on my server it is limited
      38             :  * at 16,768 and frankly over 1,000 we probably will start to have
      39             :  * real slowness issues on small VPN servers.)
      40             :  */
      41             : 
      42             : // self
      43             : //
      44             : #include    "eventdispatcher/udp_server_message_connection.h"
      45             : 
      46             : #include    "eventdispatcher/exception.h"
      47             : #include    "eventdispatcher/udp_client.h"
      48             : 
      49             : 
      50             : // snaplogger lib
      51             : //
      52             : #include    <snaplogger/message.h>
      53             : 
      54             : 
      55             : // boost lib
      56             : //
      57             : #include    <boost/preprocessor/stringize.hpp>
      58             : 
      59             : 
      60             : // last include
      61             : //
      62             : #include    <snapdev/poison.h>
      63             : 
      64             : 
      65             : 
      66             : namespace ed
      67             : {
      68             : 
      69             : 
      70             : 
      71             : /** \brief Initialize a UDP server to send and receive messages.
      72             :  *
      73             :  * This function initialises a UDP server as a Snap UDP server
      74             :  * connection attached to the specified address and port.
      75             :  *
      76             :  * It is expected to be used to send and receive UDP messages.
      77             :  *
      78             :  * Note that to send messages, you need the address and port
      79             :  * of the destination. In effect, we do not use this server
      80             :  * when sending. Instead we create a client that we immediately
      81             :  * destruct once the message was sent.
      82             :  *
      83             :  * \param[in] addr  The address to listen on.
      84             :  * \param[in] port  The port to listen on.
      85             :  */
      86           0 : udp_server_message_connection::udp_server_message_connection(std::string const & addr, int port)
      87           0 :     : udp_server_connection(addr, port)
      88             : {
      89             :     // allow for looping over all the messages in one go
      90             :     //
      91           0 :     non_blocking();
      92           0 : }
      93             : 
      94             : 
      95             : /** \brief Send a UDP message.
      96             :  *
      97             :  * This function offers you to send a UDP message to the specified
      98             :  * address and port. The message should be small enough to fit in
      99             :  * on UDP packet or the call will fail.
     100             :  *
     101             :  * \note
     102             :  * The function return true when the message was successfully sent.
     103             :  * This does not mean it was received.
     104             :  *
     105             :  * \param[in] addr  The destination address for the message.
     106             :  * \param[in] port  The destination port for the message.
     107             :  * \param[in] message  The message to send to the destination.
     108             :  * \param[in] secret_code  The secret code to send along the message.
     109             :  *
     110             :  * \return true when the message was sent, false otherwise.
     111             :  */
     112           0 : bool udp_server_message_connection::send_message(
     113             :                   std::string const & addr
     114             :                 , int port
     115             :                 , message const & msg
     116             :                 , std::string const & secret_code)
     117             : {
     118             :     // Note: contrary to the TCP version, a UDP message does not
     119             :     //       need to include the '\n' character since it is sent
     120             :     //       in one UDP packet. However, it has a maximum size
     121             :     //       limit which we enforce here.
     122             :     //
     123           0 :     udp_client client(addr, port);
     124           0 :     std::string buf;
     125           0 :     if(!secret_code.empty())
     126             :     {
     127           0 :         message m(msg);
     128           0 :         m.add_parameter("udp_secret", secret_code);
     129           0 :         buf = m.to_message();
     130             :     }
     131             :     else
     132             :     {
     133           0 :         buf = msg.to_message();
     134             :     }
     135           0 :     if(buf.length() > DATAGRAM_MAX_SIZE)
     136             :     {
     137             :         // packet too large for our buffers
     138             :         //
     139             :         throw event_dispatcher_invalid_message(
     140             :                   "message too large ("
     141           0 :                 + std::to_string(buf.length())
     142           0 :                 + " bytes) for a UDP server (max: "
     143           0 :                   BOOST_PP_STRINGIZE(DATAGRAM_MAX_SIZE));
     144             :     }
     145           0 :     if(client.send(buf.data(), buf.length()) != static_cast<ssize_t>(buf.length())) // we do not send the '\0'
     146             :     {
     147             :         // TODO: add errno to message
     148             :         SNAP_LOG_ERROR
     149           0 :             << "udp_server_message_connection::send_message(): could not send UDP message.";
     150           0 :         return false;
     151             :     }
     152             : 
     153           0 :     return true;
     154             : }
     155             : 
     156             : 
     157             : /** \brief Implementation of the process_read() callback.
     158             :  *
     159             :  * This function reads the datagram we just received using the
     160             :  * recv() function. The size of the datagram cannot be more than
     161             :  * DATAGRAM_MAX_SIZE (1Kb at time of writing.)
     162             :  *
     163             :  * The message is then parsed and further processing is expected
     164             :  * to be accomplished in your implementation of process_message().
     165             :  *
     166             :  * The function actually reads as many pending datagrams as it can.
     167             :  */
     168           0 : void udp_server_message_connection::process_read()
     169             : {
     170             :     char buf[DATAGRAM_MAX_SIZE];
     171           0 :     for(;;)
     172             :     {
     173           0 :         ssize_t const r(recv(buf, sizeof(buf) / sizeof(buf[0])));
     174           0 :         if(r <= 0)
     175             :         {
     176           0 :             break;
     177             :         }
     178           0 :         std::string const udp_message(buf, r);
     179           0 :         message msg;
     180           0 :         if(msg.from_message(udp_message))
     181             :         {
     182           0 :             std::string const expected(get_secret_code());
     183           0 :             if(msg.has_parameter("udp_secret"))
     184             :             {
     185           0 :                 std::string const secret(msg.get_parameter("udp_secret"));
     186           0 :                 if(secret != expected)
     187             :                 {
     188           0 :                     if(!expected.empty())
     189             :                     {
     190             :                         // our secret code and the message secret code do not match
     191             :                         //
     192             :                         SNAP_LOG_ERROR
     193           0 :                             << "the incoming message has an unexpected udp_secret code, message ignored.";
     194           0 :                         return;
     195             :                     }
     196             : 
     197             :                     // the sender included a UDP secret code but we don't
     198             :                     // require it so we emit a warning but still accept
     199             :                     // the message
     200             :                     //
     201             :                     SNAP_LOG_WARNING
     202           0 :                         << "no udp_secret=... parameter was expected (missing set_secret_code() call for this application?)";
     203             :                 }
     204             :             }
     205           0 :             else if(!expected.empty())
     206             :             {
     207             :                 // secret code is missing from incoming message
     208             :                 //
     209             :                 SNAP_LOG_ERROR
     210           0 :                     << "the incoming message was expected to have udp_secret code, message ignored";
     211           0 :                 return;
     212             :             }
     213             : 
     214             :             // we received a valid message, process it
     215             :             //
     216           0 :             dispatch_message(msg);
     217             :         }
     218             :         else
     219             :         {
     220             :             SNAP_LOG_ERROR
     221             :                 << "udp_server_message_connection::process_read() was asked"
     222           0 :                    " to process an invalid message ("
     223           0 :                 << udp_message
     224           0 :                 << ")";
     225             :         }
     226             :     }
     227             : }
     228             : 
     229             : 
     230             : 
     231           6 : } // namespace ed
     232             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.12