From 78f8f18e48d25547e837630d8317ef029bba6d72 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Thu, 13 Oct 2022 20:37:23 +0200 Subject: more protocol parsing done --- shared/bin.c | 11 ++++++++++ shared/bin.h | 5 +++-- shared/main | Bin 21456 -> 28568 bytes shared/makefile | 2 +- shared/protocol.c | 42 ++++++++++++++++++++++++++++++++---- shared/protocol.h | 63 ++++++++++++++++++++++++++++++++++++++++++++++-------- 6 files changed, 107 insertions(+), 16 deletions(-) create mode 100644 shared/bin.c diff --git a/shared/bin.c b/shared/bin.c new file mode 100644 index 0000000..def2aa8 --- /dev/null +++ b/shared/bin.c @@ -0,0 +1,11 @@ +#include +#include +#include + +#include "bin.h" + +ws_s_bin *ws_bin_s_alloc(uint16_t bytes) { + ws_s_bin *temp = malloc(sizeof(ws_s_bin) + sizeof(uint8_t) * bytes); + temp->bytes = bytes; + return temp; +} diff --git a/shared/bin.h b/shared/bin.h index c7405be..bfcda0c 100644 --- a/shared/bin.h +++ b/shared/bin.h @@ -2,11 +2,12 @@ #include +/** @brief binary data container with length */ typedef struct { uint16_t bytes; uint8_t data[]; } ws_s_bin; -/** allocate new ws_s_bin struct and fill with `*data` for `bytes` bytes */ -ws_s_bin *ws_bin_s_alloc(uint16_t bytes, uint8_t *data); +/** @brief allocate new ws_s_bin struct */ +ws_s_bin *ws_bin_s_alloc(uint16_t bytes); diff --git a/shared/main b/shared/main index 7d7b7fe..10b0d3c 100755 Binary files a/shared/main and b/shared/main differ diff --git a/shared/makefile b/shared/makefile index 4d538da..2ca254c 100644 --- a/shared/makefile +++ b/shared/makefile @@ -1,7 +1,7 @@ CC = gcc LD = gcc RM = rm -f -CFLAGS = +CFLAGS = -g LFLAGS = TARGET = main diff --git a/shared/protocol.c b/shared/protocol.c index 85b320f..49d1795 100644 --- a/shared/protocol.c +++ b/shared/protocol.c @@ -1,5 +1,6 @@ #include #include +#include #include "protocol.h" @@ -12,7 +13,7 @@ void ws_protocol_parse_byte(ws_s_protocol_parser_state* state, char input) { case WS_PROTOCOL_C_SPACE: { if (!state->valid) return; - printf("argument delimiter\n"); + state->arg_len++; return; } @@ -23,15 +24,39 @@ void ws_protocol_parse_byte(ws_s_protocol_parser_state* state, char input) { default: { if (!state->valid) return; - printf("recv byte 0x%02x, (\"%c\")\n", input, input); state->cmd[state->cmd_len++] = input; state->args_len[state->arg_len] += 1; if (state->cmd_len == WS_PROTOCOL_CMD_BUFFER_LEN) state->valid = false; return; } } + // arg_len is used as an index while parsing, so add 1 to get length + state->arg_len++; - printf("command done!\n"); + // parse cmd into argc and argv + ws_protocol_cmd_init(state); + // create response + ws_s_protocol_response* response = ws_protocol_parse_finished(state->target); + + //TODO: send response + + free(response->msg); + free(response); + + return; +} + +ws_s_protocol_response* ws_protocol_parse_finished(ws_s_protocol_parsed_cmd* parsed_cmd) { + ws_s_protocol_response* response = malloc(sizeof(ws_s_protocol_response)); + + if (strncmp("last-records", parsed_cmd->argv[0], 12) == 0) { + printf("last-records found!\n"); + } + + response->msg = ws_bin_s_alloc(50); + strncpy((char*) response->msg->data, "hello world!\n\0", 14); + + return response; } void ws_protocol_parse_bytes(ws_s_protocol_parser_state* state, char* input, unsigned int length) { @@ -51,8 +76,16 @@ ws_s_protocol_parser_state* ws_protocol_parser_alloc() { void ws_protocol_cmd_init(ws_s_protocol_parser_state* state) { state->target = malloc(sizeof(ws_s_protocol_parsed_cmd) + sizeof(char*) * state->arg_len); for (unsigned int i = 0; i < state->arg_len; i++) - state->target->argv[i] = malloc(sizeof(char) * state->args_len[i]); + state->target->argv[i] = malloc(sizeof(char) * (state->args_len[i] + 1)); + state->target->argc = state->arg_len; + + unsigned int head = 0; + for (unsigned int i = 0; i < state->arg_len; i++) { + strncpy(state->target->argv[i], &state->cmd[head], state->args_len[i]); + state->target->argv[i][state->args_len[i]] = 0x00; // terminate argument with null byte + head += state->args_len[i]; + } } void ws_protocol_parser_free(ws_s_protocol_parser_state* state) { @@ -63,6 +96,7 @@ void ws_protocol_parser_free(ws_s_protocol_parser_state* state) { state = NULL; return; } + void ws_protocol_cmd_free(ws_s_protocol_parsed_cmd* cmd) { for (unsigned int i = 0; i < cmd->argc; i++) free(cmd->argv[i]); diff --git a/shared/protocol.h b/shared/protocol.h index 5cf7ac6..3082af4 100644 --- a/shared/protocol.h +++ b/shared/protocol.h @@ -14,24 +14,54 @@ #define WS_PROTOCOL_C_SPACE (0x20) #define WS_PROTOCOL_C_NULL (0x00) +/** + * @brief parsed cmd struct, holds arguments similar to argc and argv provided + * to `int main()` + */ typedef struct { - int argc; - char* argv[]; + int argc; /** argument count */ + char* argv[]; /** argument array, null terminated strings */ } ws_s_protocol_parsed_cmd; +/** + * @brief holds parser state variables for `ws_protocol_parse_byte` function. + * each incoming tcp request should get it's own parser 'instance' + */ typedef struct { - ws_s_protocol_parsed_cmd* target; - bool valid; - char* cmd; - uint16_t cmd_len; - uint16_t arg_len; - uint16_t args_len[]; + ws_s_protocol_parsed_cmd* target; /** parsed cmd reference */ + bool valid; /** command still valid flag */ + char* cmd; /** raw cmd */ + uint16_t cmd_len; /** raw cmd string length */ + uint16_t arg_len; /** amount of arguments */ + uint16_t args_len[]; /** array of argument lengths */ } ws_s_protocol_parser_state; -//TODO: document +/** @brief return values for command handlers */ +typedef enum { + WS_PROTOCOL_CMD_RETURN_OK = 0, + WS_PROTOCOL_CMD_RETURN_ERROR = 1, +} ws_e_protocol_cmd_return_value; + +/** @brief request response data struct */ +typedef struct { + ws_e_protocol_cmd_return_value success; + ws_s_bin* msg; +} ws_s_protocol_response; + +/** + * @brief allocate parser struct + * + * @return pointer to newly allocated struct + */ ws_s_protocol_parser_state* ws_protocol_parser_alloc(); +/** @brief deallocate parser struct, automatically frees all child pointers */ void ws_protocol_parser_free(ws_s_protocol_parser_state* state); +/** + * @brief initialize ws_s_protocol_parsed_cmd struct pointer of + * ws_s_protocol_parser_state (internal only) + */ void ws_protocol_cmd_init(ws_s_protocol_parser_state* state); +/** @brief deallocate ws_s_protocol_parsed_cmd struct pointer (internal only) */ void ws_protocol_cmd_free(ws_s_protocol_parsed_cmd* cmd); /** @@ -53,6 +83,21 @@ void ws_protocol_parse_byte(ws_s_protocol_parser_state* state, char input); * @param length input byte array length */ void ws_protocol_parse_bytes(ws_s_protocol_parser_state* state, char* input, unsigned int length); +/** + * @brief handle complete command + * + * this function gets called when ws_protocol_parse_byte has detected a + * finished command. this function decides which command handler gets called, + * given that argv[0] contains a valid command. command argument parsing is + * handled by the command handler function. + * + * @remark [server] + * + * @return response + * + * @param parsed_cmd cmd parsed into ws_s_protocol_parsed_cmd struct + */ +ws_s_protocol_response* ws_protocol_parse_finished(ws_s_protocol_parsed_cmd* parsed_cmd); /** * @brief create a `last-records` request command -- cgit v1.2.3