view seobeo/seobeo_internal.h @ 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 04fee26ecce0
children
line wrap: on
line source

#ifndef SEOBEO_SERVER_INTERNAL_H
#define SEOBEO_SERVER_INTERNAL_H

#ifndef SEOBEO_NO_SSL
#include <openssl/ssl.h>
#include <openssl/err.h>
#define SSL_CTX_TYPE SSL_CTX
#define SSL_TYPE SSL
#else
#define SSL_CTX_TYPE void
#define SSL_TYPE void
#endif

// For web socket usages as body length are determine this...
#define MAX_INT_16 65536
#define MAX_FRAGMENT_SIZE 1024 * 1024 

#include "dowa/dowa.h"
#include <stdatomic.h>

typedef enum {
  SEOBEO_STREAM_TYPE_SERVER,
  SEOBEO_STREAM_TYPE_CLIENT,
} Seobeo_SocketType;

typedef struct {
  int32       socket;
  Seobeo_SocketType  type;
  boolean     connected;

  char        *host;
  char        *port;

  SSL_CTX_TYPE     *ssl_ctx;
  SSL_TYPE         *ssl;

  uint8       *read_buffer;
  uint32      read_buffer_capacity;
  uint32      read_buffer_len; // current size
  uint32      read_buffer_used; // TODO: Implement this for client

  uint8       *write_buffer;
  uint32      write_buffer_capacity;
  uint32      write_buffer_len; // current size

  void        *file;
  void        *text_copy;
  char        *file_name;

  atomic_bool destroyed;

  // Keep-alive support
  time_t      last_activity;  // Timestamp of last request/response
  boolean     keep_alive;     // Whether this connection should be kept alive
  boolean     is_sse;         // SSE takeover; edge loop only watches disconnects
} Seobeo_Handle;

// Cached file entry with content and size (for binary file support)
typedef struct {
  char  *content;
  size_t size;
} Seobeo_Cached_File;

// HTML cache type: maps file paths (char*) to cached file entries (Seobeo_Cached_File*)
typedef Dowa_KV(char*, Seobeo_Cached_File*) Seobeo_Cache_Entry;

typedef struct {
  Seobeo_Handle       *srv;
  Seobeo_Cache_Entry  *cache;
} WorkerArgs;

typedef enum {
  SEOBEO_MODE_FORK,
  SEOBEO_MODE_EDGE,
} Seobeo_ServerMode;


// HTTP request map type: maps header names to header values
typedef Dowa_KV(char*, char*) Seobeo_Request_Entry;

typedef struct Seobeo_SSE_Stream {
  Seobeo_Handle *p_handle;
  char *path;
  void *p_pending_frames;
  size_t pending_offset;
  atomic_uint ref_count;
  boolean started;
  boolean closed;
  boolean managed;
  /* Optional client-disconnect callback.  Called from
   * Seobeo_SSE_Server_Detach_Handle AFTER g_sse_mutex is released so that
   * the callback may safely acquire its own locks. */
  void (*detach_cb)(struct Seobeo_SSE_Stream *, void *);
  void  *detach_ctx;
} Seobeo_SSE_Stream;

typedef struct {
  const char *event;
  const char *id;
  const char *data;
  int32 retry_ms;
} Seobeo_SSE_Event;

// --- Router Types --- //
// Forward declaration
typedef struct Seobeo_Route_Struct Seobeo_Route;

// Route handler function type
typedef Seobeo_Request_Entry* (*Seobeo_Route_Handler)(
    Seobeo_Request_Entry *p_request_map,
    Dowa_Arena *p_arena
);

// Streaming handler - gets direct access to client handle for streaming responses
typedef void (*Seobeo_Stream_Handler)(
    Seobeo_Handle *p_client_handle,
    Seobeo_Request_Entry *p_request_map,
    Dowa_Arena *p_arena
);

typedef void (*Seobeo_SSE_Handler)(
    Seobeo_SSE_Stream *p_stream,
    Seobeo_Request_Entry *p_request_map,
    Dowa_Arena *p_arena
);

extern Seobeo_SSE_Stream *Seobeo_SSE_Server_Attach(
    Seobeo_Handle *p_handle,
    const char *path);
extern void Seobeo_SSE_Server_Detach_Handle(Seobeo_Handle *p_handle);
extern void Seobeo_SSE_Server_Destroy(void);

