LCOV - code coverage report
Current view: top level - eventdispatcher - connection_with_send_message.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1 86 1.2 %
Date: 2019-08-10 01:48:51 Functions: 2 16 12.5 %
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 Connection with Send Message class.
      22             :  *
      23             :  * This is a base class which ease the implementation of a connection
      24             :  * which is able to send and receive messages.
      25             :  */
      26             : 
      27             : 
      28             : // self
      29             : //
      30             : #include    "eventdispatcher/connection_with_send_message.h"
      31             : 
      32             : #include    "eventdispatcher/dispatcher_support.h"
      33             : #include    "eventdispatcher/exception.h"
      34             : 
      35             : 
      36             : // snaplogger lib
      37             : //
      38             : #include    <snaplogger/logger.h>
      39             : #include    <snaplogger/message.h>
      40             : 
      41             : 
      42             : // snapdev lib
      43             : //
      44             : #include    <snapdev/not_used.h>
      45             : 
      46             : 
      47             : // boost lib
      48             : //
      49             : #include    <boost/algorithm/string/join.hpp>
      50             : 
      51             : 
      52             : // last include
      53             : //
      54             : #include    <snapdev/poison.h>
      55             : 
      56             : 
      57             : 
      58             : namespace ed
      59             : {
      60             : 
      61             : 
      62             : 
      63             : /** \brief Initialize a connection_with_send_message object.
      64             :  *
      65             :  * This constructor initializes a connectopm which supports a send_message()
      66             :  * function. This allows that object to send a certain number of default
      67             :  * messages such as the UNKNOWN message automatically.
      68             :  */
      69           0 : connection_with_send_message::~connection_with_send_message()
      70             : {
      71           0 : }
      72             : 
      73             : 
      74             : 
      75             : /** \brief Build the HELP reply and send it.
      76             :  *
      77             :  * When a daemon registers with the snapcommunicator, it sends a REGISTER
      78             :  * command. As a result, the daemon is sent a HELP command which must be
      79             :  * answered with a COMMAND and the list of commands that this connection
      80             :  * supports.
      81             :  *
      82             :  * \note
      83             :  * If the environment logger is not currently configured, this message
      84             :  * gets ignored.
      85             :  *
      86             :  * \param[in] message  The HELP message.
      87             :  *
      88             :  * \sa msg_ready()
      89             :  */
      90           0 : void connection_with_send_message::msg_help(message & msg)
      91             : {
      92           0 :     snap::NOTUSED(msg);
      93             : 
      94           0 :     bool need_user_help(true);
      95           0 :     string_list_t commands;
      96             : 
      97             :     dispatcher_base * d;
      98           0 :     dispatcher_support * ds(dynamic_cast<dispatcher_support *>(this));
      99           0 :     if(ds != nullptr)
     100             :     {
     101             :         // we extract the bare pointer because in the other case
     102             :         // we only get a bare pointer... (which we can't safely
     103             :         // put in a shared pointer, although we could attempt to
     104             :         // use shared_from_this() but we could have a class without
     105             :         // it?)
     106             :         //
     107           0 :         d = ds->get_dispatcher().get();
     108             :     }
     109             :     else
     110             :     {
     111           0 :         d = dynamic_cast<dispatcher_base *>(this);
     112             :     }
     113           0 :     if(d != nullptr)
     114             :     {
     115           0 :         need_user_help = d->get_commands(commands);
     116             :     }
     117             : 
     118             :     // the user has "unknown" commands (as far as the dispatcher is concerned)
     119             :     // in his list of commands so we have to let him enter them "manually"
     120             :     //
     121             :     // this happens whenever there is an entry which is a regular expression
     122             :     // or something similar which we just cannot grab
     123             :     //
     124           0 :     if(need_user_help)
     125             :     {
     126           0 :         help(commands);
     127             :     }
     128             : 
     129             :     // the list of commands just cannot be empty
     130             :     //
     131           0 :     if(commands.empty())
     132             :     {
     133             :         throw event_dispatcher_implementation_error(
     134             :                 "connection_with_send_message::msg_help()"
     135           0 :                 " is not able to determine the commands this messenger supports");
     136             :     }
     137             : 
     138             :     // Now prepare the COMMAND message and send it
     139             :     //
     140             :     // Note: we turn off the caching on this message, it does not make sense
     141             :     //       because if snapcommunicator is not running, then caching won't
     142             :     //       happen work anyway (i.e. snapcommunicator has to send HELP first
     143             :     //       and then we send the reply, if it has to restart, then just
     144             :     //       sending COMMANDS will fail.)
     145             :     //
     146           0 :     message reply;
     147           0 :     reply.set_command("COMMANDS");
     148           0 :     reply.add_parameter("list", boost::algorithm::join(commands, ","));
     149           0 :     if(!send_message(reply, false))
     150             :     {
     151             :         SNAP_LOG_WARNING
     152           0 :             << "could not reply to \""
     153           0 :             << msg.get_command()
     154           0 :             << "\" with a COMMANDS message.";
     155             :     }
     156           0 : }
     157             : 
     158             : 
     159             : /** \brief Reply to the watchdog message ALIVE.
     160             :  *
     161             :  * To check whether a service is alive, send the ALIVE message. This
     162             :  * function builds a ABSOLUTELY reply and attaches the "serial" parameter
     163             :  * as is if present. It will also include the original "timestamp" parameter
     164             :  * when present.
     165             :  *
     166             :  * The function also adds one field named "reply_timestamp" with the Unix
     167             :  * time when the reply is being sent.
     168             :  *
     169             :  * \note
     170             :  * The "serial" parameter is expected to be used to make sure that no messages
     171             :  * are lost, or if loss is expected, to see whether loss is heavy or not.
     172             :  *
     173             :  * \note
     174             :  * The "serial" and "timestamp" parameters do not get checked. If present
     175             :  * in the original message, they get copied verbatim to the destination.
     176             :  * This allows you to include anything you want in those parameters although
     177             :  * we suggest you use the "timestamp" only for a value representing time.
     178             :  *
     179             :  * \param[in] message  The STOP message.
     180             :  */
     181           0 : void connection_with_send_message::msg_alive(message & msg)
     182             : {
     183           0 :     message absolutely;
     184           0 :     absolutely.reply_to(msg);
     185           0 :     absolutely.set_command("ABSOLUTELY");
     186           0 :     if(msg.has_parameter("serial"))
     187             :     {
     188           0 :         absolutely.add_parameter("serial", msg.get_parameter("serial"));
     189             :     }
     190           0 :     if(msg.has_parameter("timestamp"))
     191             :     {
     192           0 :         absolutely.add_parameter("timestamp", msg.get_parameter("timestamp"));
     193             :     }
     194           0 :     absolutely.add_parameter("reply_timestamp", time(nullptr));
     195           0 :     if(!send_message(absolutely, false))
     196             :     {
     197             :         SNAP_LOG_WARNING
     198           0 :             << "could not reply to \""
     199           0 :             << msg.get_command()
     200           0 :             << "\" with an ABSOLULTELY message.";
     201             :     }
     202           0 : }
     203             : 
     204             : 
     205             : /** \brief Reconfigure the logger.
     206             :  *
     207             :  * Whenever the logrotate runs or some changes are maed to the log
     208             :  * definitions, the corresponding daemons need to reconfigure their
     209             :  * logger to make use of the new file and settings. This command is
     210             :  * used for the purpose.
     211             :  *
     212             :  * \note
     213             :  * If the environment logger is not currently configured, this message
     214             :  * gets ignored.
     215             :  *
     216             :  * \param[in] message  The STOP message.
     217             :  */
     218           0 : void connection_with_send_message::msg_log(message & msg)
     219             : {
     220           0 :     snap::NOTUSED(msg);
     221             : 
     222           0 :     if(snaplogger::is_configured())
     223             :     {
     224             :         // send log in the old file and format
     225             :         //
     226             :         SNAP_LOG_INFO
     227           0 :             << "-------------------- Logging reconfiguration request.";
     228             : 
     229             :         // reconfigure
     230             :         //
     231           0 :         snaplogger::reopen();
     232             : 
     233             :         // send log to new file and format
     234             :         //
     235             :         SNAP_LOG_INFO
     236           0 :             << "-------------------- Logging reconfiguration done.";
     237             :     }
     238           0 : }
     239             : 
     240             : 
     241             : /** \brief Call you stop() function with true.
     242             :  *
     243             :  * This command means that someone is asking your daemon to quit as soon as
     244             :  * possible because the Snap! environment is being asked to shutdown.
     245             :  *
     246             :  * The value 'true' means that all the daemons are being asked to stop and
     247             :  * not just you.
     248             :  *
     249             :  * \param[in] message  The STOP message.
     250             :  *
     251             :  * \sa msg_stop()
     252             :  */
     253           0 : void connection_with_send_message::msg_quitting(message & msg)
     254             : {
     255           0 :     snap::NOTUSED(msg);
     256             : 
     257           0 :     stop(true);
     258           0 : }
     259             : 
     260             : 
     261             : /** \brief Call you ready() function with the message.
     262             :  *
     263             :  * All daemons using the snapcommunicator daemon have to have a ready()
     264             :  * function which gets called once the HELP and COMMAND message were
     265             :  * handled. This is why your daemon is expected to be ready to start
     266             :  * working. Some daemon, though, start working immediately no matter
     267             :  * what (i.e. snapwatchdog and snapfirewall do work either way.)
     268             :  *
     269             :  * \param[in] message  The READY message.
     270             :  *
     271             :  * \sa msg_help()
     272             :  */
     273           0 : void connection_with_send_message::msg_ready(message & msg)
     274             : {
     275             :     // pass the message so any additional info can be accessed.
     276             :     //
     277           0 :     ready(msg);
     278           0 : }
     279             : 
     280             : 
     281             : /** \brief Do nothing at the moment.
     282             :  *
     283             :  * This message has no implementation by default at the moment. What we
     284             :  * want to do is find a clean way to restart any service instantly.
     285             :  *
     286             :  * The RESTART message is expected to be used whenever a modification
     287             :  * to some file or the system environment somehow affects your service
     288             :  * in such a way that it requires a restart. For example, after an
     289             :  * upgrade of eventdispatcher library, you should restart all the services
     290             :  * that make use of  this library. For this reason, we have a RESTART
     291             :  * message.
     292             :  *
     293             :  * The messages comes with one parameter named `reason` which describes
     294             :  * why the RESTART was sent:
     295             :  *
     296             :  * \li upgrade -- something (library/tools) was upgraded
     297             :  * \li config -- a congiguration file was updated
     298             :  *
     299             :  * \note
     300             :  * There is currently some services that make use of a CONFIG message
     301             :  * whenever their configuration changes. Pretty much all services do
     302             :  * not support a live configuration change (because it initializes their
     303             :  * objects from the configuration data once on startup and in many cases
     304             :  * it would be very complicated to allow for changes to occur.)
     305             :  * \note
     306             :  * In those existing implementation, we really just do a restart anyway.
     307             :  *
     308             :  * \param[in] message  The READY message.
     309             :  *
     310             :  * \sa msg_help()
     311             :  */
     312           0 : void connection_with_send_message::msg_restart(message & msg)
     313             : {
     314             :     // pass the message so any additional info can be accessed.
     315             :     //
     316           0 :     ready(msg);
     317           0 : }
     318             : 
     319             : 
     320             : /** \brief Call you stop() function with false.
     321             :  *
     322             :  * This command means that someone is asking your daemon to stop.
     323             :  *
     324             :  * The value 'false' means just your daemon was asked to stop and not the
     325             :  * entire system to shutdown (otherwise you would receive a QUITTING command
     326             :  * instead.)
     327             :  *
     328             :  * \param[in] message  The STOP message.
     329             :  *
     330             :  * \sa msg_quitting()
     331             :  */
     332           0 : void connection_with_send_message::msg_stop(message & msg)
     333             : {
     334           0 :     snap::NOTUSED(msg);
     335             : 
     336           0 :     stop(false);
     337           0 : }
     338             : 
     339             : 
     340             : /** \brief Handle the UNKNOWN message.
     341             :  *
     342             :  * Whenever we send a command to another daemon, that command can be refused
     343             :  * by sending an UNKNOWN reply. This function handles the UNKNOWN command
     344             :  * by simply recording that as an error in the logs.
     345             :  *
     346             :  * \param[in] message  The UNKNOWN message we just received.
     347             :  */
     348           0 : void connection_with_send_message::msg_log_unknown(message & msg)
     349             : {
     350             :     // we sent a command that the other end did not understand
     351             :     // and got an UNKNOWN reply
     352             :     //
     353             :     SNAP_LOG_ERROR
     354           0 :         << "we sent unknown command \""
     355           0 :         << msg.get_parameter("command")
     356           0 :         << "\" and probably did not get the expected result.";
     357           0 : }
     358             : 
     359             : 
     360             : /** \brief Send the UNKNOWN message as a reply.
     361             :  *
     362             :  * This function replies to the \p message with the UNKNOWN message as
     363             :  * expected by all our `snap_connection`'s when a service receives a
     364             :  * message it does not know how to handle.
     365             :  *
     366             :  * It is expected to be used in your dispatcher_match array.
     367             :  *
     368             :  * \note
     369             :  * This function is virtual which allows you to add it to your array of
     370             :  * of dispatcher_match items. The following shows an example of what that
     371             :  * can look like.
     372             :  *
     373             :  * \code
     374             :  *  {
     375             :  *      ...
     376             :  *
     377             :  *      // ALWAYS LAST
     378             :  *      {
     379             :  *          nullptr
     380             :  *        , &my_service_connection::msg_reply_with_unknown
     381             :  *        , &snap::dispatcher<my_service_connection>::dispatcher_match::always_match
     382             :  *      }
     383             :  *  };
     384             :  * \endcode
     385             :  *
     386             :  * \param[in] message  The messageto reply to.
     387             :  */
     388           0 : void connection_with_send_message::msg_reply_with_unknown(message & msg)
     389             : {
     390           0 :     message unknown;
     391           0 :     unknown.reply_to(msg);
     392           0 :     unknown.set_command("UNKNOWN");
     393           0 :     unknown.add_parameter("command", msg.get_command());
     394           0 :     if(!send_message(unknown, false))
     395             :     {
     396             :         SNAP_LOG_WARNING
     397           0 :             << "could not reply to \""
     398           0 :             << msg.get_command()
     399           0 :             << "\" with UNKNOWN message.";
     400             :     }
     401           0 : }
     402             : 
     403             : 
     404             : /** \brief The default help() function does nothing.
     405             :  *
     406             :  * This implementation does nothing. It is expected that you reimplement
     407             :  * this function depending on your daemon's need.
     408             :  *
     409             :  * The help() function gets called whenever the list of commands can't be
     410             :  * 100% defined automatically.
     411             :  *
     412             :  * Your function is expected to add commands to the \p commands parameter
     413             :  * as in:
     414             :  *
     415             :  * \code
     416             :  *      commands << "MSG1";
     417             :  *      commands << "MSG2";
     418             :  *      commands << "MSG3";
     419             :  * \endcode
     420             :  *
     421             :  * This allows you to handle those three messages with a single entry in
     422             :  * your list of dispatcher_match objects with a regular expression such
     423             :  * as "MSG[1-3]".
     424             :  *
     425             :  * \param[in,out] commands  List of commands to update.
     426             :  */
     427           0 : void connection_with_send_message::help(string_list_t & commands)
     428             : {
     429           0 :     snap::NOTUSED(commands);
     430             : 
     431             :     // do nothing by default -- user is expected to overload this function
     432           0 : }
     433             : 
     434             : 
     435             : /** \brief The default ready() function does nothing.
     436             :  *
     437             :  * This implementation does nothing. It is expected that you reimplement
     438             :  * this function depending on your daemon's need. Most often this function
     439             :  * is the one that really starts your daemons process.
     440             :  *
     441             :  * \param[in,out] message  The READY message.
     442             :  */
     443           0 : void connection_with_send_message::ready(message & msg)
     444             : {
     445           0 :     snap::NOTUSED(msg);
     446             : 
     447             :     // do nothing by default -- user is expected to overload this function
     448             :     //
     449             :     SNAP_LOG_WARNING
     450           0 :         << "default ready() function was called.";
     451           0 : }
     452             : 
     453             : 
     454             : /** \brief The default stop() function does nothing.
     455             :  *
     456             :  * This implementation does nothing. It is expected that you reimplement
     457             :  * this function depending on your daemon's need.
     458             :  *
     459             :  * \param[in] quitting  Whether the QUITTING (true) or STOP (false) command
     460             :  *                      was received.
     461             :  */
     462           0 : void connection_with_send_message::stop(bool quitting)
     463             : {
     464           0 :     snap::NOTUSED(quitting);
     465             : 
     466             :     // do nothing by default -- user is expected to overload this function
     467             :     //
     468             :     SNAP_LOG_WARNING
     469           0 :         << "default stop() function was called.";
     470           0 : }
     471             : 
     472             : 
     473             : 
     474           6 : } // namespace ed
     475             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.12