From 75d1e4955b220495f6d2655b18989db567faa5ce Mon Sep 17 00:00:00 2001 From: cbdev Date: Sat, 18 May 2019 20:01:33 +0200 Subject: Document structures, introduce basic API --- websocksy.h | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 94 insertions(+), 17 deletions(-) (limited to 'websocksy.h') diff --git a/websocksy.h b/websocksy.h index 2073287..5a4f24c 100644 --- a/websocksy.h +++ b/websocksy.h @@ -3,16 +3,29 @@ #include #include +/* Version defines */ +#define WEBSOCKSY_API_VERSION 1 +#define WEBSOCKSY_VERSION "0.1" + +/* HTTP/WS read buffer size & limit */ #define WS_MAX_LINE 16384 +/* Maximum number of HTTP headers to accept */ +#define WS_HEADER_LIMIT 10 +/* + * State machine for WebSocket connections + */ typedef enum { - ws_new = 0, - ws_http, - ws_open, - ws_closed + ws_new = 0, /* Initial state */ + ws_http, /* HTTP Headers */ + ws_open, /* Upgrade performed, forwarding */ + ws_closed /* Close frame sent */ } ws_state; -//RFC Section 5.2 +/* + * WebSocket frame opcodes + * RFC Section 5.2 + */ typedef enum { ws_frame_continuation = 0, ws_frame_text = 1, @@ -22,7 +35,10 @@ typedef enum { ws_frame_pong = 10 } ws_operation; -//RFC Section 7.4.1 +/* + * WebSocket close reasons / response codes + * RFC Section 7.4.1 + */ typedef enum { ws_close_http = 100, ws_close_normal = 1000, @@ -35,30 +51,91 @@ typedef enum { ws_close_unexpected = 1011 } ws_close_reason; -struct { +/* + * HTTP header split into tag and value + */ +typedef struct /*_ws_http_header*/ { + char* tag; + char* value; +} ws_http_header; + +/* + * Peer stream framing function + * + * Since the WebSocket protocol transfers its payload using discrete frames, unlike the peer's + * underlying TCP/Unix sockets (UDP is a different matter and may be framed directly), we need + * a method to indicate whether a complete frame to be forwarded has been received from the peer + * and with what WebSocket frame type to forward it (binary/text). Since this is largely + * protocol-dependent, this functionality needs to be user-extendable. + * + * We do however provide some default framing functions: + * * binary: Always forward all reads as binary frames + * * auto: Based on the content, forward every read result as binary/text + * * separator: Separate binary frames on a sequence of bytes + * * newline: Forward text frames separated by newlines (\r\n) + * + * The separator function is called once for every succesful read from the peer socket and called + * again when it indicates a frame boundary but there is still data in the buffer. + */ +typedef int64_t (*ws_framing)(void); + +/* + * Peer connection model + */ +typedef struct /*_ws_peer_info*/ { + /* Peer protocol data */ + int transport; char* host; char* port; - struct { - char* name; - } backend; -} config = { - .host = "::", - .port = "8001", - .backend.name = "internal" -}; + /* Framing function for this peer */ + ws_framing framing; + + /* WebSocket subprotocol indication index*/ + size_t protocol; +} ws_peer_info; + +/* + * Core connection model + */ typedef struct /*_web_socket*/ { - int fd; - int peer; + /* WebSocket state & data */ + int ws_fd; uint8_t read_buffer[WS_MAX_LINE]; size_t read_buffer_offset; ws_state state; + /* HTTP request headers */ + size_t headers; + ws_http_header header[WS_HEADER_LIMIT]; + + /* WebSocket parameters */ char* request_path; unsigned websocket_version; char* socket_key; unsigned want_upgrade; + /* WebSocket indicated subprotocols*/ size_t protocols; char** protocol; + + /* Peer data */ + ws_peer_info peer; + int peer_fd; } websocket; + +/* + * Peer discovery backend + * + * Used to dynamically select the peer based on parameters supplied by the WebSocket connection. + * The backend maps WebSocket characteristics (such as the endpoint used, the supported protocols and + * HTTP client headers) to a TCP/UDP/Unix socket peer endpoint using some form of user-configurable + * provider (such as databases, files, crystal balls or sheer guesses). + * + * The return value is a structure containing the destination address and transport to be connected to + * the Web Socket, as well as the indicated subprotocol to use (or none, if set to the provided maximum + * number of protocols). + * The fields within the structure should be allocated with `calloc` and will be free'd by websocky + * after use. + */ +typedef ws_peer_info (*ws_backend)(char* endpoint, size_t protocols, char** protocol, size_t headers, ws_http_header* header, websocket* ws); -- cgit v1.2.3