// --- Parse Header into Dowa Map ---//
extern int            Seobeo_Web_Header_Parse(Seobeo_Handle *p_handle, Seobeo_Request_Entry **pp_map, Dowa_Arena *p_arena);

// --- Handle Request --- //
/* Handle a client request. Returns TRUE if connection should be kept alive. */
extern boolean        Seobeo_Web_ClientHandle_Request(Seobeo_Handle *p_cli_handle, Seobeo_Cache_Entry *p_html_cache, boolean use_keep_alive);
extern boolean        Seobeo_Web_Server_Is_Stopping(void);

// --- SSL --- //
extern void           Seobeo_Web_SSL_Init();
extern void           Seobeo_Web_SSL_Cleanup(); // Not used
extern int            Seobeo_SSL_Setup_Client(Seobeo_Handle *p_handle, const char *host, int socket_fd);
extern void           Seobeo_SSL_Cleanup(Seobeo_Handle *p_handle);
extern int32          Seobeo_SSL_Write(Seobeo_Handle *p_handle, const uint8 *data, uint32 length);
extern int32          Seobeo_SSL_Read(Seobeo_Handle *p_handle, uint8 *buffer, uint32 length);

// --- Serving using Edge --- //
extern void          *Seobeo_Web_Edge_Worker(void *vargs);
extern void           Seobeo_Web_Edge(Seobeo_Handle *p_server_handle, int thread_count, Seobeo_Cache_Entry *p_html_cache);

// --- HTTP Client Types --- //
typedef struct {
  char    *method;
  char    *url;
  char    *host;
  char    *port;
  char    *path;
  boolean  use_tls;

  // Headers can be either HashMap or Array
  Seobeo_Request_Entry *headers_map;
  char                **headers_array;

  char    *body;
  size_t   body_length;

  boolean  follow_redirects;
  int32    max_redirects;
  int32    timeout_ms;

  char    *download_path;

  Dowa_Arena *p_arena;
} Seobeo_Client_Request;

typedef struct {
  int32    status_code;
  char    *status_text;

  Seobeo_Request_Entry *headers;

  char    *body;
  size_t   body_length;

  char    *redirect_url;

  Dowa_Arena *p_arena;
} Seobeo_Client_Response;

// --- HTTP Client Functions --- //
extern Seobeo_Client_Request  *Seobeo_Client_Request_Create(const char *url);
extern void                    Seobeo_Client_Request_Set_Method(Seobeo_Client_Request *p_req, const char *method);
extern void                    Seobeo_Client_Request_Add_Header_Map(Seobeo_Client_Request *p_req, const char *key, const char *value);
extern void                    Seobeo_Client_Request_Add_Header_Array(Seobeo_Client_Request *p_req, const char *header);
extern void                    Seobeo_Client_Request_Set_Body(Seobeo_Client_Request *p_req, const char *body, size_t length);
extern void                    Seobeo_Client_Request_Set_Follow_Redirects(Seobeo_Client_Request *p_req, boolean follow, int32 max_redirects);
extern void                    Seobeo_Client_Request_Set_Timeout_Milliseconds(Seobeo_Client_Request *p_req, int32 timeout_ms);
extern void                    Seobeo_Client_Request_Set_Download_Path(Seobeo_Client_Request *p_req, const char *path);
extern Seobeo_Client_Response *Seobeo_Client_Request_Execute(Seobeo_Client_Request *p_req);
extern void                    Seobeo_Client_Request_Destroy(Seobeo_Client_Request *p_req);
extern void                    Seobeo_Client_Response_Destroy(Seobeo_Client_Response *p_resp);

// --- WebSocket Types --- //
typedef enum {
  SEOBEO_WS_OPCODE_CONTINUATION = 0x0,
  SEOBEO_WS_OPCODE_TEXT = 0x1,
  SEOBEO_WS_OPCODE_BINARY = 0x2,
  SEOBEO_WS_OPCODE_CLOSE = 0x8,
  SEOBEO_WS_OPCODE_PING = 0x9,
  SEOBEO_WS_OPCODE_PONG = 0xA
} Seobeo_WebSocket_Opcode;

typedef enum {
  SEOBEO_WS_STATE_CONNECTING = 0,
  SEOBEO_WS_STATE_OPEN,
  SEOBEO_WS_STATE_CLOSING,
  SEOBEO_WS_STATE_CLOSED
} Seobeo_WebSocket_State;

