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