aboutsummaryrefslogtreecommitdiff
path: root/shared/protocol.c
blob: 6e3bc73a69bf7bf3c68553c323625cf7b17c1d01 (plain)
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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "protocol.h"

void ws_protocol_parse_byte(ws_s_protocol_parser_state* state, char input) {
  switch(input) {
    case WS_PROTOCOL_C_NEWLINE: {
      if (!state->valid) return;
      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
	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;
}

#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_cmd_code(ws_s_protocol_parsed_cmd* parsed_cmd) {
	WS_CMD_MAP(parsed_cmd, "last-records", WS_PROTOCOL_CMD_LAST_RECORDS);

	return WS_PROTOCOL_CMD_UNKNOWN;
}

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));
	response->success = WS_PROTOCOL_CMD_RETURN_ERROR;
	response->msg = NULL;

	ws_e_protocol_cmd cmd_code = ws_protocol_get_cmd_code(parsed_cmd);
	if (cmd_code == WS_PROTOCOL_CMD_UNKNOWN) goto ws_protocol_parse_exit;
	if (cmd_code >= WS_PROTOCOL_CMD_AMOUNT) goto ws_protocol_parse_exit;

	void (*ws_protocol_res_handler)(ws_s_protocol_parsed_cmd*, ws_s_protocol_response*) =
		g_ws_protocol_res_handlers[cmd_code];
	if (ws_protocol_res_handler == NULL) goto ws_protocol_parse_exit;
	(*ws_protocol_res_handler)(parsed_cmd, response);

ws_protocol_parse_exit:

	if (response->msg == NULL) response->msg = ws_bin_s_alloc(0);
	return response;
}

void ws_protocol_parse_bytes(ws_s_protocol_parser_state* state, char* input, unsigned int length) {
  for (unsigned int i = 0; i < length; i++) ws_protocol_parse_byte(state, input[i]);
}

ws_s_protocol_parser_state* ws_protocol_parser_alloc() {
  ws_s_protocol_parser_state* parser_state = malloc(sizeof(ws_s_protocol_parser_state) + sizeof(uint16_t) * WS_PROTOCOL_CMD_MAX_ARGUMENTS);
  parser_state->cmd = malloc(sizeof(char) * WS_PROTOCOL_CMD_BUFFER_LEN);
  parser_state->valid = true;
  parser_state->cmd_len = 0;
  parser_state->arg_len = 0;
  parser_state->target = NULL;
  return parser_state;
}

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] + 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) {
  if (state == NULL) return;
  if (state->target != NULL) ws_protocol_cmd_free(state->target);
  free(state->cmd);
  free(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]);
  free(cmd);
  cmd = NULL;
  return;
}