typedef struct {
  Seobeo_WebSocket_Opcode opcode;
  uint8  *data;
  size_t  length;
  boolean is_final;
} Seobeo_WebSocket_Message;

typedef struct {
  Seobeo_Handle *p_handle;
  char          *url;
  char          *host;
  char          *port;
  char          *path;
  boolean        use_tls;

  Seobeo_WebSocket_State state;

  uint8  *fragment_buffer;
  size_t  fragment_length;
  size_t  fragment_capacity;
  Seobeo_WebSocket_Opcode fragment_opcode;

  Dowa_Arena *p_arena;
} Seobeo_WebSocket;

// --- WebSocket Common Functions --- //
extern void                      Seobeo_WebSocket_Mask_Data(uint8 *data, size_t length, const uint8 *mask);
extern void                      Seobeo_WebSocket_Message_Destroy(Seobeo_WebSocket_Message *p_msg);

// --- WebSocket Client Functions --- //
extern Seobeo_WebSocket         *Seobeo_WebSocket_Connect(const char *url);
extern int32                     Seobeo_WebSocket_Send_Text(Seobeo_WebSocket *p_ws, const char *text);
extern int32                     Seobeo_WebSocket_Send_Binary(Seobeo_WebSocket *p_ws, const uint8 *data, size_t length);
extern int32                     Seobeo_WebSocket_Send_Ping(Seobeo_WebSocket *p_ws, const char *payload);
extern int32                     Seobeo_WebSocket_Send_Pong(Seobeo_WebSocket *p_ws, const char *payload);
extern Seobeo_WebSocket_Message *Seobeo_WebSocket_Receive(Seobeo_WebSocket *p_ws);
extern int32                     Seobeo_WebSocket_Close(Seobeo_WebSocket *p_ws, uint16 code, const char *reason);
extern void                      Seobeo_WebSocket_Destroy(Seobeo_WebSocket *p_ws);

// --- WebSocket Server Types --- //
typedef struct Seobeo_WebSocket_Server_Connection_Struct Seobeo_WebSocket_Server_Connection;

struct Seobeo_WebSocket_Server_Connection_Struct {
  Seobeo_Handle *p_handle;
  char          *client_id;
  boolean        is_active;

  uint8  *fragment_buffer;
  size_t  fragment_length;
  size_t  fragment_capacity;
  Seobeo_WebSocket_Opcode fragment_opcode;

  Seobeo_WebSocket_Server_Connection *next;
};

typedef void (*Seobeo_WebSocket_Server_Handler)(
  Seobeo_WebSocket_Server_Connection *p_conn,
  Seobeo_WebSocket_Message *p_msg,
  void *p_user_data
);

typedef struct {
  char                               *path;
  Seobeo_WebSocket_Server_Handler     handler;
  void                               *p_user_data;
} Seobeo_WebSocket_Server_Route;

// --- WebSocket Server Functions --- //
extern void                               Seobeo_WebSocket_Server_Init();
extern void                               Seobeo_WebSocket_Server_Register(const char *path, Seobeo_WebSocket_Server_Handler handler, void *p_user_data);
extern boolean                            Seobeo_WebSocket_Server_Handle_Upgrade(Seobeo_Handle *p_handle, Seobeo_Request_Entry *p_req_map, const char *path);
extern void                               Seobeo_WebSocket_Server_Handle_Connection(Seobeo_WebSocket_Server_Connection *p_conn);
extern int32                              Seobeo_WebSocket_Server_Send_Text(Seobeo_WebSocket_Server_Connection *p_conn, const char *text);
extern int32                              Seobeo_WebSocket_Server_Send_Binary(Seobeo_WebSocket_Server_Connection *p_conn, const uint8 *data, size_t length);
extern void                               Seobeo_WebSocket_Server_Broadcast_Text(const char *text, Seobeo_WebSocket_Server_Connection *origin_p_conn);
extern void                               Seobeo_WebSocket_Server_Broadcast_Binary(const uint8 *data, size_t length);
extern void                               Seobeo_WebSocket_Server_Connection_Close(Seobeo_WebSocket_Server_Connection *p_conn, uint16 code, const char *reason);
extern void                               Seobeo_WebSocket_Server_Connection_Destroy(Seobeo_WebSocket_Server_Connection *p_conn);

#endif