request.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "bi-inc/attr_container.h"
  6. #include "wa-inc/request.h"
  7. #include "wa-inc/timer_wasm_app.h"
  8. #include "bi-inc/shared_utils.h"
  9. #include "wasm_app.h"
  10. #include "req_resp_api.h"
  11. #include "timer_api.h"
  12. #define TRANSACTION_TIMEOUT_MS 5000
  13. typedef enum {
  14. Reg_Event, Reg_Request
  15. } reg_type_t;
  16. typedef struct _res_register {
  17. struct _res_register *next;
  18. const char * url;
  19. reg_type_t reg_type;
  20. void (*request_handler)(request_t *);
  21. } res_register_t;
  22. typedef struct transaction {
  23. struct transaction *next;
  24. int mid;
  25. unsigned int time; /* start time */
  26. response_handler_f handler;
  27. void *user_data;
  28. } transaction_t;
  29. static res_register_t * g_resources = NULL;
  30. static transaction_t *g_transactions = NULL;
  31. static user_timer_t g_trans_timer = NULL;
  32. static transaction_t *transaction_find(int mid)
  33. {
  34. transaction_t *t = g_transactions;
  35. while (t) {
  36. if (t->mid == mid)
  37. return t;
  38. t = t->next;
  39. }
  40. return NULL;
  41. }
  42. /*
  43. * new transaction is added to the tail of the list, so the list
  44. * is sorted by expiry time naturally.
  45. */
  46. static void transaction_add(transaction_t *trans)
  47. {
  48. transaction_t *t;
  49. if (g_transactions == NULL) {
  50. g_transactions = trans;
  51. return;
  52. }
  53. t = g_transactions;
  54. while (t) {
  55. if (t->next == NULL) {
  56. t->next = trans;
  57. return;
  58. }
  59. }
  60. }
  61. static void transaction_remove(transaction_t *trans)
  62. {
  63. transaction_t *prev = NULL, *current = g_transactions;
  64. while (current) {
  65. if (current == trans) {
  66. if (prev == NULL) {
  67. g_transactions = current->next;
  68. free(current);
  69. return;
  70. }
  71. prev->next = current->next;
  72. free(current);
  73. return;
  74. }
  75. prev = current;
  76. current = current->next;
  77. }
  78. }
  79. static bool is_event_type(request_t * req)
  80. {
  81. return req->action == COAP_EVENT;
  82. }
  83. static bool register_url_handler(const char *url,
  84. request_handler_f request_handler, reg_type_t reg_type)
  85. {
  86. res_register_t * r = g_resources;
  87. while (r) {
  88. if (reg_type == r->reg_type && strcmp(r->url, url) == 0) {
  89. r->request_handler = request_handler;
  90. return true;
  91. }
  92. r = r->next;
  93. }
  94. r = (res_register_t *) malloc(sizeof(res_register_t));
  95. if (r == NULL)
  96. return false;
  97. memset(r, 0, sizeof(*r));
  98. r->url = strdup(url);
  99. if (!r->url) {
  100. free(r);
  101. return false;
  102. }
  103. r->request_handler = request_handler;
  104. r->reg_type = reg_type;
  105. r->next = g_resources;
  106. g_resources = r;
  107. // tell app mgr to route this url to me
  108. if (reg_type == Reg_Request)
  109. wasm_register_resource(url);
  110. else
  111. wasm_sub_event(url);
  112. return true;
  113. }
  114. bool api_register_resource_handler(const char *url,
  115. request_handler_f request_handler)
  116. {
  117. return register_url_handler(url, request_handler, Reg_Request);
  118. }
  119. static void transaction_timeout_handler(user_timer_t timer)
  120. {
  121. transaction_t *cur, *expired = NULL;
  122. unsigned int elpased_ms, now = wasm_get_sys_tick_ms();
  123. /*
  124. * Since he transaction list is sorted by expiry time naturally,
  125. * we can easily get all expired transactions.
  126. * */
  127. cur = g_transactions;
  128. while (cur) {
  129. if (now < cur->time)
  130. elpased_ms = now + (0xFFFFFFFF - cur->time) + 1;
  131. else
  132. elpased_ms = now - cur->time;
  133. if (elpased_ms >= TRANSACTION_TIMEOUT_MS) {
  134. g_transactions = cur->next;
  135. cur->next = expired;
  136. expired = cur;
  137. cur = g_transactions;
  138. } else {
  139. break;
  140. }
  141. }
  142. /* call each transaction's handler with response set to NULL */
  143. cur = expired;
  144. while (cur) {
  145. transaction_t *tmp = cur;
  146. cur->handler(NULL, cur->user_data);
  147. cur = cur->next;
  148. free(tmp);
  149. }
  150. /*
  151. * If the transaction list is not empty, restart the timer according
  152. * to the first transaction. Otherwise, stop the timer.
  153. */
  154. if (g_transactions != NULL) {
  155. unsigned int elpased_ms, ms_to_expiry, now = wasm_get_sys_tick_ms();
  156. if (now < g_transactions->time) {
  157. elpased_ms = now + (0xFFFFFFFF - g_transactions->time) + 1;
  158. } else {
  159. elpased_ms = now - g_transactions->time;
  160. }
  161. ms_to_expiry = TRANSACTION_TIMEOUT_MS - elpased_ms;
  162. api_timer_restart(g_trans_timer, ms_to_expiry);
  163. } else {
  164. api_timer_cancel(g_trans_timer);
  165. g_trans_timer = NULL;
  166. }
  167. }
  168. void api_send_request(request_t * request, response_handler_f response_handler,
  169. void * user_data)
  170. {
  171. int size;
  172. char *buffer;
  173. transaction_t *trans;
  174. if ((trans = (transaction_t *) malloc(sizeof(transaction_t))) == NULL) {
  175. printf(
  176. "send request: allocate memory for request transaction failed!\n");
  177. return;
  178. }
  179. memset(trans, 0, sizeof(transaction_t));
  180. trans->handler = response_handler;
  181. trans->mid = request->mid;
  182. trans->time = wasm_get_sys_tick_ms();
  183. trans->user_data = user_data;
  184. if ((buffer = pack_request(request, &size)) == NULL) {
  185. printf("send request: pack request failed!\n");
  186. free(trans);
  187. return;
  188. }
  189. transaction_add(trans);
  190. /* if the trans is the 1st one, start the timer */
  191. if (trans == g_transactions) {
  192. /* assert(g_trans_timer == NULL); */
  193. if (g_trans_timer == NULL) {
  194. g_trans_timer = api_timer_create(TRANSACTION_TIMEOUT_MS,
  195. false,
  196. true, transaction_timeout_handler);
  197. }
  198. }
  199. wasm_post_request(buffer, size);
  200. free_req_resp_packet(buffer);
  201. }
  202. /*
  203. *
  204. * APIs for the native layers to callback for request/response arrived to this app
  205. *
  206. */
  207. void on_response(char * buffer, int size)
  208. {
  209. response_t response[1];
  210. transaction_t *trans;
  211. if (NULL == unpack_response(buffer, size, response)) {
  212. printf("unpack response failed\n");
  213. return;
  214. }
  215. if ((trans = transaction_find(response->mid)) == NULL) {
  216. printf("cannot find the transaction\n");
  217. return;
  218. }
  219. /*
  220. * When the 1st transaction get response:
  221. * 1. If the 2nd trans exist, restart the timer according to its expiry time;
  222. * 2. Otherwise, stop the timer since there is no more transactions;
  223. */
  224. if (trans == g_transactions) {
  225. if (trans->next != NULL) {
  226. unsigned int elpased_ms, ms_to_expiry, now = wasm_get_sys_tick_ms();
  227. if (now < trans->next->time) {
  228. elpased_ms = now + (0xFFFFFFFF - trans->next->time) + 1;
  229. } else {
  230. elpased_ms = now - trans->next->time;
  231. }
  232. ms_to_expiry = TRANSACTION_TIMEOUT_MS - elpased_ms;
  233. api_timer_restart(g_trans_timer, ms_to_expiry);
  234. } else {
  235. api_timer_cancel(g_trans_timer);
  236. g_trans_timer = NULL;
  237. }
  238. }
  239. trans->handler(response, trans->user_data);
  240. transaction_remove(trans);
  241. }
  242. void on_request(char *buffer, int size)
  243. {
  244. request_t request[1];
  245. bool is_event;
  246. res_register_t *r = g_resources;
  247. if (NULL == unpack_request(buffer, size, request)) {
  248. printf("unpack request failed\n");
  249. return;
  250. }
  251. is_event = is_event_type(request);
  252. while (r) {
  253. if ((is_event && r->reg_type == Reg_Event)
  254. || (!is_event && r->reg_type == Reg_Request)) {
  255. if (check_url_start(request->url, strlen(request->url), r->url)
  256. > 0) {
  257. r->request_handler(request);
  258. return;
  259. }
  260. }
  261. r = r->next;
  262. }
  263. printf("on_request: exit. no service handler\n");
  264. }
  265. void api_response_send(response_t *response)
  266. {
  267. int size;
  268. char * buffer = pack_response(response, &size);
  269. if (buffer == NULL)
  270. return;
  271. wasm_response_send(buffer, size);
  272. free_req_resp_packet(buffer);
  273. }
  274. /// event api
  275. bool api_publish_event(const char *url, int fmt, void *payload, int payload_len)
  276. {
  277. int size;
  278. request_t request[1];
  279. init_request(request, (char *)url, COAP_EVENT, fmt, payload, payload_len);
  280. char * buffer = pack_request(request, &size);
  281. if (buffer == NULL)
  282. return false;
  283. wasm_post_request(buffer, size);
  284. free_req_resp_packet(buffer);
  285. return true;
  286. }
  287. bool api_subscribe_event(const char * url, request_handler_f handler)
  288. {
  289. return register_url_handler(url, handler, Reg_Event);
  290. }