diff 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
line wrap: on
line diff
--- a/seobeo/seobeo.h	Wed Jan 07 16:05:57 2026 -0800
+++ b/seobeo/seobeo.h	Thu Jan 08 03:19:59 2026 -0800
@@ -88,6 +88,221 @@
 extern void                    Seobeo_Client_Request_Destroy(Seobeo_Client_Request *p_req);
 /* Destroy response and free all resources. */
 extern void                    Seobeo_Client_Response_Destroy(Seobeo_Client_Response *p_resp);
+
+/**
+ * WebSocket Client API
+ * ------
+ *
+ * # Overview 
+ *
+ * A clean, easy-to-use WebSocket client library following RFC 6455. It will auto handle over 64 bits long data into a continous stream.
+ *
+ * ## Examples
+ * 
+ * ### 1. Simple Text Echo
+ * 
+ * ```c
+ * // Connect to WebSocket server
+ * Seobeo_WebSocket *p_ws = Seobeo_WebSocket_Connect("wss://echo.websocket.org");
+ * if (!p_ws)
+ * {
+ *   printf("Failed to connect\n");
+ *   return;
+ * }
+ * 
+ * // Send text message
+ * const char *message = "Hello, WebSocket!";
+ * Seobeo_WebSocket_Send_Text(p_ws, message);
+ * 
+ * // Receive echo response
+ * Seobeo_WebSocket_Message *p_msg = Seobeo_WebSocket_Receive(p_ws);
+ * if (p_msg && p_msg->opcode == SEOBEO_WS_OPCODE_TEXT)
+ * {
+ *   printf("Received: %.*s\n", (int)p_msg->length, (char*)p_msg->data);
+ *   Seobeo_WebSocket_Message_Destroy(p_msg);
+ * }
+ * 
+ * // Close connection
+ * Seobeo_WebSocket_Close(p_ws, 1000, "Normal closure");
+ * Seobeo_WebSocket_Destroy(p_ws);
+ * ```
+ * 
+ * ### 2. Binary Data Transfer
+ * 
+ * ```c
+ * Seobeo_WebSocket *p_ws = Seobeo_WebSocket_Connect("wss://example.com/data");
+ * 
+ * // Send binary data
+ * uint8 data[] = {0x01, 0x02, 0x03, 0xAA, 0xBB, 0xCC};
+ * Seobeo_WebSocket_Send_Binary(p_ws, data, sizeof(data));
+ * 
+ * // Receive binary response
+ * Seobeo_WebSocket_Message *p_msg = Seobeo_WebSocket_Receive(p_ws);
+ * if (p_msg && p_msg->opcode == SEOBEO_WS_OPCODE_BINARY)
+ * {
+ *   printf("Received %zu bytes\n", p_msg->length);
+ *   // Process binary data...
+ *   Seobeo_WebSocket_Message_Destroy(p_msg);
+ * }
+ * 
+ * Seobeo_WebSocket_Destroy(p_ws);
+ * ```
+ * 
+ * ### 3. Chat Application
+ * 
+ * ```c
+ * Seobeo_WebSocket *p_ws = Seobeo_WebSocket_Connect("wss://chat.example.com");
+ * 
+ * // Send chat message
+ * Seobeo_WebSocket_Send_Text(p_ws, "Hello everyone!");
+ * 
+ * // Continuous receive loop
+ * while (1)
+ * {
+ *   Seobeo_WebSocket_Message *p_msg = Seobeo_WebSocket_Receive(p_ws);
+ *   if (p_msg)
+ *   {
+ *     if (p_msg->opcode == SEOBEO_WS_OPCODE_TEXT)
+ *     {
+ *       printf("Chat: %.*s\n", (int)p_msg->length, (char*)p_msg->data);
+ *     }
+ *     Seobeo_WebSocket_Message_Destroy(p_msg);
+ *   }
+ * 
+ *   usleep(10000);  // 10ms sleep to avoid busy waiting
+ * }
+ * 
+ * Seobeo_WebSocket_Destroy(p_ws);
+ * ```
+ * 
+ * ### 4. Ping/Pong Keep-Alive
+ * 
+ * ```c
+ * Seobeo_WebSocket *p_ws = Seobeo_WebSocket_Connect("wss://api.example.com");
+ * 
+ * // Send ping to keep connection alive
+ * Seobeo_WebSocket_Send_Ping(p_ws, "keep-alive");
+ * 
+ * // Server will automatically receive pong responses
+ * // (pong responses are handled internally)
+ * 
+ * Seobeo_WebSocket_Destroy(p_ws);
+ * ```
+ * 
+ * ### 5. Handling Different Message Types
+ * 
+ * ```c
+ * Seobeo_WebSocket *p_ws = Seobeo_WebSocket_Connect("wss://example.com");
+ * 
+ * while (1)
+ * {
+ *   Seobeo_WebSocket_Message *p_msg = Seobeo_WebSocket_Receive(p_ws);
+ *   if (p_msg)
+ *   {
+ *     switch (p_msg->opcode)
+ *     {
+ *       case SEOBEO_WS_OPCODE_TEXT:
+ *         printf("Text: %.*s\n", (int)p_msg->length, (char*)p_msg->data);
+ *         break;
+ * 
+ *       case SEOBEO_WS_OPCODE_BINARY:
+ *         printf("Binary: %zu bytes\n", p_msg->length);
+ *         break;
+ * 
+ *       default:
+ *         printf("Unknown opcode: 0x%X\n", p_msg->opcode);
+ *         break;
+ *     }
+ * 
+ *     Seobeo_WebSocket_Message_Destroy(p_msg);
+ *   }
+ * 
+ *   usleep(10000);
+ * }
+ * 
+ * Seobeo_WebSocket_Destroy(p_ws);
+ * ```
+ * 
+ * ### 6. Graceful Shutdown
+ * 
+ * ```c
+ * Seobeo_WebSocket *p_ws = Seobeo_WebSocket_Connect("wss://example.com");
+ * 
+ * // Do work...
+ * 
+ * // Close with custom status code and reason
+ * Seobeo_WebSocket_Close(p_ws, 1000, "Client shutting down");
+ * Seobeo_WebSocket_Destroy(p_ws);
+ * ```
+ * 
+ * ## WebSocket Close Codes
+ * 
+ * Common close status codes (RFC 6455):
+ * 
+ * - **1000**: Normal closure
+ * - **1001**: Going away (e.g., server shutdown, browser navigation)
+ * - **1002**: Protocol error
+ * - **1003**: Unsupported data type
+ * - **1006**: Abnormal closure (no close frame received)
+ * - **1007**: Invalid frame payload data
+ * - **1008**: Policy violation
+ * - **1009**: Message too big
+ * - **1010**: Mandatory extension missing
+ * - **1011**: Internal server error
+ * 
+ * ## Building
+ * 
+ * ### Build the library:
+ * ```bash
+ * bazel build //seobeo:seobeo_client
+ * ```
+ * 
+ * ### Build and run the WebSocket test:
+ * ```bash
+ * bazel test //seobeo:seobeo_websocket_test
+ * ```
+ * 
+ * ## Message Structure
+ * 
+ * ```c
+ * typedef struct {
+ *   Seobeo_WebSocket_Opcode opcode;  // Message type
+ *   uint8  *data;                    // Message payload
+ *   size_t  length;                  // Payload length
+ *   boolean is_final;                // Final fragment flag
+ * } Seobeo_WebSocket_Message;
+ * ```
+ * 
+ * ## Protocol Details
+ * 
+ * The implementation follows RFC 6455
+ * 
+ * 1. **Handshake**: HTTP Upgrade request with `Sec-WebSocket-Key`
+ * 2. **Frame Format**: Proper FIN, opcode, mask, and payload length handling
+ * 3. **Masking**: All client-to-server frames are masked (required by RFC)
+ * 4. **Fragmentation**: Handles fragmented messages across multiple frames
+ * 5. **Control Frames**: Proper handling of ping, pong, and close frames
+ */
+
+/* Connect to WebSocket server with given URL (ws:// or wss://). */
+extern Seobeo_WebSocket         *Seobeo_WebSocket_Connect(const char *url);
+/* Send text message over WebSocket. */
+extern int32                     Seobeo_WebSocket_Send_Text(Seobeo_WebSocket *p_ws, const char *text);
+/* Send binary message over WebSocket. */
+extern int32                     Seobeo_WebSocket_Send_Binary(Seobeo_WebSocket *p_ws, const uint8 *data, size_t length);
+/* Send ping frame (for keep-alive). */
+extern int32                     Seobeo_WebSocket_Send_Ping(Seobeo_WebSocket *p_ws, const char *payload);
+/* Send pong frame (usually in response to ping). */
+extern int32                     Seobeo_WebSocket_Send_Pong(Seobeo_WebSocket *p_ws, const char *payload);
+/* Receive a message from WebSocket. Returns NULL if no message available or on error. */
+extern Seobeo_WebSocket_Message *Seobeo_WebSocket_Receive(Seobeo_WebSocket *p_ws);
+/* Destroy received message. */
+extern void                      Seobeo_WebSocket_Message_Destroy(Seobeo_WebSocket_Message *p_msg);
+/* Close WebSocket connection with status code and optional reason. */
+extern int32                     Seobeo_WebSocket_Close(Seobeo_WebSocket *p_ws, uint16 code, const char *reason);
+/* Destroy WebSocket and free all resources. */
+extern void                      Seobeo_WebSocket_Destroy(Seobeo_WebSocket *p_ws);
+
 /* Initialize the router system (called automatically by Seobeo_Web_Server_Start) */
 extern void           Seobeo_Router_Init();
 /* Register an API route handler. Call before starting server. */