Bitcoin Core 32.99.0
P2P Digital Currency
Loading...
Searching...
No Matches
protocol.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 <interfaces/init.h>
6#include <ipc/capnp/context.h>
7#include <ipc/capnp/init.capnp.h>
8#include <ipc/capnp/init.capnp.proxy.h>
10#include <ipc/exception.h>
11#include <ipc/protocol.h>
12#include <kj/async.h>
13#include <mp/proxy-io.h>
14#include <mp/proxy-types.h>
15#include <mp/util.h>
16#include <util/log.h>
17#include <util/threadnames.h>
18
19#include <cassert>
20#include <cerrno>
21#include <future>
22#include <list>
23#include <memory>
24#include <mutex>
25#include <optional>
26#include <string>
27#include <sys/socket.h>
28#include <system_error>
29#include <thread>
30
31namespace ipc {
32namespace capnp {
33namespace {
34
36{
39
40 // Info, Warning, and Error are logged unconditionally
41 return mp::Log::Info;
42}
43
44void IpcLogFn(mp::LogMessage message)
45{
46 switch (message.level) {
47 case mp::Log::Trace:
48 LogTrace(BCLog::IPC, "%s", message.message);
49 return;
50 case mp::Log::Debug:
51 LogDebug(BCLog::IPC, "%s", message.message);
52 return;
53 case mp::Log::Info:
54 LogInfo("ipc: %s", message.message);
55 return;
57 LogWarning("ipc: %s", message.message);
58 return;
59 case mp::Log::Error:
60 LogError("ipc: %s", message.message);
61 return;
62 case mp::Log::Raise:
63 LogError("ipc: %s", message.message);
64 throw Exception(message.message);
65 } // no default case, so the compiler can warn about missing cases
66
67 // Be conservative and assume that if MP ever adds a new log level, it
68 // should only be shown at our most verbose level.
69 LogTrace(BCLog::IPC, "%s", message.message);
70}
71
72class CapnpProtocol : public Protocol
73{
74public:
75 CapnpProtocol(const char* exe_name) : m_exe_name{exe_name} {}
76 ~CapnpProtocol() noexcept(true)
77 {
78 m_loop_ref.reset();
79 if (m_loop_thread.joinable()) m_loop_thread.join();
80 assert(!m_loop);
81 };
82 std::unique_ptr<interfaces::Init> connect(mp::Stream stream) override
83 {
84 startLoop();
85 return mp::ConnectStream<messages::Init>(*m_loop, std::move(stream));
86 }
87 void listen(mp::SocketId listen_fd, interfaces::Init& init, std::optional<size_t> max_connections) override
88 {
89 startLoop();
90 if (::listen(listen_fd, /*backlog=*/5) != 0) {
91 throw std::system_error(errno, std::system_category());
92 }
93 mp::ListenConnections<messages::Init>(*m_loop, listen_fd, init, max_connections);
94 }
95 void serve(interfaces::Init& init, const std::function<mp::Stream()>& make_stream) override
96 {
97 assert(!m_loop);
99 mp::LogOptions opts = {
100 .log_fn = IpcLogFn,
101 .log_level = GetRequestedIPCLogLevel()
102 };
103 m_loop.emplace(m_exe_name, std::move(opts), &m_context);
104 mp::ServeStream<messages::Init>(*m_loop, make_stream(), init);
105 m_parent_connection = &m_loop->m_incoming_connections.back();
106 m_loop->loop();
107 m_loop.reset();
108 }
109 void disconnectIncoming() override
110 {
111 if (!m_loop) return;
112 // Delete incoming connections, except the connection to a parent
113 // process (if there is one), since a parent process should be able to
114 // monitor and control this process, even during shutdown.
115 m_loop->sync([&] {
116 std::erase_if(m_loop->m_incoming_connections, [this](mp::Connection& c) { return &c != m_parent_connection; });
117 });
118 }
119 mp::Stream makeStream(mp::SocketId socket) override
120 {
121 startLoop();
122 return mp::MakeStream(*m_loop, socket);
123 }
124 void addCleanup(std::type_index type, void* iface, std::function<void()> cleanup) override
125 {
126 mp::ProxyTypeRegister::types().at(type)(iface).cleanup_fns.emplace_back(std::move(cleanup));
127 }
128 Context& context() override { return m_context; }
129 void startLoop()
130 {
131 if (m_loop) return;
132 std::promise<void> promise;
133 m_loop_thread = std::thread([&] {
134 util::ThreadRename("capnp-loop");
135 mp::LogOptions opts = {
136 .log_fn = IpcLogFn,
137 .log_level = GetRequestedIPCLogLevel()
138 };
139 m_loop.emplace(m_exe_name, std::move(opts), &m_context);
140 m_loop_ref.emplace(*m_loop);
141 promise.set_value();
142 m_loop->loop();
143 m_loop.reset();
144 });
145 promise.get_future().wait();
146 }
147 const char* m_exe_name;
148 Context m_context;
150 std::optional<mp::EventLoop> m_loop;
154 std::optional<mp::EventLoopRef> m_loop_ref;
157 std::thread m_loop_thread;
158};
159} // namespace
160
161std::unique_ptr<Protocol> MakeCapnpProtocol(const char* exe_name) { return std::make_unique<CapnpProtocol>(exe_name); }
162} // namespace capnp
163} // namespace ipc
Initial interface created when a process is first started, and used to give and get access to other i...
Definition init.h:39
Object holding network & rpc state associated with either an incoming server connection,...
Definition proxy-io.h:446
std::thread m_loop_thread
Definition protocol.cpp:157
const char * m_exe_name
Definition protocol.cpp:147
mp::Connection * m_parent_connection
Connection to parent, if this is a child process spawned by a parent process.
Definition protocol.cpp:156
std::optional< mp::EventLoop > m_loop
EventLoop object which manages I/O events for all connections.
Definition protocol.cpp:150
std::optional< mp::EventLoopRef > m_loop_ref
Reference to the same EventLoop.
Definition protocol.cpp:154
Context m_context
Definition protocol.cpp:148
#define LogWarning(...)
Definition log.h:137
#define LogInfo(...)
Definition log.h:136
#define LogError(...)
Definition log.h:138
#define LogTrace(category,...)
Definition log.h:155
#define LogDebug(category,...)
Definition log.h:154
Definition basic.cpp:11
std::unique_ptr< Protocol > MakeCapnpProtocol(const char *exe_name)
Definition protocol.cpp:161
Definition ipc.h:17
Stream MakeStream(EventLoop &loop, SocketId socket)
Wrap a socket file descriptor as an async stream, taking ownership of the fd.
Definition proxy.cpp:50
int SocketId
Definition util.h:295
ThreadContext & CurrentThread()
Return the current thread's ThreadContext.
Definition proxy.cpp:45
std::string ThreadName(const char *exe_name)
Format current thread name as "{exe_name}-{$pid}/{thread_name}-{$tid}".
Definition util.cpp:197
kj::Own< kj::AsyncIoStream > Stream
Definition util.h:292
Log
Log flags. Update stringify function if changed!
Definition proxy-io.h:133
bool ShouldDebugLog(Category)
Return whether messages with specified category should be debug logged.
bool ShouldTraceLog(Category)
Return whether messages with specified category should be trace logged.
void ThreadRename(const std::string &)
Rename a thread both in terms of an internal (in-memory) name as well as its system thread name.
Log level
The severity level of this message.
Definition proxy-io.h:150
std::string message
Message to be logged.
Definition proxy-io.h:147
LogFn log_fn
External logging callback.
Definition proxy-io.h:158
static Types & types()
std::string thread_name
Identifying string for debug.
Definition proxy-io.h:739
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.
Definition time.h:82
assert(!tx.IsCoinBase())
WalletContext context