LCOV - code coverage report
Current view: top level - src/ipc - interfaces.cpp (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 47.6 % 63 30
Test Date: 2026-04-07 04:59:12 Functions: 50.0 % 12 6
Branches: 37.7 % 53 20

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2021-present The Bitcoin Core developers
       2                 :             : // Distributed under the MIT software license, see the accompanying
       3                 :             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4                 :             : 
       5                 :             : #include <common/args.h>
       6                 :             : #include <common/system.h>
       7                 :             : #include <interfaces/init.h>
       8                 :             : #include <interfaces/ipc.h>
       9                 :             : #include <ipc/capnp/protocol.h>
      10                 :             : #include <ipc/process.h>
      11                 :             : #include <ipc/protocol.h>
      12                 :             : #include <logging.h>
      13                 :             : #include <tinyformat.h>
      14                 :             : #include <util/fs.h>
      15                 :             : 
      16                 :             : #include <csignal>
      17                 :             : #include <cstdio>
      18                 :             : #include <cstdlib>
      19                 :             : #include <cstring>
      20                 :             : #include <functional>
      21                 :             : #include <memory>
      22                 :             : #include <stdexcept>
      23                 :             : #include <string>
      24                 :             : #include <unistd.h>
      25                 :             : #include <utility>
      26                 :             : #include <vector>
      27                 :             : 
      28                 :             : namespace ipc {
      29                 :             : namespace {
      30                 :             : #ifndef WIN32
      31                 :             : std::string g_ignore_ctrl_c;
      32                 :             : 
      33                 :           0 : void HandleCtrlC(int)
      34                 :             : {
      35                 :             :     // (void)! needed to suppress -Wunused-result warning from GCC
      36         [ #  # ]:           0 :     (void)!write(STDOUT_FILENO, g_ignore_ctrl_c.data(), g_ignore_ctrl_c.size());
      37                 :           0 : }
      38                 :             : #endif
      39                 :             : 
      40                 :           0 : void IgnoreCtrlC(std::string message)
      41                 :             : {
      42                 :             : #ifndef WIN32
      43                 :           0 :     g_ignore_ctrl_c = std::move(message);
      44                 :           0 :     struct sigaction sa{};
      45                 :           0 :     sa.sa_handler = HandleCtrlC;
      46                 :           0 :     sigemptyset(&sa.sa_mask);
      47                 :           0 :     sa.sa_flags = SA_RESTART;
      48                 :           0 :     sigaction(SIGINT, &sa, nullptr);
      49                 :             : #endif
      50                 :           0 : }
      51                 :             : 
      52                 :             : class IpcImpl : public interfaces::Ipc
      53                 :             : {
      54                 :             : public:
      55                 :        1102 :     IpcImpl(const char* exe_name, const char* process_argv0, interfaces::Init& init)
      56                 :        1102 :         : m_exe_name(exe_name), m_process_argv0(process_argv0), m_init(init),
      57   [ +  -  +  - ]:        1102 :           m_protocol(ipc::capnp::MakeCapnpProtocol()), m_process(ipc::MakeProcess())
      58                 :             :     {
      59                 :        1102 :     }
      60                 :           0 :     std::unique_ptr<interfaces::Init> spawnProcess(const char* new_exe_name) override
      61                 :             :     {
      62                 :           0 :         int pid;
      63   [ #  #  #  # ]:           0 :         int fd = m_process->spawn(new_exe_name, m_process_argv0, pid);
      64         [ #  # ]:           0 :         LogDebug(::BCLog::IPC, "Process %s pid %i launched\n", new_exe_name, pid);
      65                 :           0 :         auto init = m_protocol->connect(fd, m_exe_name);
      66   [ #  #  #  # ]:           0 :         Ipc::addCleanup(*init, [this, new_exe_name, pid] {
      67                 :           0 :             int status = m_process->waitSpawned(pid);
      68         [ #  # ]:           0 :             LogDebug(::BCLog::IPC, "Process %s pid %i exited with status %i\n", new_exe_name, pid, status);
      69                 :           0 :         });
      70                 :           0 :         return init;
      71                 :           0 :     }
      72                 :           5 :     bool startSpawnedProcess(int argc, char* argv[], int& exit_status) override
      73                 :             :     {
      74                 :           5 :         exit_status = EXIT_FAILURE;
      75                 :           5 :         int32_t fd = -1;
      76         [ -  + ]:           5 :         if (!m_process->checkSpawned(argc, argv, fd)) {
      77                 :             :             return false;
      78                 :             :         }
      79                 :           0 :         IgnoreCtrlC(strprintf("[%s] SIGINT received — waiting for parent to shut down.\n", m_exe_name));
      80         [ #  # ]:           0 :         m_protocol->serve(fd, m_exe_name, m_init);
      81                 :           0 :         exit_status = EXIT_SUCCESS;
      82                 :           0 :         return true;
      83                 :             :     }
      84                 :        1097 :     std::unique_ptr<interfaces::Init> connectAddress(std::string& address) override
      85                 :             :     {
      86   [ +  -  -  + ]:        1097 :         if (address.empty() || address == "0") return nullptr;
      87                 :        1097 :         int fd;
      88         [ +  + ]:        1097 :         if (address == "auto") {
      89                 :             :             // Treat "auto" the same as "unix" except don't treat it an as error
      90                 :             :             // if the connection is not accepted. Just return null so the caller
      91                 :             :             // can work offline without a connection, or spawn a new
      92                 :             :             // bitcoin-node process and connect to it.
      93                 :        1093 :             address = "unix";
      94                 :        1093 :             try {
      95   [ +  -  +  -  :        3277 :                 fd = m_process->connect(gArgs.GetDataDirNet(), "bitcoin-node", address);
                   +  + ]
      96      [ -  +  - ]:        1091 :             } catch (const std::system_error& e) {
      97                 :             :                 // If connection type is auto and socket path isn't accepting connections, or doesn't exist, catch the error and return null;
      98   [ +  +  -  +  :        1091 :                 if (e.code() == std::errc::connection_refused || e.code() == std::errc::no_such_file_or_directory || e.code() == std::errc::not_a_directory) {
                   -  - ]
      99                 :        1091 :                     return nullptr;
     100                 :             :                 }
     101                 :           0 :                 throw;
     102                 :        1091 :             } catch (const std::invalid_argument&) {
     103                 :             :                // Catch 'Unix address path "..." exceeded maximum socket path length' error
     104                 :           0 :                return nullptr;
     105                 :           0 :             }
     106                 :             :         } else {
     107   [ +  -  +  + ]:           8 :             fd = m_process->connect(gArgs.GetDataDirNet(), "bitcoin-node", address);
     108                 :             :         }
     109                 :           4 :         return m_protocol->connect(fd, m_exe_name);
     110                 :             :     }
     111                 :           1 :     void listenAddress(std::string& address) override
     112                 :             :     {
     113   [ +  -  +  - ]:           2 :         int fd = m_process->bind(gArgs.GetDataDirNet(), m_exe_name, address);
     114                 :           1 :         m_protocol->listen(fd, m_exe_name, m_init);
     115                 :           1 :     }
     116                 :           1 :     void disconnectIncoming() override
     117                 :             :     {
     118                 :           1 :         m_protocol->disconnectIncoming();
     119                 :           1 :     }
     120                 :           0 :     void addCleanup(std::type_index type, void* iface, std::function<void()> cleanup) override
     121                 :             :     {
     122         [ #  # ]:           0 :         m_protocol->addCleanup(type, iface, std::move(cleanup));
     123                 :           0 :     }
     124                 :           0 :     Context& context() override { return m_protocol->context(); }
     125                 :             :     const char* m_exe_name;
     126                 :             :     const char* m_process_argv0;
     127                 :             :     interfaces::Init& m_init;
     128                 :             :     std::unique_ptr<Protocol> m_protocol;
     129                 :             :     std::unique_ptr<Process> m_process;
     130                 :             : };
     131                 :             : } // namespace
     132                 :             : } // namespace ipc
     133                 :             : 
     134                 :             : namespace interfaces {
     135                 :        1102 : std::unique_ptr<Ipc> MakeIpc(const char* exe_name, const char* process_argv0, Init& init)
     136                 :             : {
     137                 :        1102 :     return std::make_unique<ipc::IpcImpl>(exe_name, process_argv0, init);
     138                 :             : }
     139                 :             : } // namespace interfaces
        

Generated by: LCOV version 2.0-1