Mercurial
comparison seobeo/seobeo.h @ 120:cbbf78b17cfa
[Seobeo][Websocket] Created Web socket client logic.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Thu, 08 Jan 2026 03:19:59 -0800 |
| parents | c39582f937e5 |
| children | 7b1719fa918c |
comparison
equal
deleted
inserted
replaced
| 119:c39582f937e5 | 120:cbbf78b17cfa |
|---|---|
| 86 extern Seobeo_Client_Response *Seobeo_Client_Request_Execute(Seobeo_Client_Request *p_req); | 86 extern Seobeo_Client_Response *Seobeo_Client_Request_Execute(Seobeo_Client_Request *p_req); |
| 87 /* Destroy request and free all resources. */ | 87 /* Destroy request and free all resources. */ |
| 88 extern void Seobeo_Client_Request_Destroy(Seobeo_Client_Request *p_req); | 88 extern void Seobeo_Client_Request_Destroy(Seobeo_Client_Request *p_req); |
| 89 /* Destroy response and free all resources. */ | 89 /* Destroy response and free all resources. */ |
| 90 extern void Seobeo_Client_Response_Destroy(Seobeo_Client_Response *p_resp); | 90 extern void Seobeo_Client_Response_Destroy(Seobeo_Client_Response *p_resp); |
| 91 | |
| 92 /** | |
| 93 * WebSocket Client API | |
| 94 * ------ | |
| 95 * | |
| 96 * # Overview | |
| 97 * | |
| 98 * A clean, easy-to-use WebSocket client library following RFC 6455. It will auto handle over 64 bits long data into a continous stream. | |
| 99 * | |
| 100 * ## Examples | |
| 101 * | |
| 102 * ### 1. Simple Text Echo | |
| 103 * | |
| 104 * ```c | |
| 105 * // Connect to WebSocket server | |
| 106 * Seobeo_WebSocket *p_ws = Seobeo_WebSocket_Connect("wss://echo.websocket.org"); | |
| 107 * if (!p_ws) | |
| 108 * { | |
| 109 * printf("Failed to connect\n"); | |
| 110 * return; | |
| 111 * } | |
| 112 * | |
| 113 * // Send text message | |
| 114 * const char *message = "Hello, WebSocket!"; | |
| 115 * Seobeo_WebSocket_Send_Text(p_ws, message); | |
| 116 * | |
| 117 * // Receive echo response | |
| 118 * Seobeo_WebSocket_Message *p_msg = Seobeo_WebSocket_Receive(p_ws); | |
| 119 * if (p_msg && p_msg->opcode == SEOBEO_WS_OPCODE_TEXT) | |
| 120 * { | |
| 121 * printf("Received: %.*s\n", (int)p_msg->length, (char*)p_msg->data); | |
| 122 * Seobeo_WebSocket_Message_Destroy(p_msg); | |
| 123 * } | |
| 124 * | |
| 125 * // Close connection | |
| 126 * Seobeo_WebSocket_Close(p_ws, 1000, "Normal closure"); | |
| 127 * Seobeo_WebSocket_Destroy(p_ws); | |
| 128 * ``` | |
| 129 * | |
| 130 * ### 2. Binary Data Transfer | |
| 131 * | |
| 132 * ```c | |
| 133 * Seobeo_WebSocket *p_ws = Seobeo_WebSocket_Connect("wss://example.com/data"); | |
| 134 * | |
| 135 * // Send binary data | |
| 136 * uint8 data[] = {0x01, 0x02, 0x03, 0xAA, 0xBB, 0xCC}; | |
| 137 * Seobeo_WebSocket_Send_Binary(p_ws, data, sizeof(data)); | |
| 138 * | |
| 139 * // Receive binary response | |
| 140 * Seobeo_WebSocket_Message *p_msg = Seobeo_WebSocket_Receive(p_ws); | |
| 141 * if (p_msg && p_msg->opcode == SEOBEO_WS_OPCODE_BINARY) | |
| 142 * { | |
| 143 * printf("Received %zu bytes\n", p_msg->length); | |
| 144 * // Process binary data... | |
| 145 * Seobeo_WebSocket_Message_Destroy(p_msg); | |
| 146 * } | |
| 147 * | |
| 148 * Seobeo_WebSocket_Destroy(p_ws); | |
| 149 * ``` | |
| 150 * | |
| 151 * ### 3. Chat Application | |
| 152 * | |
| 153 * ```c | |
| 154 * Seobeo_WebSocket *p_ws = Seobeo_WebSocket_Connect("wss://chat.example.com"); | |
| 155 * | |
| 156 * // Send chat message | |
| 157 * Seobeo_WebSocket_Send_Text(p_ws, "Hello everyone!"); | |
| 158 * | |
| 159 * // Continuous receive loop | |
| 160 * while (1) | |
| 161 * { | |
| 162 * Seobeo_WebSocket_Message *p_msg = Seobeo_WebSocket_Receive(p_ws); | |
| 163 * if (p_msg) | |
| 164 * { | |
| 165 * if (p_msg->opcode == SEOBEO_WS_OPCODE_TEXT) | |
| 166 * { | |
| 167 * printf("Chat: %.*s\n", (int)p_msg->length, (char*)p_msg->data); | |
| 168 * } | |
| 169 * Seobeo_WebSocket_Message_Destroy(p_msg); | |
| 170 * } | |
| 171 * | |
| 172 * usleep(10000); // 10ms sleep to avoid busy waiting | |
| 173 * } | |
| 174 * | |
| 175 * Seobeo_WebSocket_Destroy(p_ws); | |
| 176 * ``` | |
| 177 * | |
| 178 * ### 4. Ping/Pong Keep-Alive | |
| 179 * | |
| 180 * ```c | |
| 181 * Seobeo_WebSocket *p_ws = Seobeo_WebSocket_Connect("wss://api.example.com"); | |
| 182 * | |
| 183 * // Send ping to keep connection alive | |
| 184 * Seobeo_WebSocket_Send_Ping(p_ws, "keep-alive"); | |
| 185 * | |
| 186 * // Server will automatically receive pong responses | |
| 187 * // (pong responses are handled internally) | |
| 188 * | |
| 189 * Seobeo_WebSocket_Destroy(p_ws); | |
| 190 * ``` | |
| 191 * | |
| 192 * ### 5. Handling Different Message Types | |
| 193 * | |
| 194 * ```c | |
| 195 * Seobeo_WebSocket *p_ws = Seobeo_WebSocket_Connect("wss://example.com"); | |
| 196 * | |
| 197 * while (1) | |
| 198 * { | |
| 199 * Seobeo_WebSocket_Message *p_msg = Seobeo_WebSocket_Receive(p_ws); | |
| 200 * if (p_msg) | |
| 201 * { | |
| 202 * switch (p_msg->opcode) | |
| 203 * { | |
| 204 * case SEOBEO_WS_OPCODE_TEXT: | |
| 205 * printf("Text: %.*s\n", (int)p_msg->length, (char*)p_msg->data); | |
| 206 * break; | |
| 207 * | |
| 208 * case SEOBEO_WS_OPCODE_BINARY: | |
| 209 * printf("Binary: %zu bytes\n", p_msg->length); | |
| 210 * break; | |
| 211 * | |
| 212 * default: | |
| 213 * printf("Unknown opcode: 0x%X\n", p_msg->opcode); | |
| 214 * break; | |
| 215 * } | |
| 216 * | |
| 217 * Seobeo_WebSocket_Message_Destroy(p_msg); | |
| 218 * } | |
| 219 * | |
| 220 * usleep(10000); | |
| 221 * } | |
| 222 * | |
| 223 * Seobeo_WebSocket_Destroy(p_ws); | |
| 224 * ``` | |
| 225 * | |
| 226 * ### 6. Graceful Shutdown | |
| 227 * | |
| 228 * ```c | |
| 229 * Seobeo_WebSocket *p_ws = Seobeo_WebSocket_Connect("wss://example.com"); | |
| 230 * | |
| 231 * // Do work... | |
| 232 * | |
| 233 * // Close with custom status code and reason | |
| 234 * Seobeo_WebSocket_Close(p_ws, 1000, "Client shutting down"); | |
| 235 * Seobeo_WebSocket_Destroy(p_ws); | |
| 236 * ``` | |
| 237 * | |
| 238 * ## WebSocket Close Codes | |
| 239 * | |
| 240 * Common close status codes (RFC 6455): | |
| 241 * | |
| 242 * - **1000**: Normal closure | |
| 243 * - **1001**: Going away (e.g., server shutdown, browser navigation) | |
| 244 * - **1002**: Protocol error | |
| 245 * - **1003**: Unsupported data type | |
| 246 * - **1006**: Abnormal closure (no close frame received) | |
| 247 * - **1007**: Invalid frame payload data | |
| 248 * - **1008**: Policy violation | |
| 249 * - **1009**: Message too big | |
| 250 * - **1010**: Mandatory extension missing | |
| 251 * - **1011**: Internal server error | |
| 252 * | |
| 253 * ## Building | |
| 254 * | |
| 255 * ### Build the library: | |
| 256 * ```bash | |
| 257 * bazel build //seobeo:seobeo_client | |
| 258 * ``` | |
| 259 * | |
| 260 * ### Build and run the WebSocket test: | |
| 261 * ```bash | |
| 262 * bazel test //seobeo:seobeo_websocket_test | |
| 263 * ``` | |
| 264 * | |
| 265 * ## Message Structure | |
| 266 * | |
| 267 * ```c | |
| 268 * typedef struct { | |
| 269 * Seobeo_WebSocket_Opcode opcode; // Message type | |
| 270 * uint8 *data; // Message payload | |
| 271 * size_t length; // Payload length | |
| 272 * boolean is_final; // Final fragment flag | |
| 273 * } Seobeo_WebSocket_Message; | |
| 274 * ``` | |
| 275 * | |
| 276 * ## Protocol Details | |
| 277 * | |
| 278 * The implementation follows RFC 6455 | |
| 279 * | |
| 280 * 1. **Handshake**: HTTP Upgrade request with `Sec-WebSocket-Key` | |
| 281 * 2. **Frame Format**: Proper FIN, opcode, mask, and payload length handling | |
| 282 * 3. **Masking**: All client-to-server frames are masked (required by RFC) | |
| 283 * 4. **Fragmentation**: Handles fragmented messages across multiple frames | |
| 284 * 5. **Control Frames**: Proper handling of ping, pong, and close frames | |
| 285 */ | |
| 286 | |
| 287 /* Connect to WebSocket server with given URL (ws:// or wss://). */ | |
| 288 extern Seobeo_WebSocket *Seobeo_WebSocket_Connect(const char *url); | |
| 289 /* Send text message over WebSocket. */ | |
| 290 extern int32 Seobeo_WebSocket_Send_Text(Seobeo_WebSocket *p_ws, const char *text); | |
| 291 /* Send binary message over WebSocket. */ | |
| 292 extern int32 Seobeo_WebSocket_Send_Binary(Seobeo_WebSocket *p_ws, const uint8 *data, size_t length); | |
| 293 /* Send ping frame (for keep-alive). */ | |
| 294 extern int32 Seobeo_WebSocket_Send_Ping(Seobeo_WebSocket *p_ws, const char *payload); | |
| 295 /* Send pong frame (usually in response to ping). */ | |
| 296 extern int32 Seobeo_WebSocket_Send_Pong(Seobeo_WebSocket *p_ws, const char *payload); | |
| 297 /* Receive a message from WebSocket. Returns NULL if no message available or on error. */ | |
| 298 extern Seobeo_WebSocket_Message *Seobeo_WebSocket_Receive(Seobeo_WebSocket *p_ws); | |
| 299 /* Destroy received message. */ | |
| 300 extern void Seobeo_WebSocket_Message_Destroy(Seobeo_WebSocket_Message *p_msg); | |
| 301 /* Close WebSocket connection with status code and optional reason. */ | |
| 302 extern int32 Seobeo_WebSocket_Close(Seobeo_WebSocket *p_ws, uint16 code, const char *reason); | |
| 303 /* Destroy WebSocket and free all resources. */ | |
| 304 extern void Seobeo_WebSocket_Destroy(Seobeo_WebSocket *p_ws); | |
| 305 | |
| 91 /* Initialize the router system (called automatically by Seobeo_Web_Server_Start) */ | 306 /* Initialize the router system (called automatically by Seobeo_Web_Server_Start) */ |
| 92 extern void Seobeo_Router_Init(); | 307 extern void Seobeo_Router_Init(); |
| 93 /* Register an API route handler. Call before starting server. */ | 308 /* Register an API route handler. Call before starting server. */ |
| 94 extern void Seobeo_Router_Register(const char *method, const char *path_pattern, Seobeo_Route_Handler handler); | 309 extern void Seobeo_Router_Register(const char *method, const char *path_pattern, Seobeo_Route_Handler handler); |
| 95 /* Clean up router resources */ | 310 /* Clean up router resources */ |