main.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include <stdbool.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <errno.h>
  9. #include <getopt.h>
  10. #include <termios.h>
  11. #include <unistd.h>
  12. #include "host_tool_utils.h"
  13. #include "bi-inc/shared_utils.h"
  14. #include "bi-inc/attr_container.h"
  15. #include "coap_ext.h"
  16. #include "cJSON.h"
  17. #include "app_manager_export.h" /* for Module_WASM_App */
  18. #include "host_link.h" /* for REQUEST_PACKET */
  19. #include "transport.h"
  20. #define BUF_SIZE 1024
  21. #define TIMEOUT_EXIT_CODE 2
  22. #define URL_MAX_LEN 256
  23. #define DEFAULT_TIMEOUT_MS 5000
  24. #define DEFAULT_ALIVE_TIME_MS 0
  25. #define CONNECTION_MODE_TCP 1
  26. #define CONNECTION_MODE_UART 2
  27. typedef enum {
  28. INSTALL,
  29. UNINSTALL,
  30. QUERY,
  31. REQUEST,
  32. REGISTER,
  33. UNREGISTER
  34. } op_type;
  35. typedef struct {
  36. const char *file;
  37. const char *name;
  38. const char *module_type;
  39. int heap_size;
  40. /* max timers number */
  41. int timers;
  42. int watchdog_interval;
  43. } inst_info;
  44. typedef struct {
  45. const char *name;
  46. const char *module_type;
  47. } uninst_info;
  48. typedef struct {
  49. const char *name;
  50. } query_info;
  51. typedef struct {
  52. const char *url;
  53. int action;
  54. const char *json_payload_file;
  55. } req_info;
  56. typedef struct {
  57. const char *urls;
  58. } reg_info;
  59. typedef struct {
  60. const char *urls;
  61. } unreg_info;
  62. typedef union operation_info {
  63. inst_info inst;
  64. uninst_info uinst;
  65. query_info query;
  66. req_info req;
  67. reg_info reg;
  68. unreg_info unreg;
  69. } operation_info;
  70. typedef struct {
  71. op_type type;
  72. operation_info info;
  73. } operation;
  74. typedef enum REPLY_PACKET_TYPE {
  75. REPLY_TYPE_EVENT = 0,
  76. REPLY_TYPE_RESPONSE = 1
  77. } REPLY_PACKET_TYPE;
  78. static uint32_t g_timeout_ms = DEFAULT_TIMEOUT_MS;
  79. static uint32_t g_alive_time_ms = DEFAULT_ALIVE_TIME_MS;
  80. static char *g_redirect_file_name = NULL;
  81. static int g_redirect_udp_port = -1;
  82. static int g_conn_fd; /* may be tcp or uart */
  83. static char *g_server_addr = "127.0.0.1";
  84. static int g_server_port = 8888;
  85. static char *g_uart_dev = "/dev/ttyS2";
  86. static int g_baudrate = B115200;
  87. static int g_connection_mode = CONNECTION_MODE_TCP;
  88. extern int g_mid;
  89. extern unsigned char leading[2];
  90. /* -1 fail, 0 success */
  91. static int
  92. send_request(request_t *request, uint16_t msg_type)
  93. {
  94. char *req_p;
  95. int req_size, req_size_n, ret = -1;
  96. if ((req_p = pack_request(request, &req_size)) == NULL)
  97. return -1;
  98. /* leading bytes */
  99. if (!host_tool_send_data(g_conn_fd, leading, sizeof(leading)))
  100. goto ret;
  101. /* message type */
  102. msg_type = htons(msg_type);
  103. if (!host_tool_send_data(g_conn_fd, (char *)&msg_type, sizeof(msg_type)))
  104. goto ret;
  105. /* payload length */
  106. req_size_n = htonl(req_size);
  107. if (!host_tool_send_data(g_conn_fd, (char *)&req_size_n,
  108. sizeof(req_size_n)))
  109. goto ret;
  110. /* payload */
  111. if (!host_tool_send_data(g_conn_fd, req_p, req_size))
  112. goto ret;
  113. ret = 0;
  114. ret:
  115. free_req_resp_packet(req_p);
  116. return ret;
  117. }
  118. #define url_remain_space (sizeof(url) - strlen(url))
  119. /**
  120. * return: 0: success, others: fail
  121. */
  122. static int
  123. install(inst_info *info)
  124. {
  125. request_t request[1] = { 0 };
  126. char *app_file_buf;
  127. char url[URL_MAX_LEN] = { 0 };
  128. int ret = -1, app_size;
  129. snprintf(url, sizeof(url) - 1, "/applet?name=%s", info->name);
  130. if (info->module_type != NULL && url_remain_space > 0)
  131. snprintf(url + strlen(url), url_remain_space, "&type=%s",
  132. info->module_type);
  133. if (info->heap_size > 0 && url_remain_space > 0)
  134. snprintf(url + strlen(url), url_remain_space, "&heap=%d",
  135. info->heap_size);
  136. if (info->timers > 0 && url_remain_space > 0)
  137. snprintf(url + strlen(url), url_remain_space, "&timers=%d",
  138. info->timers);
  139. if (info->watchdog_interval > 0 && url_remain_space > 0)
  140. snprintf(url + strlen(url), url_remain_space, "&wd=%d",
  141. info->watchdog_interval);
  142. if ((app_file_buf = read_file_to_buffer(info->file, &app_size)) == NULL)
  143. return -1;
  144. init_request(request, url, COAP_PUT, FMT_APP_RAW_BINARY, app_file_buf,
  145. app_size);
  146. request->mid = gen_random_id();
  147. if (info->module_type == NULL || strcmp(info->module_type, "wasm") == 0)
  148. ret = send_request(request, INSTALL_WASM_APP);
  149. else
  150. ret = send_request(request, REQUEST_PACKET);
  151. free(app_file_buf);
  152. return ret;
  153. }
  154. static int
  155. uninstall(uninst_info *info)
  156. {
  157. request_t request[1] = { 0 };
  158. char url[URL_MAX_LEN] = { 0 };
  159. snprintf(url, sizeof(url) - 1, "/applet?name=%s", info->name);
  160. if (info->module_type != NULL && url_remain_space > 0)
  161. snprintf(url + strlen(url), url_remain_space, "&type=%s",
  162. info->module_type);
  163. init_request(request, url, COAP_DELETE, FMT_ATTR_CONTAINER, NULL, 0);
  164. request->mid = gen_random_id();
  165. return send_request(request, REQUEST_PACKET);
  166. }
  167. static int
  168. query(query_info *info)
  169. {
  170. request_t request[1] = { 0 };
  171. char url[URL_MAX_LEN] = { 0 };
  172. if (info->name != NULL)
  173. snprintf(url, sizeof(url) - 1, "/applet?name=%s", info->name);
  174. else
  175. snprintf(url, sizeof(url) - 1, "/applet");
  176. init_request(request, url, COAP_GET, FMT_ATTR_CONTAINER, NULL, 0);
  177. request->mid = gen_random_id();
  178. return send_request(request, REQUEST_PACKET);
  179. }
  180. static int
  181. request(req_info *info)
  182. {
  183. request_t request[1] = { 0 };
  184. attr_container_t *payload = NULL;
  185. int ret = -1, payload_len = 0;
  186. if (info->json_payload_file != NULL) {
  187. char *payload_file;
  188. cJSON *json;
  189. int payload_file_size;
  190. if ((payload_file = read_file_to_buffer(info->json_payload_file,
  191. &payload_file_size))
  192. == NULL)
  193. return -1;
  194. if (NULL == (json = cJSON_Parse(payload_file))) {
  195. free(payload_file);
  196. goto fail;
  197. }
  198. if (NULL == (payload = json2attr(json))) {
  199. cJSON_Delete(json);
  200. free(payload_file);
  201. goto fail;
  202. }
  203. payload_len = attr_container_get_serialize_length(payload);
  204. cJSON_Delete(json);
  205. free(payload_file);
  206. }
  207. init_request(request, (char *)info->url, info->action, FMT_ATTR_CONTAINER,
  208. payload, payload_len);
  209. request->mid = gen_random_id();
  210. ret = send_request(request, REQUEST_PACKET);
  211. if (info->json_payload_file != NULL && payload != NULL)
  212. attr_container_destroy(payload);
  213. fail:
  214. return ret;
  215. }
  216. /**
  217. * TODO: currently only support 1 url.
  218. * how to handle multiple responses and set process's exit code?
  219. */
  220. static int
  221. subscribe(reg_info *info)
  222. {
  223. request_t request[1] = { 0 };
  224. int ret = -1;
  225. #if 0
  226. char *p;
  227. p = strtok(info->urls, ",");
  228. while(p != NULL) {
  229. char url[URL_MAX_LEN] = {0};
  230. snprintf(url, URL_MAX_LEN, "%s%s", "/event/", p);
  231. init_request(request,
  232. url,
  233. COAP_PUT,
  234. FMT_ATTR_CONTAINER,
  235. NULL,
  236. 0);
  237. request->mid = gen_random_id();
  238. ret = send_request(request, false);
  239. p = strtok (NULL, ",");
  240. }
  241. #else
  242. char url[URL_MAX_LEN] = { 0 };
  243. char *prefix = info->urls[0] == '/' ? "/event" : "/event/";
  244. snprintf(url, URL_MAX_LEN, "%s%s", prefix, info->urls);
  245. init_request(request, url, COAP_PUT, FMT_ATTR_CONTAINER, NULL, 0);
  246. request->mid = gen_random_id();
  247. ret = send_request(request, REQUEST_PACKET);
  248. #endif
  249. return ret;
  250. }
  251. static int
  252. unsubscribe(unreg_info *info)
  253. {
  254. request_t request[1] = { 0 };
  255. int ret = -1;
  256. #if 0
  257. char *p;
  258. p = strtok(info->urls, ",");
  259. while(p != NULL) {
  260. char url[URL_MAX_LEN] = {0};
  261. snprintf(url, URL_MAX_LEN, "%s%s", "/event/", p);
  262. init_request(request,
  263. url,
  264. COAP_DELETE,
  265. FMT_ATTR_CONTAINER,
  266. NULL,
  267. 0);
  268. request->mid = gen_random_id();
  269. ret = send_request(request, false);
  270. p = strtok (NULL, ",");
  271. }
  272. #else
  273. char url[URL_MAX_LEN] = { 0 };
  274. snprintf(url, URL_MAX_LEN, "%s%s", "/event/", info->urls);
  275. init_request(request, url, COAP_DELETE, FMT_ATTR_CONTAINER, NULL, 0);
  276. request->mid = gen_random_id();
  277. ret = send_request(request, REQUEST_PACKET);
  278. #endif
  279. return ret;
  280. }
  281. static int
  282. init()
  283. {
  284. if (g_connection_mode == CONNECTION_MODE_TCP) {
  285. int fd;
  286. if (!tcp_init(g_server_addr, g_server_port, &fd))
  287. return -1;
  288. g_conn_fd = fd;
  289. return 0;
  290. }
  291. else if (g_connection_mode == CONNECTION_MODE_UART) {
  292. int fd;
  293. if (!uart_init(g_uart_dev, g_baudrate, &fd))
  294. return -1;
  295. g_conn_fd = fd;
  296. return 0;
  297. }
  298. return -1;
  299. }
  300. static void
  301. deinit()
  302. {
  303. close(g_conn_fd);
  304. }
  305. static int
  306. parse_action(const char *str)
  307. {
  308. if (strcasecmp(str, "PUT") == 0)
  309. return COAP_PUT;
  310. if (strcasecmp(str, "GET") == 0)
  311. return COAP_GET;
  312. if (strcasecmp(str, "DELETE") == 0)
  313. return COAP_DELETE;
  314. if (strcasecmp(str, "POST") == 0)
  315. return COAP_POST;
  316. return -1;
  317. }
  318. /* clang-format off */
  319. static void showUsage()
  320. {
  321. printf("Usages:\n");
  322. printf(" host_tool -i|-u|-q|-r|-s|-d ...\n");
  323. printf(" host_tool -i <App Name> -f <App File>\n"
  324. " [--type=<App Type>]\n"
  325. " [--heap=<Heap Size>]\n"
  326. " [--timers=<Timers Number>]\n"
  327. " [--watchdog=<Watchdog Interval>]\n"
  328. " [<Control Options> ...] \n");
  329. printf(" host_tool -u <App Name> [<Control Options> ...]\n");
  330. printf(" host_tool -q[<App Name>] [<Control Options> ...]\n");
  331. printf(" host_tool -r <Resource URL> -A <Action> [-p <Payload File>] [<Control Options> ...]\n");
  332. printf(" host_tool -s <Event URLs> [<Control Options> ...]\n");
  333. printf(" host_tool -d <Event URLs> [<Control Options> ...]\n");
  334. printf("\nGeneral Options:\n");
  335. printf(" -i, --install Install an application\n");
  336. printf(" -u, --uninstall Uninstall an application\n");
  337. printf(" -q, --query Query all applications\n");
  338. printf(" -r, --request Send a request\n");
  339. printf(" -s, --register Register event(s)\n");
  340. printf(" -d, --deregister De-register event(s)\n");
  341. printf(" -f, --file Specify app binary file path\n");
  342. printf(" -A, --action Specify action of the request\n");
  343. printf(" -p, --payload Specify payload of the request\n");
  344. printf("\nControl Options:\n");
  345. printf(" -S <Address>|--address=<Address> Set server address, default to 127.0.0.1\n");
  346. printf(" -P <Port>|--port=<Port> Set server port, default to 8888\n");
  347. printf(" -D <Device>|--uart=<Device> Set uart device, default to /dev/ttyS2\n");
  348. printf(" -B <Baudrate>|--baudrate=<Baudrate> Set uart device baudrate, default to 115200\n");
  349. printf(" -t <timeout>|--timeout=<timeout> Operation timeout in ms, default to 5000\n");
  350. printf(" -a <alive_time>|--alive=<alive_time> Alive time in ms after last operation done, default to 0\n");
  351. printf(" -o <output_file>|--output=<output_file> Redirect the output to output a file\n");
  352. printf(" -U <udp_port>|--udp=<udp_port> Redirect the output to an UDP port in local machine\n");
  353. printf("\nNotes:\n");
  354. printf(" <App Name>=name of the application\n");
  355. printf(" <App File>=path of the application binary file in wasm format\n");
  356. printf(" <Resource URL>=resource descriptor, such as /app/<App Name>/res1 or /res1\n");
  357. printf(" <Event URLs>=event url list separated by ',', such as /event1,/event2,/event3\n");
  358. printf(" <Action>=action of the request, can be PUT, GET, DELETE or POST (case insensitive)\n");
  359. printf(" <Payload File>=path of the payload file in json format\n");
  360. printf(" <App Type>=Type of app. Can be 'wasm'(default) or 'jeff'\n");
  361. printf(" <Heap Size>=Heap size of app.\n");
  362. printf(" <Timers Number>=Max timers number app can use.\n");
  363. printf(" <Watchdog Interval>=Watchdog interval in ms.\n");
  364. }
  365. #define CHECK_DUPLICATE_OPERATION do { \
  366. if (operation_parsed) { \
  367. showUsage(); \
  368. return false; \
  369. } \
  370. } while(0)
  371. #define ERROR_RETURN do { \
  372. showUsage(); \
  373. return false; \
  374. } while(0)
  375. #define CHECK_ARGS_UNMATCH_OPERATION(op_type) do { \
  376. if (!operation_parsed || op->type != op_type) { \
  377. showUsage(); \
  378. return false; \
  379. } \
  380. } while(0)
  381. static bool parse_args(int argc, char *argv[], operation *op)
  382. {
  383. int c;
  384. bool operation_parsed = false;
  385. bool conn_mode_parsed = false;
  386. while (1) {
  387. int optIndex = 0;
  388. static struct option longOpts[] = {
  389. { "install", required_argument, NULL, 'i' },
  390. { "uninstall", required_argument, NULL, 'u' },
  391. { "query", optional_argument, NULL, 'q' },
  392. { "request", required_argument, NULL, 'r' },
  393. { "register", required_argument, NULL, 's' },
  394. { "deregister", required_argument, NULL, 'd' },
  395. { "timeout", required_argument, NULL, 't' },
  396. { "alive", required_argument, NULL, 'a' },
  397. { "output", required_argument, NULL, 'o' },
  398. { "udp", required_argument, NULL, 'U' },
  399. { "action", required_argument, NULL, 'A' },
  400. { "file", required_argument, NULL, 'f' },
  401. { "payload", required_argument, NULL, 'p' },
  402. { "type", required_argument, NULL, 0 },
  403. { "heap", required_argument, NULL, 1 },
  404. { "timers", required_argument, NULL, 2 },
  405. { "watchdog", required_argument, NULL, 3 },
  406. { "address", required_argument, NULL, 'S' },
  407. { "port", required_argument, NULL, 'P' },
  408. { "uart_device",required_argument, NULL, 'D' },
  409. { "baudrate", required_argument, NULL, 'B' },
  410. { "help", required_argument, NULL, 'h' },
  411. { 0, 0, 0, 0 }
  412. };
  413. c = getopt_long(argc, argv, "i:u:q::r:s:d:t:a:o:U:A:f:p:S:P:D:B:h",
  414. longOpts, &optIndex);
  415. if (c == -1)
  416. break;
  417. switch (c) {
  418. case 'i':
  419. CHECK_DUPLICATE_OPERATION;
  420. op->type = INSTALL;
  421. op->info.inst.name = optarg;
  422. operation_parsed = true;
  423. break;
  424. case 'u':
  425. CHECK_DUPLICATE_OPERATION;
  426. op->type = UNINSTALL;
  427. op->info.uinst.name = optarg;
  428. operation_parsed = true;
  429. break;
  430. case 'q':
  431. CHECK_DUPLICATE_OPERATION;
  432. op->type = QUERY;
  433. op->info.query.name = optarg;
  434. break;
  435. case 'r':
  436. CHECK_DUPLICATE_OPERATION;
  437. op->type = REQUEST;
  438. op->info.req.url = optarg;
  439. operation_parsed = true;
  440. break;
  441. case 's':
  442. CHECK_DUPLICATE_OPERATION;
  443. op->type = REGISTER;
  444. op->info.reg.urls = optarg;
  445. operation_parsed = true;
  446. break;
  447. case 'd':
  448. CHECK_DUPLICATE_OPERATION;
  449. op->type = UNREGISTER;
  450. op->info.unreg.urls = optarg;
  451. operation_parsed = true;
  452. break;
  453. case 't':
  454. g_timeout_ms = atoi(optarg);
  455. break;
  456. case 'a':
  457. g_alive_time_ms = atoi(optarg);
  458. break;
  459. case 'o':
  460. g_redirect_file_name = optarg;
  461. break;
  462. case 'U':
  463. g_redirect_udp_port = atoi(optarg);
  464. break;
  465. case 'A':
  466. CHECK_ARGS_UNMATCH_OPERATION(REQUEST);
  467. op->info.req.action = parse_action(optarg);
  468. break;
  469. case 'f':
  470. CHECK_ARGS_UNMATCH_OPERATION(INSTALL);
  471. op->info.inst.file = optarg;
  472. break;
  473. case 'p':
  474. CHECK_ARGS_UNMATCH_OPERATION(REQUEST);
  475. op->info.req.json_payload_file = optarg;
  476. break;
  477. /* module type */
  478. case 0:
  479. /* TODO: use bit mask */
  480. /* CHECK_ARGS_UNMATCH_OPERATION(INSTALL | UNINSTALL); */
  481. if (op->type == INSTALL)
  482. op->info.inst.module_type = optarg;
  483. else if (op->type == UNINSTALL)
  484. op->info.uinst.module_type = optarg;
  485. break;
  486. /* heap */
  487. case 1:
  488. CHECK_ARGS_UNMATCH_OPERATION(INSTALL);
  489. op->info.inst.heap_size = atoi(optarg);
  490. break;
  491. /* timers */
  492. case 2:
  493. CHECK_ARGS_UNMATCH_OPERATION(INSTALL);
  494. op->info.inst.timers = atoi(optarg);
  495. break;
  496. /* watchdog */
  497. case 3:
  498. CHECK_ARGS_UNMATCH_OPERATION(INSTALL);
  499. op->info.inst.watchdog_interval = atoi(optarg);
  500. break;
  501. case 'S':
  502. if (conn_mode_parsed) {
  503. showUsage();
  504. return false;
  505. }
  506. g_connection_mode = CONNECTION_MODE_TCP;
  507. g_server_addr = optarg;
  508. conn_mode_parsed = true;
  509. break;
  510. case 'P':
  511. g_server_port = atoi(optarg);
  512. break;
  513. case 'D':
  514. if (conn_mode_parsed) {
  515. showUsage();
  516. return false;
  517. }
  518. g_connection_mode = CONNECTION_MODE_UART;
  519. g_uart_dev = optarg;
  520. conn_mode_parsed = true;
  521. break;
  522. case 'B':
  523. g_baudrate = parse_baudrate(atoi(optarg));
  524. break;
  525. case 'h':
  526. showUsage();
  527. return false;
  528. default:
  529. showUsage();
  530. return false;
  531. }
  532. }
  533. /* check mandatory options for the operation */
  534. switch (op->type) {
  535. case INSTALL:
  536. if (NULL == op->info.inst.file || NULL == op->info.inst.name)
  537. ERROR_RETURN;
  538. break;
  539. case UNINSTALL:
  540. if (NULL == op->info.uinst.name)
  541. ERROR_RETURN;
  542. break;
  543. case QUERY:
  544. break;
  545. case REQUEST:
  546. if (NULL == op->info.req.url || op->info.req.action <= 0)
  547. ERROR_RETURN;
  548. break;
  549. case REGISTER:
  550. if (NULL == op->info.reg.urls)
  551. ERROR_RETURN;
  552. break;
  553. case UNREGISTER:
  554. if (NULL == op->info.unreg.urls)
  555. ERROR_RETURN;
  556. break;
  557. default:
  558. return false;
  559. }
  560. return true;
  561. }
  562. /**
  563. * return value: < 0: not complete message
  564. * REPLY_TYPE_EVENT: event(request)
  565. * REPLY_TYPE_RESPONSE: response
  566. */
  567. static int process_reply_data(const char *buf, int len,
  568. imrt_link_recv_context_t *ctx)
  569. {
  570. int result = -1;
  571. const char *pos = buf;
  572. #if DEBUG
  573. int i = 0;
  574. for (; i < len; i++) {
  575. printf(" 0x%02x", buf[i]);
  576. }
  577. printf("\n");
  578. #endif
  579. while (len-- > 0) {
  580. result = on_imrt_link_byte_arrive((unsigned char) *pos++, ctx);
  581. switch (result) {
  582. case 0: {
  583. imrt_link_message_t *message = &ctx->message;
  584. if (message->message_type == RESPONSE_PACKET)
  585. return REPLY_TYPE_RESPONSE;
  586. if (message->message_type == REQUEST_PACKET)
  587. return REPLY_TYPE_EVENT;
  588. break;
  589. }
  590. default:
  591. break;
  592. }
  593. }
  594. return -1;
  595. }
  596. static response_t *
  597. parse_response_from_imrtlink(imrt_link_message_t *message, response_t *response)
  598. {
  599. if (!unpack_response(message->payload, message->payload_size, response))
  600. return NULL;
  601. return response;
  602. }
  603. static request_t *
  604. parse_event_from_imrtlink(imrt_link_message_t *message, request_t *request)
  605. {
  606. if (!unpack_request(message->payload, message->payload_size, request))
  607. return NULL;
  608. return request;
  609. }
  610. static void output(const char *header, attr_container_t *payload,
  611. int foramt, int payload_len)
  612. {
  613. cJSON *json = NULL;
  614. char *json_str = NULL;
  615. /* output the header */
  616. printf("%s", header);
  617. if (g_redirect_file_name != NULL)
  618. wirte_buffer_to_file(g_redirect_file_name, header, strlen(header));
  619. if (g_redirect_udp_port > 0 && g_redirect_udp_port < 65535)
  620. udp_send("127.0.0.1", g_redirect_udp_port, header, strlen(header));
  621. if (foramt != FMT_ATTR_CONTAINER || payload == NULL || payload_len <= 0)
  622. return;
  623. if ((json = attr2json(payload)) == NULL)
  624. return;
  625. if ((json_str = cJSON_Print(json)) == NULL) {
  626. cJSON_Delete(json);
  627. return;
  628. }
  629. /* output the payload as json format */
  630. printf("%s", json_str);
  631. if (g_redirect_file_name != NULL)
  632. wirte_buffer_to_file(g_redirect_file_name, json_str, strlen(json_str));
  633. if (g_redirect_udp_port > 0 && g_redirect_udp_port < 65535)
  634. udp_send("127.0.0.1", g_redirect_udp_port, json_str, strlen(json_str));
  635. free(json_str);
  636. cJSON_Delete(json);
  637. }
  638. static void output_response(response_t *obj)
  639. {
  640. char header[32] = { 0 };
  641. snprintf(header, sizeof(header), "\nresponse status %d\n", obj->status);
  642. output(header, obj->payload, obj->fmt, obj->payload_len);
  643. }
  644. static void output_event(request_t *obj)
  645. {
  646. char header[256] = { 0 };
  647. snprintf(header, sizeof(header), "\nreceived an event %s\n", obj->url);
  648. output(header, obj->payload, obj->fmt, obj->payload_len);
  649. }
  650. int main(int argc, char *argv[])
  651. {
  652. int ret = -1;
  653. imrt_link_recv_context_t recv_ctx = { 0 };
  654. char buffer[BUF_SIZE] = { 0 };
  655. uint32_t last_check = 0, total_elpased_ms = 0;
  656. bool is_responsed = false;
  657. operation op;
  658. memset(&op, 0, sizeof(op));
  659. if (!parse_args(argc, argv, &op))
  660. return -1;
  661. /* TODO: reconnect 3 times */
  662. if (init() != 0)
  663. return -1;
  664. switch (op.type) {
  665. case INSTALL:
  666. ret = install((inst_info *) &op.info.inst);
  667. break;
  668. case UNINSTALL:
  669. ret = uninstall((uninst_info *) &op.info.uinst);
  670. break;
  671. case QUERY:
  672. ret = query((query_info *) &op.info.query);
  673. break;
  674. case REQUEST:
  675. ret = request((req_info *) &op.info.req);
  676. break;
  677. case REGISTER:
  678. ret = subscribe((reg_info *) &op.info.reg);
  679. break;
  680. case UNREGISTER:
  681. ret = unsubscribe((unreg_info *) &op.info.unreg);
  682. break;
  683. default:
  684. goto ret;
  685. }
  686. if (ret != 0)
  687. goto ret;
  688. bh_get_elpased_ms(&last_check);
  689. while (1) {
  690. int result = 0;
  691. fd_set readfds;
  692. struct timeval tv;
  693. total_elpased_ms += bh_get_elpased_ms(&last_check);
  694. if (!is_responsed) {
  695. if (total_elpased_ms >= g_timeout_ms) {
  696. output("operation timeout\n", NULL, 0, 0);
  697. ret = TIMEOUT_EXIT_CODE;
  698. goto ret;
  699. }
  700. } else {
  701. if (total_elpased_ms >= g_alive_time_ms) {
  702. /*ret = 0;*/
  703. goto ret;
  704. }
  705. }
  706. if (g_conn_fd == -1) {
  707. if ((init() != 0)
  708. || (g_conn_fd == -1)) {
  709. sleep(1);
  710. continue;
  711. }
  712. }
  713. FD_ZERO(&readfds);
  714. FD_SET(g_conn_fd, &readfds);
  715. tv.tv_sec = 1;
  716. tv.tv_usec = 0;
  717. result = select(FD_SETSIZE, &readfds, NULL, NULL, &tv);
  718. if (result < 0) {
  719. if (errno != EINTR) {
  720. printf("Error in select, errno: 0x%x\n", errno);
  721. ret = -1;
  722. goto ret;
  723. }
  724. }
  725. else if (result == 0) { /* select timeout */
  726. }
  727. else if (result > 0) {
  728. int n;
  729. if (FD_ISSET(g_conn_fd, &readfds)) {
  730. int reply_type = -1;
  731. n = read(g_conn_fd, buffer, BUF_SIZE);
  732. if (n <= 0) {
  733. g_conn_fd = -1;
  734. continue;
  735. }
  736. reply_type = process_reply_data((char *) buffer, n, &recv_ctx);
  737. if (reply_type == REPLY_TYPE_RESPONSE) {
  738. response_t response[1] = { 0 };
  739. parse_response_from_imrtlink(&recv_ctx.message, response);
  740. if (response->mid != g_mid) {
  741. /* ignore invalid response */
  742. continue;
  743. }
  744. is_responsed = true;
  745. ret = response->status;
  746. output_response(response);
  747. if (op.type == REGISTER || op.type == UNREGISTER) {
  748. /* alive time start */
  749. total_elpased_ms = 0;
  750. bh_get_elpased_ms(&last_check);
  751. }
  752. }
  753. else if (reply_type == REPLY_TYPE_EVENT) {
  754. request_t event[1] = { 0 };
  755. parse_event_from_imrtlink(&recv_ctx.message, event);
  756. if (op.type == REGISTER || op.type == UNREGISTER) {
  757. output_event(event);
  758. }
  759. }
  760. }
  761. }
  762. } /* end of while(1) */
  763. ret:
  764. if (recv_ctx.message.payload != NULL)
  765. free(recv_ctx.message.payload);
  766. deinit();
  767. return ret;
  768. }