main.c 25 KB

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