LCOV - code coverage report
Current view: top level - eventdispatcher - connection_with_send_message.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 3 97 3.1 %
Date: 2021-07-22 21:04:41 Functions: 3 18 16.7 %
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 along
      17             : // with this program; if not, write to the Free Software Foundation, Inc.,
      18             : // 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 connection 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           3 : connection_with_send_message::~connection_with_send_message()
      70             : {
      71           3 : }
      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 help()
      89             :  */
      90           0 : void connection_with_send_message::msg_help(message & msg)
      91             : {
      92           0 :     snap::NOT_USED(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           0 :         SNAP_LOG_WARNING
     152           0 :             << "could not reply to \""
     153           0 :             << msg.get_command()
     154             :             << "\" with a COMMANDS message."
     155             :             << SNAP_LOG_SEND;
     156             :     }
     157           0 : }
     158             : 
     159             : 
     160             : /** \brief Reply to the watchdog message ALIVE.
     161             :  *
     162             :  * To check whether a service is alive, send the ALIVE message. This
     163             :  * function builds a ABSOLUTELY reply and attaches the "serial" parameter
     164             :  * as is if present. It will also include the original "timestamp" parameter
     165             :  * when present.
     166             :  *
     167             :  * The function also adds one field named "reply_timestamp" with the Unix
     168             :  * time when the reply is being sent.
     169             :  *
     170             :  * \note
     171             :  * The "serial" parameter is expected to be used to make sure that no messages
     172             :  * are lost, or if loss is expected, to see whether loss is heavy or not.
     173             :  *
     174             :  * \note
     175             :  * The "serial" and "timestamp" parameters do not get checked. If present
     176             :  * in the original message, they get copied verbatim to the destination.
     177             :  * This allows you to include anything you want in those parameters although
     178             :  * we suggest you use the "timestamp" only for a value representing time.
     179             :  *
     180             :  * \param[in] message  The STOP message.
     181             :  */
     182           0 : void connection_with_send_message::msg_alive(message & msg)
     183             : {
     184           0 :     message absolutely;
     185           0 :     absolutely.reply_to(msg);
     186           0 :     absolutely.set_command("ABSOLUTELY");
     187           0 :     if(msg.has_parameter("serial"))
     188             :     {
     189           0 :         absolutely.add_parameter("serial", msg.get_parameter("serial"));
     190             :     }
     191           0 :     if(msg.has_parameter("timestamp"))
     192             :     {
     193           0 :         absolutely.add_parameter("timestamp", msg.get_parameter("timestamp"));
     194             :     }
     195           0 :     absolutely.add_parameter("reply_timestamp", time(nullptr));
     196           0 :     if(!send_message(absolutely, false))
     197             :     {
     198           0 :         SNAP_LOG_WARNING
     199           0 :             << "could not reply to \""
     200           0 :             << msg.get_command()
     201             :             << "\" with an ABSOLUTELY message."
     202             :             << SNAP_LOG_SEND;
     203             :     }
     204           0 : }
     205             : 
     206             : 
     207             : /** \brief Reconfigure the logger.
     208             :  *
     209             :  * Whenever the logrotate runs or some changes are made to the log
     210             :  * definitions, the corresponding daemons need to reconfigure their
     211             :  * logger to make use of the new file and settings. This command is
     212             :  * used for this purpose.
     213             :  *
     214             :  * \note
     215             :  * If the environment logger is not currently configured, this message
     216             :  * is ignored.
     217             :  *
     218             :  * \param[in] message  The STOP message.
     219             :  */
     220           0 : void connection_with_send_message::msg_log(message & msg)
     221             : {
     222           0 :     snap::NOT_USED(msg);
     223             : 
     224           0 :     if(snaplogger::is_configured())
     225             :     {
     226             :         // send log in the old file and format
     227             :         //
     228           0 :         SNAP_LOG_INFO
     229           0 :             << "-------------------- Logging reconfiguration request."
     230             :             << SNAP_LOG_SEND;
     231             : 
     232             :         // reconfigure
     233             :         //
     234           0 :         snaplogger::reopen();
     235             : 
     236             :         // send log to new file and format
     237             :         //
     238           0 :         SNAP_LOG_INFO
     239           0 :             << "-------------------- Logging reconfiguration done."
     240             :             << SNAP_LOG_SEND;
     241             :     }
     242           0 : }
     243             : 
     244             : 
     245             : /** \brief Call you stop() function with true.
     246             :  *
     247             :  * This command means that someone is asking your daemon to quit as soon as
     248             :  * possible because the Snap! environment is being asked to shutdown.
     249             :  *
     250             :  * The value 'true' means that all the daemons are being asked to stop and
     251             :  * not just you.
     252             :  *
     253             :  * \param[in] message  The STOP message.
     254             :  *
     255             :  * \sa msg_stop()
     256             :  * \sa stop()
     257             :  */
     258           0 : void connection_with_send_message::msg_quitting(message & msg)
     259             : {
     260           0 :     snap::NOT_USED(msg);
     261             : 
     262           0 :     stop(true);
     263           0 : }
     264             : 
     265             : 
     266             : /** \brief Calls your ready() function with the message.
     267             :  *
     268             :  * All daemons using the snapcommunicator daemon have to have a ready()
     269             :  * function which gets called once the HELP and COMMAND message were
     270             :  * handled. This is when your daemon is expected to be ready to start
     271             :  * working. Some daemon, though, start working immediately no matter
     272             :  * what (i.e. snapwatchdog and snapfirewall do work either way.)
     273             :  *
     274             :  * \param[in] message  The READY message.
     275             :  *
     276             :  * \sa ready()
     277             :  */
     278           0 : void connection_with_send_message::msg_ready(message & msg)
     279             : {
     280             :     // pass the message so any additional info can be accessed.
     281             :     //
     282           0 :     ready(msg);
     283           0 : }
     284             : 
     285             : 
     286             : /** \brief Calls your restart() function with the message.
     287             :  *
     288             :  * This message has no implementation by default at the moment. What we
     289             :  * want to do is find a clean way to restart any service instantly.
     290             :  *
     291             :  * The RESTART message is expected to be used whenever a modification
     292             :  * to some file or the system environment somehow affects your service
     293             :  * in such a way that it requires a restart. For example, after an
     294             :  * upgrade of eventdispatcher library, you should restart all the services
     295             :  * that make use of this library. For this reason, we have a RESTART
     296             :  * message.
     297             :  *
     298             :  * The message comes with one parameter named `reason` which describes
     299             :  * why the RESTART was sent:
     300             :  *
     301             :  * \li `reason=upgrade` -- something (library/tools) was upgraded
     302             :  * \li `reason=config` -- a configuration file was updated
     303             :  *
     304             :  * \note
     305             :  * There are currently some services that make use of a CONFIG message
     306             :  * whenever their configuration changes. Pretty much all services do
     307             :  * not support a live configuration change (because it initializes their
     308             :  * objects from the configuration data once on startup and in many cases
     309             :  * it would be very complicated to allow for changes to occur.)
     310             :  * \note
     311             :  * In those existing implementations, we really just do a restart anyway.
     312             :  *
     313             :  * \param[in] message  The RESTART message.
     314             :  *
     315             :  * \sa restart()
     316             :  */
     317           0 : void connection_with_send_message::msg_restart(message & msg)
     318             : {
     319             :     // pass the message so any additional info can be accessed.
     320             :     //
     321           0 :     restart(msg);
     322           0 : }
     323             : 
     324             : 
     325             : /** \brief Call you stop() function with false.
     326             :  *
     327             :  * This command means that someone is asking your daemon to stop.
     328             :  *
     329             :  * The value 'false' means just your daemon was asked to stop and not the
     330             :  * entire system to shutdown (otherwise you would receive a QUITTING command
     331             :  * instead.)
     332             :  *
     333             :  * \param[in] message  The STOP message.
     334             :  *
     335             :  * \sa msg_quitting()
     336             :  */
     337           0 : void connection_with_send_message::msg_stop(message & msg)
     338             : {
     339           0 :     snap::NOT_USED(msg);
     340             : 
     341           0 :     stop(false);
     342           0 : }
     343             : 
     344             : 
     345             : /** \brief Handle the UNKNOWN message.
     346             :  *
     347             :  * Whenever we send a command to another daemon, that command can be refused
     348             :  * by sending an UNKNOWN reply. This function handles the UNKNOWN command
     349             :  * by simply recording that as an error in the logs.
     350             :  *
     351             :  * \param[in] message  The UNKNOWN message we just received.
     352             :  */
     353           0 : void connection_with_send_message::msg_log_unknown(message & msg)
     354             : {
     355             :     // we sent a command that the other end did not understand
     356             :     // and got an UNKNOWN reply
     357             :     //
     358           0 :     SNAP_LOG_ERROR
     359           0 :         << "we sent unknown command \""
     360           0 :         << msg.get_parameter("command")
     361             :         << "\" and probably did not get the expected result."
     362             :         << SNAP_LOG_SEND;
     363           0 : }
     364             : 
     365             : 
     366             : /** \brief Send the UNKNOWN message as a reply.
     367             :  *
     368             :  * This function replies to the \p message with the UNKNOWN message as
     369             :  * expected by all our connection objects when a service receives a
     370             :  * message it does not know how to handle.
     371             :  *
     372             :  * It is expected to be used in your dispatcher_match array.
     373             :  *
     374             :  * \note
     375             :  * This function is virtual which allows you to add it to your array of
     376             :  * of dispatcher_match items. The following shows an example of what that
     377             :  * can look like.
     378             :  *
     379             :  * \code
     380             :  *  {
     381             :  *      ...
     382             :  *
     383             :  *      // ALWAYS LAST
     384             :  *      {
     385             :  *          nullptr
     386             :  *        , &my_service_connection::msg_reply_with_unknown
     387             :  *        , &ed::dispatcher<my_service_connection>::dispatcher_match::always_match
     388             :  *      }
     389             :  *  };
     390             :  * \endcode
     391             :  *
     392             :  * \param[in] message  The message to reply to.
     393             :  */
     394           0 : void connection_with_send_message::msg_reply_with_unknown(message & msg)
     395             : {
     396           0 :     message unknown;
     397           0 :     unknown.reply_to(msg);
     398           0 :     unknown.set_command("UNKNOWN");
     399           0 :     unknown.add_parameter("command", msg.get_command());
     400           0 :     if(!send_message(unknown, false))
     401             :     {
     402           0 :         SNAP_LOG_WARNING
     403           0 :             << "could not reply to \""
     404           0 :             << msg.get_command()
     405             :             << "\" with UNKNOWN message."
     406             :             << SNAP_LOG_SEND;
     407             :     }
     408           0 : }
     409             : 
     410             : 
     411             : /** \brief The default help() function does nothing.
     412             :  *
     413             :  * This implementation does nothing. It is expected that you reimplement
     414             :  * this function depending on your daemon's need.
     415             :  *
     416             :  * The help() function gets called whenever the list of commands can't be
     417             :  * 100% defined automatically.
     418             :  *
     419             :  * Your function is expected to add commands to the \p commands parameter
     420             :  * as in:
     421             :  *
     422             :  * \code
     423             :  *      commands << "MSG1";
     424             :  *      commands << "MSG2";
     425             :  *      commands << "MSG3";
     426             :  * \endcode
     427             :  *
     428             :  * This allows you to handle those three messages with a single entry in
     429             :  * your list of dispatcher_match objects with a regular expression such
     430             :  * as "MSG[1-3]".
     431             :  *
     432             :  * \param[in,out] commands  List of commands to update.
     433             :  */
     434           0 : void connection_with_send_message::help(string_list_t & commands)
     435             : {
     436           0 :     snap::NOT_USED(commands);
     437             : 
     438             :     // do nothing by default -- user is expected to overload this function
     439           0 : }
     440             : 
     441             : 
     442             : /** \brief The default ready() function does nothing.
     443             :  *
     444             :  * This implementation does nothing. It is expected that you reimplement
     445             :  * this function depending on your daemon's need. Most often this function
     446             :  * is the one that really starts your daemons process.
     447             :  *
     448             :  * \param[in,out] message  The READY message.
     449             :  */
     450           0 : void connection_with_send_message::ready(message & msg)
     451             : {
     452           0 :     snap::NOT_USED(msg);
     453             : 
     454             :     // do nothing by default -- user is expected to overload this function
     455             :     //
     456           0 :     SNAP_LOG_WARNING
     457           0 :         << "default ready() function was called."
     458             :         << SNAP_LOG_SEND;
     459           0 : }
     460             : 
     461             : 
     462             : /** \brief The default restart() function does nothing.
     463             :  *
     464             :  * This implementation does nothing. It is expected that you reimplement
     465             :  * this function depending on your daemon's need. Most often this function
     466             :  * calls the stop() function in order to restart the daemon. If only a
     467             :  * configuration file changed and your daemon is capable of reading the
     468             :  * new settings without a full restart, then just read that new config.
     469             :  *
     470             :  * \param[in,out] message  The RESTART message.
     471             :  *
     472             :  * \sa msg_restart()
     473             :  */
     474           0 : void connection_with_send_message::restart(message & msg)
     475             : {
     476           0 :     snap::NOT_USED(msg);
     477             : 
     478             :     // do nothing by default -- user is expected to overload this function
     479             :     //
     480           0 :     SNAP_LOG_WARNING
     481           0 :         << "default restart() function was called."
     482             :         << SNAP_LOG_SEND;
     483           0 : }
     484             : 
     485             : 
     486             : /** \brief The default stop() function does nothing.
     487             :  *
     488             :  * This implementation does nothing. It is expected that you reimplement
     489             :  * this function depending on your daemon's need.
     490             :  *
     491             :  * \param[in] quitting  Whether the QUITTING (true) or STOP (false) command
     492             :  *                      was received.
     493             :  */
     494           0 : void connection_with_send_message::stop(bool quitting)
     495             : {
     496           0 :     snap::NOT_USED(quitting);
     497             : 
     498             :     // do nothing by default -- user is expected to overload this function
     499             :     //
     500           0 :     SNAP_LOG_WARNING
     501           0 :         << "default stop() function was called."
     502             :         << SNAP_LOG_SEND;
     503           0 : }
     504             : 
     505             : 
     506             : /** \brief Check whether the last send_message() worked.
     507             :  *
     508             :  * This function returns true if the last send_message() to this connection
     509             :  * worked or not.
     510             :  *
     511             :  * \warning
     512             :  * This flag is used by the broadcast_message() function only.
     513             :  *
     514             :  * \return true if the last send_message() was successful.
     515             :  */
     516           0 : bool connection_with_send_message::get_last_send_status() const
     517             : {
     518           0 :     return f_last_send_status;
     519             : }
     520             : 
     521             : 
     522             : 
     523           6 : } // namespace ed
     524             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13