aboutsummaryrefslogtreecommitdiff
path: root/builtins.c
diff options
context:
space:
mode:
authorcbdev <cb@cbcdn.com>2019-06-20 08:19:29 +0200
committercbdev <cb@cbcdn.com>2019-06-20 08:19:29 +0200
commite60aa0c5779bce199020236c0ac3a4beace571cb (patch)
tree52b5df2816b944ceeeb6bb2762d6e7bd5cea457b /builtins.c
parent303e464579e2fc9961d4d9f4841e916f9aa8963f (diff)
downloadwebsocksy-e60aa0c5779bce199020236c0ac3a4beace571cb.tar.gz
websocksy-e60aa0c5779bce199020236c0ac3a4beace571cb.tar.bz2
websocksy-e60aa0c5779bce199020236c0ac3a4beace571cb.zip
Implement additional framing functions (Fixes #3)
Diffstat (limited to 'builtins.c')
-rw-r--r--builtins.c125
1 files changed, 118 insertions, 7 deletions
diff --git a/builtins.c b/builtins.c
index 5c1dfb8..41d76d4 100644
--- a/builtins.c
+++ b/builtins.c
@@ -1,4 +1,6 @@
#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
#include "websocksy.h"
#include "builtins.h"
@@ -151,7 +153,7 @@ int64_t framing_auto(uint8_t* data, size_t length, size_t last_read, ws_operatio
}
//if valid utf8, send as text frame
- if(valid){
+ if(valid && opcode){
*opcode = ws_frame_text;
}
@@ -165,12 +167,121 @@ int64_t framing_binary(uint8_t* data, size_t length, size_t last_read, ws_operat
return length;
}
-int64_t framing_separator(uint8_t* data, size_t length, size_t last_read, ws_operation* opcode, void** framing_data, const char* config){
- //TODO implement separator framer
- return length;
+/*
+ * The `separator` framing function waits until a variable-length separator is found in the stream and sends all
+ * data up to and including that separator as binary frame. The configuration string is used as the separator, with
+ * the escape sequences \r, \t, \n, \0, \f, \\ being recognized as their ASCII expressions. Arbitrary bytes can be
+ * specified hexadecimally using the syntax \x<hexbyte>
+ */
+typedef struct /*_separator_framing_config*/ {
+ size_t length;
+ uint8_t* separator;
+} framing_separator_config;
+
+int64_t framing_separator(uint8_t* data, size_t length, size_t last_read, ws_operation* opcode, void** framing_data, const char* framing_config){
+ size_t u, p = 0;
+ unsigned hex;
+ framing_separator_config* config = framing_data ? *framing_data : NULL;
+
+ if(data && !config){
+ //parse configuration
+ config = calloc(1, sizeof(framing_separator_config));
+ config->separator = (uint8_t*) strdup(framing_config);
+ for(u = 0; config->separator[u]; u++){
+ config->separator[p] = config->separator[u];
+ if(config->separator[u] == '\\'){
+ switch(config->separator[u + 1]){
+ case 0:
+ u--;
+ //fall through
+ case '0':
+ config->separator[p] = 0;
+ break;
+ case 't':
+ config->separator[p] = '\t';
+ break;
+ case 'n':
+ config->separator[p] = '\n';
+ break;
+ case 'f':
+ config->separator[p] = '\f';
+ break;
+ case 'r':
+ config->separator[p] = '\r';
+ break;
+ case '\\':
+ config->separator[p] = '\\';
+ break;
+ case 'x':
+ if(!isxdigit(config->separator[u + 2])
+ || !isxdigit(config->separator[u + 3])){
+ fprintf(stderr, "Prematurely terminated hex byte sequence in separator framing function\n");
+ return -1;
+ }
+ sscanf((char*) (config->separator + u + 3), "%02x", &hex);
+ config->separator[p] = hex;
+ u += 2;
+ }
+ u++;
+ }
+ p++;
+ }
+ config->length = p;
+ *framing_data = config;
+ }
+ else if(!data && config){
+ //free parsed configuration
+ free(config->separator);
+ config->separator = NULL;
+ config->length = 0;
+ free(config);
+ return 0;
+ }
+
+ if(config->length){
+ for(u = 0; u < last_read && (last_read - u) >= config->length; u++){
+ if(!memcmp(data + (length - last_read) + u, config->separator, config->length)){
+ return (length - last_read) + u + config->length;
+ }
+ }
+ }
+ else{
+ return length;
+ }
+ return 0;
}
-int64_t framing_newline(uint8_t* data, size_t length, size_t last_read, ws_operation* opcode, void** framing_data, const char* config){
- //TODO implement separator framer
- return length;
+/*
+ * The `newline` framing function waits until a newline sequence is found in the buffer and sends all data up to and
+ * including the newline as text frame, if the data is detected as valid UTF-8. Otherwise, a binary frame is used.
+ * The configuration string may be one of
+ * * crlf
+ * * lfcr
+ * * lf
+ * * cr
+ */
+int64_t framing_newline(uint8_t* data, size_t length, size_t last_read, ws_operation* opcode, void** framing_data, const char* framing_config){
+ int64_t bytes = 0;
+ char* expression = "\\r\\n";
+
+ if(data && (!framing_data || !(*framing_data))){
+ if(!strcmp(framing_config, "crlf")){
+ expression = "\\r\\n";
+ }
+ if(!strcmp(framing_config, "lfcr")){
+ expression = "\\n\\r";
+ }
+ if(!strcmp(framing_config, "lf")){
+ expression = "\\n";
+ }
+ if(!strcmp(framing_config, "cr")){
+ expression = "\\r";
+ }
+ bytes = framing_separator(data, length, last_read, opcode, framing_data, expression);
+ }
+ else{
+ bytes = framing_separator(data, length, last_read, opcode, framing_data, NULL);
+ }
+
+ return framing_auto(data, bytes, 0, opcode, NULL, NULL);
}