aboutsummaryrefslogtreecommitdiff
path: root/builtins.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtins.c')
-rw-r--r--builtins.c140
1 files changed, 132 insertions, 8 deletions
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;
}