Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
websocket_channel.hpp
Go to the documentation of this file.
1#pragma once
2
3// WebSocketChannel — RFC 6455 MessageChannel over TcpStream.
4//
5// Scope:
6// - Client handshake: `Upgrade: websocket`, Sec-WebSocket-Key / Accept
7// validation (SHA-1 + base64 via pulp::runtime::crypto).
8// - Server handshake: parse client upgrade, echo a 101 Switching
9// Protocols with the correct Sec-WebSocket-Accept.
10// - Frames: text (0x1), binary (0x2), close (0x8), ping (0x9),
11// pong (0xA). Control frames (close/ping/pong) are handled
12// internally; ping triggers an automatic pong response.
13// - 7/16/64-bit payload length. Client frames are masked (per the
14// RFC "MUST"); server frames are unmasked.
15//
16// Out of scope:
17// - Extension negotiation (permessage-deflate etc.)
18// - Fragmented messages across multiple frames (accepted but not
19// emitted; see implementation notes)
20// - TLS — for `wss://`, feed a TLS-wrapped TcpStream or use the
21// forthcoming SecureTcpStream work.
22//
23// Threading: the channel spins up one reader thread that dispatches
24// completed messages via the provided `MessageExecutor` (or inline on
25// the reader thread when none is set). `send()` is thread-safe and
26// serializes writes to the underlying TcpStream via an internal mutex.
27
30
31#include <atomic>
32#include <condition_variable>
33#include <cstdint>
34#include <memory>
35#include <mutex>
36#include <optional>
37#include <string>
38#include <string_view>
39#include <thread>
40
41namespace pulp::runtime {
42
50
54 std::size_t max_payload = 16u * 1024u * 1024u;
55
61 std::size_t max_message = 64u * 1024u * 1024u;
62};
63
64class WebSocketChannel : public MessageChannel {
65public:
69 static std::unique_ptr<WebSocketChannel> connect(
70 std::unique_ptr<TcpStream> tcp,
71 std::string_view host,
72 std::string_view path = "/",
73 WebSocketOptions options = {});
74
79 static std::unique_ptr<WebSocketChannel> accept(
80 std::unique_ptr<TcpStream> tcp,
81 WebSocketOptions options = {});
82
84
85 // MessageChannel interface
86 bool send(const std::uint8_t* data, std::size_t size) override;
87 bool send_text(std::string_view text) override;
88 void on_message(MessageCallback callback) override;
89 void on_closed(ChannelClosedCallback callback) override;
90 void on_error(ChannelErrorCallback callback) override;
91 void close() override;
92 bool is_open() const override;
93
96 static std::string compute_accept_key(std::string_view client_key);
97
98private:
99 enum class Role : uint8_t { Client, Server };
100
101 WebSocketChannel(std::unique_ptr<TcpStream> tcp, Role role,
102 WebSocketOptions options);
103
104 bool send_frame(uint8_t opcode, const std::uint8_t* data, std::size_t size);
105 void reader_main();
106 void fire_error(std::string_view reason);
107 void fire_closed();
108 void dispatch(std::function<void()> task);
109
110 std::unique_ptr<TcpStream> tcp_;
111 Role role_;
112 WebSocketOptions options_;
113
114 mutable std::mutex mutex_;
115 std::mutex write_mutex_;
116 std::atomic<bool> open_{false};
117 std::atomic<bool> closed_fired_{false};
118 std::thread reader_;
119
120 MessageCallback on_message_;
121 ChannelClosedCallback on_closed_;
122 ChannelErrorCallback on_error_;
123};
124
125} // namespace pulp::runtime
MessageChannel(const MessageChannel &)=delete
Definition websocket_channel.hpp:64
static std::unique_ptr< WebSocketChannel > connect(std::unique_ptr< TcpStream > tcp, std::string_view host, std::string_view path="/", WebSocketOptions options={})
Perform a client handshake over tcp, then start the reader.
bool send(const std::uint8_t *data, std::size_t size) override
Send a message.
void close() override
Close the channel. Idempotent. Fires the closed callback.
bool is_open() const override
Whether the channel is currently usable.
void on_message(MessageCallback callback) override
Install / replace callbacks.
void on_closed(ChannelClosedCallback callback) override
bool send_text(std::string_view text) override
static std::unique_ptr< WebSocketChannel > accept(std::unique_ptr< TcpStream > tcp, WebSocketOptions options={})
Perform a server-side handshake over an already-accepted tcp connection.
static std::string compute_accept_key(std::string_view client_key)
Expose the handshake Sec-WebSocket-Accept for debugging and for tests that want to verify RFC 6455 co...
void on_error(ChannelErrorCallback callback) override
Bounded event contracts shared by host ingress and graph-authored nodes.
Definition anticipation_eligibility.hpp:9
Definition generated_event_source.hpp:33
std::function< void()> ChannelClosedCallback
Called once when the channel transitions to a closed state — either the peer closed,...
Definition message_channel.hpp:55
std::function< void(const Message &message)> MessageCallback
Called when the channel receives a complete message.
Definition message_channel.hpp:51
std::function< void(std::string_view reason)> ChannelErrorCallback
Called when a transport-level error occurs.
Definition message_channel.hpp:60
std::function< void(std::function< void()>)> MessageExecutor
Executor used to dispatch callbacks off whichever worker thread the channel runs internally.
Definition message_channel.hpp:64
Options for WebSocketChannel construction.
Definition websocket_channel.hpp:44
std::size_t max_payload
Maximum inbound payload size (bytes).
Definition websocket_channel.hpp:54
MessageExecutor executor
Executor used to dispatch on_message, on_closed, on_error.
Definition websocket_channel.hpp:49
std::size_t max_message
Maximum total size (bytes) of a message reassembled across continuation frames.
Definition websocket_channel.hpp:61