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

Generated by: LCOV version 1.12