view seobeo/docs/web_socket_client.md @ 279:b3b547563ec7

Add Google connector service and agent wiki Implement the C/Seobeo Google Drive and Gmail connector with encrypted OAuth storage, Zenbu authentication, browser testing, AI tool discovery, chunked HTTP decoding, and Bazel coverage. Consolidate repository guidance into progressive wiki documentation and enforce arena-first allocation for new first-party C code. Co-authored-by: Copilot <[email protected]> Copilot-Session: 84c338fd-0939-4bb3-b7f3-1062eb213e5d
author MrJuneJune <me@mrjunejune.com>
date Mon, 17 Aug 2026 22:22:36 -0700
parents cbbf78b17cfa
children
line wrap: on
line source

# Seobeo WebSocket Client - Usage Guide

A clean, easy-to-use WebSocket client library following RFC 6455.

## Features

1. **WebSocket Protocol Support**: Full RFC 6455 WebSocket implementation
2. **Text and Binary Messages**: Send/receive both text and binary data
3. **Automatic Ping/Pong**: Automatic pong responses to ping frames
4. **Message Fragmentation**: Handles fragmented messages automatically
5. **Secure WebSocket**: Supports both `ws://` and `wss://` (WebSocket over TLS)
6. **Clean API**: Simple, intuitive API following seobeo coding standards

## API Overview

### Core Functions

```c
// Connect to WebSocket server
Seobeo_WebSocket *Seobeo_WebSocket_Connect(const char *url);

// Send messages
int32 Seobeo_WebSocket_Send_Text(Seobeo_WebSocket *p_ws, const char *text);
int32 Seobeo_WebSocket_Send_Binary(Seobeo_WebSocket *p_ws, const uint8 *data, size_t length);

// Send control frames
int32 Seobeo_WebSocket_Send_Ping(Seobeo_WebSocket *p_ws, const char *payload);
int32 Seobeo_WebSocket_Send_Pong(Seobeo_WebSocket *p_ws, const char *payload);

// Receive messages
Seobeo_WebSocket_Message *Seobeo_WebSocket_Receive(Seobeo_WebSocket *p_ws);

// Close connection
int32 Seobeo_WebSocket_Close(Seobeo_WebSocket *p_ws, uint16 code, const char *reason);

// Clean up
void Seobeo_WebSocket_Message_Destroy(Seobeo_WebSocket_Message *p_msg);
void Seobeo_WebSocket_Destroy(Seobeo_WebSocket *p_ws);
```

### Message Opcodes

```c
typedef enum {
  SEOBEO_WS_OPCODE_CONTINUATION = 0x0,  // Continuation frame
  SEOBEO_WS_OPCODE_TEXT = 0x1,          // Text message
  SEOBEO_WS_OPCODE_BINARY = 0x2,        // Binary message
  SEOBEO_WS_OPCODE_CLOSE = 0x8,         // Close connection
  SEOBEO_WS_OPCODE_PING = 0x9,          // Ping frame
  SEOBEO_WS_OPCODE_PONG = 0xA           // Pong frame
} Seobeo_WebSocket_Opcode;
```

### Connection States

```c
typedef enum {
  SEOBEO_WS_STATE_CONNECTING = 0,  // Handshake in progress
  SEOBEO_WS_STATE_OPEN,            // Connection established
  SEOBEO_WS_STATE_CLOSING,         // Close handshake initiated
  SEOBEO_WS_STATE_CLOSED           // Connection closed
} Seobeo_WebSocket_State;
```

## 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
6. **TLS Support**: Supports secure WebSocket (wss://) via OpenSSL

## Coding Standards

The implementation follows your specified coding standards:
- Naming: `Seobeo_WebSocket_Connect`, `Seobeo_WebSocket_Send_Text`
- Two spaces for indentation
- New line before `{` unless it's a struct
- Single statement: no need for `{}`

## Features

✅ WebSocket handshake (HTTP Upgrade)
✅ Text and binary message support
✅ Automatic masking for client frames
✅ Message fragmentation handling
✅ Ping/Pong frames
✅ Close handshake
✅ TLS/SSL support (wss://)
✅ Non-blocking receive
✅ Proper memory management with arenas