LCOV - code coverage report
Current view: top level - daemon - base_connection.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 13 93 14.0 %
Date: 2024-06-09 22:27:44 Functions: 5 32 15.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2011-2024  Made to Order Software Corp.  All Rights Reserved
       2             : //
       3             : // https://snapwebsites.org/project/communicatord
       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 3 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, see <https://www.gnu.org/licenses/>.
      18             : 
      19             : /** \file
      20             :  * \brief Base declaration for all the connections.
      21             :  *
      22             :  * The communicatord daemon has to deal with many connections. This
      23             :  * base handles some basic aspects of each connection so we do not have
      24             :  * to specialize the code everywhere.
      25             :  *
      26             :  * The several types of connections supported:
      27             :  *
      28             :  * * Connection from this server to another communicatord server
      29             :  *   (see remote_connection)
      30             :  *
      31             :  * * Connection from another communicatord server to this server
      32             :  *   (see remote_connection)
      33             :  *
      34             :  * * Connection from a communicatord to another which is expected to
      35             :  *   connect to us (see gossip_connection)
      36             :  *
      37             :  * * Connection from a local server to the communicatord
      38             :  *   (see service_connection and unix_connection)
      39             :  *
      40             :  * * Messages from a local server via UDP
      41             :  *   (see ping)
      42             :  *
      43             :  * The connections between communicators are 100% managed by each
      44             :  * communicatord. This creates the RPC functionality between all your
      45             :  * tools.
      46             :  *
      47             :  * The other type of connections happen from the various local or remote
      48             :  * services to the communicatord.
      49             :  */
      50             : 
      51             : 
      52             : 
      53             : // self
      54             : //
      55             : #include    "base_connection.h"
      56             : 
      57             : 
      58             : // communicatord
      59             : //
      60             : #include    <communicatord/exception.h>
      61             : 
      62             : 
      63             : // snapdev
      64             : //
      65             : #include    <snapdev/tokenize_string.h>
      66             : 
      67             : 
      68             : // last include
      69             : //
      70             : #include    <snapdev/poison.h>
      71             : 
      72             : 
      73             : 
      74             : namespace communicator_daemon
      75             : {
      76             : 
      77             : 
      78             : 
      79             : 
      80             : 
      81             : /** \brief Initialize the base_connection() object.
      82             :  *
      83             :  * The constructor saves the communicator server pointer
      84             :  * so one can access it from any derived version.
      85             :  */
      86           1 : base_connection::base_connection(
      87             :           server::pointer_t cs
      88           1 :         , bool is_udp)
      89           1 :     : f_server(cs)
      90           1 :     , f_is_udp(is_udp)
      91             : {
      92           1 : }
      93             : 
      94             : 
      95             : /** \brief We have a destructor to make it virtual.
      96             :  *
      97             :  * Everything is otherwise automatically released.
      98             :  */
      99           1 : base_connection::~base_connection()
     100             : {
     101           1 : }
     102             : 
     103             : 
     104             : /** \brief Save when the connection started.
     105             :  *
     106             :  * This function is called whenever a CONNECT or REGISTER message
     107             :  * is received since those mark the time when a connection starts.
     108             :  *
     109             :  * You can later retrieve when the connection started with the
     110             :  * get_connection_started() function.
     111             :  *
     112             :  * This call also resets the f_ended_on in case we were able to
     113             :  * reuse the same connection multiple times (reconnecting means
     114             :  * a new socket and thus a brand new connection object...)
     115             :  */
     116           0 : void base_connection::connection_started()
     117             : {
     118           0 :     f_started_on = time(nullptr);
     119           0 :     f_ended_on = -1;
     120           0 : }
     121             : 
     122             : 
     123             : /** \brief Return information on when the connection started.
     124             :  *
     125             :  * This function gives you the date and time when the connection
     126             :  * started, meaning when the connection received a CONNECT or
     127             :  * REGISTER event.
     128             :  *
     129             :  * If the events have no yet occured, then the connection returns
     130             :  * -1 instead.
     131             :  *
     132             :  * \return The date and time when the connection started in microseconds.
     133             :  */
     134           1 : int64_t base_connection::get_connection_started() const
     135             : {
     136           1 :     return f_started_on;
     137             : }
     138             : 
     139             : 
     140             : /** \brief Connection ended, save the date and time of the event.
     141             :  *
     142             :  * Whenever we receive a DISCONNECT or UNREGISTER we call this
     143             :  * function. It also gets called in the event a connection
     144             :  * is deleted without first receiving a graceful DISCONNECT
     145             :  * or UNREGISTER event.
     146             :  */
     147           0 : void base_connection::connection_ended()
     148             : {
     149             :     // save the current date only if the connection really started
     150             :     // before and also only once (do not update the end time again
     151             :     // until a connection_started() call happens)
     152             :     //
     153           0 :     if(f_started_on != -1
     154           0 :     && f_ended_on == -1)
     155             :     {
     156           0 :         f_ended_on = time(nullptr);
     157             :     }
     158           0 : }
     159             : 
     160             : 
     161             : /** \brief Timestamp when the connection was ended.
     162             :  *
     163             :  * This value represents the time when the UNREGISTER, DISCONNECT,
     164             :  * or the destruction of the service_connection object occurred. It
     165             :  * represents the time when the specific service was shutdown.
     166             :  *
     167             :  * \return The approximative date when the connection ended in microseconds.
     168             :  */
     169           1 : int64_t base_connection::get_connection_ended() const
     170             : {
     171           1 :     return f_ended_on;
     172             : }
     173             : 
     174             : 
     175             : /** \brief Save the name of the server.
     176             :  *
     177             :  * \param[in] server_name  The name of the server that is on the other
     178             :  *                         side of this connection.
     179             :  */
     180           0 : void base_connection::set_server_name(std::string const & server_name)
     181             : {
     182           0 :     f_server_name = server_name;
     183           0 : }
     184             : 
     185             : 
     186             : /** \brief Get the name of the server.
     187             :  *
     188             :  * \return The name of the server that is on the other
     189             :  *         side of this connection.
     190             :  */
     191           1 : std::string base_connection::get_server_name() const
     192             : {
     193           1 :     return f_server_name;
     194             : }
     195             : 
     196             : 
     197             : /** \brief Save the address of that connection.
     198             :  *
     199             :  * This is only used for remote connections on either the CONNECT
     200             :  * or ACCEPT message.
     201             :  *
     202             :  * \param[in] my_address  The address of the server that is on the
     203             :  *                        other side of this connection.
     204             :  */
     205           0 : void base_connection::set_connection_address(addr::addr const & connection_address)
     206             : {
     207           0 :     f_connection_address = connection_address;
     208           0 : }
     209             : 
     210             : 
     211             : /** \brief Get the address of that connection.
     212             :  *
     213             :  * This function returns a valid address only after the CONNECT
     214             :  * or ACCEPT message were received for this connection.
     215             :  *
     216             :  * \return The address of the server that is on the
     217             :  *         other side of this connection.
     218             :  */
     219           0 : addr::addr base_connection::get_connection_address() const
     220             : {
     221           0 :     return f_connection_address;
     222             : }
     223             : 
     224             : 
     225             : /** \brief Define the type of communicatord server.
     226             :  *
     227             :  * This function is called whenever a CONNECT or an ACCEPT is received.
     228             :  * It saves the type=... parameter. By default the type is empty meaning
     229             :  * that the connection was not yet fully initialized.
     230             :  *
     231             :  * When a REGISTER is received instead of a CONNECT or an ACCEPT, then
     232             :  * the type is set to "client".
     233             :  *
     234             :  * \param[in] type  The type of connection.
     235             :  */
     236           0 : void base_connection::set_connection_type(connection_type_t type)
     237             : {
     238           0 :     f_type = type;
     239           0 : }
     240             : 
     241             : 
     242             : /** \brief Retrieve the current type of this connection.
     243             :  *
     244             :  * By default a connection is given the type CONNECTION_TYPE_DOWN,
     245             :  * which means that it is not currently connected. To initialize
     246             :  * a connection one has to either CONNECT (between communicatord
     247             :  * servers) or REGISTER (a service such as snapbackend, snapserver,
     248             :  * sitter, and others.)
     249             :  *
     250             :  * The type is set to CONNECTION_TYPE_LOCAL for local services and
     251             :  * CONNECTION_TYPE_REMOTE when representing another snapserver.
     252             :  *
     253             :  * \return The type of server this connection represents.
     254             :  */
     255           0 : connection_type_t base_connection::get_connection_type() const
     256             : {
     257           0 :     return f_type;
     258             : }
     259             : 
     260             : 
     261             : /** \brief Set the username required to connect on this TCP connection.
     262             :  *
     263             :  * When accepting connections from remote communicatord, it is best to
     264             :  * assign a user name and password to that connection. This protects
     265             :  * your connection from hackers without such credentials.
     266             :  *
     267             :  * \param[in] username  The name of the user that can connect to this listener.
     268             :  */
     269           0 : void base_connection::set_username(std::string const & username)
     270             : {
     271           0 :     f_username = username;
     272           0 : }
     273             : 
     274             : 
     275             : /** \brief Retrieve the user name of this connection.
     276             :  *
     277             :  */
     278           0 : std::string base_connection::get_username() const
     279             : {
     280           0 :     return f_username;
     281             : }
     282             : 
     283             : 
     284           0 : void base_connection::set_password(std::string const & password)
     285             : {
     286           0 :     f_password = password;
     287           0 : }
     288             : 
     289             : 
     290             : /** \brief Return the password assigned to this connection.
     291             :  *
     292             :  * Each listener may include a password to prevent unwanted connections
     293             :  * from hackers on public facing connections.
     294             :  */
     295           0 : std::string base_connection::get_password() const
     296             : {
     297           0 :     return f_password;
     298             : }
     299             : 
     300             : 
     301             : /** \brief Define the list of services supported by the communicatord.
     302             :  *
     303             :  * Whenever a communicatord connects to another one, either by
     304             :  * doing a CONNECT or replying to a CONNECT by an ACCEPT, it is
     305             :  * expected to list services that it supports (the list could be
     306             :  * empty as it usually is on a Cassandra node.) This function
     307             :  * saves that list.
     308             :  *
     309             :  * This defines the name of services and thus where to send various
     310             :  * messages such as a PING to request a service to start doing work.
     311             :  *
     312             :  * \param[in] services  The list of services this server handles.
     313             :  */
     314           0 : void base_connection::set_services(std::string const & services)
     315             : {
     316           0 :     snapdev::tokenize_string(f_services, services, { "," });
     317           0 : }
     318             : 
     319             : 
     320             : /** \brief Retrieve the list of services offered by other communicators.
     321             :  *
     322             :  * This function saves in the input parameter \p services the list of
     323             :  * services that this very communicatord offers.
     324             :  *
     325             :  * \param[in,out] services  The map where all the services are defined.
     326             :  */
     327           0 : void base_connection::get_services(advgetopt::string_set_t & services)
     328             : {
     329           0 :     f_services.merge(services);
     330           0 : }
     331             : 
     332             : 
     333             : /** \brief Check whether the service is known by that connection.
     334             :  *
     335             :  * This function returns true if the service was defined as one
     336             :  * this connection supports.
     337             :  *
     338             :  * \param[in] name  The name of the service to check for.
     339             :  *
     340             :  * \return true if the service is known.
     341             :  */
     342           0 : bool base_connection::has_service(std::string const & name)
     343             : {
     344           0 :     return f_services.find(name) != f_services.end();
     345             : }
     346             : 
     347             : 
     348             : /** \brief Define the list of services we heard of.
     349             :  *
     350             :  * This function saves the list of services that were heard of by
     351             :  * another communicatord server. This list may be updated later
     352             :  * with an ACCEPT event.
     353             :  *
     354             :  * This list is used to know where to forward a message if we do
     355             :  * not have a more direct link to those services (i.e. the same
     356             :  * service defined in our own list or in a communicatord
     357             :  * we are directly connected to.)
     358             :  *
     359             :  * \param[in] services  The list of services heard of.
     360             :  */
     361           0 : void base_connection::set_services_heard_of(std::string const & services)
     362             : {
     363           0 :     snapdev::tokenize_string(f_services_heard_of, services, { "," });
     364           0 : }
     365             : 
     366             : 
     367             : /** \brief Retrieve the list of services heard of by another server.
     368             :  *
     369             :  * This function saves in the input parameter \p services the list of
     370             :  * services that this communicatord heard of.
     371             :  *
     372             :  * \param[in,out] services  The map where all the services are defined.
     373             :  */
     374           0 : void base_connection::get_services_heard_of(advgetopt::string_set_t & services)
     375             : {
     376           0 :     f_services_heard_of.merge(services);
     377           0 : }
     378             : 
     379             : 
     380             : /** \brief List of defined commands.
     381             :  *
     382             :  * This function saves the list of commands known by another process.
     383             :  * The \p commands parameter is broken up at each comma and the
     384             :  * resulting list saved in the f_understood_commands map for fast
     385             :  * retrieval.
     386             :  *
     387             :  * In general a process receives the COMMANDS event whenever it
     388             :  * sent the HELP event to request for this list.
     389             :  *
     390             :  * \param[in] commands  The list of understood commands.
     391             :  */
     392           0 : void base_connection::add_commands(std::string const & commands)
     393             : {
     394           0 :     snapdev::tokenize_string(
     395           0 :           f_understood_commands
     396             :         , commands
     397             :         , { "," });
     398           0 : }
     399             : 
     400             : 
     401             : /** \brief Check whether a certain command is understood by this connection.
     402             :  *
     403             :  * This function checks whether this connection understands \p command.
     404             :  *
     405             :  * \param[in] command  The command to check for.
     406             :  *
     407             :  * \return true if the command is supported, false otherwise.
     408             :  */
     409           0 : bool base_connection::understand_command(std::string const & command)
     410             : {
     411           0 :     return f_understood_commands.find(command) != f_understood_commands.end();
     412             : }
     413             : 
     414             : 
     415             : /** \brief Check whether this connection received the COMMANDS message.
     416             :  *
     417             :  * This function returns true if the list of understood commands is
     418             :  * defined. This means we do know whether a verification (i.e. a call
     419             :  * to the understand_command() function) will return false because the
     420             :  * list of commands is empty or because a command is not understood.
     421             :  *
     422             :  * \return true if one or more commands are understood.
     423             :  */
     424           0 : bool base_connection::has_commands() const
     425             : {
     426           0 :     return !f_understood_commands.empty();
     427             : }
     428             : 
     429             : 
     430             : /** \brief Remove a command.
     431             :  *
     432             :  * This function is used to make the system think that certain command
     433             :  * are actually not understood.
     434             :  *
     435             :  * At this time, it is only used when a connection goes away and we
     436             :  * want to send a STATUS message to various services interested in
     437             :  * such a message.
     438             :  *
     439             :  * \param[in] command  The command to remove.
     440             :  */
     441           0 : void base_connection::remove_command(std::string const & command)
     442             : {
     443           0 :     auto it(f_understood_commands.find(command));
     444           0 :     if(it != f_understood_commands.end())
     445             :     {
     446           0 :         f_understood_commands.erase(it);
     447             :     }
     448           0 : }
     449             : 
     450             : 
     451             : /** \brief Mark that connection as a remote connection.
     452             :  *
     453             :  * When we receive a connection from another communicatord, we call
     454             :  * this function so later we can very quickly determine whether the
     455             :  * connection is a remote connection.
     456             :  */
     457           0 : void base_connection::mark_as_remote()
     458             : {
     459           0 :     f_remote_connection = true;
     460           0 : }
     461             : 
     462             : 
     463             : /** \brief Check whether this connection is a remote connection.
     464             :  *
     465             :  * The function returns false by default. If the mark_as_remote()
     466             :  * was called, this function returns true.
     467             :  *
     468             :  * \return true if the connection was marked as a remote connection.
     469             :  */
     470           0 : bool base_connection::is_remote() const
     471             : {
     472           0 :     return f_remote_connection;
     473             : }
     474             : 
     475             : 
     476             : /** \brief The function returns true if this is a UDP connection.
     477             :  *
     478             :  * This function returns the f_is_udp flag which is true if the connection
     479             :  * represents a UDP (datagram based) connection.
     480             :  *
     481             :  * At this time, we only have one UDP connection recorded here. The connection
     482             :  * managed by the f_logrotate object is not added to the communicatord
     483             :  * system (it does not even derive from the base_connection; although we may
     484             :  * stop using that sub-object because the ping class is probably enough).
     485             :  *
     486             :  * \return true if the connection is a datagram based connection.
     487             :  */
     488           0 : bool base_connection::is_udp() const
     489             : {
     490           0 :     return f_is_udp;
     491             : }
     492             : 
     493             : 
     494             : /** \brief Set whether this connection wants to receive LOADAVG messages.
     495             :  *
     496             :  * Whenever a frontend wants to know which backend to use for its
     497             :  * current client request, it can check a set of IP addresses for
     498             :  * the least loaded computer. Then it can use that IP address to
     499             :  * process the request.
     500             :  *
     501             :  * \param[in] wants_loadavg  Whether this connection wants
     502             :  *    (REGISTERFORLOADAVG) or does not want (UNREGISTERFORLOADAVG)
     503             :  *    to receive LOADAVG messages from this communicatord.
     504             :  */
     505           0 : void base_connection::set_wants_loadavg(bool wants_loadavg)
     506             : {
     507           0 :     f_wants_loadavg = wants_loadavg;
     508           0 : }
     509             : 
     510             : 
     511             : /** \brief Check whether this connection wants LOADAVG messages.
     512             :  *
     513             :  * This function returns true if the connection last sent us a
     514             :  * REGISTERFORLOADAVG message.
     515             :  *
     516             :  * \return true if the LOADAVG should be sent to this connection.
     517             :  */
     518           0 : bool base_connection::wants_loadavg() const
     519             : {
     520           0 :     return f_wants_loadavg;
     521             : }
     522             : 
     523             : 
     524           0 : bool base_connection::send_message_to_connection(ed::message & msg, bool cache)
     525             : {
     526           0 :     ed::connection * conn(dynamic_cast<ed::connection *>(this));
     527           0 :     if(conn == nullptr)
     528             :     {
     529           0 :         throw communicatord::logic_error("somehow a dynamic_cast<ed::connection *> on our base_connection failed.");
     530             :     }
     531           0 :     ed::connection_with_send_message::pointer_t conn_msg(std::dynamic_pointer_cast<ed::connection_with_send_message>(conn->shared_from_this()));
     532           0 :     if(conn_msg == nullptr)
     533             :     {
     534           0 :         throw communicatord::logic_error("std::dynamic_pointer_cast<ed::connection_with_send_message>() on our ed::connection failed.");
     535             :     }
     536           0 :     return conn_msg->send_message(msg, cache);
     537           0 : }
     538             : 
     539             : 
     540             : 
     541             : } // namespace communicator_daemon
     542             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.14

Snap C++ | List of projects | List of versions