blob: bfc180bbe5f5b25fdbd6dbaa379e68b1f86ab6f2 [file] [log] [blame]
Vadim Iosevichd50ea462017-03-30 16:19:08 +03001/*
2 * Copyright (c) 2017, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <sstream>
34
35#include "servercmd.h"
36#include "debug.h"
37
38#define EXP_NON 0
39#define EXP_CMD (-1)
40#define EXP_IFC 1
41#define EXP_NUM 2
42#define EXP_HEX 3
43#define EXP_SEP 4
44#define EXP_END 5
45
46const char* parser_state_to_string(int parserState)
47{
48 switch (parserState)
49 {
50 case EXP_NON: return "EXP_NON";
51 case EXP_CMD: return "EXP_CMD";
52 case EXP_IFC: return "EXP_IFC";
53 case EXP_NUM: return "EXP_NUM";
54 case EXP_HEX: return "EXP_HEX";
55 case EXP_SEP: return "EXP_SEP";
56 case EXP_END: return "EXP_END";
57 default: return "<unknown>";
58 }
59}
60
61
62static int states_table[][5] =
63{
64 { EXP_END, 0, 0, 0, 0 }, // 0 - get_interfaces
65 { EXP_IFC, EXP_END, 0, 0, 0 }, // 1 - open_interface name
66 { EXP_IFC, EXP_END, 0, 0, 0 }, // 2 - close_interface name
67 { EXP_IFC, EXP_NUM, EXP_END, 0, 0 }, // 3 - r name address
68 { EXP_IFC, EXP_NUM, EXP_NUM, EXP_END, 0 }, // 4 - rb name address count
69 { EXP_IFC, EXP_NUM, EXP_NUM, EXP_END, 0 }, // 5 - w name address value
70 { EXP_IFC, EXP_NUM, EXP_HEX, EXP_END, 0 }, // 6 - wb name address hexstring
71 { EXP_IFC, EXP_END, 0, 0, 0 }, // 7 - interface_reset name
72 { EXP_IFC, EXP_END, 0, 0, 0 }, // 8 - sw_reset name
73 { EXP_END, 0, 0, 0, 0 }, // 9 - exit
74 { EXP_IFC, EXP_NUM, EXP_NUM, EXP_END, 0 }, // 10 - Alloc_PMC name number_of_descriptors size_of_descriptors
75 { EXP_IFC, EXP_NUM, EXP_END, 0, 0 }, // 11 - read_pmc interface requestReferenceNumber
76 { EXP_NUM, EXP_END, 0, 0, 0 }, // 12 - read_pmc_file requestReferenceNumber
77 { EXP_IFC, EXP_END, 0, 0, 0 }, // 13 - set_host_alias
78};
79
80
81// The return value is copied because std::stringstream::str() returns a temporary object
82std::string parser_state_machine_to_string(int* pStateMachine)
83{
84 if (!pStateMachine)
85 {
86 return std::string("{}");
87 }
88
89 std::stringstream ss;
90
91 ss << "{ ";
92
93 size_t numStates = sizeof(states_table[0])/sizeof(int);
94 for (size_t i = 0; i < numStates; ++i)
95 {
96 ss << parser_state_to_string(pStateMachine[i]) << " ";
97 }
98 ss << "}";
99
100 return ss.str();
101}
102
103
104const char* command_to_string(int cmdCode)
105{
106 switch (cmdCode)
107 {
108 case CMD_COMMAND_UNKNOWN: return "CMD_COMMAND_UNKNOWN";
109 case CMD_GET_INTERFACES: return "CMD_GET_INTERFACES";
110 case CMD_OPEN_INTERFACE: return "CMD_OPEN_INTERFACE";
111 case CMD_CLOSE_INTERFACE: return "CMD_CLOSE_INTERFACE";
112 case CMD_R: return "CMD_R";
113 case CMD_RB: return "CMD_RB";
114 case CMD_W: return "CMD_W";
115 case CMD_WB: return "CMD_WB";
116 case CMD_INTERFACE_RESET: return "CMD_INTERFACE_RESET";
117 case CMD_SW_RESET: return "CMD_SW_RESET";
118 case CMD_EXIT: return "CMD_EXIT";
119 case CMD_ALLOC_PMC: return "CMD_ALLOC_PMC";
120 case CMD_READ_PMC: return "CMD_READ_PMC";
121 case CMD_READ_PMC_FILE: return "CMD_READ_PMC_FILE";
122 case CMD_SET_HOST_ALIAS: return "CMD_SET_HOST_ALIAS";
123 default: return "<unknown>";
124 }
125}
126
127
128const char* parser_error_to_string(int parserError)
129{
130 switch (parserError)
131 {
132 case ERR_BAD_TOKEN: return "ERR_BAD_TOKEN";
133 case ERR_BAD_VALUE: return "VALUE";
134 case ERR_UNTERMINATED_STRING: return "ERR_UNTERMINATED_STRING";
135 case ERR_BAD_HEX_VALUE: return "ERR_BAD_HEX_VALUE";
136 case ERR_CMD_NOT_EXPECTED: return "ERR_CMD_NOT_EXPECTED";
137 case ERR_IFACE_NOT_EXPECTED: return "ERR_IFACE_NOT_EXPECTED";
138 case ERR_VALUE_NOT_EXPECTED: return "ERR_VALUE_NOT_EXPECTED";
139 case ERR_HEX_NOT_EXPECTED: return "ERR_HEX_NOT_EXPECTED";
140 case ERR_END_NOT_EXPECTED: return "ERR_END_NOT_EXPECTED";
141 default: return "<unknown>";
142 }
143}
144
145
146
147/*
148 Callback on parser start.
149 Returns the handler to be used in all subsequent callbacks
150 or NULL in case of error, the parsing will be aborted then
151*/
152void cb_parser_start(servercmd_t *s)
153{
154 s->states = NULL;
155 s->state = EXP_CMD; // We start with expecting a command
156 s->cmd = CMD_COMMAND_UNKNOWN;
157 s->error = 0;
158 s->address = (unsigned int)-1;
159 s->value = (unsigned int)-1;
160 s->hexdata_len = 0;
161 s->hexdata = (unsigned int*)malloc (sizeof(int)*MAX_REGS_LEN);
162}
163
164/*
165 Callback on a command. Gets the command code.
166 Returns 0 if ok, 1 if error, the parsing will be aborted then
167*/
168int cb_cmd(servercmd_t *s, int cmd)
169{
170 LOG_VERBOSE <<"cb_cmd(" << cmd << ") state index = " << s->state << std::endl;
171 LOG_VERBOSE << "State Machine: " << parser_state_machine_to_string(s->states) << std::endl;
172
173 if(s->state != EXP_CMD) {
174 s->error = ERR_CMD_NOT_EXPECTED;
175 LOG_ERROR << "Command not expected, expecting " << s->state << std::endl;
176 return -1;
177 }
178 LOG_VERBOSE << "Parsed Command: " << cmd << "(" << command_to_string(cmd) << ")" << std::endl;
179 s->cmd = cmd;
180 s->states = states_table[cmd];
181 s->state++;
182
183 return 0;
184}
185
186
187/*
188 Returns 0 if ok, 1 if error, the parsing will be aborted then
189*/
190int cb_id(servercmd_t *s, const char *id)
191{
192 LOG_VERBOSE << "cb_id(" << id << ") state index = " << s->state << std::endl;
193 LOG_VERBOSE << "State Machine: " << parser_state_machine_to_string(s->states) << std::endl;
194
195 if((s->states == NULL) || (s->states[s->state] != EXP_IFC)) {
196 s->error = ERR_IFACE_NOT_EXPECTED;
197 LOG_ERROR << "Interface not expected, expecting: "
198 << (s->states?s->states[s->state]:-1) << std::endl;
199 return -1;
200 }
201
202 LOG_VERBOSE << "Interface id: " << id << std::endl;
203 snprintf(s->interface, MAX_INTERFACE_NAME, "%s", id);
204 s->state++;
205 return 0;
206}
207
208/*
209 Returns 0 if ok, 1 if error, the parsing will be aborted then
210*/
211int cb_number(servercmd_t *s, const char *id)
212{
213 LOG_VERBOSE << "cb_number(" << id << ") state index = " << s->state << std::endl;
214 LOG_VERBOSE << "State Machine: " << parser_state_machine_to_string(s->states) << std::endl;
215
216 if((s->states == NULL) || (s->states[s->state] != EXP_NUM)) {
217 s->error = ERR_VALUE_NOT_EXPECTED;
218 LOG_ERROR << "Number not expected, expecting " << (s->states?s->states[s->state]:-1) << std::endl;
219 return -1;
220 }
221
222 // A hack now. if address already set, the number is for data
223 LOG_VERBOSE << "string number " << id << std::endl;
224
225 if(s->address != (unsigned int)-1){
226 sscanf(id, "%u", &(s->value));
227 //s->value = strtoul(id, tmp, 10); //10 is the base for conversion
228 // dprint("str to uint Parsed val %u\n", strtoul(id, tmp, 10));
229 // dprint("str to int Parsed val %u\n", atol(id));//s->value = atol(id);
230 LOG_VERBOSE << "scanf Parsed value: " << s->value << std::endl;
231 }
232 else{
233 // s->address = atol(id);
234 sscanf(id, "%u", &(s->address));
235 LOG_VERBOSE << "Parsed addr " << s->address << std::endl;
236 }
237 s->state++;
238 return 0;
239}
240
241/*
242 Callback on hex data
243 Returns 0 if ok, 1 if error, the parsing will be aborted then
244*/
245int cb_hexbyte(servercmd_t *s, int b)
246{
247 LOG_VERBOSE << "cb_hexbyte(0x" << std::hex << b << std::dec << ") state index = " << s->state << std::endl;
248 LOG_VERBOSE << "State Machine: " << parser_state_machine_to_string(s->states) << std::endl;
249
250 if((s->states == NULL) || (s->states[s->state] != EXP_HEX)) {
251 s->error = ERR_HEX_NOT_EXPECTED;
252 LOG_ERROR << "Hex not expected, expecting " << (s->states?s->states[s->state]:-1) << std::endl;
253 return -1;
254 }
255 if(s->hexdata_len == MAX_REGS_LEN) {
256 s->error = ERR_BAD_HEX_VALUE;
257 LOG_ERROR << "Too long hex data" << std::endl;
258 return -1;
259 }
260 LOG_VERBOSE << "Hex byte 0x" << std::hex << b << std::dec << std::endl;
261 s->hexdata[s->hexdata_len] = b;
262 s->hexdata_len++;
263 // Do not change the s->state here, we are still expecting hex data. cb_endhex will change the state
264 return 0;
265}
266
267/*
268 Callback on end of hex data string
269 Returns 0 if ok, 1 if error, the parsing will be aborted then
270*/
271
272int cb_endhex(servercmd_t *s)
273{
274 LOG_VERBOSE << "cb_endhex() state index = " << s->state << std::endl;
275 LOG_VERBOSE << "State Machine: " << parser_state_machine_to_string(s->states) << std::endl;
276
277 if((s->states == NULL) || (s->states[s->state] != EXP_HEX)) {
278 s->error = ERR_HEX_NOT_EXPECTED;
279 LOG_ERROR << "Hex not expected, expecting " << (s->states?s->states[s->state]:-1) << std::endl;
280 return -1;
281 }
282 s->state++;
283 return 0;
284}
285
286/*
287 Callback on a separator, not used.
288 Returns 0 if ok, 1 if error, the parsing will be aborted then
289*/
290int cb_separator(servercmd_t *s)
291{
292 (void)s;
293 return 0;
294}
295
296/*
297 Callback on the parser end
298 Returns the parser result: 0 if ok, error otherwise
299*/
300void cb_parser_end(servercmd_t *s)
301{
302 LOG_VERBOSE << "cb_parser_end() state index = " << s->state << std::endl;
303 LOG_VERBOSE << "State Machine: " << parser_state_machine_to_string(s->states) << std::endl;
304
305 if((s->error == 0) && ((s->states == NULL) || (s->states[s->state] != EXP_END))) {
306 LOG_ERROR << "End of parser while still expecting " << (s->states?s->states[s->state]:-1) << std::endl;
307 s->error = ERR_END_NOT_EXPECTED;
308 }
309
310 free(s->hexdata);
311}
312
313/*
314 Callback on parser error
315*/
316void cb_error(servercmd_t *s, int error, const char *str)
317{
318 (void)str;
319 s->error = error;
320 LOG_ERROR << "Parser error: " << error << std::endl;
321}
322
323/*
324 Service function. Converting a hex digit from a character.
325*/
326int hexdigit(char d)
327{
328 if((d >= '0') && (d <= '9'))
329 return d-'0';
330 else if((d >= 'A') && (d <= 'F'))
331 return d-'A'+10;
332 else if((d >- 'a') && (d <= 'f'))
333 return d-'a'+10;
334 else // This shouldn't happen, it's the parser's responsibility to parse valid hex digits
335 return 0;
336}