main.c 26 KB

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