Bitcoin Core 32.99.0
P2P Digital Currency
Loading...
Searching...
No Matches
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>
10#include <ipc/process.h>
11#include <ipc/protocol.h>
12#include <ipc/types.h>
13#include <tinyformat.h>
14#include <util/fs.h>
15#include <util/log.h>
16
17#include <csignal>
18#include <cstdio>
19#include <cstdlib>
20#include <cstring>
21#include <functional>
22#include <memory>
23#include <optional>
24#include <stdexcept>
25#include <string>
26#include <utility>
27#include <vector>
28
29#ifndef WIN32
30#include <unistd.h>
31#endif
32
33namespace ipc {
34namespace {
35#ifndef WIN32
36std::string g_ignore_ctrl_c;
37
38void HandleCtrlC(int)
39{
40 // (void)! needed to suppress -Wunused-result warning from GCC
41 (void)!write(STDOUT_FILENO, g_ignore_ctrl_c.data(), g_ignore_ctrl_c.size());
42}
43#endif
44
45void IgnoreCtrlC(std::string message)
46{
47#ifndef WIN32
48 g_ignore_ctrl_c = std::move(message);
49 struct sigaction sa{};
50 sa.sa_handler = HandleCtrlC;
51 sigemptyset(&sa.sa_mask);
52 sa.sa_flags = SA_RESTART;
53 sigaction(SIGINT, &sa, nullptr);
54#endif
55}
56
57class IpcImpl : public interfaces::Ipc
58{
59public:
60 IpcImpl(const char* exe_name, const char* process_argv0, interfaces::Init& init)
61 : m_exe_name(exe_name), m_process_argv0(process_argv0), m_init(init),
62 m_protocol(ipc::capnp::MakeCapnpProtocol(exe_name)), m_process(ipc::MakeProcess())
63 {
64 }
65 std::unique_ptr<interfaces::Init> spawnProcess(const char* new_exe_name) override
66 {
67 const auto [pid, socket] = m_process->spawn(new_exe_name, m_process_argv0);
68 LogDebug(::BCLog::IPC, "Process %s pid %i launched\n", new_exe_name, pid);
69 auto init = m_protocol->connect(m_protocol->makeStream(socket));
70 Ipc::addCleanup(*init, [this, new_exe_name, pid] {
71 int status = m_process->waitSpawned(pid);
72 LogDebug(::BCLog::IPC, "Process %s pid %i exited with status %i\n", new_exe_name, pid, status);
73 });
74 return init;
75 }
76 bool startSpawnedProcess(int argc, char* argv[], int& exit_status) override
77 {
79 std::optional<mp::SocketId> socket{m_process->checkSpawned(argc, argv)};
80 if (!socket) {
81 return false;
82 }
83 IgnoreCtrlC(strprintf("[%s] SIGINT received — waiting for parent to shut down.\n", m_exe_name));
84 m_protocol->serve(m_init, [&] { return m_protocol->makeStream(*socket); } );
86 return true;
87 }
88 std::unique_ptr<interfaces::Init> connectAddress(std::string& address) override
89 {
90 if (address.empty() || address == "0") return nullptr;
91 mp::SocketId fd;
92 if (address == "auto") {
93 // Treat "auto" the same as "unix" except don't treat it an as error
94 // if the connection is not accepted. Just return null so the caller
95 // can work offline without a connection, or spawn a new
96 // bitcoin-node process and connect to it.
97 address = "unix";
98 try {
99 fd = m_process->connect(gArgs.GetDataDirNet(), "bitcoin-node", address);
100 } catch (const std::system_error& e) {
101 // If connection type is auto and socket path isn't accepting connections, or doesn't exist, catch the error and return null;
102 if (e.code() == std::errc::connection_refused || e.code() == std::errc::no_such_file_or_directory || e.code() == std::errc::not_a_directory) {
103 return nullptr;
104 }
105 throw;
106 } catch (const std::invalid_argument&) {
107 // Catch 'Unix address path "..." exceeded maximum socket path length' error
108 return nullptr;
109 }
110 } else {
111 fd = m_process->connect(gArgs.GetDataDirNet(), "bitcoin-node", address);
112 }
113 return m_protocol->connect(m_protocol->makeStream(fd));
114 }
115 void listenAddress(ListenAddress& listen_address) override
116 {
117 mp::SocketId fd = m_process->bind(gArgs.GetDataDirNet(), m_exe_name, listen_address.address);
118 m_protocol->listen(fd, m_init, listen_address.max_connections);
119 }
120 void disconnectIncoming() override
121 {
122 m_protocol->disconnectIncoming();
123 }
124 void addCleanup(std::type_index type, void* iface, std::function<void()> cleanup) override
125 {
126 m_protocol->addCleanup(type, iface, std::move(cleanup));
127 }
128 Context& context() override { return m_protocol->context(); }
129 const char* m_exe_name;
130 const char* m_process_argv0;
131 interfaces::Init& m_init;
132 std::unique_ptr<Protocol> m_protocol;
133 std::unique_ptr<Process> m_process;
134};
135} // namespace
136} // namespace ipc
137
138namespace interfaces {
139std::unique_ptr<Ipc> MakeIpc(const char* exe_name, const char* process_argv0, Init& init)
140{
141 return std::make_unique<ipc::IpcImpl>(exe_name, process_argv0, init);
142}
143} // namespace interfaces
ArgsManager gArgs
Definition args.cpp:38
int exit_status
return EXIT_SUCCESS
fs::path GetDataDirNet() const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Get data directory path with appended network identifier.
Definition args.cpp:328
Initial interface created when a process is first started, and used to give and get access to other i...
Definition init.h:39
Interface providing access to interprocess-communication (IPC) functionality.
Definition ipc.h:55
const char * m_exe_name
Definition protocol.cpp:146
is a home for public enum and struct type definitions that are used internally by ipc code,...
#define LogDebug(category,...)
Definition log.h:154
Definition basic.cpp:11
std::unique_ptr< Ipc > MakeIpc(const char *exe_name, const char *process_argv0, Init &init)
Return implementation of Ipc interface.
std::unique_ptr< Protocol > MakeCapnpProtocol(const char *exe_name)
Definition protocol.cpp:160
Definition ipc.h:17
std::unique_ptr< Process > MakeProcess()
Constructor for Process interface.
Definition process.cpp:157
int SocketId
Definition util.h:27
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.
Definition time.h:82
WalletContext context