1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "protocol.h"
#define WS_CMD_MAP(parsed_cmd, name, code) \
if (strlen(parsed_cmd->argv[0]) == strlen(name) && strncmp(parsed_cmd->argv[0], name, strlen(name)) == 0) return code;
static ws_e_protocol_cmd ws_protocol_get_req_cmd_code(ws_s_protocol_parsed_req_cmd* parsed_cmd) {
if (parsed_cmd == NULL) return WS_PROTOCOL_CMD_UNKNOWN; // invalid command
WS_CMD_MAP(parsed_cmd, "last-records", WS_PROTOCOL_CMD_LAST_RECORDS);
return WS_PROTOCOL_CMD_UNKNOWN;
}
void ws_protocol_parse_req_byte(ws_s_protocol_req_parser_state* state, char input) {
switch(input) {
case WS_PROTOCOL_C_EOL: {
break;
}
case WS_PROTOCOL_C_SPACE: {
if (!state->valid) return;
state->arg_len++;
return;
}
case WS_PROTOCOL_C_NULL: {
state->valid = false;
return;
}
default: {
if (!state->valid) return;
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++;
// parse cmd into argc and argv
if (state->valid) ws_protocol_req_cmd_init(state);
// create response
ws_s_protocol_res* response = ws_protocol_parse_req_finished(state->target);
// send response
char response_first_line[16];
sprintf(response_first_line, "%s,%x\n", response->success == WS_PROTOCOL_CMD_RETURN_OK ? "ok" : "error", response->msg->bytes);
ws_protocol_send_data(response_first_line, strlen(response_first_line));
if (!response->csh) ws_protocol_send_data((char*) response->msg->data, response->msg->bytes);
else (*g_ws_protocol_res_handlers[response->cmd_code])(state->target, response, true);
// free response data containers
free(response->msg);
free(response);
// reset parser
ws_protocol_req_parser_reset(state);
return;
}
ws_s_protocol_res* ws_protocol_parse_req_finished(ws_s_protocol_parsed_req_cmd* parsed_cmd) {
ws_s_protocol_res* response = malloc(sizeof(ws_s_protocol_res));
response->success = WS_PROTOCOL_CMD_RETURN_ERROR;
response->csh = false;
response->msg = NULL;
response->cmd_code = ws_protocol_get_req_cmd_code(parsed_cmd);
if (response->cmd_code == WS_PROTOCOL_CMD_UNKNOWN) goto ws_protocol_parse_exit;
if (response->cmd_code >= WS_PROTOCOL_CMD_AMOUNT) goto ws_protocol_parse_exit;
ws_protocol_res_handler_t* ws_protocol_res_handler = g_ws_protocol_res_handlers[response->cmd_code];
if (ws_protocol_res_handler == NULL) goto ws_protocol_parse_exit;
(*ws_protocol_res_handler)(parsed_cmd, response, false);
ws_protocol_parse_exit:
if (response->msg == NULL) response->msg = ws_bin_s_alloc(0);
return response;
}
void ws_protocol_parse_req_bytes(ws_s_protocol_req_parser_state* state, char* input, unsigned int length) {
for (unsigned int i = 0; i < length; i++) ws_protocol_parse_req_byte(state, input[i]);
}
ws_s_protocol_req_parser_state* ws_protocol_req_parser_alloc() {
ws_s_protocol_req_parser_state* parser_state = malloc(sizeof(ws_s_protocol_req_parser_state) + sizeof(uint16_t) * WS_PROTOCOL_CMD_MAX_ARGUMENTS);
parser_state->cmd = malloc(sizeof(char) * WS_PROTOCOL_CMD_BUFFER_LEN);
parser_state->target = NULL;
ws_protocol_req_parser_reset(parser_state);
return parser_state;
}
void ws_protocol_req_cmd_init(ws_s_protocol_req_parser_state* state) {
state->target = malloc(sizeof(ws_s_protocol_parsed_req_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] + 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_req_parser_free(ws_s_protocol_req_parser_state* state) {
if (state == NULL) return;
if (state->target != NULL) ws_protocol_req_cmd_free(state->target);
state->target = NULL;
free(state->cmd);
free(state);
return;
}
void ws_protocol_req_parser_reset(ws_s_protocol_req_parser_state* state) {
if (state->target != NULL) ws_protocol_req_cmd_free(state->target);
state->target = NULL;
state->valid = true;
state->cmd_len = 0;
state->arg_len = 0;
memset(state->args_len, 0, sizeof(uint16_t) * WS_PROTOCOL_CMD_MAX_ARGUMENTS);
}
void ws_protocol_req_cmd_free(ws_s_protocol_parsed_req_cmd* cmd) {
for (int i = 0; i < cmd->argc; i++)
free(cmd->argv[i]);
free(cmd);
return;
}
|