From 79e063d6aa6116231fdfb374f52507236ca3770e Mon Sep 17 00:00:00 2001 From: cbdev Date: Sat, 25 May 2019 09:10:55 +0200 Subject: Basic forwarding and builtin extension functions --- builtins.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 132 insertions(+), 8 deletions(-) (limited to 'builtins.c') diff --git a/builtins.c b/builtins.c index b75dcd0..fa73260 100644 --- a/builtins.c +++ b/builtins.c @@ -1,26 +1,150 @@ -static ws_peer_info default_peer = { - .transport = peer_tcp_client, - .host = "localhost", - .port = "5900" -}; +#define UTF8_BYTE(a) ((a & 0xC0) == 0x80) -//TODO backend configuration +/* + * The defaultpeer backend returns the same peer configured peer for any + * incoming connection. This may be useful for testing or for configurations + * where there is just one peer anyway. + */ + +/* Global data storage for the backend */ +static ws_peer_info default_peer = {0}; +static char* default_peer_proto = NULL; + +/* + * Initialization function for the defaultpeer backend + * Heap-allocate all data so it can be safely free'd at cleanup + */ +uint64_t backend_defaultpeer_init(){ + ws_peer_info startup_peer = { + .transport = peer_tcp_client, + .host = strdup("localhost"), + .port = strdup("5900") + }; + + default_peer = startup_peer; + return WEBSOCKSY_API_VERSION; +} + +/* + * Configuration function for the defaultpeer backend + */ +uint64_t backend_defaultpeer_configure(char* key, char* value){ + if(!strcmp(key, "host")){ + //TODO extract peer protocol + free(default_peer.host); + default_peer.host = strdup(value); + } + else if(!strcmp(key, "port")){ + free(default_peer.port); + default_peer.port = strdup(value); + } + else if(!strcmp(key, "protocol")){ + free(default_peer_proto); + default_peer_proto = strdup(value); + } + return 1; +} + +/* + * defaultpeer backend core + * Returns the configured default peer for any incoming request and selects either + * a matching or no subprotocol. + */ ws_peer_info backend_defaultpeer_query(char* endpoint, size_t protocols, char** protocol, size_t headers, ws_http_header* header, websocket* ws){ + size_t p; //return a copy of the default peer ws_peer_info peer = default_peer; peer.host = (default_peer.host) ? strdup(default_peer.host) : NULL; peer.port = (default_peer.port) ? strdup(default_peer.port) : NULL; - //TODO backend protocol discovery + //if none set, announce none peer.protocol = protocols; + + if(default_peer_proto){ + for(p = 0; p < protocols; p++){ + if(!strcasecmp(protocol[p], default_peer_proto)){ + peer.protocol = p; + break; + } + } + + //if any, return first + if(!strcmp(default_peer_proto, "*")){ + peer.protocol = 0; + } + } return peer; } +/* + * Cleanup function for the defaultpeer backend. + * Frees all allocated data. + */ +void backend_defaultpeer_cleanup(){ + free(default_peer.host); + default_peer.host = NULL; + free(default_peer.port); + default_peer.port = NULL; + free(default_peer_proto); + default_peer_proto = NULL; +} + +/* + * The `auto` stream framing function forwards all incoming data from the peer immediately, + * with the text frame type if the data is valid UTF8 and the binary frame type otherwise. + */ int64_t framing_auto(uint8_t* data, size_t length, size_t last_read, ws_operation* opcode, void** framing_data, char* config){ - //TODO implement auto framer + size_t p; + uint8_t valid = 1; + for(p = 0; p < length; p++){ + //4-byte codepoint + if((data[p] & 0xF8) == 0xF0){ + if((p + 3) >= length + || !UTF8_BYTE(data[p + 1]) + || !UTF8_BYTE(data[p + 2]) + || !UTF8_BYTE(data[p + 3])){ + valid = 0; + break; + } + p += 3; + } + //3 byte codepoint + else if((data[p] & 0xF0) == 0xE0){ + if((p + 2) >= length + || !UTF8_BYTE(data[p + 1]) + || !UTF8_BYTE(data[p + 2])){ + valid = 0; + break; + } + p += 2; + } + //2 byte codepoint + else if((data[p] & 0xE0) == 0xC0){ + if((p + 1) >= length + || !UTF8_BYTE(data[p + 1])){ + valid = 0; + break; + } + p++; + } + //not a 1 byte codepoint -> not utf8 + else if(data[p] & 0x80){ + valid = 0; + break; + } + } + + //if valid utf8, send as text frame + if(valid){ + *opcode = ws_frame_text; + } + return length; } +/* + * The `binary` peer stream framing function forwards all incoming data from the peer immediately as binary frames + */ int64_t framing_binary(uint8_t* data, size_t length, size_t last_read, ws_operation* opcode, void** framing_data, char* config){ return length; } -- cgit v1.2.3