1 /*
2 * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3 */
4
5 #include <stdio.h>
6 #include "CoAPExport.h"
7 #include "CoAPSerialize.h"
8 #include "CoAPDeserialize.h"
9 #include "CoAPResource.h"
10 #include "CoAPObserve.h"
11 #include "CoAPPlatform.h"
12 #include "CoAPInternal.h"
13 #include "iotx_coap_internal.h"
14
15 #define COAPAckMsg(header) \
16 ((header.code == COAP_MSG_CODE_EMPTY_MESSAGE) && \
17 (header.type == COAP_MESSAGE_TYPE_ACK))
18
19 #define CoAPRespMsg(header) ((header.code >= 0x40) && (header.code < 0xc0))
20
21 #define CoAPPingMsg(header) \
22 ((header.code == COAP_MSG_CODE_EMPTY_MESSAGE) && \
23 (header.type == COAP_MESSAGE_TYPE_CON))
24
25 #define CoAPResetMsg(header) (header.type == COAP_MESSAGE_TYPE_RST)
26
27 #define CoAPCONRespMsg(header) \
28 ((header.code == COAP_MSG_CODE_205_CONTENT) && \
29 (header.type == COAP_MESSAGE_TYPE_CON))
30
31 #define CoAPReqMsg(header) ((1 <= header.code) && (32 > header.code))
32
33 #define NOKEEP 0
34 #define KEEPING 1
35 #define TOREMOVEKEEP 2
36 #define COAP_CUR_VERSION 1
37 #define COAP_MAX_MESSAGE_ID 65535
38 #define COAP_MAX_RETRY_COUNT 8
39 #define COAP_ACK_TIMEOUT 600
40 #define COAP_ACK_RANDOM_FACTOR 1
41
CoAPMessageId_gen(CoAPContext * context)42 unsigned short CoAPMessageId_gen(CoAPContext *context)
43 {
44 unsigned short msg_id = 0;
45 CoAPIntContext *ctx = NULL;
46 if (!context) {
47 return msg_id;
48 }
49 ctx = (CoAPIntContext *)context;
50 HAL_MutexLock(ctx->mutex);
51 msg_id = ((COAP_MAX_MESSAGE_ID == ctx->message_id) ? (ctx->message_id = 1)
52 : ctx->message_id++);
53 HAL_MutexUnlock(ctx->mutex);
54 return msg_id;
55 }
56
CoAPMessageHandler_set(CoAPMessage * message,CoAPSendMsgHandler handler)57 int CoAPMessageHandler_set(CoAPMessage *message, CoAPSendMsgHandler handler)
58 {
59 if (NULL == message) {
60 return COAP_ERROR_NULL;
61 }
62 message->handler = handler;
63 return COAP_SUCCESS;
64 }
65
CoAPMessageList_add(CoAPContext * context,NetworkAddr * remote,CoAPMessage * message,unsigned char * buffer,int len)66 static int CoAPMessageList_add(CoAPContext *context, NetworkAddr *remote,
67 CoAPMessage *message, unsigned char *buffer,
68 int len)
69 {
70 CoAPIntContext *ctx = (CoAPIntContext *)context;
71 CoAPSendNode *node = NULL;
72 uint64_t tick;
73 node = coap_malloc(sizeof(CoAPSendNode));
74
75 if (NULL != node) {
76 memset(node, 0x00, sizeof(CoAPSendNode));
77 node->acked = 0;
78 node->user = message->user;
79 node->header = message->header;
80 node->handler = message->handler;
81 node->msglen = len;
82 node->message = buffer;
83 node->timeout_val = COAP_ACK_TIMEOUT * COAP_ACK_RANDOM_FACTOR;
84 memcpy(&node->remote, remote, sizeof(NetworkAddr));
85 if (platform_is_multicast((const char *)remote->addr) ||
86 1 == message->keep) {
87 COAP_FLOW("The message %d need keep", message->header.msgid);
88 node->keep = KEEPING;
89 } else {
90 node->keep = NOKEEP;
91 }
92
93 tick = HAL_UptimeMs();
94
95 if (COAP_MESSAGE_TYPE_CON == message->header.type) {
96 node->timeout = node->timeout_val + tick;
97 node->retrans_count = COAP_MAX_RETRY_COUNT;
98 } else {
99 node->timeout = node->timeout_val * 4 + tick;
100 node->retrans_count = 0;
101 }
102
103 memcpy(node->token, message->token, message->header.tokenlen);
104
105 HAL_MutexLock(ctx->sendlist.list_mutex);
106 if (ctx->sendlist.count >= ctx->sendlist.maxcount) {
107 HAL_MutexUnlock(ctx->sendlist.list_mutex);
108 coap_free(node);
109 COAP_ERR("The send list is full, maxcount %d",
110 ctx->sendlist.maxcount);
111 return COAP_ERROR_DATA_SIZE;
112 } else {
113 list_add_tail(&node->sendlist, &ctx->sendlist.list);
114 ctx->sendlist.count++;
115 HAL_MutexUnlock(ctx->sendlist.list_mutex);
116 COAP_INFO("add message %d in list, keep:%d, cur:%d",
117 message->header.msgid, node->keep, ctx->sendlist.count);
118 return COAP_SUCCESS;
119 }
120 } else {
121 return COAP_ERROR_NULL;
122 }
123 }
124
CoAPMessageToken_dump(unsigned char * token,unsigned char tokenlen)125 void CoAPMessageToken_dump(unsigned char *token, unsigned char tokenlen)
126 {
127 int index = 0, count = 0;
128 int total = 2 * COAP_MSG_MAX_TOKEN_LEN;
129 char buff[2 * COAP_MSG_MAX_TOKEN_LEN + 1] = { 0 }, *ptr = NULL;
130
131 ptr = buff;
132 for (index = 0; index < tokenlen; index++) {
133 count = HAL_Snprintf(ptr, total, "%02X", token[index]);
134 ptr += count;
135 total -= count;
136 }
137
138 COAP_FLOW("Token Len : %d", tokenlen);
139 COAP_FLOW("Token : %s", buff);
140 }
141
CoAPMessage_dump(NetworkAddr * remote,CoAPMessage * message)142 void CoAPMessage_dump(NetworkAddr *remote, CoAPMessage *message)
143 {
144 int ret = COAP_SUCCESS;
145 unsigned int ctype;
146 unsigned char code, msgclass, detail;
147
148 if (NULL == remote || NULL == message) {
149 return;
150 }
151 code = (unsigned char)message->header.code;
152 msgclass = code >> 5;
153 detail = code & 0x1F;
154
155 COAP_FLOW("*********Message Info**********");
156 COAP_FLOW("Version : %d", message->header.version);
157 COAP_FLOW("Code : %d.%02d(0x%x)", msgclass, detail, code);
158 COAP_FLOW("Type : 0x%x", message->header.type);
159 COAP_FLOW("Msgid : %d", message->header.msgid);
160 COAP_FLOW("Option : %d", message->optcount);
161 COAP_FLOW("Payload Len : %d", message->payloadlen);
162 (void)msgclass;
163 (void)detail;
164 CoAPMessageToken_dump(message->token, message->header.tokenlen);
165 COAP_FLOW("Remote : %s:%d", remote->addr, remote->port);
166 ret = CoAPUintOption_get(message, COAP_OPTION_CONTENT_FORMAT, &ctype);
167 if (COAP_SUCCESS == ret && NULL != message->payload &&
168 (COAP_CT_APP_OCTET_STREAM != ctype && COAP_CT_APP_CBOR != ctype)) {
169 /* COAP_FLOW("Payload : %s", message->payload); */
170 }
171
172 COAP_FLOW("********************************");
173 }
174
CoAPMessage_send(CoAPContext * context,NetworkAddr * remote,CoAPMessage * message)175 int CoAPMessage_send(CoAPContext *context, NetworkAddr *remote,
176 CoAPMessage *message)
177 {
178 int ret = COAP_SUCCESS;
179 unsigned short msglen = 0;
180 unsigned char *buff = NULL;
181 unsigned short readlen = 0;
182 CoAPIntContext *ctx = NULL;
183
184 if (NULL == message || NULL == context) {
185 return COAP_ERROR_INVALID_PARAM;
186 }
187
188 ctx = (CoAPIntContext *)context;
189 msglen = CoAPSerialize_MessageLength(message);
190 if (COAP_MSG_MAX_PDU_LEN < msglen) {
191 COAP_INFO("The message length %d is too loog", msglen);
192 return COAP_ERROR_DATA_SIZE;
193 }
194
195 buff = (unsigned char *)coap_malloc(msglen);
196 if (NULL == buff) {
197 COAP_INFO("Malloc memory failed");
198 return COAP_ERROR_NULL;
199 }
200 memset(buff, 0x00, msglen);
201 msglen = CoAPSerialize_Message(message, buff, msglen);
202
203 #ifndef COAP_OBSERVE_CLIENT_DISABLE
204 CoAPObsClient_delete(ctx, message);
205 #endif
206 readlen = CoAPNetwork_write(ctx->p_network, remote, buff,
207 (unsigned int)msglen, ctx->waittime);
208 if (msglen == readlen) { /*Send message success*/
209 if (CoAPReqMsg(message->header) || CoAPCONRespMsg(message->header)) {
210 COAP_FLOW("The message id %d len %d send success, add to the list",
211 message->header.msgid, msglen);
212 ret = CoAPMessageList_add(ctx, remote, message, buff, msglen);
213 if (COAP_SUCCESS != ret) {
214 coap_free(buff);
215 COAP_ERR("Add the message %d to list failed",
216 message->header.msgid);
217 return ret;
218 }
219 } else {
220 coap_free(buff);
221 COAP_FLOW(
222 "The message %d isn't CON msg, needless to be retransmitted",
223 message->header.msgid);
224 }
225 } else {
226 coap_free(buff);
227 COAP_ERR("CoAP transport write failed, send message %d return %d",
228 message->header.msgid, ret);
229 return COAP_ERROR_WRITE_FAILED;
230 }
231
232 CoAPMessage_dump(remote, message);
233 return COAP_SUCCESS;
234 }
235
CoAPMessage_cancel(CoAPContext * context,CoAPMessage * message)236 int CoAPMessage_cancel(CoAPContext *context, CoAPMessage *message)
237 {
238 CoAPSendNode *node = NULL, *next = NULL;
239 CoAPIntContext *ctx = (CoAPIntContext *)context;
240
241 if (NULL == context || NULL == message) {
242 return COAP_ERROR_NULL;
243 }
244
245 HAL_MutexLock(ctx->sendlist.list_mutex);
246 list_for_each_entry_safe(node, next, &ctx->sendlist.list, sendlist,
247 CoAPSendNode)
248 {
249 if (node->header.msgid == message->header.msgid) {
250 list_del(&node->sendlist);
251 ctx->sendlist.count--;
252 COAP_INFO("Cancel message %d from list, cur count %d",
253 node->header.msgid, ctx->sendlist.count);
254 coap_free(node->message);
255 coap_free(node);
256 }
257 }
258 HAL_MutexUnlock(ctx->sendlist.list_mutex);
259 return COAP_SUCCESS;
260 }
261
CoAPMessageId_cancel(CoAPContext * context,unsigned short msgid)262 int CoAPMessageId_cancel(CoAPContext *context, unsigned short msgid)
263 {
264 CoAPSendNode *node = NULL, *next = NULL;
265 CoAPIntContext *ctx = (CoAPIntContext *)context;
266
267 if (NULL == context || NULL == ctx->sendlist.list_mutex) {
268 return COAP_ERROR_NULL;
269 }
270
271 HAL_MutexLock(ctx->sendlist.list_mutex);
272 list_for_each_entry_safe(node, next, &ctx->sendlist.list, sendlist,
273 CoAPSendNode)
274 {
275 if (NULL != node) {
276 if (node->header.msgid == msgid) {
277 list_del(&node->sendlist);
278 ctx->sendlist.count--;
279 COAP_FLOW("Cancel message %d from list, cur count %d",
280 node->header.msgid, ctx->sendlist.count);
281 coap_free(node->message);
282 coap_free(node);
283 }
284 }
285 }
286 HAL_MutexUnlock(ctx->sendlist.list_mutex);
287
288 return COAP_SUCCESS;
289 }
290
CoAPAckMessage_handle(CoAPContext * context,CoAPMessage * message)291 static int CoAPAckMessage_handle(CoAPContext *context, CoAPMessage *message)
292 {
293 CoAPSendNode *node = NULL, *next;
294 CoAPIntContext *ctx = (CoAPIntContext *)context;
295
296 HAL_MutexLock(ctx->sendlist.list_mutex);
297 list_for_each_entry_safe(node, next, &ctx->sendlist.list, sendlist,
298 CoAPSendNode)
299 {
300 if (node->header.msgid == message->header.msgid) {
301 CoAPSendMsgHandler handler = node->handler;
302 void *user_data = node->user;
303 NetworkAddr remote = { 0 };
304 memcpy(&remote, &node->remote, sizeof(remote));
305 node->acked = 1;
306 if (CoAPRespMsg(node->header)) { /* CON response message */
307 list_del(&node->sendlist);
308 coap_free(node->message);
309 coap_free(node);
310 ctx->sendlist.count--;
311 COAP_DEBUG("The CON response message %d receive ACK, remove it",
312 message->header.msgid);
313 }
314 if (handler) {
315 handler(ctx, COAP_RECV_RESP_SUC, user_data, &remote, NULL);
316 }
317 HAL_MutexUnlock(ctx->sendlist.list_mutex);
318 return COAP_SUCCESS;
319 }
320 }
321 HAL_MutexUnlock(ctx->sendlist.list_mutex);
322
323 return COAP_SUCCESS;
324 }
325
CoAPAckMessage_send(CoAPContext * context,NetworkAddr * remote,unsigned short msgid)326 static int CoAPAckMessage_send(CoAPContext *context, NetworkAddr *remote,
327 unsigned short msgid)
328 {
329 int ret = COAP_SUCCESS;
330 CoAPMessage message;
331 CoAPIntContext *ctx = (CoAPIntContext *)context;
332
333 CoAPMessage_init(&message);
334 CoAPMessageId_set(&message, msgid);
335 COAP_DEBUG("Send Ack Response Message");
336 ret = CoAPMessage_send(ctx, remote, &message);
337 CoAPMessage_destory(&message);
338 return ret;
339 }
340
CoAPRestMessage_send(CoAPContext * context,NetworkAddr * remote,unsigned short msgid)341 static int CoAPRestMessage_send(CoAPContext *context, NetworkAddr *remote,
342 unsigned short msgid)
343 {
344 int ret = COAP_SUCCESS;
345 CoAPMessage message;
346 CoAPIntContext *ctx = (CoAPIntContext *)context;
347
348 CoAPMessage_init(&message);
349 CoAPMessageType_set(&message, COAP_MESSAGE_TYPE_RST);
350 CoAPMessageId_set(&message, msgid);
351 COAP_DEBUG("Send Rest Pong Message");
352 ret = CoAPMessage_send(ctx, remote, &message);
353 CoAPMessage_destory(&message);
354 return ret;
355 }
356
CoAPErrRespMessage_send(CoAPContext * context,NetworkAddr * remote,CoAPMessage * message,unsigned char err_code)357 static int CoAPErrRespMessage_send(CoAPContext *context, NetworkAddr *remote,
358 CoAPMessage *message, unsigned char err_code)
359 {
360 CoAPMessage response;
361 int ret = COAP_SUCCESS;
362 CoAPIntContext *ctx = (CoAPIntContext *)context;
363
364 CoAPMessage_init(&response);
365 CoAPMessageCode_set(&response, err_code);
366 CoAPMessageId_set(&response, message->header.msgid);
367 CoAPMessageToken_set(&response, message->token, message->header.tokenlen);
368 if (COAP_MESSAGE_TYPE_CON == message->header.type) {
369 CoAPMessageType_set(&response, COAP_MESSAGE_TYPE_ACK);
370 } else {
371 CoAPMessageType_set(&response, message->header.type);
372 }
373 COAP_FLOW("Send Error Response Message");
374 ret = CoAPMessage_send(ctx, remote, &response);
375 CoAPMessage_destory(&response);
376 return ret;
377 }
378
CoAPRespMessage_handle(CoAPContext * context,NetworkAddr * remote,CoAPMessage * message)379 static int CoAPRespMessage_handle(CoAPContext *context, NetworkAddr *remote,
380 CoAPMessage *message)
381 {
382 char found = 0;
383 CoAPSendNode *node = NULL, *next = NULL;
384 CoAPIntContext *ctx = (CoAPIntContext *)context;
385
386 if (COAP_MESSAGE_TYPE_CON == message->header.type) {
387 CoAPAckMessage_send(ctx, remote, message->header.msgid);
388 }
389
390 HAL_MutexLock(ctx->sendlist.list_mutex);
391 list_for_each_entry_safe(node, next, &ctx->sendlist.list, sendlist,
392 CoAPSendNode)
393 {
394 if (0 != node->header.tokenlen &&
395 node->header.tokenlen == message->header.tokenlen &&
396 0 ==
397 memcmp(node->token, message->token, message->header.tokenlen)) {
398 if (!node->keep) {
399 list_del(&node->sendlist);
400 ctx->sendlist.count--;
401 COAP_FLOW("Remove the message id %d from list",
402 node->header.msgid);
403 } else {
404 COAP_FLOW("Find the message id %d, It need keep",
405 node->header.msgid);
406 }
407 found = 1;
408
409 break;
410 }
411 }
412
413 if (found && NULL != node) {
414 message->user = node->user;
415 /* TODO: comment it */
416 /*
417 if (COAP_MSG_CODE_400_BAD_REQUEST <= message->header.code) {
418 if (NULL != ctx->notifier) {
419 ctx->notifier(message->header.code, remote, message);
420 }
421 }
422 */
423 if (NULL != node->handler) {
424 CoAPSendMsgHandler handler = node->handler;
425 #ifndef COAP_OBSERVE_CLIENT_DISABLE
426 CoAPObsClient_add(ctx, message, remote, node);
427 #endif
428 HAL_MutexUnlock(ctx->sendlist.list_mutex);
429 COAP_FLOW("Call the response message callback %p", handler);
430 handler(ctx, COAP_REQUEST_SUCCESS, message->user, remote, message);
431 } else {
432 HAL_MutexUnlock(ctx->sendlist.list_mutex);
433 }
434
435 if (!node->keep) {
436 if (NULL != node->message) {
437 coap_free(node->message);
438 }
439 coap_free(node);
440 COAP_DEBUG("The message needless keep, free it");
441 }
442 } else {
443 HAL_MutexUnlock(ctx->sendlist.list_mutex);
444 #ifndef COAP_OBSERVE_CLIENT_DISABLE
445 CoAPObsClient_add(ctx, message, remote, NULL);
446 #endif
447 }
448 return COAP_ERROR_NOT_FOUND;
449 }
450
451 #define PACKET_INTERVAL_THRE_MS 800
452 #define PACKET_TRIGGER_NUM 100
453
CoAPRequestMessage_ack_send(CoAPContext * context,NetworkAddr * remote,unsigned short msgid)454 static int CoAPRequestMessage_ack_send(CoAPContext *context,
455 NetworkAddr *remote,
456 unsigned short msgid)
457 {
458 int ret = COAP_SUCCESS;
459 CoAPMessage message;
460 CoAPIntContext *ctx = (CoAPIntContext *)context;
461
462 CoAPMessage_init(&message);
463 CoAPMessageId_set(&message, msgid);
464 COAP_INFO("Send Ack Response Message: %d", msgid);
465 ret = CoAPMessage_send(ctx, remote, &message);
466 CoAPMessage_destory(&message);
467 return ret;
468 }
469
CoAPRequestMessage_handle(CoAPContext * context,NetworkAddr * remote,CoAPMessage * message)470 static int CoAPRequestMessage_handle(CoAPContext *context, NetworkAddr *remote,
471 CoAPMessage *message)
472 {
473 int index = 0;
474 int ret = COAP_SUCCESS;
475 CoAPResource *resource = NULL;
476 unsigned char path[COAP_MSG_MAX_PATH_LEN] = { 0 };
477 unsigned char *tmp = path;
478 CoAPIntContext *ctx = (CoAPIntContext *)context;
479
480 COAP_FLOW("CoAPRequestMessage_handle: %p", ctx);
481 /* TODO: if need only one callback */
482 for (index = 0; index < message->optcount; index++) {
483 if (COAP_OPTION_URI_PATH == message->options[index].num) {
484 if ((COAP_MSG_MAX_PATH_LEN - 1) >=
485 (tmp - path + message->options[index].len)) {
486 *tmp = '/';
487 tmp += 1;
488 strncpy((char *)tmp, (const char *)message->options[index].val,
489 message->options[index].len);
490 tmp += message->options[index].len;
491 }
492 }
493 }
494 if (strcmp("/sys/device/info/notify", (const char *)path)) {
495 COAP_DEBUG("Request path is %s msgid %d", path, message->header.msgid);
496 }
497
498 resource = CoAPResourceByPath_get(ctx, (char *)path);
499 if (NULL != resource) {
500 if (NULL != resource->callback) {
501 if (((resource->permission) & (1 << ((message->header.code) - 1))) >
502 0) {
503 if (message->header.type == COAP_MESSAGE_TYPE_CON) {
504 CoAPRequestMessage_ack_send(ctx, remote,
505 message->header.msgid);
506 }
507 resource->callback(ctx, (char *)path, remote, message);
508 } else {
509 COAP_FLOW("The resource %s isn't allowed", resource->path);
510 ret = CoAPErrRespMessage_send(
511 ctx, remote, message, COAP_MSG_CODE_405_METHOD_NOT_ALLOWED);
512 }
513 } else {
514 COAP_FLOW("The resource %s handler isn't exist", resource->path);
515 ret = CoAPErrRespMessage_send(ctx, remote, message,
516 COAP_MSG_CODE_405_METHOD_NOT_ALLOWED);
517 }
518 } else {
519 COAP_FLOW("The resource %s isn't found", path);
520 ret = CoAPErrRespMessage_send(ctx, remote, message,
521 COAP_MSG_CODE_404_NOT_FOUND);
522 }
523
524 return ret;
525 }
526
527 static int last_msg_id = -1;
CoAPMessage_handle(CoAPContext * context,NetworkAddr * remote,unsigned char * buf,unsigned short datalen)528 static void CoAPMessage_handle(CoAPContext *context, NetworkAddr *remote,
529 unsigned char *buf, unsigned short datalen)
530 {
531 int ret = COAP_SUCCESS;
532 CoAPMessage message;
533 CoAPIntContext *ctx = (CoAPIntContext *)context;
534
535 COAP_FLOW("CoAPMessage_handle: %p", ctx);
536 memset(&message, 0x00, sizeof(CoAPMessage));
537
538 ret = CoAPDeserialize_Message(&message, buf, datalen);
539 if (COAP_SUCCESS != ret) {
540 if (NULL != ctx->notifier) {
541 /* TODO: */
542 /* context->notifier(context, event); */
543 }
544 }
545
546 COAP_FLOW("--------Receive a Message------");
547 CoAPMessage_dump(remote, &message);
548
549 if (message.header.msgid == last_msg_id) {
550 COAP_FLOW("Discard duplicate Message id %d", last_msg_id);
551 return;
552 }
553 last_msg_id = message.header.msgid;
554
555 if (COAPAckMsg(message.header) || CoAPResetMsg(message.header)) {
556 /* TODO: implement handle client observe */
557
558 /* TODO: if need call response callback */
559 CoAPAckMessage_handle(ctx, &message);
560
561 } else if (CoAPRespMsg(message.header)) {
562 CoAPRespMessage_handle(ctx, remote, &message);
563 } else if (CoAPPingMsg(message.header)) {
564 CoAPRestMessage_send(ctx, remote, message.header.msgid);
565 } else if (CoAPReqMsg(message.header)) {
566 CoAPRequestMessage_handle(ctx, remote, &message);
567 } else {
568 COAP_INFO("Weird packet,drop it");
569 }
570 }
571
CoAPMessage_process(CoAPContext * context,unsigned int timeout)572 int CoAPMessage_process(CoAPContext *context, unsigned int timeout)
573 {
574 int len = 0;
575 NetworkAddr remote;
576 char ip_addr[17] = { 0 };
577 CoAPIntContext *ctx = (CoAPIntContext *)context;
578
579 if (NULL == context) {
580 return COAP_ERROR_NULL;
581 }
582
583 HAL_Wifi_Get_IP(ip_addr, NULL);
584
585 memset(&remote, 0x00, sizeof(NetworkAddr));
586 memset(ctx->recvbuf, 0x00, COAP_MSG_MAX_PDU_LEN);
587 len = CoAPNetwork_read(ctx->p_network, &remote, ctx->recvbuf,
588 COAP_MSG_MAX_PDU_LEN, timeout);
589 if (len > 0) {
590 if (strncmp((const char *)ip_addr, (const char *)remote.addr,
591 sizeof(ip_addr)) == 0) { /* drop the packet from itself*/
592 COAP_DEBUG("drop the packet from itself");
593 } else {
594 CoAPMessage_handle(ctx, &remote, ctx->recvbuf, len);
595 }
596 }
597
598 return len;
599 }
600
Check_timeout(void * context)601 static void Check_timeout(void *context)
602 {
603 CoAPIntContext *ctx = (CoAPIntContext *)context;
604 CoAPSendNode *node = NULL, *next = NULL, *timeout_node = NULL;
605 uint64_t tick = HAL_UptimeMs();
606 do {
607 timeout_node = NULL;
608 HAL_MutexLock(ctx->sendlist.list_mutex);
609 list_for_each_entry_safe(node, next, &ctx->sendlist.list, sendlist,
610 CoAPSendNode)
611 {
612 if (node->keep != NOKEEP) {
613 continue;
614 }
615 if ((node->retrans_count > 0) || (node->timeout >= tick)) {
616 continue;
617 }
618
619 /*Remove the node from the list*/
620 list_del_init(&node->sendlist);
621 ctx->sendlist.count--;
622 COAP_INFO("Retransmit timeout,remove the message id %d count %d",
623 node->header.msgid, ctx->sendlist.count);
624 #ifndef COAP_OBSERVE_SERVER_DISABLE
625 CoapObsServerAll_delete(ctx, &node->remote);
626 #endif
627 timeout_node = node;
628 break;
629 }
630 HAL_MutexUnlock(ctx->sendlist.list_mutex);
631
632 if (timeout_node) {
633 if (NULL != timeout_node->handler) {
634 timeout_node->handler(ctx, COAP_RECV_RESP_TIMEOUT,
635 timeout_node->user, &timeout_node->remote,
636 NULL);
637 }
638 coap_free(timeout_node->message);
639 coap_free(timeout_node);
640 }
641 } while (timeout_node);
642 }
643
Retansmit(void * context)644 static void Retansmit(void *context)
645 {
646 CoAPIntContext *ctx = (CoAPIntContext *)context;
647 CoAPSendNode *node = NULL, *next = NULL;
648 unsigned int ret = 0;
649
650 uint64_t tick = HAL_UptimeMs();
651 HAL_MutexLock(ctx->sendlist.list_mutex);
652 list_for_each_entry_safe(node, next, &ctx->sendlist.list, sendlist,
653 CoAPSendNode)
654 {
655 if (NULL == node || node->timeout > tick) {
656 continue;
657 }
658
659 if (node->retrans_count > 0) {
660 /*If has received ack message, don't resend the message*/
661 if (0 == node->acked) {
662 COAP_DEBUG(
663 "Retansmit the message id %d len %d timout %d tick %d",
664 node->header.msgid, node->msglen, node->timeout, tick);
665 ret = CoAPNetwork_write(ctx->p_network, &node->remote,
666 node->message, node->msglen,
667 ctx->waittime);
668 }
669 node->timeout_val = node->timeout_val * 3 / 2;
670 --node->retrans_count;
671 if (node->retrans_count == 0) {
672 node->timeout = tick + COAP_ACK_TIMEOUT;
673 } else {
674 node->timeout = tick + node->timeout_val;
675 }
676
677 COAP_FLOW("node->timeout_val = %d , node->timeout= %d ,tick= %d",
678 node->timeout_val, node->timeout, tick);
679 }
680 }
681 HAL_MutexUnlock(ctx->sendlist.list_mutex);
682 }
683
684 extern void *coap_yield_mutex;
685
686 #define COAP_CYCLE_DURATION 100
CoAPMessage_cycle(CoAPContext * context)687 int CoAPMessage_cycle(CoAPContext *context)
688 {
689 int res = 0;
690
691 CoAPIntContext *ctx = (CoAPIntContext *)context;
692 uint32_t exp_time, after_time;
693 exp_time = (uint32_t)HAL_UptimeMs() + COAP_CYCLE_DURATION;
694
695 if (NULL == context) {
696 return COAP_ERROR_NULL;
697 }
698
699 if (coap_yield_mutex != NULL) {
700 HAL_MutexLock(coap_yield_mutex);
701 }
702
703 res = CoAPMessage_process(ctx, ctx->waittime);
704 Retansmit(ctx);
705 Check_timeout(ctx);
706
707 if (coap_yield_mutex != NULL) {
708 HAL_MutexUnlock(coap_yield_mutex);
709 }
710
711 after_time = (uint32_t)HAL_UptimeMs();
712
713 if ((exp_time - after_time) < (UINT32_MAX / 2)) {
714 HAL_SleepMs(exp_time - after_time);
715 }
716 return res;
717 }
718