Piac test code coverage report
Current view: top level - src - daemon.cpp (source / functions) Hit Total Coverage
Commit: Piac-DEBUG Lines: 214 257 83.3 %
Date: 2022-12-16 13:46:15 Functions: 7 7 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 242 512 47.3 %

           Branch data     Line data    Source code
       1                 :            : // *****************************************************************************
       2                 :            : /*!
       3                 :            :   \file      src/daemon.cpp
       4                 :            :   \copyright 2022-2025 J. Bakosi,
       5                 :            :              All rights reserved. See the LICENSE file for details.
       6                 :            :   \brief     Piac daemon
       7                 :            : */
       8                 :            : // *****************************************************************************
       9                 :            : 
      10                 :            : #include <vector>
      11                 :            : #include <iostream>
      12                 :            : #include <thread>
      13                 :            : #include <mutex>
      14                 :            : #include <condition_variable>
      15                 :            : 
      16                 :            : #include <getopt.h>
      17                 :            : #include <unistd.h>
      18                 :            : 
      19                 :            : #include "macro.hpp"
      20                 :            : #include "project_config.hpp"
      21                 :            : #include "logging_util.hpp"
      22                 :            : #include "daemon_p2p_thread.hpp"
      23                 :            : #include "daemon_db_thread.hpp"
      24                 :            : 
      25                 :         11 : [[noreturn]] static void s_signal_handler( int /*signal_value*/ ) {
      26 [ +  - ][ +  - ]:         11 :   MDEBUG( "interrupted" );
                 [ +  - ]
      27                 :         11 :   exit( EXIT_SUCCESS );
      28                 :            : }
      29                 :            : 
      30                 :            : #if defined(__clang__)
      31                 :            :   #pragma clang diagnostic push
      32                 :            :   #pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
      33                 :            : #endif
      34                 :            : 
      35                 :         11 : static void s_catch_signals() {
      36                 :            :   struct sigaction action;
      37                 :         11 :   action.sa_handler = s_signal_handler;
      38                 :         11 :   action.sa_flags = 0;
      39                 :         11 :   sigemptyset( &action.sa_mask );
      40                 :         11 :   sigaction( SIGINT, &action, nullptr );
      41                 :         11 :   sigaction( SIGTERM, &action, nullptr );
      42                 :         11 : }
      43                 :            : 
      44                 :            : #if defined(__clang__)
      45                 :            :   #pragma clang diagnostic pop
      46                 :            : #endif
      47                 :            : 
      48                 :            : namespace piac {
      49                 :            : 
      50                 :            : std::mutex g_hashes_mtx;
      51                 :            : std::condition_variable g_hashes_cv;
      52                 :            : bool g_hashes_access = false;
      53                 :            : 
      54                 :            : static void
      55                 :          1 : save_public_key( const std::string& filename, const std::string& public_key )
      56                 :            : // *****************************************************************************
      57                 :            : //! Save generated public key to file
      58                 :            : //! \param[in] filename File to save keys to
      59                 :            : //! \param[in] public_key Public key to save
      60                 :            : // *****************************************************************************
      61                 :            : {
      62         [ -  + ]:          1 :   if (filename.empty()) return;
      63         [ +  - ]:          2 :   std::ofstream f( filename );
      64 [ +  - ][ +  - ]:          1 :   if (f.is_open()) {
      65         [ +  - ]:          1 :     f << public_key;
      66         [ +  - ]:          1 :     f.close();
      67 [ +  - ][ +  - ]:          1 :     MINFO( "Public key saved to file: " << filename );
         [ +  - ][ +  - ]
                 [ +  - ]
      68                 :            :   } else {
      69 [ -  - ][ -  - ]:          0 :     std::cerr << "Cannot open file for writing: " << filename << '\n';
                 [ -  - ]
      70                 :            :   }
      71                 :            : }
      72                 :            : 
      73                 :            : static void
      74                 :          6 : load_server_key( const std::string& filename, std::string& key )
      75                 :            : // *****************************************************************************
      76                 :            : //! Load server key from file
      77                 :            : //! \param[in] filename File to load key from
      78                 :            : //! \param[in] key String to store key in
      79                 :            : // *****************************************************************************
      80                 :            : {
      81         [ +  + ]:          6 :   if (filename.empty()) return;
      82         [ +  - ]:          4 :   std::ifstream f( filename );
      83 [ +  - ][ -  + ]:          4 :   if (not f.good()) {
      84         [ -  - ]:          0 :     epee::set_console_color( epee::console_color_red, /*bright=*/ false );
      85 [ -  - ][ -  - ]:          0 :     std::cerr <<  "Cannot open file for reading: " << filename << '\n';
                 [ -  - ]
      86         [ -  - ]:          0 :     epee::set_console_color( epee::console_color_default, /*bright=*/ false );
      87                 :          0 :     return;
      88                 :            :   }
      89         [ +  - ]:          4 :   f >> key;
      90         [ -  + ]:          4 :   assert( key.size() == 40 );
      91         [ +  - ]:          4 :   f.close();
      92 [ +  - ][ +  - ]:          4 :   MINFO( "Read key from file " + filename );
         [ +  - ][ +  - ]
                 [ +  - ]
      93                 :            : }
      94                 :            : 
      95                 :            : static void
      96                 :          3 : load_client_keys( const std::string& filename,
      97                 :            :                   std::vector< std::string >& keys )
      98                 :            : // *****************************************************************************
      99                 :            : //! Load keys from file
     100                 :            : //! \param[in] filename File to load keys from
     101                 :            : //! \param[in] keys Vector of strings to store key in
     102                 :            : // *****************************************************************************
     103                 :            : {
     104         [ +  + ]:          3 :   if (filename.empty()) return;
     105         [ +  - ]:          2 :   std::ifstream f( filename );
     106 [ +  - ][ -  + ]:          1 :   if (not f.good()) {
     107         [ -  - ]:          0 :     epee::set_console_color( epee::console_color_red, /*bright=*/ false );
     108 [ -  - ][ -  - ]:          0 :     std::cerr <<  "Cannot open file for reading: " << filename << '\n';
                 [ -  - ]
     109         [ -  - ]:          0 :     epee::set_console_color( epee::console_color_default, /*bright=*/ false );
     110                 :          0 :     exit( EXIT_FAILURE );
     111                 :            :   }
     112 [ +  - ][ +  + ]:          4 :   while (not f.eof()) {
     113                 :          3 :     std::string key;
     114         [ +  - ]:          3 :     f >> key;
     115         [ +  + ]:          3 :     if (key.size() != 40) continue;
     116         [ +  - ]:          2 :     keys.emplace_back( std::move(key) );
     117                 :            :   }
     118         [ +  - ]:          1 :   f.close();
     119 [ +  - ][ +  - ]:          1 :   MINFO("Read " << keys.size() << " client keys from file " + filename);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     120                 :            : }
     121                 :            : 
     122                 :            : static std::string
     123                 :          2 : usage( const std::string& db_name,
     124                 :            :        const std::string& logfile,
     125                 :            :        const std::string& rpc_server_save_public_key_file,
     126                 :            :        int rpc_port,
     127                 :            :        int p2p_port )
     128                 :            : // *****************************************************************************
     129                 :            : //! Return program usage information
     130                 :            : //! \param[in] db_name Name of database to use to store ads
     131                 :            : //! \param[in] rpc_server_save_public_key_file File to save generated public key
     132                 :            : //! \param[in] rpc_port Port to use for client communication
     133                 :            : //! \param[in] p2p_port Port to use for peer-to-peer communication
     134                 :            : //! \param[in] logfile Logfile name
     135                 :            : //! \return String containing usage information
     136                 :            : // *****************************************************************************
     137                 :            : {
     138 [ +  - ][ +  - ]:          4 :   return "Usage: " + piac::daemon_executable() + " [OPTIONS]\n\n"
     139                 :            :           "OPTIONS\n"
     140                 :            :           "  --db <directory>\n"
     141 [ +  - ][ +  - ]:          4 :           "         Use database, default: " + db_name + ".\n\n"
     142                 :            :           "  --detach\n"
     143                 :            :           "         Run as a daemon in the background.\n\n"
     144                 :            :           "  --help\n"
     145                 :            :           "         Show help message.\n\n"
     146                 :            :           "  --log-file <filename.log>\n"
     147 [ +  - ][ +  - ]:          4 :           "         Specify log filename, default: " + logfile + ".\n\n"
     148                 :            :           "  --log-level <[0-4]>\n"
     149                 :            :           "         Specify log level: 0: minimum, 4: maximum.\n\n"
     150                 :            :           "  --max-log-file-size <size-in-bytes> \n"
     151         [ +  - ]:          4 :           "         Specify maximum log file size in bytes. Default: " +
     152 [ +  - ][ +  - ]:          8 :           std::to_string( MAX_LOG_FILE_SIZE ) + ". Once the log file\n"
     153                 :            :           "         grows past that limit, the next log file is created with "
     154                 :            :                    "a UTC timestamp postfix\n"
     155         [ +  - ]:          2 :           "         -YYYY-MM-DD-HH-MM-SS. Set --max-log-file-size 0 to prevent "
     156 [ +  - ][ +  - ]:          8 :                   + piac::cli_executable() + " from managing\n"
     157                 :            :           "         the log files.\n\n"
     158                 :            :           "  --max-log-files <num> \n"
     159         [ +  - ]:          4 :           "         Specify a limit on the number of log files. Default: " +
     160 [ +  - ][ +  - ]:          8 :           std::to_string( MAX_LOG_FILES ) + ". The oldest log files\n"
     161                 :            :           "         are removed. In production deployments, you would "
     162                 :            :                    "probably prefer to use\n"
     163                 :            :           "         established solutions like logrotate instead.\n\n"
     164                 :            :           "  --peer <hostname>[:port]\n"
     165                 :            :           "         Specify a peer to connect to.\n\n"
     166                 :            :           "  --rpc-bind-port <port>\n"
     167         [ +  - ]:          2 :           "         Listen on RPC port given, default: "
     168 [ +  - ][ +  - ]:          8 :                   + std::to_string( rpc_port ) + ".\n\n"
     169                 :            :           "  --rpc-secure\n"
     170                 :            :           "         Enable secure connection to clients.\n\n"
     171                 :            :           "  --rpc-server-public-key-file <filename>\n"
     172                 :            :           "         Load server public key from file. Need to also set "
     173                 :            :                    "--rpc-secure.\n\n"
     174                 :            :           "  --rpc-server-secret-key-file <filename>\n"
     175                 :            :           "         Load server secret key from file. Need to also set "
     176                 :            :                    "--rpc-secure.\n\n"
     177                 :            :           "  --rpc-authorized-clients-file <filename>\n"
     178                 :            :           "         Only allow client connections with public keys read "
     179                 :            :                    "from this file. Need to also\n"
     180                 :            :           "         set --rpc-secure.\n\n"
     181                 :            :           "  --rpc-server-save-public-key-file <filename>\n"
     182         [ +  - ]:          2 :           "         Save self-generated server public key to file. Default: "
     183         [ +  - ]:          4 :                   + rpc_server_save_public_key_file + ". Need to\n"
     184                 :            :           "         also set --rpc-secure.\n\n"
     185                 :            :           "  --p2p-bind-port <port>\n"
     186         [ +  - ]:          2 :           "         Listen on P2P port given, default: "
     187         [ +  - ]:          8 :                   + std::to_string( p2p_port ) + ".\n\n"
     188                 :            :           "  --version\n"
     189         [ +  - ]:          4 :           "         Show version information.\n\n";
     190                 :            : }
     191                 :            : 
     192                 :            : } // piac::
     193                 :            : 
     194                 :            : int
     195                 :         17 : main( int argc, char **argv )
     196                 :            : // *****************************************************************************
     197                 :            : //! Piac daemon main function
     198                 :            : //! \param[in] argc Number of command line arguments passed from shell
     199                 :            : //! \param[in] argv List of command line arguments passed from shell
     200                 :            : //! \return Error code to return to shell
     201                 :            : // *****************************************************************************
     202                 :            : {
     203                 :            :   // save command line
     204         [ +  - ]:         34 :   std::vector< std::string > args( argv, argv+argc );
     205         [ +  - ]:         34 :   std::stringstream cmdline;
     206 [ +  + ][ +  - ]:        138 :   for (const auto& a : args) cmdline << a << ' ';
                 [ +  - ]
     207                 :            : 
     208                 :            :   // defaults
     209                 :         17 :   int rpc_port = 55090;         // for client/server communication
     210                 :         17 :   int default_p2p_port = 65090; // for peer-to-peer communication
     211                 :         17 :   int p2p_port = default_p2p_port;
     212                 :         17 :   bool use_strict_ports = false;
     213         [ +  - ]:         34 :   std::string db_name( "piac.db" );
     214 [ +  - ][ +  - ]:         34 :   std::string logfile( piac::daemon_executable() + ".log" );
     215         [ +  - ]:         34 :   std::string log_level( "4" );
     216                 :         17 :   std::size_t max_log_file_size = MAX_LOG_FILE_SIZE;
     217                 :         17 :   std::size_t max_log_files = MAX_LOG_FILES;
     218 [ +  - ][ +  - ]:         34 :   std::string version( "piac: " + piac::daemon_executable() + " v"
                 [ +  - ]
     219 [ +  - ][ +  - ]:         85 :                        + piac::project_version() + "-" + piac::build_type() );
         [ +  - ][ +  - ]
                 [ +  - ]
     220                 :         34 :   std::vector< std::string > peers;
     221                 :         34 :   std::string rpc_server_public_key_file;
     222                 :         34 :   std::string rpc_server_secret_key_file;
     223                 :         34 :   std::string rpc_authorized_clients_file;
     224                 :         34 :   std::vector< std::string > rpc_authorized_clients;
     225         [ +  - ]:         34 :   std::string rpc_server_save_public_key_file = "stonehouse.pub";
     226                 :            : 
     227                 :            :   // Process command line arguments
     228                 :            :   int c;
     229                 :         17 :   int option_index = 0;
     230                 :         17 :   int detach = 0;
     231                 :         17 :   int rpc_secure = 0;
     232                 :         17 :   int num_err = 0;
     233                 :         17 :   const int ARG_DB                              = 1000;
     234                 :         17 :   const int ARG_HELP                            = 1001;
     235                 :         17 :   const int ARG_LOG_FILE                        = 1002;
     236                 :         17 :   const int ARG_LOG_LEVEL                       = 1003;
     237                 :         17 :   const int ARG_MAX_LOG_FILE_SIZE               = 1004;
     238                 :         17 :   const int ARG_MAX_LOG_FILES                   = 1005;
     239                 :         17 :   const int ARG_PEER                            = 1006;
     240                 :         17 :   const int ARG_RPC_PORT                        = 1007;
     241                 :         17 :   const int ARG_RPC_SERVER_PUBLIC_KEY_FILE      = 1008;
     242                 :         17 :   const int ARG_RPC_SERVER_SECRET_KEY_FILE      = 1009;
     243                 :         17 :   const int ARG_RPC_AUTHORIZED_CLIENTS_FILE     = 1010;
     244                 :         17 :   const int ARG_RPC_SERVER_SAVE_PUBLIC_KEY_FILE = 1011;
     245                 :         17 :   const int ARG_P2P_PORT                        = 1012;
     246                 :         17 :   const int ARG_VERSION                         = 1013;
     247                 :            :   static struct option long_options[] =
     248                 :            :     {
     249                 :            :       { "db", required_argument, nullptr, ARG_DB },
     250                 :            :       { "detach", no_argument, &detach, 1 },
     251                 :            :       { "help", no_argument, nullptr, ARG_HELP },
     252                 :            :       { "log-file", required_argument, nullptr, ARG_LOG_FILE },
     253                 :            :       { "log-level", required_argument, nullptr, ARG_LOG_LEVEL },
     254                 :            :       { "max-log-file-size", required_argument, nullptr, ARG_MAX_LOG_FILE_SIZE },
     255                 :            :       { "max-log-files", required_argument, nullptr, ARG_MAX_LOG_FILES },
     256                 :            :       { "peer", required_argument, nullptr, ARG_PEER },
     257                 :            :       { "rpc-bind-port", required_argument, nullptr, ARG_RPC_PORT },
     258                 :            :       { "rpc-secure", no_argument, &rpc_secure, 1 },
     259                 :            :       { "rpc-server-public-key-file", required_argument, nullptr,
     260                 :            :         ARG_RPC_SERVER_PUBLIC_KEY_FILE },
     261                 :            :       { "rpc-server-secret-key-file", required_argument, nullptr,
     262                 :            :         ARG_RPC_SERVER_SECRET_KEY_FILE },
     263                 :            :       { "rpc-authorized-clients-file", required_argument, nullptr,
     264                 :            :         ARG_RPC_AUTHORIZED_CLIENTS_FILE },
     265                 :            :       { "rpc-server-save-public-key-file", required_argument, nullptr,
     266                 :            :         ARG_RPC_SERVER_SAVE_PUBLIC_KEY_FILE },
     267                 :            :       { "p2p-bind-port", required_argument, nullptr, ARG_P2P_PORT },
     268                 :            :       { "version", no_argument, nullptr, ARG_VERSION },
     269                 :            :       { nullptr, 0, nullptr, 0 }
     270 [ +  - ][ +  - ]:         17 :     };
     271                 :            : 
     272         [ +  + ]:         73 :   while ((c = getopt_long(argc, argv, "", long_options, &option_index)) != -1) {
     273 [ +  + ][ +  + ]:         60 :     switch (c) {
         [ +  + ][ +  + ]
         [ +  + ][ -  - ]
         [ -  + ][ -  + ]
     274                 :            : 
     275                 :          2 :       case ARG_DB: {
     276         [ +  - ]:          2 :         db_name = optarg;
     277                 :          2 :         break;
     278                 :            :       }
     279                 :            : 
     280                 :          2 :       case ARG_HELP: {
     281                 :            :         std::cout << version << "\n\n" <<
     282                 :          2 :           piac::usage( db_name, logfile, rpc_server_save_public_key_file,
     283 [ +  - ][ +  - ]:          2 :                        rpc_port, p2p_port );
         [ +  - ][ +  - ]
     284                 :          2 :         return EXIT_SUCCESS;
     285                 :            :       }
     286                 :            : 
     287                 :          4 :       case ARG_PEER: {
     288 [ +  - ][ +  - ]:          4 :         peers.push_back( optarg );
     289                 :          4 :         break;
     290                 :            :       }
     291                 :            : 
     292                 :         11 :       case ARG_RPC_PORT: {
     293                 :         11 :         rpc_port = atoi( optarg );
     294                 :         11 :         use_strict_ports = true;
     295                 :         11 :         break;
     296                 :            :       }
     297                 :            : 
     298                 :          2 :       case ARG_RPC_SERVER_PUBLIC_KEY_FILE: {
     299         [ +  - ]:          2 :         rpc_server_public_key_file = optarg;
     300                 :          2 :         break;
     301                 :            :       }
     302                 :            : 
     303                 :          2 :       case ARG_RPC_SERVER_SECRET_KEY_FILE: {
     304         [ +  - ]:          2 :         rpc_server_secret_key_file = optarg;
     305                 :          2 :         break;
     306                 :            :       }
     307                 :            : 
     308                 :          1 :       case ARG_RPC_AUTHORIZED_CLIENTS_FILE: {
     309         [ +  - ]:          1 :         rpc_authorized_clients_file = optarg;
     310                 :          1 :         break;
     311                 :            :       }
     312                 :            : 
     313                 :          1 :       case ARG_RPC_SERVER_SAVE_PUBLIC_KEY_FILE: {
     314         [ +  - ]:          1 :         rpc_server_save_public_key_file = optarg;
     315                 :          1 :         break;
     316                 :            :       }
     317                 :            : 
     318                 :         11 :       case ARG_P2P_PORT: {
     319                 :         11 :         default_p2p_port = atoi( optarg );
     320                 :         11 :         p2p_port = default_p2p_port;
     321                 :         11 :         use_strict_ports = true;
     322                 :         11 :         break;
     323                 :            :       }
     324                 :            : 
     325                 :          8 :       case ARG_LOG_FILE: {
     326         [ +  - ]:          8 :         logfile = optarg;
     327                 :          8 :         break;
     328                 :            :       }
     329                 :            : 
     330                 :          0 :       case ARG_LOG_LEVEL: {
     331         [ -  - ]:          0 :         std::stringstream s;
     332         [ -  - ]:          0 :         s << optarg;
     333                 :            :         int level;
     334         [ -  - ]:          0 :         s >> level;
     335         [ -  - ]:          0 :         if (level < 0) level = 0;
     336         [ -  - ]:          0 :         if (level > 4) level = 4;
     337         [ -  - ]:          0 :         log_level = std::to_string( level );
     338                 :          0 :         break;
     339                 :            :       }
     340                 :            : 
     341                 :          0 :       case ARG_MAX_LOG_FILE_SIZE: {
     342         [ -  - ]:          0 :         std::stringstream s;
     343         [ -  - ]:          0 :         s << optarg;
     344         [ -  - ]:          0 :         s >> max_log_file_size;
     345                 :          0 :         break;
     346                 :            :       }
     347                 :            : 
     348                 :          0 :       case ARG_MAX_LOG_FILES: {
     349         [ -  - ]:          0 :         std::stringstream s;
     350         [ -  - ]:          0 :         s << optarg;
     351         [ -  - ]:          0 :         s >> max_log_files;
     352                 :          0 :         break;
     353                 :            :       }
     354                 :            : 
     355                 :          2 :       case ARG_VERSION: {
     356 [ +  - ][ +  - ]:          2 :         std::cout << version << '\n';
     357                 :          2 :         return EXIT_SUCCESS;
     358                 :            :       }
     359                 :            : 
     360                 :          0 :       case '?': {
     361                 :          0 :         ++num_err;
     362                 :          0 :         break;
     363                 :            :       }
     364                 :            :     }
     365                 :            :   }
     366                 :            : 
     367         [ +  + ]:         13 :   if (optind < argc) {
     368         [ +  - ]:          2 :     printf( "%s: invalid options -- ", argv[0] );
     369 [ +  + ][ +  - ]:          4 :     while (optind < argc) printf( "%s ", argv[optind++] );
     370         [ +  - ]:          2 :     printf( "\n" );
     371                 :          2 :     return EXIT_FAILURE;
     372                 :            :   }
     373                 :            : 
     374         [ -  + ]:         11 :   if (num_err) {
     375                 :            :     std::cerr << "Erros during parsing command line\n"
     376         [ -  - ]:          0 :               << "Command line: " + cmdline.str() << '\n'
     377                 :          0 :               << piac::usage( db_name, logfile,rpc_server_save_public_key_file,
     378 [ -  - ][ -  - ]:          0 :                               rpc_port, p2p_port );
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
     379                 :          0 :     return EXIT_FAILURE;
     380                 :            :   }
     381                 :            : 
     382                 :         11 :   if ((not rpc_server_public_key_file.empty() ||
     383         [ +  - ]:          9 :        not rpc_server_secret_key_file.empty() ||
     384 [ +  + ][ -  + ]:         22 :        not rpc_authorized_clients_file.empty()) &&
                 [ -  + ]
     385         [ -  + ]:          2 :        not rpc_secure)
     386                 :            :   {
     387         [ -  - ]:          0 :     std::cerr << "Need --rpc-secure to secure RPC channel.\n";
     388                 :          0 :     return EXIT_FAILURE;
     389                 :            :   }
     390                 :            : 
     391         [ +  - ]:         13 :   if ((not rpc_server_public_key_file.empty() &&
     392 [ +  + ][ +  + ]:         31 :        rpc_server_secret_key_file.empty()) ||
                 [ -  + ]
     393                 :         11 :       (rpc_server_public_key_file.empty() &&
     394         [ -  + ]:          9 :        not rpc_server_secret_key_file.empty()))
     395                 :            :   {
     396                 :            :     std::cerr << "Need --rpc-authorized-clients-file for authorized RPC "
     397         [ -  - ]:          0 :                  "clients.\n";
     398                 :          0 :     return EXIT_FAILURE;
     399                 :            :   }
     400                 :            : 
     401         [ +  - ]:         11 :   if (detach) {
     402                 :            :     // Fork the current process. The parent process continues with a process ID
     403                 :            :     // greater than 0.  A process ID lower than 0 indicates a failure in either
     404                 :            :     // process.
     405                 :         11 :     pid_t pid = fork();
     406         [ +  + ]:         22 :     if (pid > 0) {
     407         [ +  - ]:         11 :       std::cout << "Running in daemon mode. Forked PID: " << pid
     408 [ +  - ][ +  - ]:         11 :                 << ". See the log file for details." << std::endl;
                 [ +  - ]
     409                 :         11 :       return EXIT_SUCCESS;
     410         [ -  + ]:         11 :     } else if (pid < 0) {
     411                 :          0 :       return EXIT_FAILURE;
     412                 :            :     }
     413                 :            : 
     414                 :            :     // Generate a session ID for the child process and ensure it is valid.
     415         [ -  + ]:         11 :     if (setsid() < 0) {
     416                 :            :       // Log failure and exit
     417         [ -  - ]:          0 :       std::cerr << "Could not generate session ID for child process\n";
     418                 :            :       // If a new session ID could not be generated, we must terminate the child
     419                 :            :       // process or it will be orphaned.
     420                 :          0 :       return EXIT_FAILURE;
     421                 :            :     }
     422                 :            : 
     423                 :            :     // A daemon cannot use the terminal, so close standard file descriptors for
     424                 :            :     // security reasons and also because ctest hangs in daemon mode waiting for
     425                 :            :     // stdout and stderr to be closed.
     426         [ +  - ]:         11 :     close( STDIN_FILENO );
     427         [ +  - ]:         11 :     close( STDOUT_FILENO );
     428         [ +  - ]:         11 :     close( STDERR_FILENO );
     429                 :            : 
     430                 :         11 :     s_catch_signals();
     431                 :            :   }
     432                 :            : 
     433         [ +  - ]:         11 :   epee::set_console_color( epee::console_color_green, /* bright = */ false );
     434 [ +  - ][ +  - ]:         11 :   std::cout << version << '\n';
     435         [ +  - ]:         11 :   epee::set_console_color( epee::console_color_default, /* bright = */ false );
     436                 :            :   std::cout <<
     437                 :            :     "Welcome to piac, where anyone can buy and sell anything privately and\n"
     438                 :            :     "securely using the private digital cash, monero. For more information\n"
     439                 :            :     "on monero, see https://getmonero.org. This is the server of piac. It\n"
     440                 :            :     "can run standalone or as a daemon in the background using --detach.\n"
     441 [ +  - ][ +  - ]:         11 :     "You can use " + piac::cli_executable() + " to interact with it.\n";
         [ +  - ][ +  - ]
     442                 :            : 
     443         [ +  - ]:         11 :   piac::setup_logging( logfile, log_level, /* console_logging = */ false,
     444                 :            :                        max_log_file_size, max_log_files );
     445                 :            : 
     446 [ +  - ][ +  - ]:         11 :   MINFO( "Command line: " + cmdline.str() );
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     447                 :            : 
     448                 :            :   // setup RPC security
     449                 :         11 :   int rpc_ironhouse = 1;
     450                 :         11 :   zmqpp::curve::keypair rpc_server_keys;
     451         [ +  + ]:         11 :   if (rpc_secure) {
     452         [ +  - ]:          3 :     piac::load_server_key( rpc_server_public_key_file,
     453                 :            :                            rpc_server_keys.public_key );
     454         [ +  - ]:          3 :     piac::load_server_key( rpc_server_secret_key_file,
     455                 :            :                            rpc_server_keys.secret_key );
     456         [ +  - ]:          3 :     piac::load_client_keys( rpc_authorized_clients_file,
     457                 :            :                             rpc_authorized_clients );
     458                 :            :     // fallback to stonehouse if needed
     459         [ +  - ]:          5 :     if (rpc_server_keys.secret_key.empty() ||
     460 [ +  + ][ +  + ]:          5 :         rpc_server_keys.public_key.empty() ||
                 [ +  + ]
     461                 :          2 :         rpc_authorized_clients.empty())
     462                 :            :     {
     463                 :          2 :       rpc_ironhouse = 0;
     464 [ +  + ][ -  + ]:          3 :       if (rpc_server_keys.secret_key.empty() ||
                 [ +  + ]
     465                 :          1 :           rpc_server_keys.public_key.empty())
     466                 :            :       {
     467         [ +  - ]:          1 :         rpc_server_keys = zmqpp::curve::generate_keypair();
     468         [ +  - ]:          1 :         piac::save_public_key( rpc_server_save_public_key_file,
     469                 :            :                                rpc_server_keys.public_key );
     470                 :            :       }
     471                 :          2 :       rpc_authorized_clients.clear();
     472                 :            :     }
     473                 :            :   }
     474                 :            : 
     475                 :            :   // echo RPC security configured
     476         [ +  + ]:         11 :   if (rpc_secure) {
     477         [ +  + ]:          3 :     if (rpc_ironhouse) {
     478         [ +  - ]:          1 :       epee::set_console_color( epee::console_color_green, /*bright=*/ false );
     479                 :            :       std::string ironhouse( "Connections to this server are secure: "
     480         [ +  - ]:          2 :         "Only authenticated connections are accepted." );
     481 [ +  - ][ +  - ]:          1 :       std::cout << ironhouse << '\n';
     482         [ +  - ]:          1 :       epee::set_console_color( epee::console_color_white, /*bright=*/false );
     483 [ +  - ][ +  - ]:          1 :       MINFO( ironhouse );
         [ +  - ][ +  - ]
     484                 :            :     } else {
     485                 :            :       std::string stonehouse( "Connections to this server are secure but not "
     486         [ +  - ]:          4 :         "authenticated: ALL client connections are accepted." );
     487         [ +  - ]:          2 :       epee::set_console_color( epee::console_color_yellow, /*bright=*/ false );
     488 [ +  - ][ +  - ]:          2 :       std::cout << stonehouse << '\n';
     489         [ +  - ]:          2 :       epee::set_console_color( epee::console_color_white, /*bright=*/false );
     490 [ +  - ][ +  - ]:          2 :       MINFO( stonehouse );
         [ +  - ][ +  - ]
     491                 :            :       std::cout << "RPC server public key: "
     492 [ +  - ][ +  - ]:          2 :                 << rpc_server_keys.public_key << '\n';
                 [ +  - ]
     493                 :            :     }
     494                 :            :   } else {
     495         [ +  - ]:          8 :     epee::set_console_color( epee::console_color_red, /* bright = */ false );
     496                 :            :     std::string grasslands( "WARNING: Connections to this server are not "
     497         [ +  - ]:         16 :       "secure" );
     498 [ +  - ][ +  - ]:          8 :     std::cout << grasslands << '\n';
     499 [ +  - ][ +  - ]:          8 :     MWARNING( grasslands );
         [ +  - ][ +  - ]
     500                 :            :   }
     501         [ +  - ]:         11 :   epee::set_console_color( epee::console_color_default, /* bright = */false );
     502                 :            : 
     503         [ +  + ]:         11 :   if (rpc_secure) {
     504 [ +  - ][ +  - ]:          3 :     MINFO( "RPC server public key: " << rpc_server_keys.public_key );
         [ +  - ][ +  - ]
                 [ +  - ]
     505                 :            :   }
     506                 :            : 
     507         [ +  - ]:         11 :   if (detach) {
     508 [ +  - ][ +  - ]:         11 :     MINFO( "Forked PID: " << getpid() );
         [ +  - ][ +  - ]
                 [ +  - ]
     509                 :            :   }
     510                 :            : 
     511                 :            :   // initialize (thread-safe) zmq contexts
     512         [ +  - ]:         11 :   zmqpp::context ctx_p2p;       // for p2p comm
     513         [ +  - ]:         11 :   zmqpp::context ctx_db;        // for inproc comm
     514                 :            : 
     515                 :            :   // add initial peers
     516                 :         11 :   std::unordered_map< std::string, zmqpp::socket > my_peers;
     517         [ +  + ]:         15 :   for (const auto& p : peers)
     518 [ +  - ][ +  - ]:          4 :     my_peers.emplace( p, zmqpp::socket( ctx_p2p, zmqpp::socket_type::dealer ) );
     519                 :            : 
     520                 :            :   // will store db entry hashes
     521                 :         11 :   std::unordered_set< std::string > my_hashes;
     522                 :            : 
     523                 :            :   // start threads
     524                 :         11 :   std::vector< std::thread > threads;
     525                 :            : 
     526                 :            :   threads.emplace_back( piac::p2p_thread,
     527                 :         11 :     std::ref(ctx_p2p), std::ref(ctx_db), std::ref(my_peers),
     528         [ +  - ]:         22 :     std::ref(my_hashes), default_p2p_port, p2p_port, use_strict_ports );
     529                 :            : 
     530                 :            :   threads.emplace_back( piac::db_thread,
     531                 :         11 :     std::ref(ctx_db), db_name, rpc_port, use_strict_ports, std::ref(my_peers),
     532                 :         11 :     std::ref(my_hashes), rpc_secure, std::ref(rpc_server_keys),
     533         [ +  - ]:         22 :     std::ref(rpc_authorized_clients) );
     534                 :            : 
     535                 :            :   // wait for all threads to finish
     536 [ +  - ][ -  - ]:         11 :   for (auto& t : threads) t.join();
     537                 :            : 
     538 [ -  - ][ -  - ]:          0 :   MDEBUG( "graceful exit" );
         [ -  - ][ -  - ]
     539                 :            : 
     540                 :            :   // Terminate the child process when the daemon completes
     541                 :          0 :   return EXIT_SUCCESS;
     542                 :            : }

Generated by: LCOV version 1.14