• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "coap_discover.h"
17 #include <errno.h>
18 #include <string.h>
19 #include <securec.h>
20 
21 #include "coap_app.h"
22 #include "coap_client.h"
23 #include "nstackx_dfinder_log.h"
24 #include "nstackx_dfinder_mgt_msg_log.h"
25 #include "nstackx_util.h"
26 #include "nstackx_timer.h"
27 #include "nstackx_error.h"
28 #include "nstackx_device.h"
29 #include "json_payload.h"
30 #include "nstackx_statistics.h"
31 
32 #define TAG "nStackXCoAP"
33 
34 #define COAP_URI_BUFFER_LENGTH 64 /* the size of the buffer or variable used to save uri. */
35 #define COAP_MAX_NUM_SUBSCRIBE_MODULE_COUNT 32 /* the maximum count of subscribed module */
36 
37 #define COAP_RECV_COUNT_INTERVAL 1000
38 #define COAP_DISVOCER_MAX_RATE 200
39 #define COAP_MSGID_SURVIVAL_SECONDS 100
40 #define COAP_MAX_MSGID_RESERVE_NUM 100
41 
42 #ifdef DFINDER_SUPPORT_MULTI_NIF
43 typedef struct {
44     coap_context_t *context;
45     char networkName[NSTACKX_MAX_INTERFACE_NAME_LEN];
46 } DiscoverCtx;
47 static DiscoverCtx g_discoverCtxList[NSTACKX_MAX_LISTENED_NIF_NUM] = {{0}, {0}};
48 #else
49 static coap_context_t *g_context = NULL;
50 static coap_context_t *g_p2pContext = NULL;
51 static coap_context_t *g_usbContext = NULL;
52 #endif /* END OF DFINDER_SUPPORT_MULTI_NIF */
53 
54 typedef struct {
55     coap_mid_t msgId;
56     struct timespec recvTime;
57 } MsgIdRecord;
58 
59 typedef struct {
60     MsgIdRecord msgIdRecord[COAP_MAX_MSGID_RESERVE_NUM];
61     uint32_t startIdx;
62     uint32_t endIdx;
63 } MsgIdList;
64 
65 typedef struct {
66     coap_context_t *context;
67     char ipString[INET_ADDRSTRLEN];
68 } CoapContextWrapper;
69 
70 typedef struct {
71     coap_context_t *context;
72     uint8_t serverType; // used when DFINDER_SUPPORT_MULTI_NIF is not defined
73 } CoapRequestPara;
74 
75 static int g_resourceFlags = COAP_RESOURCE_FLAGS_NOTIFY_CON;
76 static Timer *g_discoverTimer = NULL;
77 static uint32_t g_discoverCount;
78 static uint32_t g_coapMaxDiscoverCount = COAP_DEFAULT_DISCOVER_COUNT;
79 static uint32_t g_coapDiscoverType = COAP_BROADCAST_TYPE_DEFAULT;
80 static uint32_t g_coapUserMaxDiscoverCount;
81 static uint32_t g_coapUserDiscoverInterval;
82 static uint32_t g_coapDiscoverTargetCount;
83 static uint8_t g_userRequest;
84 static uint8_t g_forceUpdate;
85 static Timer *g_recvRecountTimer = NULL;
86 static uint32_t g_recvDiscoverMsgNum;
87 static MsgIdList *g_msgIdList = NULL;
88 static uint8_t g_subscribeCount;
89 
CoapUriParse(const char * uriString,coap_uri_t * uriPtr)90 static int32_t CoapUriParse(const char *uriString, coap_uri_t *uriPtr)
91 {
92     coap_uri_t localUri;
93 
94     (void)memset_s(&localUri, sizeof(localUri), 0, sizeof(localUri));
95     if ((uriString == NULL) || (uriPtr == NULL)) {
96         return NSTACKX_EFAILED;
97     }
98 
99     if (coap_split_uri((unsigned char *)uriString, strlen(uriString), &localUri) < 0) {
100         DFINDER_LOGE(TAG, "invalid CoAP URI");
101         return NSTACKX_EFAILED;
102     }
103     if (localUri.scheme != COAP_URI_SCHEME_COAP) {
104         DFINDER_LOGE(TAG, "coaps URI scheme not supported in this version of libcoap");
105         return NSTACKX_EFAILED;
106     }
107 
108     (void)memcpy_s(uriPtr, sizeof(coap_uri_t), &localUri, sizeof(coap_uri_t));
109     return NSTACKX_EOK;
110 }
111 
CoapPackToPdu(const CoapRequest * coapRequest,const coap_uri_t * uriPtr,coap_session_t * session)112 static coap_pdu_t *CoapPackToPdu(const CoapRequest *coapRequest, const coap_uri_t *uriPtr, coap_session_t *session)
113 {
114     coap_pdu_t *pdu = NULL;
115     if (coapRequest == NULL) {
116         return NULL;
117     }
118     if (coapRequest->remoteUrl == NULL) {
119         return NULL;
120     }
121     if (session == NULL) {
122         return NULL;
123     }
124     pdu = coap_new_pdu(coapRequest->type, coapRequest->code, session);
125     if (pdu == NULL) {
126         return NULL;
127     }
128     if (coapRequest->tokenLength) {
129         if (!coap_add_token(pdu, coapRequest->tokenLength, coapRequest->token)) {
130             DFINDER_LOGW(TAG, "cannot add token to request");
131         }
132     }
133     coap_add_option(pdu, COAP_OPTION_URI_HOST, uriPtr->host.length, uriPtr->host.s);
134     coap_add_option(pdu, COAP_OPTION_URI_PATH, uriPtr->path.length, uriPtr->path.s);
135     if (coapRequest->dataLength) {
136         coap_add_data(pdu, coapRequest->dataLength, (uint8_t *)(coapRequest->data));
137     }
138 
139     return pdu;
140 }
141 
142 #ifndef DFINDER_SUPPORT_MULTI_NIF
GetTargetIpString(uint8_t serverType,char * ipString,size_t length)143 static int32_t GetTargetIpString(uint8_t serverType, char *ipString, size_t length)
144 {
145     if (ipString == NULL || length == 0) {
146         return NSTACKX_EFAILED;
147     }
148 
149     if (serverType == SERVER_TYPE_WLANORETH) {
150         return GetLocalIpString(ipString, length);
151     }
152 
153     if (serverType == SERVER_TYPE_P2P) {
154         return GetP2pIpString(ipString, length);
155     }
156 
157     if (serverType == SERVER_TYPE_USB) {
158         return GetUsbIpString(ipString, length);
159     }
160 
161     return NSTACKX_EFAILED;
162 }
163 #endif
164 
165 #ifdef DFINDER_SUPPORT_MULTI_NIF
GetTargetIpStringWithIdx(char * ipString,size_t length,uint8_t idx)166 static int32_t GetTargetIpStringWithIdx(char *ipString, size_t length, uint8_t idx)
167 {
168     if (ipString == NULL || length == 0) {
169         return NSTACKX_EFAILED;
170     }
171     return GetLocalIpStringWithIdx(ipString, length, idx);
172 }
173 
GetIndexFromContext(coap_context_t * context)174 static uint32_t GetIndexFromContext(coap_context_t *context)
175 {
176     uint32_t i;
177     for (i = 0; i < NSTACKX_MAX_LISTENED_NIF_NUM; ++i) {
178         if (g_discoverCtxList[i].context == NULL) {
179             continue;
180         }
181         if (g_discoverCtxList[i].context == context) {
182             break;
183         }
184     }
185     if (i == NSTACKX_MAX_LISTENED_NIF_NUM) {
186         DFINDER_LOGW(TAG, "can not find legal ctx");
187     }
188     return i;
189 }
190 #endif
191 
FillCoapRequest(CoapRequest * coapRequest,uint8_t coapType,const char * url,char * data,size_t dataLen)192 static void FillCoapRequest(CoapRequest *coapRequest, uint8_t coapType, const char *url, char *data, size_t dataLen)
193 {
194     (void)memset_s(coapRequest, sizeof(CoapRequest), 0, sizeof(CoapRequest));
195     coapRequest->type = coapType;
196     coapRequest->code = COAP_REQUEST_POST;
197     coapRequest->remoteUrl = url;
198     coapRequest->data = data;
199     coapRequest->dataLength = dataLen;
200 }
CoapSendRequestInner(uint8_t coapType,const char * url,char * data,size_t dataLen,const CoapContextWrapper * wrapper)201 static int32_t CoapSendRequestInner(uint8_t coapType, const char *url, char *data, size_t dataLen,
202     const CoapContextWrapper *wrapper)
203 {
204     CoapRequest coapRequest;
205     coap_session_t *session = NULL;
206     coap_address_t dst = {0};
207     coap_str_const_t remote;
208     int32_t tid;
209     int32_t res;
210     coap_pdu_t *pdu = NULL;
211     coap_uri_t coapUri;
212     CoapServerParameter coapServerParameter = {0};
213 
214     FillCoapRequest(&coapRequest, coapType, url, data, dataLen);
215 
216     (void)memset_s(&remote, sizeof(remote), 0, sizeof(remote));
217     (void)memset_s(&coapUri, sizeof(coapUri), 0, sizeof(coapUri));
218     if (CoapUriParse(coapRequest.remoteUrl, &coapUri) != NSTACKX_EOK) {
219         goto DATA_FREE;
220     }
221     remote = coapUri.host;
222     res = CoapResolveAddress(&remote, &dst.addr.sa);
223     if (res < 0) {
224         DFINDER_LOGE(TAG, "fail to resolve address");
225         goto DATA_FREE;
226     }
227 
228     dst.size = res;
229     dst.addr.sin.sin_port = htons(COAP_DEFAULT_PORT);
230 
231     coapServerParameter.proto = COAP_PROTO_UDP;
232     coapServerParameter.dst = &dst;
233     session = CoapGetSession(wrapper->context, wrapper->ipString, COAP_SRV_DEFAULT_PORT, &coapServerParameter);
234     if (session == NULL) {
235         DFINDER_LOGE(TAG, "get client session failed");
236         goto DATA_FREE;
237     }
238     pdu = CoapPackToPdu(&coapRequest, &coapUri, session);
239     if (pdu == NULL) {
240         goto SESSION_RELEASE;
241     }
242     DFINDER_MGT_REQ_LOG(&coapRequest);
243     tid = coap_send(session, pdu);
244     if (tid == COAP_INVALID_TID) {
245         DFINDER_LOGE(TAG, "coap send failed");
246         goto SESSION_RELEASE;
247     }
248     free(coapRequest.data);
249     coap_session_release(session);
250     return NSTACKX_EOK;
251 SESSION_RELEASE:
252     coap_session_release(session);
253 DATA_FREE:
254     free(coapRequest.data);
255     return NSTACKX_EFAILED;
256 }
257 
258 // Caller must make sure that reqeustPara, reqeustPara->serverType/context are all valid.
CoapSendRequestEx(uint8_t coapType,const char * url,char * data,size_t dataLen,const CoapRequestPara * reqeustPara)259 static int32_t CoapSendRequestEx(uint8_t coapType, const char *url, char *data, size_t dataLen,
260     const CoapRequestPara *reqeustPara)
261 {
262     CoapContextWrapper wrapper = {
263         .context = reqeustPara->context,
264         .ipString = {0},
265     };
266 #ifdef DFINDER_SUPPORT_MULTI_NIF
267     uint32_t index = GetIndexFromContext(reqeustPara->context);
268     if (index == NSTACKX_MAX_LISTENED_NIF_NUM) {
269         free(data);
270         return NSTACKX_EFAILED;
271     }
272     if (GetTargetIpStringWithIdx(wrapper.ipString, sizeof(wrapper.ipString), index) != NSTACKX_EOK) {
273         DFINDER_LOGE(TAG, "can't get target IP with idx-%d", index);
274         free(data);
275         return NSTACKX_EFAILED;
276     }
277 #else
278     if (GetTargetIpString(reqeustPara->serverType, wrapper.ipString, sizeof(wrapper.ipString)) != NSTACKX_EOK) {
279         DFINDER_LOGE(TAG, "can't get target IP with type %u", SERVER_TYPE_WLANORETH);
280         free(data);
281         return NSTACKX_EFAILED;
282     }
283 #endif
284     return CoapSendRequestInner(coapType, url, data, dataLen, &wrapper);
285 }
286 
CoapSendRequest(uint8_t coapType,const char * url,char * data,size_t dataLen,const CoapRequestPara * reqeustPara)287 static int32_t CoapSendRequest(uint8_t coapType, const char *url, char *data, size_t dataLen,
288     const CoapRequestPara *reqeustPara)
289 {
290     int32_t ret = CoapSendRequestEx(coapType, url, data, dataLen, reqeustPara);
291     if (ret != NSTACKX_EOK) {
292         IncStatistics(STATS_SEND_REQUEST_FAILED);
293     }
294     return ret;
295 }
296 
CoapResponseService(const char * remoteUrl,coap_context_t * context)297 static int32_t CoapResponseService(const char *remoteUrl, coap_context_t *context)
298 {
299     CoapRequestPara para = {
300         .context = context,
301         .serverType = SERVER_TYPE_WLANORETH,
302     };
303 #ifdef DFINDER_SUPPORT_MULTI_NIF
304      uint32_t index = GetIndexFromContext(context);
305     if (index == NSTACKX_MAX_LISTENED_NIF_NUM) {
306         return NSTACKX_EFAILED;
307     }
308     char *data = PrepareServiceDiscoverWithIdx(NSTACKX_FALSE, index);
309 #else
310     char *data = PrepareServiceDiscover(NSTACKX_FALSE);
311 #endif
312     if (data == NULL) {
313         DFINDER_LOGE(TAG, "failed to prepare coap data");
314         return NSTACKX_EFAILED;
315     }
316 
317     return CoapSendRequest(COAP_MESSAGE_CON, remoteUrl, data, strlen(data) + 1, &para);
318 }
319 
IncreaseRecvDiscoverNum(void)320 static void IncreaseRecvDiscoverNum(void)
321 {
322     if (g_recvDiscoverMsgNum < UINT32_MAX) {
323         g_recvDiscoverMsgNum++;
324     }
325 }
326 
CheckBusinessTypeCanNotify(const uint8_t businessType)327 static int32_t CheckBusinessTypeCanNotify(const uint8_t businessType)
328 {
329     uint8_t localBusinessType = GetLocalDeviceInfoPtr()->businessType;
330     if (businessType == localBusinessType) {
331         return NSTACKX_EOK;
332     }
333     if ((localBusinessType == (uint8_t)NSTACKX_BUSINESS_TYPE_NEARBY) ||
334         (businessType == (uint8_t)NSTACKX_BUSINESS_TYPE_NEARBY)) {
335         return NSTACKX_EFAILED;
336     }
337     return NSTACKX_EOK;
338 }
339 
HndPostServiceDiscoverInner(const coap_pdu_t * request,char ** remoteUrl,DeviceInfo * deviceInfo)340 static int32_t HndPostServiceDiscoverInner(const coap_pdu_t *request, char **remoteUrl, DeviceInfo *deviceInfo)
341 {
342     size_t size;
343     const uint8_t *buf = NULL;
344     IncreaseRecvDiscoverNum();
345     if (g_recvDiscoverMsgNum > COAP_DISVOCER_MAX_RATE) {
346         return NSTACKX_EFAILED;
347     }
348     if (coap_get_data(request, &size, &buf) == 0 || size == 0 || size > COAP_RXBUFFER_SIZE) {
349         return NSTACKX_EFAILED;
350     }
351     (void)memset_s(deviceInfo, sizeof(*deviceInfo), 0, sizeof(*deviceInfo));
352     if (GetServiceDiscoverInfo(buf, size, deviceInfo, remoteUrl) != NSTACKX_EOK) {
353         return NSTACKX_EFAILED;
354     }
355     if (CheckBusinessTypeCanNotify(deviceInfo->businessType) != NSTACKX_EOK) {
356         return NSTACKX_EFAILED;
357     }
358     /* receive coap broadcast, set peer device's discovery type to passive,
359      * to identify the local device is in passive discovery
360      */
361     deviceInfo->discoveryType = (*remoteUrl != NULL) ? NSTACKX_DISCOVERY_TYPE_PASSIVE : NSTACKX_DISCOVERY_TYPE_ACTIVE;
362     if (deviceInfo->mode == PUBLISH_MODE_UPLINE || deviceInfo->mode == PUBLISH_MODE_OFFLINE) {
363         DFINDER_LOGD(TAG, "peer is not DISCOVER_MODE");
364         NSTACKX_DeviceInfo deviceList[PUBLISH_DEVICE_NUM];
365         (void)memset_s(deviceList, sizeof(deviceList), 0, sizeof(deviceList));
366         PushPublishInfo(deviceInfo, deviceList, PUBLISH_DEVICE_NUM);
367         NotifyDeviceFound(deviceList, PUBLISH_DEVICE_NUM);
368         return NSTACKX_EFAILED;
369     }
370     return NSTACKX_EOK;
371 }
372 
HndPostServiceDiscoverEx(coap_session_t * session,const coap_pdu_t * request,coap_pdu_t * response)373 static int32_t HndPostServiceDiscoverEx(coap_session_t *session, const coap_pdu_t *request, coap_pdu_t *response)
374 {
375     int32_t ret = NSTACKX_EFAILED;
376     coap_context_t *currCtx = coap_session_get_context(session);
377     if (currCtx == NULL) {
378         return ret;
379     }
380     char *remoteUrl = NULL;
381     DeviceInfo *deviceInfo = malloc(sizeof(DeviceInfo));
382     if (deviceInfo == NULL) {
383         return ret;
384     }
385     if (HndPostServiceDiscoverInner(request, &remoteUrl, deviceInfo) != NSTACKX_EOK) {
386         goto L_ERR;
387     }
388     if (GetModeInfo() == PUBLISH_MODE_UPLINE || GetModeInfo() == PUBLISH_MODE_OFFLINE) {
389         DFINDER_LOGD(TAG, "local is not DISCOVER_MODE");
390         goto L_ERR;
391     }
392 #ifdef DFINDER_SUPPORT_MULTI_NIF
393     uint32_t idx = GetIndexFromContext(currCtx);
394     if (idx == NSTACKX_MAX_LISTENED_NIF_NUM || UpdateDeviceDbWithIdx(deviceInfo, g_forceUpdate, idx) != NSTACKX_EOK) {
395         goto L_ERR;
396     }
397 #else
398 #ifdef DFINDER_SAVE_DEVICE_LIST
399     if (UpdateDeviceDb(deviceInfo, g_forceUpdate) != NSTACKX_EOK) {
400 #else
401     if (DeviceInfoNotify(deviceInfo, g_forceUpdate) != NSTACKX_EOK) {
402 #endif /* END OF DFINDER_SAVE_DEVICE_LIST */
403         goto L_ERR;
404     }
405 #endif /* END OF DFINDER_SUPPORT_MULTI_NIF */
406     g_forceUpdate = NSTACKX_FALSE;
407     if (deviceInfo->mode == PUBLISH_MODE_PROACTIVE) {
408         DFINDER_LOGD(TAG, "peer is PUBLISH_MODE_PROACTIVE");
409         goto L_ERR;
410     }
411     if (remoteUrl != NULL) {
412         if (CheckBusinessTypeReplyUnicast(deviceInfo->businessType) == NSTACKX_EOK) {
413             (void)CoapResponseService(remoteUrl, currCtx);
414         }
415     } else {
416         coap_pdu_set_code(response, COAP_RESPONSE_CODE_CREATED);
417     }
418     ret = NSTACKX_EOK;
419 L_ERR:
420     free(deviceInfo);
421     free(remoteUrl);
422     return ret;
423 }
424 
425 static void HndPostServiceDiscover(coap_resource_t *resource, coap_session_t *session,
426     const coap_pdu_t *request, const coap_string_t *query, coap_pdu_t *response)
427 {
428     (void)resource;
429     (void)query;
430     if (request == NULL || response == NULL) {
431         return;
432     }
433 
434     if (HndPostServiceDiscoverEx(session, request, response) != NSTACKX_EOK) {
435         IncStatistics(STATS_HANDLE_DEVICE_DISCOVER_MSG_FAILED);
436     }
437 }
438 
439 static void DeleteOverTimeMsgIdRecord(MsgIdList *msgIdList, struct timespec *curTime)
440 {
441     uint32_t i = msgIdList->startIdx;
442     if (msgIdList->startIdx >= COAP_MAX_MSGID_RESERVE_NUM || msgIdList->endIdx >= COAP_MAX_MSGID_RESERVE_NUM) {
443         return;
444     }
445     uint32_t cycleTimes = 0;
446     while (NSTACKX_TRUE) {
447         if (curTime->tv_sec - msgIdList->msgIdRecord[i].recvTime.tv_sec < COAP_MSGID_SURVIVAL_SECONDS) {
448             return;
449         }
450         if (i == msgIdList->endIdx) {
451             msgIdList->startIdx = COAP_MAX_MSGID_RESERVE_NUM;
452             msgIdList->endIdx = COAP_MAX_MSGID_RESERVE_NUM;
453             return;
454         }
455         msgIdList->startIdx = (msgIdList->startIdx + 1) % COAP_MAX_MSGID_RESERVE_NUM;
456         i = msgIdList->startIdx;
457         if (cycleTimes > COAP_MAX_MSGID_RESERVE_NUM) {
458             IncStatistics(STATS_DROP_MSG_ID);
459             DFINDER_LOGE(TAG, "cycle too many times, error must occurred and init msgList");
460             msgIdList->startIdx = COAP_MAX_MSGID_RESERVE_NUM;
461             msgIdList->endIdx = COAP_MAX_MSGID_RESERVE_NUM;
462             break;
463         }
464         cycleTimes++;
465     }
466 }
467 
468 static void AddMsgIdRecord(MsgIdList *msgIdList, coap_mid_t msgId, struct timespec *curTime)
469 {
470     int32_t ret;
471     uint32_t idx;
472     if (msgIdList->endIdx == COAP_MAX_MSGID_RESERVE_NUM) {
473         msgIdList->endIdx = 0;
474         msgIdList->startIdx = 0;
475         idx = 0;
476     } else {
477         idx = (msgIdList->endIdx + 1) % COAP_MAX_MSGID_RESERVE_NUM;
478         if (idx == msgIdList->startIdx) {
479             msgIdList->startIdx = (msgIdList->startIdx + 1) % COAP_MAX_MSGID_RESERVE_NUM;
480         }
481     }
482     msgIdList->msgIdRecord[idx].msgId = msgId;
483     ret = memcpy_s(&msgIdList->msgIdRecord[idx].recvTime, sizeof(struct timespec), curTime, sizeof(struct timespec));
484     if (ret != NSTACKX_EOK) {
485         DFINDER_LOGE(TAG, "set msg id time error");
486         return;
487     }
488     msgIdList->endIdx = idx;
489 }
490 
491 static uint8_t RefreshMsgIdList(coap_mid_t msgId)
492 {
493     struct timespec curTime;
494     uint32_t i;
495     if (g_msgIdList == NULL) {
496         return NSTACKX_TRUE;
497     }
498     ClockGetTime(CLOCK_MONOTONIC, &curTime);
499     DeleteOverTimeMsgIdRecord(g_msgIdList, &curTime);
500     if (g_msgIdList->startIdx >= COAP_MAX_MSGID_RESERVE_NUM || g_msgIdList->endIdx >= COAP_MAX_MSGID_RESERVE_NUM) {
501         AddMsgIdRecord(g_msgIdList, msgId, &curTime);
502         return NSTACKX_TRUE;
503     }
504     i = g_msgIdList->startIdx;
505     uint32_t cycleTimes = 0;
506     while (NSTACKX_TRUE) {
507         if (g_msgIdList->msgIdRecord[i].msgId == msgId) {
508             (void)memcpy_s(&g_msgIdList->msgIdRecord[i].recvTime, sizeof(struct timespec), &curTime,
509                            sizeof(struct timespec));
510             return NSTACKX_FALSE;
511         }
512         if (i == g_msgIdList->endIdx) {
513             break;
514         }
515         i = (i + 1) % COAP_MAX_MSGID_RESERVE_NUM;
516         if (cycleTimes > COAP_MAX_MSGID_RESERVE_NUM) {
517             IncStatistics(STATS_DROP_MSG_ID);
518             DFINDER_LOGE(TAG, "cycle too many times, error must occurred and init msgList");
519             g_msgIdList->startIdx = COAP_MAX_MSGID_RESERVE_NUM;
520             g_msgIdList->endIdx = COAP_MAX_MSGID_RESERVE_NUM;
521             break;
522         }
523         cycleTimes++;
524     }
525     AddMsgIdRecord(g_msgIdList, msgId, &curTime);
526     return NSTACKX_TRUE;
527 }
528 
529 static uint16_t GetServiceMsgFrameLen(const uint8_t *frame, uint16_t size)
530 {
531     uint16_t frameLen, ret;
532     if (size < sizeof(frameLen)) {
533         DFINDER_LOGE(TAG, "input size %u is too small", size);
534         return 0;
535     }
536     if (memcpy_s(&frameLen, sizeof(frameLen), frame, sizeof(frameLen)) != EOK) {
537         DFINDER_LOGE(TAG, "memcpy frame len failed");
538         return 0;
539     }
540     ret = ntohs(frameLen);
541     if (size < ret) {
542         DFINDER_LOGE(TAG, "input size %u is smaller than decoded frame len %u", size, ret);
543         return 0;
544     }
545     return ret;
546 }
547 
548 static uint16_t GetUnitInfo(const uint8_t *data, uint16_t dataLen, uint8_t *outBuf, uint32_t outLen, uint8_t unitType)
549 {
550     if (dataLen < sizeof(CoapMsgUnit)) {
551         DFINDER_LOGE(TAG, "dataLen %u is too small", dataLen);
552         return 0;
553     }
554     CoapMsgUnit *unit = (CoapMsgUnit *)data;
555     if (unit->type != unitType) {
556         DFINDER_LOGE(TAG, "unit type %u does match target type %u", unit->type, unitType);
557         return 0;
558     }
559     uint16_t valueLen = ntohs(unit->len);
560     if (valueLen == 0 || valueLen > outLen || valueLen + sizeof(CoapMsgUnit) > dataLen) {
561         DFINDER_LOGE(TAG, "valueLen %u is illegal", valueLen);
562         return 0;
563     }
564     if (memcpy_s(outBuf, outLen, unit->value, valueLen) != EOK) {
565         DFINDER_LOGE(TAG, "memcpy unit->value failed");
566         return 0;
567     }
568     if (unitType == COAP_MODULE_NAME_TYPE || unitType == COAP_DEVICE_ID_TYPE) {
569         if (outBuf[valueLen - 1] != '\0') {
570             DFINDER_LOGE(TAG, "uint type is %u but value is not end with 0", unitType);
571             return 0;
572         }
573     }
574     return valueLen;
575 }
576 
577 static uint16_t ParseServiceMsgFrame(const uint8_t *frame, uint16_t size, char *moduleName, char *deviceId,
578                                      uint8_t **msg)
579 {
580     if (frame == NULL || size == 0) {
581         return 0;
582     }
583     uint16_t frameLen = GetServiceMsgFrameLen(frame, size);
584     if (frameLen < sizeof(frameLen) + sizeof(CoapMsgUnit)) {
585         return 0;
586     }
587 
588     /* get modulename info */
589     uint16_t len = sizeof(frameLen);
590     uint16_t moduleNameLen = GetUnitInfo(frame + len, frameLen - len, (uint8_t *)moduleName,
591                                          NSTACKX_MAX_MODULE_NAME_LEN, COAP_MODULE_NAME_TYPE);
592     if (moduleNameLen == 0 || moduleNameLen + sizeof(CoapMsgUnit) >= frameLen - len) {
593         return 0;
594     }
595 
596     /* get deviceIdLen info */
597     len += moduleNameLen + sizeof(CoapMsgUnit);
598     uint16_t deviceIdLen = GetUnitInfo(frame + len, frameLen - len, (uint8_t *)deviceId,
599                                        NSTACKX_MAX_DEVICE_ID_LEN, COAP_DEVICE_ID_TYPE);
600     if (deviceIdLen == 0 || deviceIdLen + sizeof(CoapMsgUnit) >= frameLen - len) {
601         return 0;
602     }
603 
604     /* get msg info */
605     len += deviceIdLen + sizeof(CoapMsgUnit);
606     uint8_t *msgPtr = (uint8_t *)calloc(1U, frameLen - len);
607     if (msgPtr == NULL) {
608         return 0;
609     }
610     uint16_t msgLen = GetUnitInfo(frame + len, frameLen - len, msgPtr, frameLen - len, COAP_MSG_TYPE);
611     if (msgLen == 0) {
612         free(msgPtr);
613         return 0;
614     }
615     *msg = msgPtr;
616     return msgLen;
617 }
618 
619 static int32_t HndPostServiceMsgEx(coap_resource_t *resource, coap_session_t *session,
620     const coap_pdu_t *request, const coap_string_t *query, coap_pdu_t *response)
621 {
622     (void)resource;
623     (void)session;
624     (void)query;
625     if (request == NULL || response == NULL) {
626         return NSTACKX_EFAILED;
627     }
628     char deviceId[NSTACKX_MAX_DEVICE_ID_LEN] = {0};
629     char moduleName[NSTACKX_MAX_MODULE_NAME_LEN] = {0};
630     uint8_t *msg = NULL;
631     const uint8_t *buf = NULL;
632     uint16_t msgLen;
633     size_t size;
634 
635     if (coap_get_data(request, &size, &buf) == 0 || size == 0 || size > COAP_RXBUFFER_SIZE) {
636         return NSTACKX_EFAILED;
637     }
638 
639     if (!RefreshMsgIdList(coap_pdu_get_mid(request))) {
640         DFINDER_LOGE(TAG, "repeated msg id");
641         return NSTACKX_EFAILED;
642     }
643 
644     DFINDER_LOGD(TAG, "handling post service msg request");
645     msgLen = ParseServiceMsgFrame(buf, size, moduleName, deviceId, &msg);
646     if (msgLen == 0) {
647         DFINDER_LOGD(TAG, "parse service msg frame error");
648         return NSTACKX_EFAILED;
649     }
650 
651     NotifyMsgReceived(moduleName, deviceId, msg, msgLen);
652 
653     coap_pdu_set_code(response, COAP_RESPONSE_CODE_CREATED);
654     free(msg);
655     return NSTACKX_EOK;
656 }
657 
658 static void HndPostServiceMsg(coap_resource_t *resource, coap_session_t *session,
659     const coap_pdu_t *request, const coap_string_t *query, coap_pdu_t *response)
660 {
661     if (HndPostServiceMsgEx(resource, session, request, query, response) != NSTACKX_EOK) {
662         IncStatistics(STATS_HANDLE_SERVICE_MSG_FAILED);
663     }
664 }
665 
666 #ifdef DFINDER_SUPPORT_MULTI_NIF
667 static int32_t CoapPostServiceDiscoverEx(void)
668 {
669     char ifName[NSTACKX_MAX_INTERFACE_NAME_LEN] = {0};
670     char ipString[NSTACKX_MAX_IP_STRING_LEN] = {0};
671     char discoverUri[COAP_URI_BUFFER_LENGTH] = {0};
672     char *data = NULL;
673 
674     int32_t errCnt = 0;
675     int32_t postResult = 0;
676 
677     for (uint32_t i = 0; i < NSTACKX_MAX_LISTENED_NIF_NUM; ++i) {
678         if (g_discoverCtxList[i].context == NULL) {
679             continue;
680         }
681         (void)memset_s(ifName, sizeof(ifName), 0, sizeof(ifName));
682         (void)memset_s(ipString, sizeof(ipString), 0, sizeof(ipString));
683         (void)memset_s(discoverUri, sizeof(discoverUri), 0, sizeof(discoverUri));
684         data = NULL;
685 
686         if (GetLocalInterfaceNameWithIdx(ifName, sizeof(ifName), i) != NSTACKX_EOK) {
687             DFINDER_LOGE(TAG, "get local interface name with idx-%d failed", i);
688             continue;
689         }
690 
691         if (GetIfBroadcastIp(ifName, ipString, sizeof(ipString)) != NSTACKX_EOK) {
692             DFINDER_LOGE(TAG, "get local interface bcast ip with idx-%d failed", i);
693             continue;
694         }
695 
696         if (sprintf_s(discoverUri, sizeof(discoverUri), "coap://%s/%s", ipString, COAP_DEVICE_DISCOVER_URI) < 0) {
697             DFINDER_LOGE(TAG, "set discoverUri failed with idx-%d", i);
698             continue;
699         }
700 
701         data = PrepareServiceDiscoverWithIdx(NSTACKX_TRUE, i);
702         if (data == NULL) {
703             DFINDER_LOGE(TAG, "service discover data is NULL with idx-%d", i);
704             ++errCnt;
705             continue;
706         }
707         CoapRequestPara para = {0};
708         para.context = g_discoverCtxList[i].context;
709         postResult = CoapSendRequest(COAP_MESSAGE_NON, discoverUri, data, strlen(data) + 1, &para);
710         if (postResult != NSTACKX_EOK) {
711             DFINDER_LOGE(TAG, "coap send request with idx-%d failed", i);
712             ++errCnt;
713         }
714     }
715     if (errCnt == NSTACKX_MAX_LISTENED_NIF_NUM) {
716         DFINDER_LOGE(TAG, "coap post service discover on all nif failed");
717         return NSTACKX_EFAILED;
718     }
719     return NSTACKX_EOK;
720 }
721 #else
722 static int32_t CoapPostServiceDiscoverEx(void)
723 {
724     char ipString[NSTACKX_MAX_IP_STRING_LEN] = {0};
725     char discoverUri[COAP_URI_BUFFER_LENGTH] = {0};
726     char *data = NULL;
727     CoapRequestPara para = {0};
728 #ifndef _WIN32
729     char ifName[NSTACKX_MAX_INTERFACE_NAME_LEN] = {0};
730 
731     if (GetLocalInterfaceName(ifName, sizeof(ifName)) != NSTACKX_EOK) {
732         DFINDER_LOGE(TAG, "GetLocalInterfaceName failed");
733         return NSTACKX_EFAILED;
734     }
735 
736     if (GetIfBroadcastIp(ifName, ipString, sizeof(ipString)) != NSTACKX_EOK) {
737         DFINDER_LOGE(TAG, "GetIfBroadcastIp failed");
738         return NSTACKX_EFAILED;
739     }
740 #else
741     struct in_addr ipNow;
742     GetLocalIp(&ipNow);
743     if (ipNow.s_addr == 0) {
744         DFINDER_LOGE(TAG, "GetLocalIp failed");
745         return NSTACKX_EFAILED;
746     }
747 
748     if (GetIfBroadcastAddr(&ipNow, ipString, NSTACKX_MAX_IP_STRING_LEN) != NSTACKX_EOK) {
749         DFINDER_LOGE(TAG, "GetIfBroadcastAddr failed");
750         return NSTACKX_EFAILED;
751     }
752 #endif
753 
754     if (sprintf_s(discoverUri, sizeof(discoverUri), "coap://%s/%s", ipString, COAP_DEVICE_DISCOVER_URI) < 0) {
755         return NSTACKX_EFAILED;
756     }
757     para.serverType = SERVER_TYPE_WLANORETH;
758     para.context = GetContext(SERVER_TYPE_WLANORETH);
759     if (para.context == NULL) {
760         DFINDER_LOGE(TAG, "Failed to get coap context");
761         return NSTACKX_EFAILED;
762     }
763     data = PrepareServiceDiscover(NSTACKX_TRUE);
764     if (data == NULL) {
765         DFINDER_LOGE(TAG, "failed to prepare coap data");
766         return NSTACKX_EFAILED;
767     }
768 
769     return CoapSendRequest(COAP_MESSAGE_NON, discoverUri, data, strlen(data) + 1, &para);
770 }
771 #endif /* END OF DFINDER_SUPPORT_MULTI_NIF */
772 
773 static int32_t CoapPostServiceDiscover(void)
774 {
775     int32_t ret = CoapPostServiceDiscoverEx();
776     if (ret != NSTACKX_EOK) {
777         IncStatistics(STATS_POST_SD_REQUEST_FAILED);
778     }
779     return ret;
780 }
781 
782 static uint32_t GetDiscoverInterval(uint32_t discoverCount)
783 {
784     switch (g_coapDiscoverType) {
785         case COAP_BROADCAST_TYPE_USER:
786             return g_coapUserDiscoverInterval;
787         case COAP_BROADCAST_TYPE_DEFAULT:
788             return GetDefaultDiscoverInterval(discoverCount);
789         default:
790             return GetDefaultDiscoverInterval(discoverCount);
791     }
792 }
793 
794 static void CoapServiceDiscoverStop(void)
795 {
796     g_forceUpdate = NSTACKX_FALSE;
797     g_discoverCount = 0;
798     SetModeInfo(DISCOVER_MODE);
799 #ifdef DFINDER_SAVE_DEVICE_LIST
800     ClearDevices(GetDeviceDBBackup());
801     DFINDER_LOGW(TAG, "clear device list backup");
802 #endif
803     g_coapDiscoverType = COAP_BROADCAST_TYPE_DEFAULT;
804     g_coapMaxDiscoverCount = COAP_DEFAULT_DISCOVER_COUNT;
805     /* Can call PostDeviceFindWrapper() to notify user if needed. */
806     g_userRequest = NSTACKX_FALSE;
807 }
808 
809 static void CoapServiceDiscoverTimerHandle(void *argument)
810 {
811     uint32_t discoverInterval;
812 
813     (void)argument;
814 
815 #ifdef DFINDER_SUPPORT_MULTI_NIF
816     if (g_discoverCount >= g_coapDiscoverTargetCount || !IsApConnected()) {
817         IncStatistics(STATS_ABORT_SD);
818         CoapServiceDiscoverStop();
819         return;
820     }
821 #else
822     if (g_discoverCount >= g_coapDiscoverTargetCount || !IsWifiApConnected()) {
823         IncStatistics(STATS_ABORT_SD);
824         /* Discover done, or wifi AP disconnected. */
825         CoapServiceDiscoverStop();
826         return;
827     }
828 #endif /* END OF DFINDER_SUPPORT_MULTI_NIF */
829 
830     if (CoapPostServiceDiscover() != NSTACKX_EOK) {
831         DFINDER_LOGE(TAG, "failed when posting service discover request");
832         goto L_ERR_DISCOVER;
833     }
834     DFINDER_LOGI(TAG, "the %u time for device discovery.", g_discoverCount + 1);
835 
836     /* Restart timer */
837     discoverInterval = GetDiscoverInterval(g_discoverCount);
838 
839     ++g_discoverCount;
840     if (TimerSetTimeout(g_discoverTimer, discoverInterval, NSTACKX_FALSE) != NSTACKX_EOK) {
841         DFINDER_LOGE(TAG, "failed to set timer for service discovery");
842         goto L_ERR_DISCOVER;
843     }
844     return;
845 
846 L_ERR_DISCOVER:
847     IncStatistics(STATS_ABORT_SD);
848     /* Abort service discover by not starting timer. */
849     DFINDER_LOGE(TAG, "abort service discovery, have tried %u request", g_discoverCount);
850     /* Reset g_discoverCount to allow new request from user. */
851     g_discoverCount = 0;
852     return;
853 }
854 
855 void CoapInitSubscribeModuleInner(void)
856 {
857     g_subscribeCount = 0;
858     return;
859 }
860 
861 void CoapSubscribeModuleInner(uint8_t isSubscribe)
862 {
863     if (isSubscribe && (g_subscribeCount < COAP_MAX_NUM_SUBSCRIBE_MODULE_COUNT)) {
864         g_subscribeCount++;
865     }
866     return;
867 }
868 
869 void CoapUnsubscribeModuleInner(uint8_t isUnsubscribe)
870 {
871     if (isUnsubscribe && (g_subscribeCount > 0)) {
872         g_subscribeCount--;
873     }
874 }
875 
876 static void SetCoapMaxDiscoverCount(void)
877 {
878     switch (g_coapDiscoverType) {
879         case COAP_BROADCAST_TYPE_DEFAULT:
880             g_coapMaxDiscoverCount = COAP_DEFAULT_DISCOVER_COUNT;
881             break;
882         case COAP_BROADCAST_TYPE_USER:
883             g_coapMaxDiscoverCount = g_coapUserMaxDiscoverCount;
884             break;
885         default:
886             g_coapMaxDiscoverCount = COAP_DEFAULT_DISCOVER_COUNT;
887             break;
888     }
889 }
890 
891 #ifdef DFINDER_SUPPORT_MULTI_NIF
892 static uint8_t CheckAllContextDown(void)
893 {
894     for (uint32_t i = 0; i < NSTACKX_MAX_LISTENED_NIF_NUM; ++i) {
895         if (g_discoverCtxList[i].context != NULL) {
896             return NSTACKX_FALSE;
897         }
898     }
899     return NSTACKX_TRUE;
900 }
901 #endif
902 
903 static void CoapServiceDiscoverFirstTime(void)
904 {
905     SetCoapMaxDiscoverCount();
906     g_coapDiscoverTargetCount = g_coapMaxDiscoverCount;
907     if (CoapPostServiceDiscover() != NSTACKX_EOK) {
908         // update log to avoid duplicate code.
909         DFINDER_LOGE(TAG, "failed to send service discover request");
910         return;
911     }
912 
913     uint32_t discoverInterval = GetDiscoverInterval(g_discoverCount);
914     if (TimerSetTimeout(g_discoverTimer, discoverInterval, NSTACKX_FALSE) != NSTACKX_EOK) {
915         // update log to avoid duplicate code.
916         DFINDER_LOGE(TAG, "failed to set timer when doing service discover");
917         return;
918     }
919     ++g_discoverCount;
920     // update log to avoid duplicate code.
921     DFINDER_LOGI(TAG, "first time for device discover.");
922 }
923 
924 static uint8_t NetworkIsConnected()
925 {
926 #ifdef DFINDER_SUPPORT_MULTI_NIF
927     if (!IsApConnected()) {
928         DFINDER_LOGE(TAG, "all ap is not connected in coap service discover inner");
929         return NSTACKX_FALSE;
930     }
931     if (CheckAllContextDown()) {
932         DFINDER_LOGW(TAG, "all context down");
933         return NSTACKX_FALSE;
934     }
935 #else
936     if (!IsWifiApConnected() || g_context == NULL) {
937         return NSTACKX_FALSE;
938     }
939 #endif
940     return NSTACKX_TRUE;
941 }
942 
943 void CoapServiceDiscoverInner(uint8_t userRequest)
944 {
945     if (!NetworkIsConnected()) {
946         IncStatistics(STATS_START_SD_FAILED);
947         LOGI(TAG, "Network not connected when discovery inner");
948         return;
949     }
950 
951     if (userRequest) {
952         g_userRequest = NSTACKX_TRUE;
953         g_forceUpdate = NSTACKX_TRUE;
954     }
955 
956     if (g_coapDiscoverTargetCount > 0 &&
957         g_discoverCount >= g_coapDiscoverTargetCount) {
958         g_discoverCount = 0;
959         SetModeInfo(DISCOVER_MODE);
960 #ifdef DFINDER_SAVE_DEVICE_LIST
961         ClearDevices(GetDeviceDBBackup());
962         DFINDER_LOGW(TAG, "clear device list backup");
963 #endif
964         (void)TimerSetTimeout(g_discoverTimer, 0, NSTACKX_FALSE);
965     }
966 
967     if (g_discoverCount) {
968         /* Service discover is ongoing, return. */
969         return;
970     }
971 #ifdef DFINDER_SAVE_DEVICE_LIST
972     /* First discover */
973     if (BackupDeviceDB() != NSTACKX_EOK) {
974         IncStatistics(STATS_START_SD_FAILED);
975         DFINDER_LOGE(TAG, "backup device list fail when discovery inner");
976         return;
977     }
978     ClearDevices(GetDeviceDB());
979     DFINDER_LOGW(TAG, "clear device list when discovery inner");
980 #endif /* END OF DFINDER_SAVE_DEVICE_LIST */
981     SetModeInfo(DISCOVER_MODE);
982     CoapServiceDiscoverFirstTime();
983     return;
984 }
985 
986 void CoapServiceDiscoverInnerAn(uint8_t userRequest)
987 {
988     if (!NetworkIsConnected()) {
989         IncStatistics(STATS_START_SD_FAILED);
990         LOGI(TAG, "Network not connected when discovery inner AN");
991         return;
992     }
993 
994     if (userRequest) {
995         g_userRequest = NSTACKX_TRUE;
996     }
997 
998     if (g_discoverCount != 0) {
999         g_discoverCount = 0;
1000         /* Service discover is ongoing, reset. */
1001         (void)TimerSetTimeout(g_discoverTimer, 0, NSTACKX_FALSE);
1002     }
1003 
1004     CoapServiceDiscoverFirstTime();
1005     return;
1006 }
1007 
1008 void CoapServiceDiscoverInnerConfigurable(uint8_t userRequest)
1009 {
1010     if (!NetworkIsConnected()) {
1011         IncStatistics(STATS_START_SD_FAILED);
1012         LOGI(TAG, "Network not connected when discovery configurable");
1013         return;
1014     }
1015 
1016     if (userRequest) {
1017         g_userRequest = NSTACKX_TRUE;
1018         g_forceUpdate = NSTACKX_TRUE;
1019     }
1020 
1021     if (g_coapDiscoverTargetCount > 0 && g_discoverCount >= g_coapDiscoverTargetCount) {
1022         g_discoverCount = 0;
1023 #ifdef DFINDER_SAVE_DEVICE_LIST
1024         ClearDevices(GetDeviceDBBackup());
1025         DFINDER_LOGW(TAG, "clear device list backup when discovery configurable");
1026 #endif
1027         (void)TimerSetTimeout(g_discoverTimer, 0, NSTACKX_FALSE);
1028     }
1029 
1030     if (g_discoverCount != 0) {
1031         g_discoverCount = 0;
1032         /* Service discover is ongoing, return. */
1033         (void)TimerSetTimeout(g_discoverTimer, 0, NSTACKX_FALSE);
1034     } else {
1035         /* First discover */
1036 #ifdef DFINDER_SAVE_DEVICE_LIST
1037         if (BackupDeviceDB() != NSTACKX_EOK) {
1038             IncStatistics(STATS_START_SD_FAILED);
1039             DFINDER_LOGE(TAG, "backup device list fail when discovery configurable");
1040             return;
1041         }
1042         ClearDevices(GetDeviceDB());
1043         DFINDER_LOGW(TAG, "clear device list when discovery configurable");
1044 #endif
1045     }
1046     CoapServiceDiscoverFirstTime();
1047     return;
1048 }
1049 
1050 void CoapServiceDiscoverStopInner(void)
1051 {
1052     (void)TimerSetTimeout(g_discoverTimer, 0, NSTACKX_FALSE);
1053     CoapServiceDiscoverStop();
1054     DFINDER_LOGI(TAG, "device discover inner stopped");
1055 }
1056 
1057 uint8_t CoapDiscoverRequestOngoing(void)
1058 {
1059     return ((g_discoverCount > 0 && g_userRequest) || (g_subscribeCount > 0));
1060 }
1061 
1062 #ifndef DFINDER_SUPPORT_MULTI_NIF
1063 static uint8_t *CreateServiceMsgFrame(const char *moduleName, const char *deviceId, const uint8_t *msg, uint32_t msgLen,
1064                                       uint16_t *dataLen)
1065 {
1066     uint16_t frameLen, moduleNameUnitLen, deviceIdUnitLen, msgUnitLen, bufferLen;
1067     uint8_t *frame = NULL;
1068     uint16_t len = 0;
1069     CoapMsgUnit *unit = NULL;
1070 
1071     moduleNameUnitLen = sizeof(CoapMsgUnit) + strlen(moduleName) + 1;
1072     deviceIdUnitLen = sizeof(CoapMsgUnit) + strlen(deviceId) + 1;
1073     msgUnitLen = sizeof(CoapMsgUnit) + msgLen;
1074     bufferLen = sizeof(frameLen) + moduleNameUnitLen + deviceIdUnitLen + msgUnitLen;
1075     frameLen = htons(bufferLen);
1076 
1077     frame = (uint8_t *)calloc(1U, bufferLen);
1078     if (frame == NULL) {
1079         IncStatistics(STATS_CREATE_SERVICE_MSG_FAILED);
1080         return NULL;
1081     }
1082     if (memcpy_s(frame, bufferLen, &frameLen, sizeof(frameLen)) != EOK) {
1083         goto L_ERR_SEND_MSG;
1084     }
1085     len += sizeof(frameLen);
1086 
1087     unit = (CoapMsgUnit *)(frame + len);
1088     unit->type = COAP_MODULE_NAME_TYPE;
1089     unit->len = htons(moduleNameUnitLen - sizeof(CoapMsgUnit));
1090     if (memcpy_s(unit->value, bufferLen - len - sizeof(CoapMsgUnit), moduleName, strlen(moduleName) + 1) != EOK) {
1091         goto L_ERR_SEND_MSG;
1092     }
1093     len += moduleNameUnitLen;
1094 
1095     unit = (CoapMsgUnit *)(frame + len);
1096     unit->type = COAP_DEVICE_ID_TYPE;
1097     unit->len = htons(deviceIdUnitLen - sizeof(CoapMsgUnit));
1098     if (memcpy_s(unit->value, bufferLen - len - sizeof(CoapMsgUnit), deviceId, strlen(deviceId) + 1) != EOK) {
1099         goto L_ERR_SEND_MSG;
1100     }
1101     len += deviceIdUnitLen;
1102 
1103     unit = (CoapMsgUnit *)(frame + len);
1104     unit->type = COAP_MSG_TYPE;
1105     unit->len = htons(msgUnitLen - sizeof(CoapMsgUnit));
1106     if (memcpy_s(unit->value, bufferLen - len - sizeof(CoapMsgUnit), msg, msgLen) != EOK) {
1107         goto L_ERR_SEND_MSG;
1108     }
1109     *dataLen = bufferLen;
1110     return frame;
1111 L_ERR_SEND_MSG:
1112     IncStatistics(STATS_CREATE_SERVICE_MSG_FAILED);
1113     free(frame);
1114     return NULL;
1115 }
1116 
1117 int32_t CoapSendServiceMsg(MsgCtx *msgCtx, DeviceInfo *deviceInfo)
1118 {
1119     return CoapSendServiceMsgWithDefiniteTargetIp(msgCtx, deviceInfo);
1120 }
1121 
1122 coap_context_t *GetContext(uint8_t serverType)
1123 {
1124     if (serverType == SERVER_TYPE_WLANORETH) {
1125         if (g_context == NULL) {
1126             DFINDER_LOGE(TAG, "DefiniteTargetIp getContext: g_context for wlan or eth is null");
1127         }
1128         return g_context;
1129     } else if (serverType == SERVER_TYPE_P2P) {
1130         if (g_p2pContext == NULL) {
1131             DFINDER_LOGE(TAG, "DefiniteTargetIp getContext: g_p2pContext for p2p is null");
1132         }
1133         return g_p2pContext;
1134     } else if (serverType == SERVER_TYPE_USB) {
1135         if (g_usbContext == NULL) {
1136             DFINDER_LOGE(TAG, "DefiniteTargetIp getContext: g_usbContext for usb is null");
1137         }
1138         return g_usbContext;
1139     } else {
1140         DFINDER_LOGE(TAG, "CoapSendServiceMsgWithDefiniteTargetIp serverType is unknown");
1141         return NULL;
1142     }
1143 }
1144 
1145 int32_t CoapSendServiceMsgWithDefiniteTargetIp(MsgCtx *msgCtx, DeviceInfo *deviceInfo)
1146 {
1147     char ipString[INET_ADDRSTRLEN] = {0};
1148     char uriBuffer[COAP_URI_BUFFER_LENGTH] = {0};
1149     uint16_t dataLen = 0;
1150     if (msgCtx == NULL) {
1151         return NSTACKX_EFAILED;
1152     }
1153     uint8_t autcualType = GetActualType(msgCtx->type, msgCtx->p2pAddr);
1154     char *data = NULL;
1155     DFINDER_LOGD(TAG, "autcualType is %hhu", autcualType);
1156     if (msgCtx->len == 0 || msgCtx->len > NSTACKX_MAX_SENDMSG_DATA_LEN) {
1157         return NSTACKX_EINVAL;
1158     }
1159 
1160     if (strlen(msgCtx->p2pAddr) == 0) {
1161         if (deviceInfo == NULL) {
1162             return NSTACKX_EFAILED;
1163         }
1164         if (inet_ntop(AF_INET, &deviceInfo->netChannelInfo.wifiApInfo.ip, ipString, sizeof(ipString)) == NULL) {
1165             DFINDER_LOGE(TAG, "inet_ntop failed: %d", errno);
1166             return NSTACKX_EFAILED;
1167         }
1168     } else {
1169         if (strcpy_s(ipString, sizeof(ipString), msgCtx->p2pAddr) != EOK) {
1170             DFINDER_LOGE(TAG, "failed to get ip");
1171             return NSTACKX_EFAILED;
1172         }
1173     }
1174 
1175     if (sprintf_s(uriBuffer, sizeof(uriBuffer), "coap://%s/" COAP_SERVICE_MSG_URI, ipString) < 0) {
1176         return NSTACKX_EFAILED;
1177     }
1178 
1179     CoapRequestPara para = {0};
1180     para.serverType = autcualType;
1181     para.context = GetContext(autcualType);
1182     if (para.context == NULL) {
1183         DFINDER_LOGE(TAG, "Failed to get coap context");
1184         return NSTACKX_EFAILED;
1185     }
1186 
1187     data = (char *)CreateServiceMsgFrame(msgCtx->moduleName,
1188         GetLocalDeviceInfoPtr()->deviceId, msgCtx->data, msgCtx->len, &dataLen);
1189     if (data == NULL) {
1190         DFINDER_LOGE(TAG, "failed to prepare msg data");
1191         return NSTACKX_EFAILED;
1192     }
1193 
1194     return CoapSendRequest(COAP_MESSAGE_CON, uriBuffer, data, dataLen, &para);
1195 }
1196 #endif /* END OF DFINDER_SUPPORT_MULTI_NIF */
1197 
1198 uint8_t GetActualType(const uint8_t type, const char *dstIp)
1199 {
1200     if (type != INVALID_TYPE) {
1201         return type;
1202     }
1203     struct sockaddr_in localAddr;
1204     localAddr.sin_addr.s_addr = inet_addr(dstIp);
1205 #ifndef _WIN32
1206     struct ifreq localDev;
1207     (void)memset_s(&localDev, sizeof(struct ifreq), 0, sizeof(struct ifreq));
1208     if (GetTargetInterface(&localAddr, &localDev) != NSTACKX_EOK) {
1209         return INVALID_TYPE;
1210     }
1211     if (IsWlanIpAddr(localDev.ifr_ifrn.ifrn_name) == NSTACKX_TRUE) {
1212         return SERVER_TYPE_WLANORETH;
1213     }
1214     if (IsEthIpAddr(localDev.ifr_ifrn.ifrn_name) == NSTACKX_TRUE) {
1215         return SERVER_TYPE_WLANORETH;
1216     }
1217     if (IsP2pIpAddr(localDev.ifr_ifrn.ifrn_name) == NSTACKX_TRUE) {
1218         return SERVER_TYPE_P2P;
1219     }
1220     if (IsUsbIpAddr(localDev.ifr_ifrn.ifrn_name) == NSTACKX_TRUE) {
1221         return SERVER_TYPE_USB;
1222     }
1223 #else
1224     InterfaceInfo localDev;
1225     (void)memset_s(&localDev, sizeof(InterfaceInfo), 0, sizeof(InterfaceInfo));
1226     if (GetTargetAdapter(&localAddr, &localDev) != NSTACKX_EOK) {
1227         return INVALID_TYPE;
1228     }
1229     struct in_addr *sa = (struct in_addr *)&(localDev.ipAddr);
1230     if (IsWlanIpAddr(sa) == NSTACKX_TRUE) {
1231         return SERVER_TYPE_WLANORETH;
1232     }
1233     if (IsEthIpAddr(sa) == NSTACKX_TRUE) {
1234         return SERVER_TYPE_WLANORETH;
1235     }
1236     if (IsP2pIpAddr(sa) == NSTACKX_TRUE) {
1237         return SERVER_TYPE_P2P;
1238     }
1239     if (IsUsbIpAddr(sa) == NSTACKX_TRUE) {
1240         return SERVER_TYPE_USB;
1241     }
1242 #endif
1243     return type;
1244 }
1245 
1246 static void CoapRecvRecountTimerHandle(void *argument)
1247 {
1248     (void)argument;
1249     if (g_recvDiscoverMsgNum > COAP_DISVOCER_MAX_RATE) {
1250         DFINDER_LOGI(TAG, "received %u discover msg in this interval", g_recvDiscoverMsgNum);
1251     }
1252     g_recvDiscoverMsgNum = 0;
1253     return;
1254 }
1255 
1256 static void CoapInitResourcesInner(coap_context_t *ctx)
1257 {
1258     coap_resource_t *r = NULL;
1259 
1260     r = coap_resource_init(coap_make_str_const(COAP_DEVICE_DISCOVER_URI), g_resourceFlags);
1261     if (r == NULL) {
1262         return;
1263     }
1264     coap_register_handler(r, COAP_REQUEST_POST, HndPostServiceDiscover);
1265     coap_resource_set_get_observable(r, NSTACKX_TRUE);
1266     coap_add_resource(ctx, r);
1267 
1268     r = coap_resource_init(coap_make_str_const(COAP_SERVICE_MSG_URI), 0);
1269     if (r == NULL) {
1270         return;
1271     }
1272     coap_register_handler(r, COAP_REQUEST_POST, HndPostServiceMsg);
1273     coap_add_resource(ctx, r);
1274 }
1275 
1276 #ifdef DFINDER_SUPPORT_MULTI_NIF
1277 void CoapInitResourcesWithIdx(coap_context_t *ctx, uint32_t idx, const char *networkName)
1278 {
1279     CoapInitResourcesInner(ctx);
1280     g_discoverCtxList[idx].context = ctx;
1281     if (networkName != NULL) {
1282         (void)memset_s(g_discoverCtxList[idx].networkName, sizeof(g_discoverCtxList[idx].networkName),
1283                         0, sizeof(g_discoverCtxList[idx].networkName));
1284         if (strcpy_s(g_discoverCtxList[idx].networkName,
1285             sizeof(g_discoverCtxList[idx].networkName), networkName) != EOK) {
1286             DFINDER_LOGE(TAG, "strcpy failed");
1287         }
1288     }
1289     DFINDER_LOGD(TAG, "coap init resources with idx-%u update", idx);
1290 }
1291 
1292 #else
1293 void CoapInitResources(coap_context_t *ctx, uint8_t serverType)
1294 {
1295     CoapInitResourcesInner(ctx);
1296 
1297     if (serverType == SERVER_TYPE_WLANORETH) {
1298         g_context = ctx;
1299         DFINDER_LOGD(TAG, "CoapInitResources g_wlanOrEthContext update");
1300     } else if (serverType == SERVER_TYPE_P2P) {
1301         g_p2pContext = ctx;
1302         DFINDER_LOGD(TAG, "CoapInitResources g_p2pContext update");
1303     } else if (serverType == SERVER_TYPE_USB) {
1304         g_usbContext = ctx;
1305         DFINDER_LOGD(TAG, "CoapInitResources g_usbContext update");
1306     } else {
1307         DFINDER_LOGE(TAG, "CoapInitResources serverType is unknown!");
1308     }
1309 }
1310 #endif /* END OF DFINDER_SUPPORT_MULTI_NIF */
1311 
1312 int32_t CoapDiscoverInit(EpollDesc epollfd)
1313 {
1314     if (g_recvRecountTimer == NULL) {
1315         g_recvRecountTimer = TimerStart(epollfd, COAP_RECV_COUNT_INTERVAL, NSTACKX_TRUE,
1316                                         CoapRecvRecountTimerHandle, NULL);
1317     }
1318     if (g_recvRecountTimer == NULL) {
1319         DFINDER_LOGE(TAG, "failed to start timer for receive discover message recount");
1320         return NSTACKX_EFAILED;
1321     }
1322 
1323     if (g_discoverTimer == NULL) {
1324         g_discoverTimer = TimerStart(epollfd, 0, NSTACKX_FALSE, CoapServiceDiscoverTimerHandle, NULL);
1325     }
1326     if (g_discoverTimer == NULL) {
1327         DFINDER_LOGE(TAG, "failed to start timer for service discover");
1328         TimerDelete(g_recvRecountTimer);
1329         g_recvRecountTimer = NULL;
1330         return NSTACKX_EFAILED;
1331     }
1332 
1333     g_msgIdList = (MsgIdList *)calloc(1U, sizeof(MsgIdList));
1334     if (g_msgIdList == NULL) {
1335         DFINDER_LOGE(TAG, "message Id record list calloc error");
1336         TimerDelete(g_discoverTimer);
1337         g_discoverTimer = NULL;
1338         TimerDelete(g_recvRecountTimer);
1339         g_recvRecountTimer = NULL;
1340         return NSTACKX_EFAILED;
1341     }
1342 
1343     g_msgIdList->startIdx = COAP_MAX_MSGID_RESERVE_NUM;
1344     g_msgIdList->endIdx = COAP_MAX_MSGID_RESERVE_NUM;
1345     g_userRequest = NSTACKX_FALSE;
1346     g_forceUpdate = NSTACKX_FALSE;
1347     g_recvDiscoverMsgNum = 0;
1348     g_subscribeCount = 0;
1349     g_discoverCount = 0;
1350     return NSTACKX_EOK;
1351 }
1352 
1353 #ifdef DFINDER_SUPPORT_MULTI_NIF
1354 void CoapDestroyCtxWithIdx(uint32_t ctxIdx)
1355 {
1356     g_discoverCtxList[ctxIdx].context = NULL;
1357     (void)memset_s(g_discoverCtxList[ctxIdx].networkName, sizeof(g_discoverCtxList[ctxIdx].networkName),
1358         0, sizeof(g_discoverCtxList[ctxIdx].networkName));
1359     DFINDER_LOGD(TAG, "coap destroy ctx with idx-%u success", ctxIdx);
1360 }
1361 #else
1362 void CoapDestroyCtx(uint8_t serverType)
1363 {
1364     if (serverType == SERVER_TYPE_WLANORETH) {
1365         g_context = NULL;
1366         DFINDER_LOGD(TAG, "CoapDestroyCtx, g_context is set to NULL");
1367     } else if (serverType == SERVER_TYPE_P2P) {
1368         g_p2pContext = NULL;
1369         DFINDER_LOGD(TAG, "CoapDestroyCtx, g_p2pContext is set to NULL");
1370     } else if (serverType == SERVER_TYPE_USB) {
1371         g_usbContext = NULL;
1372         DFINDER_LOGD(TAG, "CoapDestroyCtx, g_usbContext is set to NULL");
1373     } else {
1374         DFINDER_LOGE(TAG, "CoapDestroyCtx, serverType is unknown");
1375     }
1376 }
1377 #endif /* END OF DFINDER_SUPPORT_MULTI_NIF */
1378 
1379 void CoapDiscoverDeinit(void)
1380 {
1381     if (g_discoverTimer != NULL) {
1382         TimerDelete(g_discoverTimer);
1383         g_discoverTimer = NULL;
1384     }
1385     if (g_recvRecountTimer != NULL) {
1386         TimerDelete(g_recvRecountTimer);
1387         g_recvRecountTimer = NULL;
1388     }
1389     if (g_msgIdList != NULL) {
1390         free(g_msgIdList);
1391         g_msgIdList = NULL;
1392     }
1393 }
1394 
1395 void ResetCoapDiscoverTaskCount(uint8_t isBusy)
1396 {
1397     if (g_discoverTimer != NULL) {
1398         if (isBusy) {
1399             DFINDER_LOGI(TAG, "in busy state: g_discoverTimer task count %llu", g_discoverTimer->task.count);
1400         }
1401         g_discoverTimer->task.count = 0;
1402     }
1403     if (g_recvRecountTimer != NULL) {
1404         if (isBusy) {
1405             DFINDER_LOGI(TAG, "in busy state: g_recvRecountTimer task count %llu",
1406                          g_recvRecountTimer->task.count);
1407         }
1408         g_recvRecountTimer->task.count = 0;
1409     }
1410 }
1411 
1412 void SetCoapDiscoverType(CoapBroadcastType type)
1413 {
1414     g_coapDiscoverType = (uint32_t)type;
1415 }
1416 
1417 void SetCoapUserDiscoverInfo(uint32_t advCount, uint32_t advDuration)
1418 {
1419     g_coapUserMaxDiscoverCount = advCount;
1420     if (advCount != 0) {
1421         g_coapUserDiscoverInterval = advDuration / advCount;
1422     }
1423 }
1424 
1425 static int32_t SendDiscoveryRspEx(const NSTACKX_ResponseSettings *responseSettings)
1426 {
1427     char remoteUrl[NSTACKX_MAX_URI_BUFFER_LENGTH] = {0};
1428     char host[NSTACKX_MAX_IP_STRING_LEN] = {0};
1429     if (responseSettings == NULL) {
1430         return NSTACKX_EFAILED;
1431     }
1432     if (responseSettings->businessData == NULL) {
1433         DFINDER_LOGE(TAG, "businessData is null");
1434         return NSTACKX_EFAILED;
1435     }
1436 
1437     if (SetLocalDeviceBusinessDataUnicast(responseSettings->businessData, responseSettings->length) != NSTACKX_EOK) {
1438         return NSTACKX_EFAILED;
1439     }
1440 
1441     if (strncpy_s(host, sizeof(host), responseSettings->remoteIp, strlen(responseSettings->remoteIp)) != EOK) {
1442         DFINDER_LOGE(TAG, "discoveryRsp remoteIp copy error");
1443         return NSTACKX_EFAILED;
1444     }
1445     if (sprintf_s(remoteUrl, sizeof(remoteUrl), "coap://%s/" COAP_DEVICE_DISCOVER_URI, host) < 0) {
1446         DFINDER_LOGE(TAG, "failed to get discoveryRsp remoteUrl");
1447         return NSTACKX_EFAILED;
1448     }
1449 #ifdef DFINDER_SUPPORT_MULTI_NIF
1450     uint32_t i;
1451     for (i = 0; i < NSTACKX_MAX_LISTENED_NIF_NUM; ++i) {
1452         if (g_discoverCtxList[i].context == NULL) {
1453             continue;
1454         }
1455         if (strcmp(responseSettings->localNetworkName, g_discoverCtxList[i].networkName) == 0) {
1456             DFINDER_LOGD(TAG, "find right discover context to call CoapResponseService with idx-%u", i);
1457             return CoapResponseService(remoteUrl, g_discoverCtxList[i].context);
1458         }
1459     }
1460 
1461     DFINDER_LOGE(TAG, "can not find right discover context to call CoapResponseService");
1462     return NSTACKX_EFAILED;
1463 #else
1464     coap_context_t *context = GetContext(SERVER_TYPE_WLANORETH);
1465     if (context == NULL) {
1466         DFINDER_LOGE(TAG, "can not find right discover context to call CoapResponseService");
1467         return NSTACKX_EFAILED;
1468     }
1469     return CoapResponseService(remoteUrl, context);
1470 #endif
1471 }
1472 
1473 void SendDiscoveryRsp(const NSTACKX_ResponseSettings *responseSettings)
1474 {
1475     if (SendDiscoveryRspEx(responseSettings) != NSTACKX_EOK) {
1476         IncStatistics(STATS_SEND_SD_RESPONSE_FAILED);
1477     }
1478 }