request.c 8.6 KB

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