jrpc.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925
  1. /*
  2. * This file is part of the PikaPython project.
  3. * http://github.com/pikastech/pikapython
  4. *
  5. * MIT License
  6. *
  7. * Copyright (c) 2024 lyon liang6516@outlook.com
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining a
  10. * copy of this software and associated documentation files (the "Software"),
  11. * to deal in the Software without restriction, including without limitation
  12. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  13. * and/or sell copies of the Software, and to permit persons to whom the
  14. * Software is furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be included in
  17. * all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  22. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  24. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  25. * DEALINGS IN THE SOFTWARE.
  26. */
  27. #include "jrpc.h"
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. // Function pointers for memory management
  32. static void* (*port_mem_malloc)(size_t size) = malloc;
  33. static void (*port_mem_free)(void* ptr) = free;
  34. static int (*port_vprintf)(const char* format, va_list args) = vprintf;
  35. static void jrpc_debug(const char* format, ...) {
  36. va_list args;
  37. va_start(args, format);
  38. if (port_vprintf) {
  39. port_vprintf(format, args);
  40. }
  41. va_end(args);
  42. }
  43. // API to set memory management functions
  44. void set_jrpc_memory_functions(void* (*malloc_func)(size_t),
  45. void (*free_func)(void*)) {
  46. port_mem_malloc = malloc_func;
  47. port_mem_free = free_func;
  48. cJSON_Hooks cJson_hooks = {.free_fn = free_func, .malloc_fn = malloc_func};
  49. cJSON_InitHooks(&cJson_hooks);
  50. }
  51. void set_jrpc_vprintf_function(int (*vprintf_func)(const char*, va_list)) {
  52. port_vprintf = vprintf_func;
  53. }
  54. char* jrpc_strdup(const char* str) {
  55. size_t len = strlen(str) + 1;
  56. char* copy = (char*)port_mem_malloc(len);
  57. if (copy) {
  58. memcpy(copy, str, len);
  59. }
  60. return copy;
  61. }
  62. void* jrpc_malloc(size_t size) {
  63. return port_mem_malloc(size);
  64. }
  65. void jrpc_free(void* ptr) {
  66. port_mem_free(ptr);
  67. }
  68. /* private function */
  69. static int JRPC_send_message_wait_ACK_with_retry(JRPC* self,
  70. const char* request_str,
  71. int retry_count,
  72. unsigned long ack_timeout,
  73. int id,
  74. const char* label);
  75. static void JRPC_send_acknowledgement(JRPC* self,
  76. int id,
  77. ack_status status,
  78. const char* label);
  79. static const char* JRPC_type_2_string(int type) {
  80. switch (type) {
  81. case TYPE_REQUEST:
  82. return STR_TYPE_REQUEST;
  83. case TYPE_ACK:
  84. return STR_TYPE_ACK;
  85. case TYPE_RESULT:
  86. return STR_TYPE_RESULT;
  87. default:
  88. return "UNKNOWN";
  89. }
  90. }
  91. // Example function: add
  92. static cJSON* add(cJSON* params[], int param_count) {
  93. int a = params[0]->valueint;
  94. int b = params[1]->valueint;
  95. int sum = a + b;
  96. cJSON* result = cJSON_CreateNumber(sum);
  97. return result;
  98. }
  99. // Example non-blocking function: add_nonblocking
  100. static int add_nonblocking(int id,
  101. cJSON* params[],
  102. int param_count,
  103. JRPC* self) {
  104. int a = params[0]->valueint;
  105. int b = params[1]->valueint;
  106. int sum = a + b;
  107. cJSON* result = cJSON_CreateNumber(sum);
  108. JRPC_send_response(self, id, result);
  109. return 0;
  110. }
  111. // Example function: subtract
  112. static cJSON* subtract(cJSON* params[], int param_count) {
  113. int a = params[0]->valueint;
  114. int b = params[1]->valueint;
  115. int difference = a - b;
  116. cJSON* result = cJSON_CreateNumber(difference);
  117. return result;
  118. }
  119. static rpc_mapping default_rpc_map[] = {{"add", add, 2},
  120. {"subtract", subtract, 2},
  121. RPC_MAP_END};
  122. static rpc_mapping_nonblocking default_nonblocking_rpc_map[] = {
  123. {"add_nonblocking", add_nonblocking, 2},
  124. RPC_MAP_END};
  125. // Function to create an acknowledgement string
  126. char* create_acknowledgement_string(int id, ack_status status) {
  127. cJSON* response = cJSON_CreateObject();
  128. cJSON_AddStringToObject(response, STR_JSON_RPC_FIELD, STR_JSON_RPC_VERSION);
  129. cJSON_AddStringToObject(
  130. response, STR_STATUS_FIELD,
  131. (status == ACK_SUCCESS) ? STR_RECEIVED_STATUS
  132. : (status == ACK_METHOD_NOT_FOUND) ? STR_METHOD_NOT_FOUND_STATUS
  133. : (status == ACK_INVALID_PARAMS) ? STR_INVALID_PARAMS_STATUS
  134. : STR_UNKNOWN_STATUS);
  135. cJSON_AddNumberToObject(response, STR_ID_FIELD, id);
  136. cJSON_AddNumberToObject(response, STR_TYPE_FIELD,
  137. TYPE_ACK); // Add type field
  138. char* response_str = cJSON_Print(response);
  139. cJSON_Delete(response);
  140. return response_str;
  141. }
  142. // Function to send an acknowledgement
  143. static void JRPC_send_acknowledgement(JRPC* self,
  144. int id,
  145. ack_status status,
  146. const char* label) {
  147. char* response_str = create_acknowledgement_string(id, status);
  148. jrpc_debug("[%s] ACK: %s\n", label, response_str);
  149. self->send(response_str);
  150. jrpc_free(response_str);
  151. }
  152. void JRPC_send_response(JRPC* self, int id, cJSON* result) {
  153. cJSON* response = cJSON_CreateObject();
  154. cJSON_AddStringToObject(response, STR_JSON_RPC_FIELD, STR_JSON_RPC_VERSION);
  155. cJSON_AddItemToObject(response, STR_RESULT_FIELD, result);
  156. cJSON_AddNumberToObject(response, STR_ID_FIELD, id);
  157. cJSON_AddNumberToObject(response, STR_TYPE_FIELD,
  158. TYPE_RESULT); // Add type field
  159. char* response_str = cJSON_Print(response);
  160. jrpc_debug("[Server] Response: %s\n", response_str);
  161. self->send(response_str);
  162. jrpc_free(response_str);
  163. cJSON_Delete(response);
  164. }
  165. void JRPC_server_handle_string(JRPC* self, char* json_str) {
  166. cJSON* json = cJSON_Parse(json_str);
  167. if (json == NULL) {
  168. jrpc_debug("Error parsing JSON\n");
  169. return;
  170. }
  171. cJSON* jsonrpc = cJSON_GetObjectItem(json, STR_JSON_RPC_FIELD);
  172. cJSON* method = cJSON_GetObjectItem(json, STR_METHOD_FIELD);
  173. cJSON* params = cJSON_GetObjectItem(json, STR_PARAMS_FIELD);
  174. cJSON* id = cJSON_GetObjectItem(json, STR_ID_FIELD);
  175. cJSON* type = cJSON_GetObjectItem(json, STR_TYPE_FIELD);
  176. if (!cJSON_IsString(jsonrpc) || !cJSON_IsString(method) ||
  177. !cJSON_IsArray(params) || !cJSON_IsNumber(id) ||
  178. !cJSON_IsNumber(type)) {
  179. jrpc_debug("[Server] Invalid JSON RPC request format: %s\n", json_str);
  180. cJSON_Delete(json);
  181. return;
  182. }
  183. if (strcmp(jsonrpc->valuestring, STR_JSON_RPC_VERSION) != 0) {
  184. jrpc_debug("Unsupported JSON RPC version: %s\n", jsonrpc->valuestring);
  185. cJSON_Delete(json);
  186. return;
  187. }
  188. if (type->valueint != TYPE_REQUEST) {
  189. jrpc_debug("Invalid JSON RPC message type\n");
  190. cJSON_Delete(json);
  191. return;
  192. }
  193. int expected_param_count;
  194. rpc_function_nonblocking func_nonblocking =
  195. JRPC_find_nonblocking_rpc_function(self, method->valuestring,
  196. &expected_param_count);
  197. rpc_function func = NULL;
  198. int is_nonblocking = (func_nonblocking != NULL);
  199. if (!is_nonblocking) {
  200. func = JRPC_find_rpc_function(self, method->valuestring,
  201. &expected_param_count);
  202. if (func == NULL) {
  203. JRPC_send_acknowledgement(self, id->valueint, ACK_METHOD_NOT_FOUND,
  204. "Server");
  205. cJSON_Delete(json);
  206. return;
  207. }
  208. }
  209. int param_count = cJSON_GetArraySize(params);
  210. if (expected_param_count != PARAM_COUNT_NO_CHECK &&
  211. param_count != expected_param_count) {
  212. JRPC_send_acknowledgement(self, id->valueint, ACK_INVALID_PARAMS,
  213. "Server");
  214. cJSON_Delete(json);
  215. return;
  216. }
  217. // Try to get ACK from client to start task
  218. char* ack_str = create_acknowledgement_string(id->valueint, ACK_SUCCESS);
  219. #if JRPC_USING_DOUBLE_ACK
  220. JRPC_send_message_wait_ACK_with_retry(self, ack_str, 1, ACK_TIMEOUT,
  221. id->valueint, "Server");
  222. #else
  223. self->send(ack_str);
  224. #endif
  225. if (ack_str) {
  226. jrpc_free(ack_str);
  227. }
  228. cJSON** param_array =
  229. (cJSON**)jrpc_malloc(param_count * sizeof(cJSON*) + 1);
  230. if (param_array == NULL) {
  231. jrpc_debug("Memory allocation failed for param_array\n");
  232. JRPC_send_acknowledgement(self, id->valueint, ACK_MEMORY_ERROR,
  233. "Server");
  234. cJSON_Delete(json);
  235. return;
  236. }
  237. for (int i = 0; i < param_count; i++) {
  238. param_array[i] = cJSON_GetArrayItem(params, i);
  239. }
  240. if (is_nonblocking) {
  241. func_nonblocking(id->valueint, param_array, param_count, self);
  242. } else {
  243. cJSON* result = func(param_array, param_count);
  244. JRPC_send_response(self, id->valueint, result);
  245. }
  246. jrpc_free(param_array);
  247. cJSON_Delete(json);
  248. }
  249. void JRPC_server_handle(JRPC* self) {
  250. char* json_str = self->receive();
  251. if (NULL != json_str) {
  252. JRPC_server_handle_string(self, json_str);
  253. }
  254. if (self->receive_need_free) {
  255. jrpc_free(json_str);
  256. }
  257. }
  258. rpc_function JRPC_find_rpc_function(JRPC* self,
  259. const char* name,
  260. int* param_count) {
  261. if (NULL == self->map) {
  262. return NULL;
  263. }
  264. for (int i = 0; self->map[i].name != NULL; i++) {
  265. if (strcmp(self->map[i].name, name) == 0) {
  266. *param_count = self->map[i].param_count;
  267. return self->map[i].func;
  268. }
  269. }
  270. return NULL; // Function not found
  271. }
  272. rpc_function_nonblocking JRPC_find_nonblocking_rpc_function(JRPC* self,
  273. const char* name,
  274. int* param_count) {
  275. if (NULL == self->nonblocking_map) {
  276. return NULL;
  277. }
  278. for (int i = 0; self->nonblocking_map[i].name != NULL; i++) {
  279. if (strcmp(self->nonblocking_map[i].name, name) == 0) {
  280. *param_count = self->nonblocking_map[i].param_count;
  281. return self->nonblocking_map[i].func;
  282. }
  283. }
  284. return NULL; // Function not found
  285. }
  286. // Cache add function
  287. void JRPC_cache_add(JRPC* self, cJSON* item) {
  288. if (self->cache_count < CACHE_SIZE) {
  289. self->cache[self->cache_count++] = item;
  290. } else {
  291. // Cache full, delete oldest
  292. cJSON_Delete(self->cache[0]);
  293. for (int i = 0; i < CACHE_SIZE - 1; i++) {
  294. self->cache[i] = self->cache[i + 1];
  295. }
  296. self->cache[CACHE_SIZE - 1] = item;
  297. }
  298. }
  299. // Cache get function
  300. cJSON* JRPC_cache_get(JRPC* self, int id, int type) {
  301. for (int i = 0; i < self->cache_count; i++) {
  302. cJSON* cached_json = self->cache[i];
  303. cJSON* cached_id = cJSON_GetObjectItem(cached_json, STR_ID_FIELD);
  304. cJSON* cached_type = cJSON_GetObjectItem(cached_json, STR_TYPE_FIELD);
  305. if (cached_id && cJSON_IsNumber(cached_id) &&
  306. cached_id->valueint == id && cached_type &&
  307. cJSON_IsNumber(cached_type) && cached_type->valueint == type) {
  308. // Found match, return and remove from cache
  309. cJSON* result = cached_json;
  310. for (int j = i; j < self->cache_count - 1; j++) {
  311. self->cache[j] = self->cache[j + 1];
  312. }
  313. self->cache[--self->cache_count] = NULL;
  314. return result;
  315. }
  316. }
  317. return NULL;
  318. }
  319. cJSON* JRPC_receive_with_id_and_type(JRPC* self, int id, int type) {
  320. // Check cache first
  321. cJSON* cached_json = JRPC_cache_get(self, id, type);
  322. if (cached_json != NULL) {
  323. return cached_json;
  324. }
  325. // No match in cache, receive from interface
  326. char* received_str = self->receive();
  327. if (received_str != NULL) {
  328. cJSON* received_json = cJSON_Parse(received_str);
  329. if (self->receive_need_free) {
  330. jrpc_free(received_str);
  331. }
  332. if (received_json != NULL) {
  333. cJSON* received_id =
  334. cJSON_GetObjectItem(received_json, STR_ID_FIELD);
  335. cJSON* received_type =
  336. cJSON_GetObjectItem(received_json, STR_TYPE_FIELD);
  337. if (received_id && cJSON_IsNumber(received_id) &&
  338. received_id->valueint == id && received_type &&
  339. cJSON_IsNumber(received_type) &&
  340. received_type->valueint == type) {
  341. return received_json;
  342. } else {
  343. // Cache data
  344. JRPC_cache_add(self, received_json);
  345. }
  346. }
  347. }
  348. return NULL;
  349. }
  350. static int JRPC_send_message_wait_ACK_with_retry(JRPC* self,
  351. const char* request_str,
  352. int retry_count,
  353. unsigned long ack_timeout,
  354. int id,
  355. const char* label) {
  356. cJSON* ack_json = NULL;
  357. int result = -1;
  358. for (int retry = 0; retry < retry_count; retry++) {
  359. jrpc_debug("[%s] Send and await %s with retry [%d]: %s\n", label,
  360. JRPC_type_2_string(TYPE_ACK), retry, request_str);
  361. self->send(request_str);
  362. unsigned long start_time = self->tick();
  363. while (1) {
  364. ack_json = JRPC_receive_with_id_and_type(self, id, TYPE_ACK);
  365. if (ack_json != NULL) {
  366. jrpc_debug("[%s] Received ACK, id: %d\n", label, id);
  367. // check status for ACK
  368. if (cJSON_HasObjectItem(ack_json, STR_STATUS_FIELD)) {
  369. cJSON* status =
  370. cJSON_GetObjectItem(ack_json, STR_STATUS_FIELD);
  371. if (status && cJSON_IsString(status) &&
  372. strcmp(status->valuestring, STR_RECEIVED_STATUS) == 0) {
  373. result = 0; // Received correct ACK
  374. goto __exit;
  375. } else {
  376. jrpc_debug("[%s] Received ACK status: [%s]\n", label,
  377. status->valuestring);
  378. result = -1; // Received incorrect ACK
  379. goto __exit;
  380. }
  381. }
  382. }
  383. if (self->tick() - start_time >= ack_timeout) {
  384. jrpc_debug("[%s] ACK timeout, retrying...\n", label);
  385. break;
  386. }
  387. self->yield(); // Thread switch
  388. }
  389. }
  390. jrpc_debug("[%s] Failed to receive ACK after %d retries\n", label,
  391. retry_count);
  392. __exit:
  393. if (ack_json) {
  394. cJSON_Delete(ack_json);
  395. }
  396. return result; // Return the result based on ACK reception
  397. }
  398. void JRPC_send_request_no_blocking(JRPC* self,
  399. const char* method,
  400. cJSON* params[],
  401. int param_count,
  402. rpc_callback callback) {
  403. // Build request
  404. int id = ++self->current_id;
  405. cJSON* request = cJSON_CreateObject();
  406. cJSON_AddStringToObject(request, STR_JSON_RPC_FIELD, STR_JSON_RPC_VERSION);
  407. cJSON_AddStringToObject(request, STR_METHOD_FIELD, method);
  408. cJSON* params_array = cJSON_CreateArray();
  409. for (int i = 0; i < param_count; i++) {
  410. cJSON_AddItemToArray(params_array, cJSON_Duplicate(params[i], 1));
  411. }
  412. cJSON_AddItemToObject(request, STR_PARAMS_FIELD, params_array);
  413. cJSON_AddNumberToObject(request, STR_ID_FIELD, id);
  414. cJSON_AddNumberToObject(request, STR_TYPE_FIELD,
  415. TYPE_REQUEST); // Add type field
  416. char* request_str = cJSON_Print(request);
  417. jrpc_debug("[Client] Sending Request (no_blocking): %s\n", request_str);
  418. if (JRPC_send_message_wait_ACK_with_retry(self, request_str, RETRY_COUNT,
  419. ACK_TIMEOUT, id, "Client") != 0) {
  420. // If ACK received
  421. callback(NULL); // Simulate callback, no result
  422. }
  423. JRPC_send_acknowledgement(self, id, ACK_SUCCESS, "Client");
  424. jrpc_free(request_str);
  425. cJSON_Delete(request);
  426. }
  427. cJSON* JRPC_send_request_blocking(JRPC* self,
  428. const char* method,
  429. cJSON* params[],
  430. int param_count) {
  431. // Build request
  432. cJSON* resObj = NULL;
  433. int id = ++self->current_id;
  434. cJSON* request = cJSON_CreateObject();
  435. cJSON_AddStringToObject(request, STR_JSON_RPC_FIELD, STR_JSON_RPC_VERSION);
  436. cJSON_AddStringToObject(request, STR_METHOD_FIELD, method);
  437. cJSON* params_array = cJSON_CreateArray();
  438. for (int i = 0; i < param_count; i++) {
  439. cJSON_AddItemToArray(params_array, cJSON_Duplicate(params[i], 1));
  440. }
  441. cJSON_AddItemToObject(request, STR_PARAMS_FIELD, params_array);
  442. cJSON_AddNumberToObject(request, STR_ID_FIELD, id);
  443. cJSON_AddNumberToObject(request, STR_TYPE_FIELD,
  444. TYPE_REQUEST); // Add type field
  445. char* request_str = cJSON_Print(request);
  446. jrpc_debug("[Client] Sending Request (blocking): %s\n", request_str);
  447. if (JRPC_send_message_wait_ACK_with_retry(self, request_str, RETRY_COUNT,
  448. ACK_TIMEOUT, id, "Client") != 0) {
  449. resObj = NULL;
  450. goto __exit;
  451. }
  452. JRPC_send_acknowledgement(self, id, ACK_SUCCESS, "Client");
  453. // Wait for response
  454. unsigned long start_time = self->tick();
  455. while (1) {
  456. cJSON* response_json =
  457. JRPC_receive_with_id_and_type(self, id, TYPE_RESULT);
  458. if (response_json != NULL) {
  459. char* response_str = cJSON_Print(response_json);
  460. jrpc_debug("[Client] Received Response: %s\n", response_str);
  461. jrpc_free(response_str);
  462. resObj = response_json;
  463. goto __exit;
  464. }
  465. if (self->tick() - start_time >= BLOCKING_TIMEOUT) {
  466. jrpc_debug("[Client] Response timeout\n");
  467. resObj = NULL;
  468. goto __exit;
  469. }
  470. self->yield(); // Thread switch
  471. }
  472. __exit:
  473. cJSON_Delete(request);
  474. if (NULL != request_str) {
  475. jrpc_free(request_str);
  476. }
  477. return resObj;
  478. }
  479. // Mock send function with validation
  480. static char* mock_sent_message = NULL;
  481. static void mock_send(const char* message) {
  482. jrpc_debug("[Mock] send: %s\n", message);
  483. if (mock_sent_message) {
  484. jrpc_free(mock_sent_message);
  485. }
  486. mock_sent_message = jrpc_strdup(message); // Capture sent message
  487. }
  488. // Mock receive function (non-blocking)
  489. static char* mock_receive(void) {
  490. static int call_count = 0;
  491. call_count++;
  492. switch (call_count) {
  493. case 3:
  494. return jrpc_strdup(
  495. "{\"jsonrpc\": \"1.0\", \"status\": \"received\", \"id\": 1, "
  496. "\"type\": 1}");
  497. case 6:
  498. return jrpc_strdup(
  499. "{\"jsonrpc\": \"1.0\", \"status\": \"received\", \"id\": 2, "
  500. "\"type\": 1}");
  501. case 9:
  502. return jrpc_strdup(
  503. "{\"jsonrpc\": \"1.0\", \"result\": 8, \"id\": 2, \"type\": "
  504. "2}");
  505. default:
  506. return NULL;
  507. }
  508. }
  509. static char* mock_receive_server_test(void) {
  510. static int call_count = 0;
  511. call_count++;
  512. switch (call_count) {
  513. case 3:
  514. return jrpc_strdup(
  515. "{\"jsonrpc\": \"1.0\", \"status\": \"received\", \"id\": 1, "
  516. "\"type\": 1}");
  517. case 6:
  518. return jrpc_strdup(
  519. "{\"jsonrpc\": \"1.0\", \"status\": \"received\", \"id\": 2, "
  520. "\"type\": 1}");
  521. case 9:
  522. return jrpc_strdup(
  523. "{\"jsonrpc\": \"1.0\", \"status\": \"received\", \"id\": 3, "
  524. "\"type\": 1}");
  525. default:
  526. return NULL;
  527. }
  528. }
  529. // Mock yield function
  530. static void mock_yield(void) {
  531. jrpc_debug("[Y]");
  532. }
  533. // Mock tick function
  534. static unsigned long mock_tick_ms(void) {
  535. static unsigned long tick = 0;
  536. tick += 100; // Simulate 100ms per call
  537. return tick;
  538. }
  539. static void result_callback(cJSON* result) {
  540. jrpc_debug("Callback executed. Result: %s\n",
  541. result ? cJSON_Print(result) : "No result");
  542. }
  543. int jrpc_test_client() {
  544. int ret = 0;
  545. JRPC jrpc = {0};
  546. JRPC_init(&jrpc, default_rpc_map, default_nonblocking_rpc_map, mock_send,
  547. mock_receive, 1, mock_yield, mock_tick_ms);
  548. // Test no_blocking
  549. cJSON* params1[] = {cJSON_CreateNumber(5), cJSON_CreateNumber(3)};
  550. JRPC_send_request_no_blocking(&jrpc, "add_nonblocking", params1, 2,
  551. result_callback);
  552. // Test blocking
  553. cJSON* params2[] = {cJSON_CreateNumber(5), cJSON_CreateNumber(3)};
  554. cJSON* response = JRPC_send_request_blocking(&jrpc, "add", params2, 2);
  555. char* call_result = cJSON_Print(response);
  556. jrpc_debug("[Client] Blocking call result: %s\n", call_result);
  557. jrpc_free(call_result);
  558. // Result should be 8
  559. if (response == NULL ||
  560. cJSON_GetObjectItem(response, "result")->valueint != 8) {
  561. ret = -1;
  562. }
  563. cJSON_Delete(response);
  564. for (int i = 0; i < 2; i++) {
  565. cJSON_Delete(params1[i]);
  566. cJSON_Delete(params2[i]);
  567. }
  568. if (mock_sent_message) {
  569. jrpc_free(mock_sent_message);
  570. mock_sent_message = NULL;
  571. }
  572. return ret;
  573. }
  574. int jrpc_compare_json_strings(const char* json_str1, const char* json_str2) {
  575. cJSON* json1 = cJSON_Parse(json_str1);
  576. cJSON* json2 = cJSON_Parse(json_str2);
  577. if (json1 == NULL || json2 == NULL) {
  578. if (json1) {
  579. cJSON_Delete(json1);
  580. } else {
  581. jrpc_debug("json1 is NULL\n");
  582. }
  583. if (json2) {
  584. cJSON_Delete(json2);
  585. } else {
  586. jrpc_debug("json2 is NULL\n");
  587. }
  588. return -1;
  589. }
  590. int result = cJSON_Compare(json1, json2, 1) ? 0 : -1;
  591. if (0 != result) {
  592. jrpc_debug("Json compare failed\n");
  593. jrpc_debug("json1: %s\n", json_str1);
  594. jrpc_debug("json2: %s\n", json_str2);
  595. }
  596. cJSON_Delete(json1);
  597. cJSON_Delete(json2);
  598. return result;
  599. }
  600. int jrpc_validate_response(const char* expected_response) {
  601. if (mock_sent_message == NULL) {
  602. return -1;
  603. }
  604. return jrpc_compare_json_strings(mock_sent_message, expected_response);
  605. }
  606. int jrpc_test_server() {
  607. JRPC jrpc = {0};
  608. JRPC_init(&jrpc, default_rpc_map, default_nonblocking_rpc_map, mock_send,
  609. mock_receive_server_test, 1, mock_yield, mock_tick_ms);
  610. const char* requests[] = {
  611. "{\"jsonrpc\": \"1.0\", \"method\": \"add\", \"params\": [5, 3], "
  612. "\"id\": 1, \"type\": 0}",
  613. "{\"jsonrpc\": \"1.0\", \"method\": \"subtract\", \"params\": [10, 4], "
  614. "\"id\": 2, \"type\": 0}",
  615. "{\"jsonrpc\": \"1.0\", \"method\": \"add_nonblocking\", \"params\": "
  616. "[2, 2], \"id\": 3, \"type\": 0}",
  617. };
  618. const char* expected_responses[] = {
  619. "{\"jsonrpc\": \"1.0\", \"result\": 8, \"id\": 1, \"type\": 2}",
  620. "{\"jsonrpc\": \"1.0\", \"result\": 6, \"id\": 2, \"type\": 2}",
  621. "{\"jsonrpc\": \"1.0\", \"result\": 4, \"id\": 3, \"type\": 2}"};
  622. int ret = 0;
  623. for (int i = 0; i < sizeof(requests) / sizeof(requests[0]); i++) {
  624. JRPC_server_handle_string(&jrpc, (char*)requests[i]);
  625. if (jrpc_validate_response(expected_responses[i]) != 0) {
  626. ret = -1;
  627. break;
  628. }
  629. }
  630. JRPC_deinit(&jrpc);
  631. if (mock_sent_message) {
  632. jrpc_free(mock_sent_message);
  633. mock_sent_message = NULL;
  634. }
  635. return ret;
  636. }
  637. char* jrpc_strtok(char* str, const char* delimiters, char** context) {
  638. char* start = str ? str : *context;
  639. if (!start) {
  640. return NULL;
  641. }
  642. // Skip initial delimiters
  643. while (*start && strchr(delimiters, *start)) {
  644. ++start;
  645. }
  646. if (!*start) {
  647. *context = NULL;
  648. return NULL;
  649. }
  650. char* end = start;
  651. while (*end && !strchr(delimiters, *end)) {
  652. ++end;
  653. }
  654. if (*end) {
  655. *end = '\0';
  656. *context = end + 1;
  657. } else {
  658. *context = NULL;
  659. }
  660. return start;
  661. }
  662. static char* extract_quoted_string(const char** input) {
  663. const char* start = *input;
  664. if (*start != '"') {
  665. return NULL;
  666. }
  667. start++;
  668. const char* end = strchr(start, '"');
  669. if (!end) {
  670. return NULL;
  671. }
  672. size_t len = end - start;
  673. char* result = (char*)malloc(len + 1);
  674. if (!result) {
  675. return NULL;
  676. }
  677. memcpy(result, start, len);
  678. result[len] = '\0';
  679. *input = end + 1;
  680. return result;
  681. }
  682. static void skip_whitespace(const char** input) {
  683. if (input == NULL || *input == NULL) {
  684. return;
  685. }
  686. while (**input == ' ' || **input == '\t' || **input == '\n') {
  687. (*input)++;
  688. }
  689. }
  690. char* JRPC_cmd(JRPC* jrpc, const char* cmd) {
  691. char* cmd_copy = NULL;
  692. char* method = NULL;
  693. cJSON* params_array[10] = {NULL};
  694. int param_count = 0;
  695. char* result_str = NULL;
  696. cJSON* result = NULL;
  697. cmd_copy = jrpc_strdup(cmd);
  698. if (!cmd_copy) {
  699. jrpc_debug("Failed to duplicate command\n");
  700. goto __exit;
  701. }
  702. const char* cursor = cmd_copy;
  703. skip_whitespace(&cursor);
  704. char* token = jrpc_strtok(cmd_copy, " ", (char**)&cursor);
  705. if (token == NULL) {
  706. jrpc_debug("Invalid command\n");
  707. goto __exit;
  708. }
  709. method = jrpc_strdup(token);
  710. if (!method) {
  711. jrpc_debug("Failed to duplicate method\n");
  712. goto __exit;
  713. }
  714. skip_whitespace(&cursor);
  715. while (cursor && *cursor != '\0') {
  716. cJSON* param = NULL;
  717. if (*cursor == '"') {
  718. char* str_param = extract_quoted_string(&cursor);
  719. if (!str_param) {
  720. jrpc_debug("Failed to extract quoted string\n");
  721. goto __exit;
  722. }
  723. param = cJSON_CreateString(str_param);
  724. free(str_param);
  725. } else {
  726. const char* start = cursor;
  727. while (*cursor != ' ' && *cursor != '\0') {
  728. cursor++;
  729. }
  730. size_t len = cursor - start;
  731. char* token_param = (char*)malloc(len + 1);
  732. if (!token_param) {
  733. jrpc_debug("Failed to allocate memory for token_param\n");
  734. goto __exit;
  735. }
  736. memcpy(token_param, start, len);
  737. token_param[len] = '\0';
  738. param = cJSON_Parse(token_param);
  739. if (!param) {
  740. param = cJSON_CreateString(token_param);
  741. }
  742. free(token_param);
  743. }
  744. if (!param) {
  745. jrpc_debug("Failed to create JSON parameter\n");
  746. goto __exit;
  747. }
  748. params_array[param_count] = param;
  749. param_count++;
  750. skip_whitespace(&cursor);
  751. }
  752. // Ensure params_array and param_count are handled correctly when
  753. // param_count is 0
  754. result = JRPC_send_request_blocking(
  755. jrpc, method, param_count > 0 ? params_array : NULL, param_count);
  756. if (result == NULL) {
  757. jrpc_debug("No result\n");
  758. goto __exit;
  759. }
  760. cJSON* result_data = cJSON_GetObjectItem(result, "result");
  761. if (result_data == NULL) {
  762. jrpc_debug("No result item\n");
  763. goto __exit;
  764. }
  765. result_str = cJSON_Print(result_data);
  766. if (!result_str) {
  767. jrpc_debug("Failed to print JSON result\n");
  768. goto __exit;
  769. }
  770. __exit:
  771. for (int i = 0; i < param_count; i++) {
  772. if (params_array[i]) {
  773. cJSON_Delete(params_array[i]);
  774. }
  775. }
  776. if (result) {
  777. cJSON_Delete(result);
  778. }
  779. if (method) {
  780. jrpc_free(method);
  781. }
  782. if (cmd_copy) {
  783. jrpc_free(cmd_copy);
  784. }
  785. return result_str;
  786. }
  787. void JRPC_init(JRPC* jrpc,
  788. rpc_mapping* rpc_map,
  789. rpc_mapping_nonblocking* nonblocking_rpc_map,
  790. void (*send_func)(const char* message),
  791. char* (*receive_func)(void),
  792. int receive_need_free,
  793. void (*yield_func)(void),
  794. unsigned long (*tick_func)(void)) {
  795. jrpc->map = rpc_map;
  796. jrpc->nonblocking_map = nonblocking_rpc_map;
  797. jrpc->send = send_func;
  798. jrpc->receive = receive_func;
  799. jrpc->receive_need_free = receive_need_free;
  800. jrpc->yield = yield_func;
  801. jrpc->tick = tick_func;
  802. jrpc->current_id = 0;
  803. memset(jrpc->cache, 0, sizeof(jrpc->cache));
  804. jrpc->cache_count = 0;
  805. }
  806. void JRPC_deinit(JRPC* jrpc) {
  807. for (int i = 0; i < jrpc->cache_count; i++) {
  808. cJSON_Delete(jrpc->cache[i]);
  809. jrpc->cache[i] = NULL;
  810. }
  811. jrpc->cache_count = 0;
  812. }