LCOV - code coverage report
Current view: top level - eventdispatcher - local_dgram_server_message_connection.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 28 56 50.0 %
Date: 2021-09-19 09:06:58 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2012-2021  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 AF_UNIX socket class handling message packets.
      22             :  *
      23             :  */
      24             : 
      25             : // self
      26             : //
      27             : #include    "eventdispatcher/local_dgram_server_message_connection.h"
      28             : 
      29             : #include    "eventdispatcher/exception.h"
      30             : #include    "eventdispatcher/local_dgram_client.h"
      31             : 
      32             : 
      33             : // snaplogger lib
      34             : //
      35             : #include    <snaplogger/message.h>
      36             : 
      37             : 
      38             : // boost lib
      39             : //
      40             : #include    <boost/preprocessor/stringize.hpp>
      41             : 
      42             : 
      43             : // last include
      44             : //
      45             : #include    <snapdev/poison.h>
      46             : 
      47             : 
      48             : 
      49             : namespace ed
      50             : {
      51             : 
      52             : 
      53             : 
      54             : /** \brief Initialize a UDP server to send and receive messages.
      55             :  *
      56             :  * This function initializes a UDP server as a Snap UDP server
      57             :  * connection attached to the specified address and port.
      58             :  *
      59             :  * It is expected to be used to send and receive UDP messages.
      60             :  *
      61             :  * Note that to send messages, you need the address and port
      62             :  * of the destination. In effect, we do not use this server
      63             :  * when sending. Instead we create a client that we immediately
      64             :  * destruct once the message was sent.
      65             :  *
      66             :  * \param[in] address  The address to listen on. It may be set to "0.0.0.0".
      67             :  * \param[in] sequential  Whether the packets are kept in order.
      68             :  * \param[in] close_on_exec  Whether the socket is closed on execve().
      69             :  * \param[in] force_reuse_addr  Whether caller is okay with an unlink() of
      70             :  * a file socket if it exists.
      71             :  */
      72           2 : local_dgram_server_message_connection::local_dgram_server_message_connection(
      73             :               addr::unix const & address
      74             :             , bool sequential
      75             :             , bool close_on_exec
      76           2 :             , bool force_reuse_addr)
      77             :     : local_dgram_server_connection(
      78             :           address
      79             :         , sequential
      80             :         , close_on_exec
      81           2 :         , force_reuse_addr)
      82             : {
      83             :     // allow for looping over all the messages in one go
      84             :     //
      85           2 :     non_blocking();
      86           2 : }
      87             : 
      88             : 
      89             : /** \brief Send a UDP message.
      90             :  *
      91             :  * This function offers you to send a UDP message to the specified
      92             :  * address and port. The message should be small enough to fit in
      93             :  * one UDP packet or the call will fail.
      94             :  *
      95             :  * \note
      96             :  * The function returns true when the message was successfully sent.
      97             :  * This does not mean it was received.
      98             :  *
      99             :  * \param[in] address  The destination Unix address for the message.
     100             :  * \param[in] msg  The message to send to the destination.
     101             :  * \param[in] secret_code  The secret code to send along the message.
     102             :  *
     103             :  * \return true when the message was sent, false otherwise.
     104             :  */
     105           3 : bool local_dgram_server_message_connection::send_message(
     106             :                   addr::unix const & address
     107             :                 , message const & msg
     108             :                 , std::string const & secret_code)
     109             : {
     110             :     // Note: contrary to the Stream version, a Datagram message does not
     111             :     //       need to include the '\n' character since it is sent
     112             :     //       in one packet. However, it has a maximum size limit
     113             :     //       which we enforce here.
     114             :     //
     115           6 :     std::string buf;
     116           3 :     if(!secret_code.empty())
     117             :     {
     118           0 :         message m(msg);
     119           0 :         m.add_parameter("secret_code", secret_code);
     120           0 :         buf = m.to_message();
     121             :     }
     122             :     else
     123             :     {
     124           3 :         buf = msg.to_message();
     125             :     }
     126             : 
     127             :     // TODO: this maximum size needs to be checked dynamically
     128             :     //
     129           3 :     if(buf.length() > DATAGRAM_MAX_SIZE)
     130             :     {
     131             :         // packet too large for the socket buffers
     132             :         //
     133             :         throw event_dispatcher_invalid_message(
     134             :                   "message too large ("
     135           0 :                 + std::to_string(buf.length())
     136           0 :                 + " bytes) for a Unix socket (max: "
     137           0 :                   BOOST_PP_STRINGIZE(DATAGRAM_MAX_SIZE));
     138             :     }
     139             : 
     140           6 :     local_dgram_client client(address);
     141           3 :     int const r(client.send(buf.data(), buf.length()));
     142           3 :     if(r != static_cast<ssize_t>(buf.length())) // we do not send the '\0'
     143             :     {
     144             :         // TODO: add errno to message
     145           0 :         int const e(errno);
     146           0 :         SNAP_LOG_ERROR
     147           0 :             << "local_dgram_server_message_connection::send_message(): could not send Datagram message to \""
     148           0 :             << address.to_uri()
     149           0 :             << "\", errno: "
     150             :             << e
     151             :             << ", "
     152           0 :             << strerror(e)
     153           0 :             << " (r = "
     154             :             << r
     155             :             << ")."
     156             :             << SNAP_LOG_SEND;
     157           0 :         errno = e;
     158           0 :         return false;
     159             :     }
     160             : 
     161           3 :     return true;
     162             : }
     163             : 
     164             : 
     165             : /** \brief Implementation of the process_read() callback.
     166             :  *
     167             :  * This function reads the datagram we just received using the
     168             :  * recv() function. The size of the datagram cannot be more than
     169             :  * DATAGRAM_MAX_SIZE (1Kb at time of writing.)
     170             :  *
     171             :  * The message is then parsed and further processing is expected
     172             :  * to be accomplished in your implementation of process_message().
     173             :  *
     174             :  * The function actually reads as many pending datagrams as it can.
     175             :  */
     176           3 : void local_dgram_server_message_connection::process_read()
     177             : {
     178           3 :     char buf[DATAGRAM_MAX_SIZE];
     179             :     for(;;)
     180             :     {
     181           6 :         ssize_t const r(recv(buf, sizeof(buf) / sizeof(buf[0])));
     182           6 :         if(r <= 0)
     183             :         {
     184           3 :             break;
     185             :         }
     186           6 :         std::string const local_dgram_message(buf, r);
     187           6 :         message msg;
     188           3 :         if(msg.from_message(local_dgram_message))
     189             :         {
     190           6 :             std::string const expected(get_secret_code());
     191           3 :             if(msg.has_parameter("secret_code"))
     192             :             {
     193           0 :                 std::string const secret(msg.get_parameter("secret_code"));
     194           0 :                 if(secret != expected)
     195             :                 {
     196           0 :                     if(!expected.empty())
     197             :                     {
     198             :                         // our secret code and the message secret code do not match
     199             :                         //
     200           0 :                         SNAP_LOG_ERROR
     201           0 :                             << "the incoming message has an unexpected secret_code code, message ignored."
     202             :                             << SNAP_LOG_SEND;
     203           0 :                         return;
     204             :                     }
     205             : 
     206             :                     // the sender included a UDP secret code but we don't
     207             :                     // require it so we emit a warning but still accept
     208             :                     // the message
     209             :                     //
     210           0 :                     SNAP_LOG_WARNING
     211           0 :                         << "no secret_code=... parameter was expected (missing set_secret_code() call for this application?)."
     212             :                         << SNAP_LOG_SEND;
     213             :                 }
     214             :             }
     215           3 :             else if(!expected.empty())
     216             :             {
     217             :                 // secret code is missing from incoming message
     218             :                 //
     219           0 :                 SNAP_LOG_ERROR
     220           0 :                     << "the incoming message was expected to have a secret_code parameter, message dropped."
     221             :                     << SNAP_LOG_SEND;
     222           0 :                 return;
     223             :             }
     224             : 
     225             :             // we received a valid message, process it
     226             :             //
     227           3 :             dispatch_message(msg);
     228             :         }
     229             :         else
     230             :         {
     231           0 :             SNAP_LOG_ERROR
     232             :                 << "local_dgram_server_message_connection::process_read() was"
     233           0 :                    " asked to process an invalid message ("
     234             :                 << local_dgram_message
     235             :                 << ")"
     236             :                 << SNAP_LOG_SEND;
     237             :         }
     238           3 :     }
     239             : }
     240             : 
     241             : 
     242             : 
     243           6 : } // namespace ed
     244             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13