LCOV - code coverage report
Current view: top level - src/ipc - process.cpp (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 67.6 % 71 48
Test Date: 2025-08-25 05:11:47 Functions: 50.0 % 8 4
Branches: 36.4 % 132 48

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

Generated by: LCOV version 2.0-1