Bitcoin Core  31.0.0
P2P Digital Currency
interfaces.cpp
Go to the documentation of this file.
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 void HandleCtrlC(int)
34 {
35  // (void)! needed to suppress -Wunused-result warning from GCC
36  (void)!write(STDOUT_FILENO, g_ignore_ctrl_c.data(), g_ignore_ctrl_c.size());
37 }
38 #endif
39 
40 void IgnoreCtrlC(std::string message)
41 {
42 #ifndef WIN32
43  g_ignore_ctrl_c = std::move(message);
44  struct sigaction sa{};
45  sa.sa_handler = HandleCtrlC;
46  sigemptyset(&sa.sa_mask);
47  sa.sa_flags = SA_RESTART;
48  sigaction(SIGINT, &sa, nullptr);
49 #endif
50 }
51 
52 class IpcImpl : public interfaces::Ipc
53 {
54 public:
55  IpcImpl(const char* exe_name, const char* process_argv0, interfaces::Init& init)
56  : m_exe_name(exe_name), m_process_argv0(process_argv0), m_init(init),
57  m_protocol(ipc::capnp::MakeCapnpProtocol()), m_process(ipc::MakeProcess())
58  {
59  }
60  std::unique_ptr<interfaces::Init> spawnProcess(const char* new_exe_name) override
61  {
62  int pid;
63  int fd = m_process->spawn(new_exe_name, m_process_argv0, pid);
64  LogDebug(::BCLog::IPC, "Process %s pid %i launched\n", new_exe_name, pid);
65  auto init = m_protocol->connect(fd, m_exe_name);
66  Ipc::addCleanup(*init, [this, new_exe_name, pid] {
67  int status = m_process->waitSpawned(pid);
68  LogDebug(::BCLog::IPC, "Process %s pid %i exited with status %i\n", new_exe_name, pid, status);
69  });
70  return init;
71  }
72  bool startSpawnedProcess(int argc, char* argv[], int& exit_status) override
73  {
74  exit_status = EXIT_FAILURE;
75  int32_t fd = -1;
76  if (!m_process->checkSpawned(argc, argv, fd)) {
77  return false;
78  }
79  IgnoreCtrlC(strprintf("[%s] SIGINT received — waiting for parent to shut down.\n", m_exe_name));
80  m_protocol->serve(fd, m_exe_name, m_init);
82  return true;
83  }
84  std::unique_ptr<interfaces::Init> connectAddress(std::string& address) override
85  {
86  if (address.empty() || address == "0") return nullptr;
87  int fd;
88  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  address = "unix";
94  try {
95  fd = m_process->connect(gArgs.GetDataDirNet(), "bitcoin-node", address);
96  } 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  if (e.code() == std::errc::connection_refused || e.code() == std::errc::no_such_file_or_directory) {
99  return nullptr;
100  }
101  throw;
102  }
103  } else {
104  fd = m_process->connect(gArgs.GetDataDirNet(), "bitcoin-node", address);
105  }
106  return m_protocol->connect(fd, m_exe_name);
107  }
108  void listenAddress(std::string& address) override
109  {
110  int fd = m_process->bind(gArgs.GetDataDirNet(), m_exe_name, address);
111  m_protocol->listen(fd, m_exe_name, m_init);
112  }
113  void disconnectIncoming() override
114  {
115  m_protocol->disconnectIncoming();
116  }
117  void addCleanup(std::type_index type, void* iface, std::function<void()> cleanup) override
118  {
119  m_protocol->addCleanup(type, iface, std::move(cleanup));
120  }
121  Context& context() override { return m_protocol->context(); }
122  const char* m_exe_name;
123  const char* m_process_argv0;
124  interfaces::Init& m_init;
125  std::unique_ptr<Protocol> m_protocol;
126  std::unique_ptr<Process> m_process;
127 };
128 } // namespace
129 } // namespace ipc
130 
131 namespace interfaces {
132 std::unique_ptr<Ipc> MakeIpc(const char* exe_name, const char* process_argv0, Init& init)
133 {
134  return std::make_unique<ipc::IpcImpl>(exe_name, process_argv0, init);
135 }
136 } // namespace interfaces
return EXIT_SUCCESS
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
fs::path GetDataDirNet() const
Get data directory path with appended network identifier.
Definition: args.h:239
std::unique_ptr< interfaces::Init > init
std::unique_ptr< Ipc > MakeIpc(const char *exe_name, const char *process_argv0, Init &init)
Return implementation of Ipc interface.
Definition: interfaces.cpp:132
Definition: ipc.h:12
std::unique_ptr< Protocol > MakeCapnpProtocol()
Definition: protocol.cpp:154
ArgsManager gArgs
Definition: args.cpp:40
#define LogDebug(category,...)
Definition: log.h:115
int exit_status
Initial interface created when a process is first started, and used to give and get access to other i...
Definition: init.h:30
Interface providing access to interprocess-communication (IPC) functionality.
Definition: ipc.h:49
std::unique_ptr< Process > MakeProcess()
Constructor for Process interface.
Definition: process.cpp:156