Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
interprocess_connection.hpp
Go to the documentation of this file.
1#pragma once
2
3// InterprocessConnection — bidirectional IPC over named pipes, TCP sockets,
4// or credential-bearing OS-local sockets.
5// Provides length-prefixed message framing, connection lifecycle callbacks,
6// and background receive thread. Used for crash-isolated plugin scanning,
7// multi-process architectures, and standalone↔plugin communication.
8
11#include <string>
12#include <string_view>
13#include <vector>
14#include <functional>
15#include <memory>
16#include <optional>
17#include <atomic>
18#include <thread>
19#include <mutex>
20#include <cstdint>
21#include <chrono>
22
23namespace pulp::events {
24
27
30
34public:
37
38 // ── Connection lifecycle ────────────────────────────────────────────
39
45 bool connect(
46 std::string_view name,
48 std::chrono::milliseconds timeout = {});
49
54 bool create_server(std::string_view name, IpcTransport transport = IpcTransport::NamedPipe,
55 int timeout_ms = 0);
56
59 std::string server_bind_address() const;
60
63 bool attach_inherited_local_socket(std::intptr_t handle);
64
66 void disconnect();
67
69 bool is_connected() const { return state_.load() == IpcState::Connected; }
70
72 IpcState state() const { return state_.load(); }
73
76 std::optional<runtime::LocalPeerCredentials> local_peer_credentials() const;
77
78 // ── Messaging ───────────────────────────────────────────────────────
79
82 bool send_message(const void* data, size_t size);
83
85 bool send_message(std::string_view message);
86
91 void set_max_message_bytes(std::size_t bytes);
92 std::size_t max_message_bytes() const {
93 return max_message_bytes_.load(std::memory_order_relaxed);
94 }
95
99 void set_write_timeout(std::chrono::milliseconds timeout);
100
104 void set_frame_read_timeout(std::chrono::milliseconds timeout);
105
108 void set_secure_receive_buffer(bool enabled);
109
110 // ── Callbacks (override or set) ─────────────────────────────────────
111
113 virtual void connection_made() {}
114
116 virtual void connection_lost() {}
117
119 virtual void message_received(const void* data, size_t size) {
120 (void)data; (void)size;
121 }
122
124 virtual void message_received(std::string_view message) {
125 (void)message;
126 }
127
133 std::function<void()> on_connected;
134 std::function<void()> on_disconnected;
135 std::function<void(const void*, size_t)> on_message;
136 std::function<void(std::string_view)> on_text_message;
137
138 void set_on_connected(std::function<void()> callback);
139 void set_on_disconnected(std::function<void()> callback);
140 void set_on_message(std::function<void(const void*, size_t)> callback);
141 void set_on_text_message(std::function<void(std::string_view)> callback);
142
143 // No copy
146
147 friend class InterprocessConnectionServer; // Needs to inject accepted sockets
148
149private:
150 struct Impl;
151 std::shared_ptr<Impl> impl_;
152 std::atomic<IpcState> state_{IpcState::Disconnected};
153 std::atomic<bool> running_{false};
154 std::atomic<std::uint64_t> connection_generation_{0};
155 std::atomic<std::uint64_t> read_generation_{0};
156 std::atomic<std::size_t> max_message_bytes_{64u * 1024u * 1024u};
157 std::atomic<std::int64_t> write_timeout_ms_{0};
158 std::atomic<std::int64_t> frame_read_timeout_ms_{0};
159 std::atomic<bool> secure_receive_buffer_{false};
160 std::atomic<bool> write_poisoned_{false};
161 std::atomic<bool> defer_first_dispatch_until_callback_{false};
162 std::shared_ptr<std::atomic<bool>> first_dispatch_gate_;
163 mutable std::mutex callback_mutex_;
164 runtime::AliveToken alive_;
165
166 void disconnect_impl(bool destroying);
167 void release_first_dispatch_gate();
168 void start_read_thread(bool allow_active_disconnect_owner = false,
169 std::uint64_t expected_connection_generation = 0);
170 void read_loop(std::uint64_t generation);
171};
172
176public:
179
183 bool start(std::string_view name, IpcTransport transport = IpcTransport::Socket);
184
186 void stop();
187
189 void set_max_message_bytes(std::size_t bytes);
190 void set_write_timeout(std::chrono::milliseconds timeout);
191 void set_frame_read_timeout(std::chrono::milliseconds timeout);
192
194 bool is_running() const { return running_.load(); }
195
198 std::uint16_t bound_port() const;
199
202 std::string bound_address() const;
203
206 virtual void client_connected(std::unique_ptr<InterprocessConnection> connection);
207
209 std::function<void(std::unique_ptr<InterprocessConnection>)> on_client_connected;
210
211 // No copy
214
215private:
216 std::atomic<bool> running_{false};
217 std::atomic<std::size_t> max_message_bytes_{64u * 1024u * 1024u};
218 std::atomic<std::int64_t> write_timeout_ms_{0};
219 std::atomic<std::int64_t> frame_read_timeout_ms_{0};
220 std::thread accept_thread_;
221 std::vector<std::unique_ptr<InterprocessConnection>> clients_;
222 struct ServerImpl;
223 std::unique_ptr<ServerImpl> server_impl_;
224};
225
226} // namespace pulp::events
void set_write_timeout(std::chrono::milliseconds timeout)
void stop()
Stop listening and disconnect all clients.
InterprocessConnectionServer & operator=(const InterprocessConnectionServer &)=delete
void set_max_message_bytes(std::size_t bytes)
Apply a framing ceiling to every subsequently accepted connection.
std::function< void(std::unique_ptr< InterprocessConnection >)> on_client_connected
Lambda callback alternative.
Definition interprocess_connection.hpp:209
bool start(std::string_view name, IpcTransport transport=IpcTransport::Socket)
Start listening on the given name.
std::string bound_address() const
Actual bound IPv4 address after binding (e.g.
std::uint16_t bound_port() const
Actual TCP port after binding, including an OS-assigned port requested with host:0.
InterprocessConnectionServer(const InterprocessConnectionServer &)=delete
virtual void client_connected(std::unique_ptr< InterprocessConnection > connection)
Called when a new client connects.
bool is_running() const
Whether the server is running.
Definition interprocess_connection.hpp:194
void set_frame_read_timeout(std::chrono::milliseconds timeout)
void set_frame_read_timeout(std::chrono::milliseconds timeout)
Bound a frame once its first byte arrives.
void set_on_text_message(std::function< void(std::string_view)> callback)
virtual void connection_made()
Called when a connection is established.
Definition interprocess_connection.hpp:113
InterprocessConnection(const InterprocessConnection &)=delete
virtual void message_received(std::string_view message)
Convenience: called with string view for text messages.
Definition interprocess_connection.hpp:124
void disconnect()
Disconnect and clean up.
void set_max_message_bytes(std::size_t bytes)
Override the framing ceiling before connecting or accepting work.
std::size_t max_message_bytes() const
Definition interprocess_connection.hpp:92
bool send_message(const void *data, size_t size)
Send a message (length-prefixed).
std::function< void(const void *, size_t)> on_message
Definition interprocess_connection.hpp:135
IpcState state() const
Current state.
Definition interprocess_connection.hpp:72
void set_write_timeout(std::chrono::milliseconds timeout)
Apply a blocking write deadline for socket transports.
std::function< void()> on_connected
Lambda-based callbacks (alternative to overriding).
Definition interprocess_connection.hpp:133
std::string server_bind_address() const
Address the most recent socket create_server() bound its listener to (e.g.
friend class InterprocessConnectionServer
Definition interprocess_connection.hpp:147
bool connect(std::string_view name, IpcTransport transport=IpcTransport::NamedPipe, std::chrono::milliseconds timeout={})
Connect as client to a named pipe, TCP socket, or OS-local socket.
std::optional< runtime::LocalPeerCredentials > local_peer_credentials() const
Kernel-observed credentials for the process on the other end of a connected local socket.
void set_on_message(std::function< void(const void *, size_t)> callback)
void set_on_disconnected(std::function< void()> callback)
bool send_message(std::string_view message)
Send a string message.
void set_secure_receive_buffer(bool enabled)
Securely clear each received frame buffer after callbacks return.
bool attach_inherited_local_socket(std::intptr_t handle)
Attach to a duplicate of an already-connected OS-local socket handle.
bool create_server(std::string_view name, IpcTransport transport=IpcTransport::NamedPipe, int timeout_ms=0)
Create a server that listens for one client connection.
std::function< void(std::string_view)> on_text_message
Definition interprocess_connection.hpp:136
bool is_connected() const
Whether currently connected.
Definition interprocess_connection.hpp:69
std::function< void()> on_disconnected
Definition interprocess_connection.hpp:134
InterprocessConnection & operator=(const InterprocessConnection &)=delete
virtual void connection_lost()
Called when the connection is lost.
Definition interprocess_connection.hpp:116
virtual void message_received(const void *data, size_t size)
Called when a message is received. Called on the background read thread.
Definition interprocess_connection.hpp:119
void set_on_connected(std::function< void()> callback)
Definition child_process_manager.hpp:18
IpcState
Connection state.
Definition interprocess_connection.hpp:29
@ Connected
Definition interprocess_connection.hpp:29
@ Error
Definition interprocess_connection.hpp:29
@ Connecting
Definition interprocess_connection.hpp:29
@ Disconnected
Definition interprocess_connection.hpp:29
IpcTransport
Transport type for IPC.
Definition interprocess_connection.hpp:26
@ NamedPipe
Definition interprocess_connection.hpp:26
@ Socket
Definition interprocess_connection.hpp:26
@ LocalSocket
Definition interprocess_connection.hpp:26