LCOV - code coverage report
Current view: top level - src/ipc - interfaces.cpp (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 0.0 % 62 0
Test Date: 2026-08-07 06:33:33 Functions: 0.0 % 13 0
Branches: 0.0 % 53 0

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

Generated by: LCOV version 2.0-1