master
h 265 lines 12 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #ifndef NETDATA_WEBSOCKET_INTERNAL_H
4 #define NETDATA_WEBSOCKET_INTERNAL_H
5
6 #include "websocket.h"
7
8 // Maximum number of WebSocket threads
9 #define WEBSOCKET_MAX_THREADS 2
10
11 #define WORKERS_WEBSOCKET_POLL 0
12 #define WORKERS_WEBSOCKET_CMD_READ 1
13 #define WORKERS_WEBSOCKET_CMD_EXIT 2
14 #define WORKERS_WEBSOCKET_CMD_ADD 3
15 #define WORKERS_WEBSOCKET_CMD_DEL 4
16 #define WORKERS_WEBSOCKET_CMD_BROADCAST 5
17 #define WORKERS_WEBSOCKET_CMD_UNKNOWN 6
18 #define WORKERS_WEBSOCKET_SOCK_RECEIVE 7
19 #define WORKERS_WEBSOCKET_SOCK_SEND 8
20 #define WORKERS_WEBSOCKET_SOCK_ERROR 9
21 #define WORKERS_WEBSOCKET_CLIENT_TIMEOUT 10
22 #define WORKERS_WEBSOCKET_SEND_PING 11
23 #define WORKERS_WEBSOCKET_CLIENT_STUCK 12
24
25 #define WORKERS_WEBSOCKET_INCOMPLETE_FRAME 13
26 #define WORKERS_WEBSOCKET_COMPLETE_FRAME 14
27 #define WORKERS_WEBSOCKET_MESSAGE 15
28 #define WORKERS_WEBSOCKET_MSG_PING 16
29 #define WORKERS_WEBSOCKET_MSG_PONG 17
30 #define WORKERS_WEBSOCKET_MSG_CLOSE 18
31 #define WORKERS_WEBSOCKET_MSG_INVALID 19
32
33 // Forward declaration for thread structure
34 struct websocket_thread;
35
36 #include "websocket-compression.h"
37
38 // WebSocket protocol constants
39 #define WS_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
40
41 // WebSocket frame constants
42 #define WS_FIN 0x80 // Final frame bit
43 #define WS_RSV1 0x40 // Reserved bit 1 (used for compression)
44 #define WS_MASK 0x80 // Mask bit
45
46 // Frame size limits for protection against DoS and browser compatibility
47 #define WS_MAX_INCOMING_FRAME_SIZE (20ULL * 1024 * 1024) // 20MB max incoming frame size (browsers have ~16MiB)
48 #define WS_MAX_OUTGOING_FRAME_SIZE (4ULL * 1024 * 1024) // 4MB max outgoing frame size for browser compatibility
49 #define WS_MAX_DECOMPRESSED_SIZE (200ULL * 1024 * 1024) // 200MB max inbound uncompressed message
50 #define WS_DEBUG_DUMP_BYTES 32 // max payload bytes captured in debug hex dumps
51
52 // WebSocket timeout constants (in seconds)
53 #define WS_PERIODIC_PING_INTERVAL 60 // Send periodic ping every 60 seconds
54 #define WS_IDLE_CHECK_INTERVAL 120 // Check if client is idle after 120 seconds
55 #define WS_INACTIVITY_TIMEOUT 1800 // Disconnect after 30 minutes (1800 seconds) of inactivity
56 #define WS_CLOSING_STATE_TIMEOUT 5 // Force close if stuck in closing state for 5 seconds
57
58 // WebSocket frame header structure - used for processing frame headers
59 typedef struct websocket_frame_header {
60 unsigned char fin:1;
61 unsigned char rsv1:1;
62 unsigned char rsv2:1;
63 unsigned char rsv3:1;
64 unsigned char opcode:4;
65 unsigned char mask:1;
66 unsigned char len:7;
67
68 unsigned char mask_key[4]; // Masking key (if present)
69 size_t frame_size; // Size of the entire frame
70 size_t header_size; // Size of the header
71 size_t payload_length; // Length of the payload data
72 void *payload; // Pointer to the payload data
73 } WEBSOCKET_FRAME_HEADER;
74
75 // Buffer for message data (used for reassembly of fragmented messages)
76 typedef struct websocket_buffer {
77 char *data; // Buffer holding message data
78 size_t length; // Current buffer length
79 size_t size; // Allocated buffer size
80 } WS_BUF;
81
82 // Forward declaration for client structure
83 struct websocket_server_client;
84
85 // Function prototypes for buffer handling
86
87 // Message and payload processing functions
88 void websocket_client_message_reset(struct websocket_server_client *wsc);
89 bool websocket_client_process_message(struct websocket_server_client *wsc);
90 bool websocket_client_decompress_message(struct websocket_server_client *wsc);
91
92 // Additional helper functions
93 bool websocket_frame_is_control_opcode(WEBSOCKET_OPCODE opcode);
94 bool websocket_validate_utf8(const char *data, size_t length);
95
96 #include "websocket-buffer.h"
97
98 // WebSocket connection context - full structure definition
99 struct websocket_server_client {
100 WEBSOCKET_STATE state;
101 ND_SOCK sock; // Socket with SSL abstraction
102 uint32_t id; // Unique client ID
103 size_t max_message_size;
104 size_t max_outbound_frame_size; // Maximum size of outgoing frames for this client
105 time_t connected_t; // Connection timestamp
106 time_t last_activity_t; // Last activity timestamp
107
108 // Buffer for I/O data
109 struct circular_buffer in_buffer; // Incoming raw data (circular buffer)
110 struct circular_buffer out_buffer; // Outgoing raw data (circular buffer)
111 size_t next_frame_size; // The size of the next complete frame to read
112
113 // Connection info
114 char client_ip[INET6_ADDRSTRLEN];
115 char client_port[NI_MAXSERV];
116 WEBSOCKET_PROTOCOL protocol; // The negotiated subprotocol
117
118 // Authentication info
119 USER_AUTH user_auth; // Authentication information copied from web_client
120
121 // Thread management
122 struct websocket_thread *wth; // The thread handling this client
123 struct websocket_server_client *prev; // Linked list for thread's client management
124 struct websocket_server_client *next; // Linked list for thread's client management
125
126 // Message processing state
127 WS_BUF payload; // Pre-allocated buffer for message data
128 WS_BUF u_payload; // Pre-allocated buffer for uncompressed message data
129 WS_BUF c_payload; // Pre-allocated buffer for outbound compressed data
130 WEBSOCKET_OPCODE opcode; // Current message opcode
131 bool is_compressed; // Whether the current message is compressed
132 bool message_complete; // Whether the current message is complete
133 size_t message_id; // Sequential ID for messages, starting from 0
134 size_t frame_id; // Sequential ID for frames within current message
135
136 // Compression state
137 WEBSOCKET_COMPRESSION_CTX compression;
138
139 // Connection closing state
140 bool flush_and_remove_client; // Flag to indicate we're just flushing buffer before close
141
142 // Protocol handler callbacks
143 void (*on_connect)(struct websocket_server_client *wsc); // Called when a client is successfully connected
144 void (*on_message)(struct websocket_server_client *wsc, const char *message, size_t length, WEBSOCKET_OPCODE opcode); // Called when a message is received
145 void (*on_close)(struct websocket_server_client *wsc, WEBSOCKET_CLOSE_CODE code, const char *reason); // Called BEFORE sending close frame
146 void (*on_disconnect)(struct websocket_server_client *wsc); // Called when a client is disconnected
147
148 // User data for application use
149 void *user_data;
150 };
151
152 // Forward declarations for websocket client
153 typedef struct websocket_server_client WS_CLIENT;
154
155 // WebSocket thread structure
156 typedef struct websocket_thread {
157 size_t id; // Thread ID
158 pid_t tid;
159
160 struct {
161 ND_THREAD *thread; // Thread handle
162 bool running; // Thread running status
163 SPINLOCK spinlock; // Thread spinlock
164 };
165
166 size_t clients_current; // Current number of clients in the thread
167 SPINLOCK clients_spinlock; // Spinlock for client operations
168 struct websocket_server_client *clients; // Head of the clients double-linked list
169
170 nd_poll_t *ndpl; // Poll instance
171
172 struct {
173 int pipe[2]; // Command pipe [0] = read, [1] = write
174 char *buffer; // Reusable scratch buffer for command payloads
175 size_t buffer_size;
176 } cmd;
177
178 } WEBSOCKET_THREAD;
179
180 // Global array of WebSocket threads
181 extern WEBSOCKET_THREAD websocket_threads[WEBSOCKET_MAX_THREADS];
182
183 // Define JudyL typed structure for WebSocket clients
184 DEFINE_JUDYL_TYPED(WS_CLIENTS, struct websocket_server_client *);
185
186 // WebSocket thread commands
187 #define WEBSOCKET_THREAD_CMD_EXIT 1
188 #define WEBSOCKET_THREAD_CMD_ADD_CLIENT 2
189 #define WEBSOCKET_THREAD_CMD_REMOVE_CLIENT 3
190 #define WEBSOCKET_THREAD_CMD_BROADCAST 4
191
192 // Buffer size definitions for WebSocket operations
193 #define WEBSOCKET_RECEIVE_BUFFER_SIZE 4096 // Size used for network read operations
194
195 // Initial buffer sizes
196 #define WEBSOCKET_IN_BUFFER_INITIAL_SIZE 8192UL // Initial size for incoming data buffer
197 #define WEBSOCKET_OUT_BUFFER_INITIAL_SIZE 16384UL // Initial size for outgoing data buffer
198 #define WEBSOCKET_PAYLOAD_INITIAL_SIZE 8192UL // Initial size for message payload buffer
199 #define WEBSOCKET_UNPACKED_INITIAL_SIZE 16384UL // Initial size for uncompressed message buffer
200
201 // Maximum buffer sizes to protect against memory exhaustion
202 #define WEBSOCKET_IN_BUFFER_MAX_SIZE (20UL * 1024 * 1024) // 10MiB max for incoming data buffer
203 #define WEBSOCKET_OUT_BUFFER_MAX_SIZE (20UL * 1024 * 1024) // 10MiB max for outgoing data buffer
204
205 NEVERNULL
206 WS_CLIENT *websocket_client_create(void);
207
208 // Thread management
209 void websocket_threads_init(void);
210 void websocket_threads_join(void);
211 bool websocket_thread_send_command(WEBSOCKET_THREAD *wth, uint8_t cmd, uint32_t id);
212 bool websocket_thread_send_broadcast(WEBSOCKET_THREAD *wth, WEBSOCKET_OPCODE opcode, const char *message);
213 void websocket_thread(void *ptr);
214 void websocket_thread_enqueue_client(WEBSOCKET_THREAD *wth, struct websocket_server_client *wsc);
215 bool websocket_thread_update_client_poll_flags(struct websocket_server_client *wsc);
216
217 // Client registry internals
218 void websocket_client_free(WS_CLIENT *wsc);
219 bool websocket_client_register(struct websocket_server_client *wsc);
220 void websocket_client_unregister(struct websocket_server_client *wsc);
221 struct websocket_server_client *websocket_client_find_by_id(size_t id);
222
223 // Utility functions
224 // Validates a WebSocket close code according to RFC 6455
225 bool websocket_validate_close_code(uint16_t code);
226 void websocket_debug(WS_CLIENT *wsc, const char *format, ...);
227 void websocket_info(WS_CLIENT *wsc, const char *format, ...);
228 void websocket_error(WS_CLIENT *wsc, const char *format, ...);
229 void websocket_dump_debug(WS_CLIENT *wsc, const char *payload, size_t payload_length, const char *format, ...);
230
231 // Frame processing result codes
232 typedef enum {
233 WS_FRAME_ERROR = -1, // Processing error occurred
234 WS_FRAME_COMPLETE = 0, // Frame processing completed successfully
235 WS_FRAME_NEED_MORE_DATA = 1, // Need more data to complete frame processing
236 WS_FRAME_MESSAGE_READY = 2 // A complete message is ready to be processed
237 } WEBSOCKET_FRAME_RESULT;
238
239 // Centralized protocol validation functions
240 void websocket_protocol_exception(WS_CLIENT *wsc, WEBSOCKET_CLOSE_CODE reason_code, const char *reason_txt);
241
242 // Protocol receiver functions - websocket-protocol-rcv.c
243 ssize_t websocket_protocol_got_data(WS_CLIENT *wsc, char *data, size_t length);
244
245 // Payload sender - breaks large messages into multiple frames
246 int websocket_protocol_send_payload(
247 WS_CLIENT *wsc, const char *payload,
248 size_t payload_len, WEBSOCKET_OPCODE opcode, bool use_compression);
249 int websocket_protocol_send_text(WS_CLIENT *wsc, const char *text);
250 int websocket_protocol_send_binary(WS_CLIENT *wsc, const void *data, size_t length);
251 int websocket_protocol_send_close(WS_CLIENT *wsc, WEBSOCKET_CLOSE_CODE code, const char *reason);
252 int websocket_protocol_send_ping(WS_CLIENT *wsc, const char *data, size_t length);
253 int websocket_protocol_send_pong(WS_CLIENT *wsc, const char *data, size_t length);
254
255 // IO functions from old implementation - will be refactored
256 ssize_t websocket_receive_data(struct websocket_server_client *wsc);
257 ssize_t websocket_write_data(struct websocket_server_client *wsc);
258
259 // WebSocket message sending functions
260 int websocket_send_message(WS_CLIENT *wsc, const char *message, size_t length, WEBSOCKET_OPCODE opcode);
261 int websocket_broadcast_message(const char *message, WEBSOCKET_OPCODE opcode);
262
263 bool websocket_protocol_parse_header_from_buffer(const char *buffer, size_t length,
264 WEBSOCKET_FRAME_HEADER *header);
265 #endif // NETDATA_WEBSOCKET_INTERNAL_H