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

Generated by: LCOV version 1.13