request.c 8.9 KB

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