LCOV - code coverage report
Current view: top level - src/ipc - process.cpp (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 66.7 % 72 48
Test Date: 2026-08-07 06:33:33 Functions: 50.0 % 8 4
Branches: 35.3 % 136 48

             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 <ipc/process.h>
       6                 :             : #include <ipc/protocol.h>
       7                 :             : #include <mp/util.h>
       8                 :             : #include <tinyformat.h>
       9                 :             : #include <util/fs.h>
      10                 :             : #include <util/log.h>
      11                 :             : #include <util/strencodings.h>
      12                 :             : #include <util/syserror.h>
      13                 :             : 
      14                 :             : #include <cstdint>
      15                 :             : #include <cstdlib>
      16                 :             : #include <cstring>
      17                 :             : #include <cerrno>
      18                 :             : #include <exception>
      19                 :             : #include <iostream>
      20                 :             : #include <stdexcept>
      21                 :             : #include <utility>
      22                 :             : #include <vector>
      23                 :             : 
      24                 :             : #include <sys/socket.h>
      25                 :             : #include <sys/un.h>
      26                 :             : #include <unistd.h>
      27                 :             : 
      28                 :             : using util::RemovePrefixView;
      29                 :             : 
      30                 :             : namespace ipc {
      31                 :             : namespace {
      32                 :           2 : class ProcessImpl : public Process
      33                 :             : {
      34                 :             : public:
      35                 :           0 :     std::tuple<mp::ProcessId, mp::SocketId> spawn(const std::string& new_exe_name, const fs::path& argv0_path) override
      36                 :             :     {
      37         [ #  # ]:           0 :         return mp::SpawnProcess([&](std::string connect_info) {
      38                 :           0 :             fs::path path = argv0_path;
      39         [ #  # ]:           0 :             path.remove_filename();
      40         [ #  # ]:           0 :             path /= fs::PathFromString(new_exe_name);
      41   [ #  #  #  #  :           0 :             return std::vector<std::string>{fs::PathToString(path), "-ipcfd", std::move(connect_info)};
                   #  # ]
      42   [ #  #  #  #  :           0 :         });
             #  #  #  # ]
      43                 :             :     }
      44                 :           0 :     int waitSpawned(mp::ProcessId pid) override { return mp::WaitProcess(pid); }
      45                 :           0 :     bool checkSpawned(int argc, char* argv[], mp::SocketId& socket) override
      46                 :             :     {
      47                 :             :         // If this process was not started with a single -ipcfd argument, it is
      48                 :             :         // not a process spawned by the spawn() call above, so return false and
      49                 :             :         // do not try to serve requests.
      50   [ #  #  #  # ]:           0 :         if (argc != 3 || strcmp(argv[1], "-ipcfd") != 0) {
      51                 :             :             return false;
      52                 :             :         }
      53                 :             :         // If a single -ipcfd argument was provided, return true and get the
      54                 :             :         // file descriptor so Protocol::serve() can be called to handle
      55                 :             :         // requests from the parent process. The -ipcfd argument is not valid
      56                 :             :         // in combination with other arguments because the parent process
      57                 :             :         // should be able to control the child process through the IPC protocol
      58                 :             :         // without passing information out of band.
      59                 :           0 :         try {
      60   [ #  #  #  # ]:           0 :            socket = mp::StartSpawned(argv[2]);
      61         [ -  - ]:           0 :         } catch (const std::exception& e) {
      62   [ -  -  -  - ]:           0 :            throw std::runtime_error(strprintf("Invalid -ipcfd number '%s' (%s)", argv[2], e.what()));
      63                 :           0 :         }
      64                 :           0 :         return true;
      65                 :             :     }
      66                 :             :     mp::SocketId connect(const fs::path& data_dir,
      67                 :             :                 const std::string& dest_exe_name,
      68                 :             :                 std::string& address) override;
      69                 :             :     mp::SocketId bind(const fs::path& data_dir, const std::string& exe_name, std::string& address) override;
      70                 :             : };
      71                 :             : 
      72                 :          14 : static bool ParseAddress(std::string& address,
      73                 :             :                   const fs::path& data_dir,
      74                 :             :                   const std::string& dest_exe_name,
      75                 :             :                   struct sockaddr_un& addr,
      76                 :             :                   std::string& error)
      77                 :             : {
      78   [ +  +  +  + ]:          27 :     if (address == "unix" || address.starts_with("unix:")) {
      79                 :          11 :         fs::path path;
      80   [ -  +  +  + ]:          11 :         if (address.size() <= 5) {
      81   [ -  +  +  -  :          12 :             path = data_dir / fs::PathFromString(strprintf("%s.sock", RemovePrefixView(dest_exe_name, "bitcoin-")));
          +  -  +  -  +  
                      - ]
      82                 :             :         } else {
      83   [ +  -  +  -  :          54 :             path = data_dir / fs::PathFromString(address.substr(5));
                   +  - ]
      84                 :             :         }
      85         [ -  + ]:          11 :         std::string path_str = fs::PathToString(path);
      86         [ +  - ]:          11 :         address = strprintf("unix:%s", path_str);
      87   [ -  +  +  + ]:          11 :         if (path_str.size() >= sizeof(addr.sun_path)) {
      88   [ -  +  +  - ]:           2 :             error = strprintf("Unix address path %s exceeded maximum socket path length", fs::quoted(fs::PathToString(path)));
      89                 :           1 :             return false;
      90                 :             :         }
      91                 :          10 :         memset(&addr, 0, sizeof(addr));
      92                 :          10 :         addr.sun_family = AF_UNIX;
      93                 :          10 :         strncpy(addr.sun_path, path_str.c_str(), sizeof(addr.sun_path)-1);
      94                 :          10 :         return true;
      95                 :          22 :     }
      96                 :             : 
      97                 :           3 :     error = strprintf("Unrecognized address '%s'", address);
      98                 :           3 :     return false;
      99                 :             : }
     100                 :             : 
     101                 :          11 : mp::SocketId ProcessImpl::connect(const fs::path& data_dir,
     102                 :             :                          const std::string& dest_exe_name,
     103                 :             :                          std::string& address)
     104                 :             : {
     105                 :          11 :     struct sockaddr_un addr;
     106         [ +  - ]:          11 :     std::string error;
     107   [ +  -  +  + ]:          11 :     if (!ParseAddress(address, data_dir, dest_exe_name, addr, error)) {
     108         [ +  - ]:           3 :         throw std::invalid_argument(error);
     109                 :             :     }
     110                 :             : 
     111                 :           8 :     mp::SocketId fd;
     112         [ -  + ]:           8 :     if ((fd = ::socket(addr.sun_family, SOCK_STREAM, 0)) == mp::SocketError) {
     113         [ #  # ]:           0 :         throw std::system_error(errno, std::system_category());
     114                 :             :     }
     115   [ +  -  +  + ]:           8 :     if (::connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
     116                 :           5 :         return fd;
     117                 :             :     }
     118                 :           3 :     int connect_error = errno;
     119   [ +  -  -  + ]:           3 :     if (::close(fd) != 0) {
     120   [ #  #  #  # ]:           0 :         LogWarning("Error closing file descriptor %i '%s': %s", fd, address, SysErrorString(errno));
     121                 :             :     }
     122         [ +  - ]:           3 :     throw std::system_error(connect_error, std::system_category());
     123                 :           5 : }
     124                 :             : 
     125                 :           3 : mp::SocketId ProcessImpl::bind(const fs::path& data_dir, const std::string& exe_name, std::string& address)
     126                 :             : {
     127                 :           3 :     struct sockaddr_un addr;
     128         [ +  - ]:           3 :     std::string error;
     129   [ +  -  +  + ]:           3 :     if (!ParseAddress(address, data_dir, exe_name, addr, error)) {
     130         [ +  - ]:           1 :         throw std::invalid_argument(error);
     131                 :             :     }
     132                 :             : 
     133         [ +  - ]:           2 :     if (addr.sun_family == AF_UNIX) {
     134         [ +  - ]:           2 :         fs::path path = addr.sun_path;
     135   [ +  -  +  -  :           4 :         if (path.has_parent_path()) fs::create_directories(path.parent_path());
                   +  - ]
     136   [ +  -  -  + ]:           2 :         if (fs::symlink_status(path).type() == fs::file_type::socket) {
     137         [ #  # ]:           0 :             fs::remove(path);
     138                 :             :         }
     139                 :           2 :     }
     140                 :             : 
     141                 :           2 :     mp::SocketId fd;
     142         [ -  + ]:           2 :     if ((fd = ::socket(addr.sun_family, SOCK_STREAM, 0)) == mp::SocketError) {
     143         [ #  # ]:           0 :         throw std::system_error(errno, std::system_category());
     144                 :             :     }
     145                 :             : 
     146         [ +  - ]:           2 :     if (::bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
     147                 :           2 :         return fd;
     148                 :             :     }
     149                 :           0 :     int bind_error = errno;
     150   [ #  #  #  # ]:           0 :     if (::close(fd) != 0) {
     151   [ #  #  #  # ]:           0 :         LogWarning("Error closing file descriptor %i: %s", fd, SysErrorString(errno));
     152                 :             :     }
     153         [ #  # ]:           0 :     throw std::system_error(bind_error, std::system_category());
     154                 :           2 : }
     155                 :             : } // namespace
     156                 :             : 
     157                 :           2 : std::unique_ptr<Process> MakeProcess() { return std::make_unique<ProcessImpl>(); }
     158                 :             : } // namespace ipc
        

Generated by: LCOV version 2.0-1