-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patherpc.c
173 lines (153 loc) · 4.69 KB
/
erpc.c
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/**
* Copyright (c) Project Iota
*
* uCbor is licensed under an Apache license, version 2.0 license.
* All rights not explicitly granted in the Apache license, version 2.0 are reserved.
* See the included LICENSE file for more details.
*
* @author Drasko Draskovic
* @author Paul Rathgeb <[email protected]>
*/
#include "global.h"
#include "jsmn.h"
#include "api.h"
#define JSONRPC_METHOD_KEY "method"
#define JSONRPC_PARAMS_KEY "params"
#define JSONRPC_REPLY_TO_KEY "rto"
#define JSONRPC_NULL "null"
/**
* Globals
*/
static unsigned char method[16] = {0};
static unsigned char fncIdx = 0;
JSMN_PARAMS_t params = {{0}};
static unsigned char replyTo[32] = {0};
static unsigned char paramNb = 0;
/**
* fncTable is an array of function pointers.
* Function pointers are installed by the user.
*/
void (*fncTable[FNC_TABLE_SIZE])(int argc, JSMN_PARAMS_t argv) = {NULL};
/**
* Fowler/Noll/Vo (FNV) hash function, variant 1a
*/
static size_t fnv1a_hash(const unsigned char* cp)
{
size_t hash = 0x811c9dc5;
while (*cp) {
hash ^= (unsigned char) *cp++;
hash *= 0x01000193;
}
return hash;
}
/**
* Helper function to compare strings
*/
static int jsoneq(const char *json, jsmntok_t *tok, const char *s) {
if (tok->type == JSMN_STRING && (int) strlen(s) == tok->end - tok->start &&
strncmp(json + tok->start, s, tok->end - tok->start) == 0) {
return 0;
}
return -1;
}
/**
* Parse JSON and call adequate function from lookup table
*/
int erpcCall(char* req, uint8_t size)
{
int i;
int r;
jsmn_parser p;
jsmntok_t t[16]; /* We expect no more than 128 tokens */
jsmn_init(&p);
r = jsmn_parse(&p, req, size, t, sizeof(t)/sizeof(t[0]));
if (r < 0) {
#ifdef ERPC_DEBUG
printf("Failed to parse JSON: %d\n", r);
#endif
return 1;
}
/* Assume the top-level element is an object */
if (r < 1 || t[0].type != JSMN_OBJECT) {
#ifdef ERPC_DEBUG
printf("Object expected\n");
#endif
return 1;
}
/* Loop over all keys of the root object */
for (i = 1; i < r; i++) {
if (jsoneq(req, &t[i], JSONRPC_METHOD_KEY) == 0) {
int size = t[i+1].end-t[i+1].start;
/* We may use strndup() to fetch string value */
memcpy(method, req + t[i+1].start, t[i+1].end-t[i+1].start);
method[size] = '\0';
#ifdef ERPC_DEBUG
printf("- Method: %s\n", method);
#endif
fncIdx = fnv1a_hash(method) % FNC_TABLE_SIZE;
#ifdef ERPC_DEBUG
printf("- Function Table Index: %d\n", fncIdx);
#endif
i++;
} else if (jsoneq(req, &t[i], JSONRPC_PARAMS_KEY) == 0) {
int j;
#ifdef ERPC_DEBUG
printf("- Params:\n");
#endif
/** Reset paramNb */
paramNb = 0;
if (t[i+1].type != JSMN_ARRAY) {
continue; /* We expect params to be an array of strings */
}
for (j = 0; j < t[i+1].size; j++) {
jsmntok_t *g = &t[i+j+2];
int paramSize = g->end - g->start;
memcpy(params[paramNb], req + g->start, paramSize);
params[paramNb][paramSize] = '\0';
#ifdef ERPC_DEBUG
printf(" * %s\n", params[paramNb]);
#endif
paramNb++;
}
i += t[i+1].size + 1;
} else if (jsoneq(req, &t[i], JSONRPC_REPLY_TO_KEY) == 0) {
int size = t[i+1].end-t[i+1].start;
/* We may want to do strtol() here to get numeric value */
memcpy(replyTo, req + t[i+1].start, size);
replyTo[size] = '\0';
#ifdef ERPC_DEBUG
printf("- replyTo: %s\n", replyTo);
#endif
i++;
} else {
#ifdef ERPC_DEBUG
printf("Unexpected key: %.*s\n", t[i].end-t[i].start,
req + t[i].start);
#endif
}
}
/** Call the function only if the pointer is not pointing on the reset
* vecotr (0x0) */
if (fncTable[fncIdx] == 0)
SendStatus(STATUS_UNRECOGNIZED);
else
fncTable[fncIdx](paramNb, params);
return 0;
}
/**
* Set function table:
* user declares custom functions and stores them in the table
* in his high level program, then tells erpc library to use these functions.
*
* Erpc is platform agnostic - it knows only to parse JSON and call
* method with name `fncIdx` with correct parameters. What will this method
* actually do, it is on user to define.
*/
void erpcAddFunction(char* fncName, void (*f)(int argc, JSMN_PARAMS_t argv))
{
fncIdx = fnv1a_hash((const unsigned char *)fncName) % FNC_TABLE_SIZE;
fncTable[fncIdx] = f;
#ifdef ERPC_DEBUG
printf("Hash %d - %s\n", fncIdx, (const unsigned char*)fncName);
#endif
}