1 /*
2  * Copyright (C) 2021-2023 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 #include "nstackx_device_local.h"
32 #include "nstackx_device_remote.h"
33 
34 #define TAG "nStackXCoAP"
35 
36 #define COAP_URI_BUFFER_LENGTH 64 /* the size of the buffer or variable used to save uri. */
37 #define COAP_MAX_NUM_SUBSCRIBE_MODULE_COUNT 32 /* the maximum count of subscribed module */
38 
39 #define COAP_RECV_COUNT_INTERVAL 1000
40 #define COAP_DISVOCER_MAX_RATE 200
41 #define COAP_MSGID_SURVIVAL_SECONDS 100
42 #define COAP_MAX_MSGID_RESERVE_NUM 100
43 
44 typedef struct {
45     coap_mid_t msgId;
46     struct timespec recvTime;
47 } MsgIdRecord;
48 
49 typedef struct {
50     MsgIdRecord msgIdRecord[COAP_MAX_MSGID_RESERVE_NUM];
51     uint32_t startIdx;
52     uint32_t endIdx;
53 } MsgIdList;
54 
55 static int g_resourceFlags = COAP_RESOURCE_FLAGS_NOTIFY_CON;
56 static uint32_t g_coapMaxDiscoverCount = COAP_DEFAULT_DISCOVER_COUNT;
57 static uint32_t g_coapDiscoverType = COAP_BROADCAST_TYPE_DEFAULT;
58 
59 static uint8_t g_userRequest;
60 static uint8_t g_forceUpdate;
61 static Timer *g_discoverTimer = NULL;
62 static uint32_t g_discoverCount;
63 static uint32_t g_coapUserMaxDiscoverCount;
64 static uint32_t g_coapUserDiscoverInterval;
65 static uint32_t *g_coapIntervalArr = NULL;
66 static uint32_t g_coapDiscoverTargetCount;
67 static Timer *g_recvRecountTimer = NULL;
68 static uint32_t g_recvDiscoverMsgNum;
69 static MsgIdList *g_msgIdList = NULL;
70 static uint8_t g_subscribeCount;
71 
72 static uint16_t *g_notificationIntervals = NULL;
73 static uint8_t g_notificationTargetCnt = 0;
74 static uint8_t g_notificationRunCnt = 0;
75 static Timer *g_notificationTimer = NULL;
76 
77 #ifdef DFINDER_SUPPORT_SET_SCREEN_STATUS
78 static bool g_isScreenOn = true;
79 
SetScreenStatus(bool isScreenOn)80 void SetScreenStatus(bool isScreenOn)
81 {
82     g_isScreenOn = isScreenOn;
83 }
84 #endif
85 
CoapUriParse(const char * uriString,coap_uri_t * uriPtr)86 static int32_t CoapUriParse(const char *uriString, coap_uri_t *uriPtr)
87 {
88     coap_uri_t localUri;
89 
90     (void)memset_s(&localUri, sizeof(localUri), 0, sizeof(localUri));
91     if ((uriString == NULL) || (uriPtr == NULL)) {
92         return NSTACKX_EFAILED;
93     }
94 
95     if (coap_split_uri((unsigned char *)uriString, strlen(uriString), &localUri) < 0) {
96         DFINDER_LOGE(TAG, "invalid CoAP URI");
97         return NSTACKX_EFAILED;
98     }
99 #ifdef DFINDER_SUPPORT_MULTI_COAP_SCHEME
100     if (!coap_dtls_is_supported() && localUri.scheme == COAP_URI_SCHEME_COAPS) {
101         DFINDER_LOGE(TAG, "coap uri sheme coaps with no dtls support");
102         return NSTACKX_EFAILED;
103     }
104     if (((localUri.scheme == COAP_URI_SCHEME_COAPS_TCP) || (localUri.scheme == COAP_URI_SCHEME_COAPS)) &&
105         !coap_tls_is_supported()) {
106         DFINDER_LOGE(TAG, "coaps + tcp uri scheme not supported in this version of libcoap");
107         return NSTACKX_EFAILED;
108     }
109 #else
110     if (localUri.scheme != COAP_URI_SCHEME_COAP) {
111         DFINDER_LOGE(TAG, "coaps uri scheme not supported in this version of libcoap");
112         return NSTACKX_EFAILED;
113     }
114 #endif
115     (void)memcpy_s(uriPtr, sizeof(coap_uri_t), &localUri, sizeof(coap_uri_t));
116     return NSTACKX_EOK;
117 }
118 
CoapPackToPdu(const CoapRequest * coapRequest,const coap_uri_t * uriPtr,coap_session_t * session)119 static coap_pdu_t *CoapPackToPdu(const CoapRequest *coapRequest, const coap_uri_t *uriPtr, coap_session_t *session)
120 {
121     coap_pdu_t *pdu = NULL;
122     if (coapRequest == NULL || coapRequest->remoteUrl == NULL || session == NULL) {
123         return NULL;
124     }
125     pdu = coap_new_pdu(coapRequest->type, coapRequest->code, session);
126     if (pdu == NULL) {
127         return NULL;
128     }
129     if (coapRequest->tokenLength) {
130         if (!coap_add_token(pdu, coapRequest->tokenLength, coapRequest->token)) {
131             DFINDER_LOGW(TAG, "cannot add token to request");
132         }
133     }
134     coap_add_option(pdu, COAP_OPTION_URI_HOST, uriPtr->host.length, uriPtr->host.s);
135     coap_add_option(pdu, COAP_OPTION_URI_PATH, uriPtr->path.length, uriPtr->path.s);
136     if (coapRequest->dataLength) {
137         coap_add_data(pdu, coapRequest->dataLength, (uint8_t *)(coapRequest->data));
138     }
139 
140     return pdu;
141 }
142 
FillCoapRequest(CoapRequest * coapRequest,uint8_t coapType,const char * url,char * data,size_t dataLen)143 static void FillCoapRequest(CoapRequest *coapRequest, uint8_t coapType, const char *url, char *data, size_t dataLen)
144 {
145     (void)memset_s(coapRequest, sizeof(CoapRequest), 0, sizeof(CoapRequest));
146     coapRequest->type = coapType;
147     coapRequest->code = COAP_REQUEST_POST;
148     coapRequest->remoteUrl = url;
149     coapRequest->data = data;
150     coapRequest->dataLength = dataLen;
151 }
152 
CoapSendRequestEx(CoapCtxType * ctx,uint8_t coapType,const char * url,char * data,size_t dataLen)153 static int32_t CoapSendRequestEx(CoapCtxType *ctx, uint8_t coapType, const char *url, char *data, size_t dataLen)
154 {
155     CoapRequest coapRequest;
156     coap_session_t *session = NULL;
157     coap_address_t dst = {0};
158     coap_str_const_t remote;
159     int32_t tid;
160     int32_t res;
161     coap_pdu_t *pdu = NULL;
162     coap_uri_t coapUri;
163     CoapServerParameter coapServerParameter = {0};
164 
165     FillCoapRequest(&coapRequest, coapType, url, data, dataLen);
166 
167     (void)memset_s(&remote, sizeof(remote), 0, sizeof(remote));
168     (void)memset_s(&coapUri, sizeof(coapUri), 0, sizeof(coapUri));
169     if (CoapUriParse(coapRequest.remoteUrl, &coapUri) != NSTACKX_EOK) {
170         DFINDER_LOGE(TAG, "fail to parse uri");
171         return NSTACKX_EFAILED;
172     }
173     remote = coapUri.host;
174     res = CoapResolveAddress(&remote, &dst.addr.sa);
175     if (res < 0) {
176         DFINDER_LOGE(TAG, "fail to resolve address");
177         return NSTACKX_EFAILED;
178     }
179 
180     dst.size = (uint32_t)res;
181     dst.addr.sin.sin_port = htons(COAP_DEFAULT_PORT);
182     coapServerParameter.proto = COAP_PROTO_UDP;
183     coapServerParameter.dst = &dst;
184     session = CoapGetSession(ctx->ctx, GetLocalIfaceIpStr(ctx->iface), COAP_SRV_DEFAULT_PORT, &coapServerParameter);
185     if (session == NULL) {
186         DFINDER_LOGE(TAG, "get client session failed");
187         return NSTACKX_EFAILED;
188     }
189     pdu = CoapPackToPdu(&coapRequest, &coapUri, session);
190     if (pdu == NULL) {
191         DFINDER_LOGE(TAG, "pack to pdu failed");
192         goto SESSION_RELEASE;
193     }
194     DFINDER_LOGD("MYCOAP", "send coap pdu mid: %d", coap_pdu_get_mid(pdu));
195     DFINDER_MGT_REQ_LOG(&coapRequest);
196     tid = coap_send(session, pdu);
197     if (tid == COAP_INVALID_MID) {
198         DFINDER_LOGE(TAG, "coap send failed");
199         goto SESSION_RELEASE;
200     }
201 
202     coap_session_release(session);
203     return NSTACKX_EOK;
204 
205 SESSION_RELEASE:
206     coap_session_release(session);
207     return NSTACKX_EFAILED;
208 }
209 
CoapSendRequest(CoapCtxType * ctx,uint8_t coapType,const char * url,char * data,size_t dataLen)210 static int32_t CoapSendRequest(CoapCtxType *ctx, uint8_t coapType, const char *url, char *data, size_t dataLen)
211 {
212     int32_t ret = CoapSendRequestEx(ctx, coapType, url, data, dataLen);
213     if (ret != NSTACKX_EOK) {
214         IncStatistics(STATS_SEND_REQUEST_FAILED);
215     }
216     return ret;
217 }
218 
CoapResponseService(CoapCtxType * ctx,const char * remoteUrl,uint8_t businessType)219 static int32_t CoapResponseService(CoapCtxType *ctx, const char *remoteUrl, uint8_t businessType)
220 {
221     char *data = PrepareServiceDiscover(GetLocalIfaceIpStr(ctx->iface), NSTACKX_FALSE, businessType);
222     if (data == NULL) {
223         DFINDER_LOGE(TAG, "prepare service failed");
224         return NSTACKX_EFAILED;
225     }
226 
227     int ret = CoapSendRequest(ctx, COAP_MESSAGE_CON, remoteUrl, data, strlen(data) + 1);
228     cJSON_free(data);
229     return ret;
230 }
231 
IncreaseRecvDiscoverNum(void)232 static void IncreaseRecvDiscoverNum(void)
233 {
234     if (g_recvDiscoverMsgNum < UINT32_MAX) {
235         g_recvDiscoverMsgNum++;
236     }
237 }
238 
HndPostServiceDiscoverInner(const coap_pdu_t * request,char ** remoteUrl,DeviceInfo * deviceInfo)239 static int32_t HndPostServiceDiscoverInner(const coap_pdu_t *request, char **remoteUrl, DeviceInfo *deviceInfo)
240 {
241     size_t size;
242     const uint8_t *buf = NULL;
243     IncreaseRecvDiscoverNum();
244     if (g_recvDiscoverMsgNum > COAP_DISVOCER_MAX_RATE) {
245         DFINDER_LOGD(TAG, "too many dicover messages received");
246         return NSTACKX_EFAILED;
247     }
248     if (coap_get_data(request, &size, &buf) == 0 || size == 0 || size > COAP_RXBUFFER_SIZE) {
249         DFINDER_LOGE(TAG, "coap_get_data failed, size: %zu", size);
250         return NSTACKX_EFAILED;
251     }
252     if (GetServiceDiscoverInfo(buf, size, deviceInfo, remoteUrl) != NSTACKX_EOK) {
253         return NSTACKX_EFAILED;
254     }
255     /* receive coap broadcast, set peer device's discovery type to passive,
256      * to identify the local device is in passive discovery
257      */
258     deviceInfo->discoveryType = (*remoteUrl != NULL) ? NSTACKX_DISCOVERY_TYPE_PASSIVE : NSTACKX_DISCOVERY_TYPE_ACTIVE;
259     if (deviceInfo->mode == PUBLISH_MODE_UPLINE || deviceInfo->mode == PUBLISH_MODE_OFFLINE) {
260         DFINDER_LOGD(TAG, "peer is not DISCOVER_MODE");
261         NSTACKX_DeviceInfo deviceList;
262         (void)memset_s(&deviceList, sizeof(NSTACKX_DeviceInfo), 0, sizeof(NSTACKX_DeviceInfo));
263         if (GetNotifyDeviceInfo(&deviceList, deviceInfo) == NSTACKX_EOK) {
264             NotifyDeviceFound(&deviceList, 1);
265         } else {
266             DFINDER_LOGE(TAG, "GetNotifyDeviceInfo failed");
267         }
268         return NSTACKX_EFAILED;
269     }
270     return NSTACKX_EOK;
271 }
272 
CoapResponseServiceDiscovery(const char * remoteUrl,const coap_context_t * currCtx,coap_pdu_t * response,uint8_t businessType)273 static void CoapResponseServiceDiscovery(const char *remoteUrl, const coap_context_t *currCtx,
274     coap_pdu_t *response, uint8_t businessType)
275 {
276     if (remoteUrl != NULL) {
277         if (CheckBusinessTypeReplyUnicast(businessType) == NSTACKX_EOK) {
278             CoapCtxType *ctx = CoapGetCoapCtxType(currCtx);
279             if (ctx != NULL) {
280                 (void)CoapResponseService(ctx, remoteUrl, businessType);
281             }
282         }
283     } else {
284         coap_pdu_set_code(response, COAP_RESPONSE_CODE_CREATED);
285     }
286 }
287 
HndPostServiceDiscoverEx(coap_session_t * session,const coap_pdu_t * request,coap_pdu_t * response)288 static int32_t HndPostServiceDiscoverEx(coap_session_t *session, const coap_pdu_t *request, coap_pdu_t *response)
289 {
290     int32_t ret = NSTACKX_EFAILED;
291     coap_context_t *currCtx = coap_session_get_context(session);
292     if (currCtx == NULL) {
293         DFINDER_LOGE(TAG, "coap_session_get_context return null");
294         return ret;
295     }
296     char *remoteUrl = NULL;
297     DeviceInfo *deviceInfo = calloc(1, sizeof(DeviceInfo));
298     if (deviceInfo == NULL) {
299         DFINDER_LOGE(TAG, "calloc for device info failed");
300         return ret;
301     }
302 
303     const CoapCtxType *coapCtx = CoapGetCoapCtxType(currCtx);
304     if (coapCtx == NULL) {
305         DFINDER_LOGE(TAG, "get coap ctx type failed");
306         goto L_ERR;
307     }
308 
309     if (strcpy_s(deviceInfo->networkName, sizeof(deviceInfo->networkName),
310         GetLocalIfaceName(coapCtx->iface)) != EOK) {
311         DFINDER_LOGE(TAG, "copy network name failed");
312         goto L_ERR;
313     }
314 
315     if (HndPostServiceDiscoverInner(request, &remoteUrl, deviceInfo) != NSTACKX_EOK) {
316         goto L_ERR;
317     }
318     if (GetModeInfo() == PUBLISH_MODE_UPLINE || GetModeInfo() == PUBLISH_MODE_OFFLINE) {
319         DFINDER_LOGD(TAG, "local is not DISCOVER_MODE");
320         goto L_ERR;
321     }
322 
323     uint8_t receiveBcast = (remoteUrl == NULL) ? NSTACKX_FALSE : NSTACKX_TRUE;
324     if (ReportDiscoveredDevice(coapCtx, deviceInfo, g_forceUpdate, receiveBcast) != NSTACKX_EOK) {
325         goto L_ERR;
326     }
327 
328     g_forceUpdate = NSTACKX_FALSE;
329     if (deviceInfo->mode == PUBLISH_MODE_PROACTIVE) {
330         DFINDER_LOGD(TAG, "peer is PUBLISH_MODE_PROACTIVE");
331         goto L_ERR;
332     }
333     CoapResponseServiceDiscovery(remoteUrl, currCtx, response, deviceInfo->businessType);
334 
335     ret = NSTACKX_EOK;
336 L_ERR:
337     free(deviceInfo);
338     free(remoteUrl);
339     return ret;
340 }
341 
HndPostServiceDiscover(coap_resource_t * resource,coap_session_t * session,const coap_pdu_t * request,const coap_string_t * query,coap_pdu_t * response)342 static void HndPostServiceDiscover(coap_resource_t *resource, coap_session_t *session,
343     const coap_pdu_t *request, const coap_string_t *query, coap_pdu_t *response)
344 {
345     Coverity_Tainted_Set((void *)request);
346 
347     (void)resource;
348     (void)query;
349 #ifdef DFINDER_SUPPORT_SET_SCREEN_STATUS
350     if (request == NULL || response == NULL || !g_isScreenOn) {
351 #else
352     if (request == NULL || response == NULL) {
353 #endif
354         DFINDER_LOGD(TAG, "invalid params");
355         return;
356     }
357     DFINDER_LOGD("MYCOAP", "recv coap pdu mid: %d", coap_pdu_get_mid(request));
358     if (HndPostServiceDiscoverEx(session, request, response) != NSTACKX_EOK) {
359         IncStatistics(STATS_HANDLE_DEVICE_DISCOVER_MSG_FAILED);
360     }
361 }
362 
363 static void DeleteOverTimeMsgIdRecord(MsgIdList *msgIdList, struct timespec *curTime)
364 {
365     uint32_t i = msgIdList->startIdx;
366     if (msgIdList->startIdx >= COAP_MAX_MSGID_RESERVE_NUM || msgIdList->endIdx >= COAP_MAX_MSGID_RESERVE_NUM) {
367         return;
368     }
369     uint32_t cycleTimes = 0;
370     while (NSTACKX_TRUE) {
371         if (curTime->tv_sec - msgIdList->msgIdRecord[i].recvTime.tv_sec < COAP_MSGID_SURVIVAL_SECONDS) {
372             return;
373         }
374         if (i == msgIdList->endIdx) {
375             msgIdList->startIdx = COAP_MAX_MSGID_RESERVE_NUM;
376             msgIdList->endIdx = COAP_MAX_MSGID_RESERVE_NUM;
377             return;
378         }
379         msgIdList->startIdx = (msgIdList->startIdx + 1) % COAP_MAX_MSGID_RESERVE_NUM;
380         i = msgIdList->startIdx;
381         if (cycleTimes > COAP_MAX_MSGID_RESERVE_NUM) {
382             IncStatistics(STATS_DROP_MSG_ID);
383             DFINDER_LOGE(TAG, "cycle too many times, error must occurred and init msgList");
384             msgIdList->startIdx = COAP_MAX_MSGID_RESERVE_NUM;
385             msgIdList->endIdx = COAP_MAX_MSGID_RESERVE_NUM;
386             break;
387         }
388         cycleTimes++;
389     }
390 }
391 
392 static void AddMsgIdRecord(MsgIdList *msgIdList, coap_mid_t msgId, struct timespec *curTime)
393 {
394     int32_t ret;
395     uint32_t idx;
396     if (msgIdList->endIdx == COAP_MAX_MSGID_RESERVE_NUM) {
397         msgIdList->endIdx = 0;
398         msgIdList->startIdx = 0;
399         idx = 0;
400     } else {
401         idx = (msgIdList->endIdx + 1) % COAP_MAX_MSGID_RESERVE_NUM;
402         if (idx == msgIdList->startIdx) {
403             msgIdList->startIdx = (msgIdList->startIdx + 1) % COAP_MAX_MSGID_RESERVE_NUM;
404         }
405     }
406     msgIdList->msgIdRecord[idx].msgId = msgId;
407     ret = memcpy_s(&msgIdList->msgIdRecord[idx].recvTime, sizeof(struct timespec), curTime, sizeof(struct timespec));
408     if (ret != NSTACKX_EOK) {
409         DFINDER_LOGE(TAG, "set msg id time error");
410         return;
411     }
412     msgIdList->endIdx = idx;
413 }
414 
415 static uint8_t RefreshMsgIdList(coap_mid_t msgId)
416 {
417     struct timespec curTime;
418     uint32_t i;
419     if (g_msgIdList == NULL) {
420         return NSTACKX_TRUE;
421     }
422     ClockGetTime(CLOCK_MONOTONIC, &curTime);
423     DeleteOverTimeMsgIdRecord(g_msgIdList, &curTime);
424     if (g_msgIdList->startIdx >= COAP_MAX_MSGID_RESERVE_NUM || g_msgIdList->endIdx >= COAP_MAX_MSGID_RESERVE_NUM) {
425         AddMsgIdRecord(g_msgIdList, msgId, &curTime);
426         return NSTACKX_TRUE;
427     }
428     i = g_msgIdList->startIdx;
429     uint32_t cycleTimes = 0;
430     while (NSTACKX_TRUE) {
431         if (g_msgIdList->msgIdRecord[i].msgId == msgId) {
432             (void)memcpy_s(&g_msgIdList->msgIdRecord[i].recvTime, sizeof(struct timespec), &curTime,
433                            sizeof(struct timespec));
434             return NSTACKX_FALSE;
435         }
436         if (i == g_msgIdList->endIdx) {
437             break;
438         }
439         i = (i + 1) % COAP_MAX_MSGID_RESERVE_NUM;
440         if (cycleTimes > COAP_MAX_MSGID_RESERVE_NUM) {
441             IncStatistics(STATS_DROP_MSG_ID);
442             DFINDER_LOGE(TAG, "cycle too many times, error must occurred and init msgList");
443             g_msgIdList->startIdx = COAP_MAX_MSGID_RESERVE_NUM;
444             g_msgIdList->endIdx = COAP_MAX_MSGID_RESERVE_NUM;
445             break;
446         }
447         cycleTimes++;
448     }
449     AddMsgIdRecord(g_msgIdList, msgId, &curTime);
450     return NSTACKX_TRUE;
451 }
452 
453 static uint16_t GetServiceMsgFrameLen(const uint8_t *frame, uint16_t size)
454 {
455     uint16_t frameLen, ret;
456     if (size < sizeof(frameLen)) {
457         DFINDER_LOGE(TAG, "input size %u is too small", size);
458         return 0;
459     }
460     if (memcpy_s(&frameLen, sizeof(frameLen), frame, sizeof(frameLen)) != EOK) {
461         DFINDER_LOGE(TAG, "memcpy frame len failed");
462         return 0;
463     }
464     ret = ntohs(frameLen);
465     if (size < ret) {
466         DFINDER_LOGE(TAG, "input size %u is smaller than decoded frame len %u", size, ret);
467         return 0;
468     }
469     return ret;
470 }
471 
472 static uint16_t GetUnitInfo(const uint8_t *data, uint16_t dataLen, uint8_t *outBuf, uint32_t outLen, uint8_t unitType)
473 {
474     if (dataLen < sizeof(CoapMsgUnit)) {
475         DFINDER_LOGE(TAG, "dataLen %u is too small", dataLen);
476         return 0;
477     }
478     CoapMsgUnit *unit = (CoapMsgUnit *)data;
479     if (unit->type != unitType) {
480         DFINDER_LOGE(TAG, "unit type %u does match target type %u", unit->type, unitType);
481         return 0;
482     }
483     uint16_t valueLen = ntohs(unit->len);
484     if (valueLen == 0 || valueLen > outLen || valueLen + sizeof(CoapMsgUnit) > dataLen) {
485         DFINDER_LOGE(TAG, "valueLen %u is illegal", valueLen);
486         return 0;
487     }
488     if (memcpy_s(outBuf, outLen, unit->value, valueLen) != EOK) {
489         DFINDER_LOGE(TAG, "memcpy unit->value failed");
490         return 0;
491     }
492     if (unitType == COAP_MODULE_NAME_TYPE || unitType == COAP_DEVICE_ID_TYPE) {
493         if (outBuf[valueLen - 1] != '\0') {
494             DFINDER_LOGE(TAG, "uint type is %u but value is not end with 0", unitType);
495             return 0;
496         }
497     }
498     return valueLen;
499 }
500 
501 static uint16_t ParseServiceMsgFrame(const uint8_t *frame, size_t size, char *moduleName, char *deviceId,
502                                      uint8_t **msg)
503 {
504     if (frame == NULL || size == 0) {
505         return 0;
506     }
507     uint16_t frameLen = GetServiceMsgFrameLen(frame, size);
508     if (frameLen < sizeof(frameLen) + sizeof(CoapMsgUnit)) {
509         return 0;
510     }
511 
512     /* get modulename info */
513     uint16_t len = sizeof(frameLen);
514     uint16_t moduleNameLen = GetUnitInfo(frame + len, frameLen - len, (uint8_t *)moduleName,
515                                          NSTACKX_MAX_MODULE_NAME_LEN, COAP_MODULE_NAME_TYPE);
516     if (moduleNameLen == 0 || moduleNameLen + sizeof(CoapMsgUnit) >= frameLen - len) {
517         return 0;
518     }
519 
520     /* get deviceIdLen info */
521     len += moduleNameLen + sizeof(CoapMsgUnit);
522     uint16_t deviceIdLen = GetUnitInfo(frame + len, frameLen - len, (uint8_t *)deviceId,
523                                        NSTACKX_MAX_DEVICE_ID_LEN, COAP_DEVICE_ID_TYPE);
524     if (deviceIdLen == 0 || deviceIdLen + sizeof(CoapMsgUnit) >= frameLen - len) {
525         return 0;
526     }
527 
528     /* get msg info */
529     len += deviceIdLen + sizeof(CoapMsgUnit);
530     uint8_t *msgPtr = (uint8_t *)calloc(1U, frameLen - len);
531     if (msgPtr == NULL) {
532         return 0;
533     }
534     uint16_t msgLen = GetUnitInfo(frame + len, frameLen - len, msgPtr, frameLen - len, COAP_MSG_TYPE);
535     if (msgLen == 0) {
536         free(msgPtr);
537         return 0;
538     }
539     *msg = msgPtr;
540     return msgLen;
541 }
542 
543 static int32_t HndPostServiceMsgEx(coap_resource_t *resource, coap_session_t *session,
544     const coap_pdu_t *request, const coap_string_t *query, coap_pdu_t *response)
545 {
546     Coverity_Tainted_Set((void *)request);
547 
548     (void)resource;
549     (void)session;
550     (void)query;
551     if (request == NULL || response == NULL) {
552         return NSTACKX_EFAILED;
553     }
554     char deviceId[NSTACKX_MAX_DEVICE_ID_LEN] = {0};
555     char moduleName[NSTACKX_MAX_MODULE_NAME_LEN] = {0};
556     uint8_t *msg = NULL;
557     const uint8_t *buf = NULL;
558     uint16_t msgLen;
559     size_t size;
560 
561     if (coap_get_data(request, &size, &buf) == 0 || size == 0 || size > COAP_RXBUFFER_SIZE) {
562         return NSTACKX_EFAILED;
563     }
564 
565     if (!RefreshMsgIdList(coap_pdu_get_mid(request))) {
566         DFINDER_LOGE(TAG, "repeated msg id");
567         return NSTACKX_EFAILED;
568     }
569 
570     DFINDER_LOGD(TAG, "handling post service msg request");
571     msgLen = ParseServiceMsgFrame(buf, size, moduleName, deviceId, &msg);
572     if (msgLen == 0) {
573         DFINDER_LOGD(TAG, "parse service msg frame error");
574         return NSTACKX_EFAILED;
575     }
576     const coap_address_t *addPtr = coap_session_get_addr_remote(session);
577     if (addPtr == NULL) {
578         DFINDER_LOGE(TAG, "coap session get remote addr failed");
579         free(msg);
580         return NSTACKX_EFAILED;
581     }
582     char srcIp[NSTACKX_MAX_IP_STRING_LEN] = {0};
583     if (inet_ntop(AF_INET, &((addPtr->addr).sin.sin_addr), srcIp, sizeof(srcIp)) == NULL) {
584         free(msg);
585         return NSTACKX_EFAILED;
586     }
587     NotifyMsgReceived(moduleName, deviceId, msg, msgLen, srcIp);
588 
589     coap_pdu_set_code(response, COAP_RESPONSE_CODE_CREATED);
590     free(msg);
591     return NSTACKX_EOK;
592 }
593 
594 static void HndPostServiceMsg(coap_resource_t *resource, coap_session_t *session,
595     const coap_pdu_t *request, const coap_string_t *query, coap_pdu_t *response)
596 {
597     if (HndPostServiceMsgEx(resource, session, request, query, response) != NSTACKX_EOK) {
598         IncStatistics(STATS_HANDLE_SERVICE_MSG_FAILED);
599     }
600 }
601 
602 static int32_t CoapPostServiceDiscoverEx(CoapCtxType *ctx)
603 {
604     char broadcastIp[NSTACKX_MAX_IP_STRING_LEN] = {0};
605     if (GetBroadcastIp(ctx->iface, broadcastIp, sizeof(broadcastIp)) != NSTACKX_EOK) {
606         DFINDER_LOGE(TAG, "get broadcast ip failed");
607         return NSTACKX_EFAILED;
608     }
609 
610     char discoverUri[COAP_URI_BUFFER_LENGTH] = {0};
611     if (sprintf_s(discoverUri, sizeof(discoverUri), "coap://%s/%s", broadcastIp, COAP_DEVICE_DISCOVER_URI) < 0) {
612         DFINDER_LOGE(TAG, "formate uri failed");
613         return NSTACKX_EFAILED;
614     }
615 
616     char *data = PrepareServiceDiscover(GetLocalIfaceIpStr(ctx->iface), NSTACKX_TRUE, GetLocalDeviceBusinessType());
617     if (data == NULL) {
618         DFINDER_LOGE(TAG, "prepare json failed");
619         return NSTACKX_EFAILED;
620     }
621 
622     int ret = CoapSendRequest(ctx, COAP_MESSAGE_NON, discoverUri, data, strlen(data) + 1);
623     cJSON_free(data);
624     return ret;
625 }
626 
627 static int32_t CoapPostServiceDiscover(void)
628 {
629     List *pos = NULL;
630     List *head = GetCoapContextList();
631     int successCnt = 0;
632     LIST_FOR_EACH(pos, head) {
633         int ret = CoapPostServiceDiscoverEx((CoapCtxType *)pos);
634         if (ret == NSTACKX_EOK) {
635             successCnt++;
636         }
637     }
638 
639     if (successCnt == 0) {
640         DFINDER_LOGE(TAG, "no iface send request");
641         IncStatistics(STATS_POST_SD_REQUEST_FAILED);
642         return NSTACKX_EFAILED;
643     }
644 
645     return NSTACKX_EOK;
646 }
647 
648 static uint32_t GetUserDefineInterval(uint32_t discoverCount)
649 {
650     if (discoverCount >= (g_coapMaxDiscoverCount - 1)) {
651         DFINDER_LOGD(TAG, "discover end");
652         return 0;
653     }
654     return g_coapIntervalArr[discoverCount];
655 }
656 
657 static uint32_t GetDiscoverInterval(uint32_t discoverCount)
658 {
659     switch (g_coapDiscoverType) {
660         case COAP_BROADCAST_TYPE_USER:
661             return g_coapUserDiscoverInterval;
662         case COAP_BROADCAST_TYPE_USER_DEFINE_INTERVAL:
663             return GetUserDefineInterval(discoverCount);
664         case COAP_BROADCAST_TYPE_DEFAULT:
665             return GetDefaultDiscoverInterval(discoverCount);
666         default:
667             return GetDefaultDiscoverInterval(discoverCount);
668     }
669 }
670 
671 static void CoapServiceDiscoverStop(void)
672 {
673     g_forceUpdate = NSTACKX_FALSE;
674     g_discoverCount = 0;
675     SetModeInfo(DISCOVER_MODE);
676 #ifdef DFINDER_SAVE_DEVICE_LIST
677     ClearRemoteDeviceListBackup();
678     DFINDER_LOGD(TAG, "clear device list backup");
679 #endif
680     g_coapDiscoverType = COAP_BROADCAST_TYPE_DEFAULT;
681     g_coapMaxDiscoverCount = COAP_DEFAULT_DISCOVER_COUNT;
682     /* Can call PostDeviceFindWrapper() to notify user if needed. */
683     g_userRequest = NSTACKX_FALSE;
684     // release interval array
685     if (g_coapIntervalArr != NULL) {
686         free(g_coapIntervalArr);
687         g_coapIntervalArr = NULL;
688     }
689 }
690 
691 static void CoapServiceDiscoverTimerHandle(void *argument)
692 {
693     uint32_t discoverInterval;
694 
695     (void)argument;
696 
697     if (g_discoverCount >= g_coapDiscoverTargetCount || !IsCoapContextReady()) {
698         IncStatistics(STATS_ABORT_SD);
699         CoapServiceDiscoverStop();
700         return;
701     }
702 
703     if (CoapPostServiceDiscover() != NSTACKX_EOK) {
704         DFINDER_LOGE(TAG, "failed when posting service discover request");
705         goto L_ERR_DISCOVER;
706     }
707 
708     /* Restart timer */
709     discoverInterval = GetDiscoverInterval(g_discoverCount);
710 
711     ++g_discoverCount;
712     if (TimerSetTimeout(g_discoverTimer, discoverInterval, NSTACKX_FALSE) != NSTACKX_EOK) {
713         DFINDER_LOGE(TAG, "failed to set timer for service discovery");
714         goto L_ERR_DISCOVER;
715     }
716     return;
717 
718 L_ERR_DISCOVER:
719     IncStatistics(STATS_ABORT_SD);
720     /* Abort service discover by not starting timer. */
721     DFINDER_LOGE(TAG, "abort service discovery, have tried %u request", g_discoverCount);
722     /* Reset g_discoverCount to allow new request from user. */
723     g_discoverCount = 0;
724     return;
725 }
726 
727 void CoapInitSubscribeModuleInner(void)
728 {
729     g_subscribeCount = 0;
730     return;
731 }
732 
733 void CoapSubscribeModuleInner(uint8_t isSubscribe)
734 {
735     if (isSubscribe && (g_subscribeCount < COAP_MAX_NUM_SUBSCRIBE_MODULE_COUNT)) {
736         g_subscribeCount++;
737     }
738     return;
739 }
740 
741 void CoapUnsubscribeModuleInner(uint8_t isUnsubscribe)
742 {
743     if (isUnsubscribe && (g_subscribeCount > 0)) {
744         g_subscribeCount--;
745     }
746 }
747 
748 static void SetCoapMaxDiscoverCount(void)
749 {
750     switch (g_coapDiscoverType) {
751         case COAP_BROADCAST_TYPE_DEFAULT:
752             g_coapMaxDiscoverCount = COAP_DEFAULT_DISCOVER_COUNT;
753             break;
754         case COAP_BROADCAST_TYPE_USER:
755         case COAP_BROADCAST_TYPE_USER_DEFINE_INTERVAL:
756             g_coapMaxDiscoverCount = g_coapUserMaxDiscoverCount;
757             break;
758         default:
759             g_coapMaxDiscoverCount = COAP_DEFAULT_DISCOVER_COUNT;
760             break;
761     }
762 }
763 
764 static void CoapServiceDiscoverFirstTime(void)
765 {
766     SetCoapMaxDiscoverCount();
767     g_coapDiscoverTargetCount = g_coapMaxDiscoverCount;
768     if (CoapPostServiceDiscover() != NSTACKX_EOK) {
769         DFINDER_LOGE(TAG, "failed to send service discover request");
770         return;
771     }
772 
773     uint32_t discoverInterval = GetDiscoverInterval(g_discoverCount);
774     if (TimerSetTimeout(g_discoverTimer, discoverInterval, NSTACKX_FALSE) != NSTACKX_EOK) {
775         DFINDER_LOGE(TAG, "failed to set timer when doing service discover");
776         return;
777     }
778     ++g_discoverCount;
779     DFINDER_LOGI(TAG, "first time for device discover.");
780 }
781 
782 void CoapServiceDiscoverInner(uint8_t userRequest)
783 {
784     if (!IsCoapContextReady()) {
785         IncStatistics(STATS_START_SD_FAILED);
786         DFINDER_LOGI(TAG, "Network not connected when discovery inner");
787         return;
788     }
789 
790     if (userRequest) {
791         g_userRequest = NSTACKX_TRUE;
792         g_forceUpdate = NSTACKX_TRUE;
793     }
794 
795     if (g_coapDiscoverTargetCount > 0 &&
796         g_discoverCount >= g_coapDiscoverTargetCount) {
797         g_discoverCount = 0;
798         SetModeInfo(DISCOVER_MODE);
799 #ifdef DFINDER_SAVE_DEVICE_LIST
800         ClearRemoteDeviceListBackup();
801         DFINDER_LOGW(TAG, "clear device list backup");
802 #endif
803         (void)TimerSetTimeout(g_discoverTimer, 0, NSTACKX_FALSE);
804     }
805 
806     if (g_discoverCount) {
807         /* Service discover is ongoing, return. */
808         return;
809     }
810 #ifdef DFINDER_SAVE_DEVICE_LIST
811     /* First discover */
812     BackupRemoteDeviceList();
813     DFINDER_LOGW(TAG, "clear device list when discovery inner");
814 #endif /* END OF DFINDER_SAVE_DEVICE_LIST */
815     SetModeInfo(DISCOVER_MODE);
816     CoapServiceDiscoverFirstTime();
817     return;
818 }
819 
820 void CoapServiceDiscoverInnerAn(uint8_t userRequest)
821 {
822     if (!IsCoapContextReady()) {
823         IncStatistics(STATS_START_SD_FAILED);
824         DFINDER_LOGI(TAG, "Network not connected when discovery inner AN");
825         return;
826     }
827 
828     if (userRequest) {
829         g_userRequest = NSTACKX_TRUE;
830     }
831 
832     if (g_discoverCount != 0) {
833         g_discoverCount = 0;
834         /* Service discover is ongoing, reset. */
835         (void)TimerSetTimeout(g_discoverTimer, 0, NSTACKX_FALSE);
836     }
837 
838     CoapServiceDiscoverFirstTime();
839     return;
840 }
841 
842 void CoapServiceDiscoverInnerConfigurable(uint8_t userRequest)
843 {
844     if (!IsCoapContextReady()) {
845         IncStatistics(STATS_START_SD_FAILED);
846         DFINDER_LOGI(TAG, "Network not connected when discovery configurable");
847         return;
848     }
849 
850     if (userRequest) {
851         g_userRequest = NSTACKX_TRUE;
852         g_forceUpdate = NSTACKX_TRUE;
853     }
854 
855     if (g_coapDiscoverTargetCount > 0 && g_discoverCount >= g_coapDiscoverTargetCount) {
856         g_discoverCount = 0;
857 #ifdef DFINDER_SAVE_DEVICE_LIST
858         ClearRemoteDeviceListBackup();
859         DFINDER_LOGW(TAG, "clear device list backup when discovery configurable");
860 #endif
861         (void)TimerSetTimeout(g_discoverTimer, 0, NSTACKX_FALSE);
862     }
863 
864     if (g_discoverCount != 0) {
865         g_discoverCount = 0;
866         /* Service discover is ongoing, return. */
867         (void)TimerSetTimeout(g_discoverTimer, 0, NSTACKX_FALSE);
868     } else {
869         /* First discover */
870 #ifdef DFINDER_SAVE_DEVICE_LIST
871         BackupRemoteDeviceList();
872         DFINDER_LOGW(TAG, "clear device list when discovery configurable");
873 #endif
874     }
875     CoapServiceDiscoverFirstTime();
876     return;
877 }
878 
879 void CoapServiceDiscoverStopInner(void)
880 {
881     (void)TimerSetTimeout(g_discoverTimer, 0, NSTACKX_FALSE);
882     CoapServiceDiscoverStop();
883     DFINDER_LOGI(TAG, "device discover inner stopped");
884 }
885 
886 uint8_t CoapDiscoverRequestOngoing(void)
887 {
888     return ((g_discoverCount > 0 && g_userRequest) || (g_subscribeCount > 0));
889 }
890 
891 static uint8_t *CreateServiceMsgFrame(const char *moduleName, const char *deviceId, const uint8_t *msg, uint32_t msgLen,
892                                       uint16_t *dataLen)
893 {
894     uint16_t frameLen, moduleNameUnitLen, deviceIdUnitLen, msgUnitLen, bufferLen;
895     uint8_t *frame = NULL;
896     uint16_t len = 0;
897     CoapMsgUnit *unit = NULL;
898     moduleNameUnitLen = sizeof(CoapMsgUnit) + strlen(moduleName) + 1;
899     deviceIdUnitLen = sizeof(CoapMsgUnit) + strlen(deviceId) + 1;
900     msgUnitLen = sizeof(CoapMsgUnit) + msgLen;
901     bufferLen = sizeof(frameLen) + moduleNameUnitLen + deviceIdUnitLen + msgUnitLen;
902     frameLen = htons(bufferLen);
903 
904     frame = (uint8_t *)calloc(1U, bufferLen);
905     if (frame == NULL) {
906         IncStatistics(STATS_CREATE_SERVICE_MSG_FAILED);
907         return NULL;
908     }
909     if (memcpy_s(frame, bufferLen, &frameLen, sizeof(frameLen)) != EOK) {
910         goto L_ERR_SEND_MSG;
911     }
912     len += sizeof(frameLen);
913 
914     unit = (CoapMsgUnit *)(frame + len);
915     unit->type = COAP_MODULE_NAME_TYPE;
916     unit->len = htons(moduleNameUnitLen - sizeof(CoapMsgUnit));
917     if (memcpy_s(unit->value, bufferLen - len - sizeof(CoapMsgUnit), moduleName, strlen(moduleName) + 1) != EOK) {
918         goto L_ERR_SEND_MSG;
919     }
920     len += moduleNameUnitLen;
921 
922     unit = (CoapMsgUnit *)(frame + len);
923     unit->type = COAP_DEVICE_ID_TYPE;
924     unit->len = htons(deviceIdUnitLen - sizeof(CoapMsgUnit));
925     if (memcpy_s(unit->value, bufferLen - len - sizeof(CoapMsgUnit), deviceId, strlen(deviceId) + 1) != EOK) {
926         goto L_ERR_SEND_MSG;
927     }
928     len += deviceIdUnitLen;
929 
930     unit = (CoapMsgUnit *)(frame + len);
931     unit->type = COAP_MSG_TYPE;
932     unit->len = htons(msgUnitLen - sizeof(CoapMsgUnit));
933     if (memcpy_s(unit->value, bufferLen - len - sizeof(CoapMsgUnit), msg, msgLen) != EOK) {
934         goto L_ERR_SEND_MSG;
935     }
936     *dataLen = bufferLen;
937     return frame;
938 L_ERR_SEND_MSG:
939     IncStatistics(STATS_CREATE_SERVICE_MSG_FAILED);
940     free(frame);
941     return NULL;
942 }
943 
944 int32_t CoapSendServiceMsg(MsgCtx *msgCtx, const char *remoteIpStr, const struct in_addr *remoteIp)
945 {
946     char uriBuffer[COAP_URI_BUFFER_LENGTH] = {0};
947     uint16_t dataLen = 0;
948 
949     CoapCtxType *ctx = LocalIfaceGetCoapCtxByRemoteIp(remoteIp, msgCtx->type);
950     if (ctx == NULL) {
951         DFINDER_LOGE(TAG, "can not find the local iface");
952         return NSTACKX_EFAILED;
953     }
954 
955     if (sprintf_s(uriBuffer, sizeof(uriBuffer), "coap://%s/" COAP_SERVICE_MSG_URI, remoteIpStr) < 0) {
956         DFINDER_LOGE(TAG, "sprintf_s for coap service msg uri failed");
957         return NSTACKX_EFAILED;
958     }
959 
960     char *data = (char *)CreateServiceMsgFrame(msgCtx->moduleName,
961         GetLocalDeviceId(), msgCtx->data, msgCtx->len, &dataLen);
962     if (data == NULL) {
963         DFINDER_LOGE(TAG, "failed to prepare msg data");
964         return NSTACKX_EFAILED;
965     }
966 
967     int ret = CoapSendRequest(ctx, COAP_MESSAGE_CON, uriBuffer, data, dataLen);
968     free(data);
969     return ret;
970 }
971 
972 static void CoapRecvRecountTimerHandle(void *argument)
973 {
974     (void)argument;
975     if (g_recvDiscoverMsgNum > COAP_DISVOCER_MAX_RATE) {
976         DFINDER_LOGI(TAG, "received %u discover msg in this interval", g_recvDiscoverMsgNum);
977     }
978     g_recvDiscoverMsgNum = 0;
979     return;
980 }
981 
982 static int32_t CoapPostServiceNotificationEx(CoapCtxType *ctx)
983 {
984     char broadcastIp[NSTACKX_MAX_IP_STRING_LEN] = {0};
985     if (GetBroadcastIp(ctx->iface, broadcastIp, sizeof(broadcastIp)) != NSTACKX_EOK) {
986         DFINDER_LOGE(TAG, "get %s broadcast ip failed, please check nic status with ifconfig or reconnect to network",
987             GetLocalIfaceName(ctx->iface));
988         return NSTACKX_EFAILED;
989     }
990     char notificationUri[COAP_URI_BUFFER_LENGTH] = {0};
991     if (sprintf_s(notificationUri, sizeof(notificationUri),
992         "coap://%s/%s", broadcastIp, COAP_SERVICE_NOTIFICATION_URI) < 0) {
993         DFINDER_LOGE(TAG, "format coap service notification uri failed");
994         return NSTACKX_EFAILED;
995     }
996     char *data = PrepareServiceNotification();
997     if (data == NULL) {
998         DFINDER_LOGE(TAG, "prepare service notification data fail");
999         return NSTACKX_EFAILED;
1000     }
1001     int32_t ret = CoapSendRequest(ctx, COAP_MESSAGE_NON, notificationUri, data, strlen(data) + 1);
1002     cJSON_free(data);
1003     return ret;
1004 }
1005 
1006 static int32_t CoapPostServiceNotification(void)
1007 {
1008     List *pos = NULL;
1009     List *head = GetCoapContextList();
1010     int successCnt = 0;
1011     LIST_FOR_EACH(pos, head) {
1012         int32_t ret = CoapPostServiceNotificationEx((CoapCtxType *)pos);
1013         if (ret == NSTACKX_EOK) {
1014             successCnt++;
1015         }
1016     }
1017     if (successCnt == 0) {
1018         DFINDER_LOGE(TAG, "no iface to send request, coap context ready: %d", IsCoapContextReady());
1019         IncStatistics(STATS_POST_SD_REQUEST_FAILED);
1020         return NSTACKX_EFAILED;
1021     }
1022     return NSTACKX_EOK;
1023 }
1024 
1025 static inline uint16_t GetNextNotificationInterval(uint8_t runCnt)
1026 {
1027     return (runCnt >= g_notificationTargetCnt) ? 0 : g_notificationIntervals[runCnt];
1028 }
1029 
1030 static void ResetNotificationConfig(void)
1031 {
1032     g_notificationRunCnt = 0;
1033     g_notificationTargetCnt = 0;
1034     if (g_notificationIntervals != NULL) {
1035         free(g_notificationIntervals);
1036         g_notificationIntervals = NULL;
1037     }
1038 }
1039 
1040 void CoapServiceNotificationStop(void)
1041 {
1042     (void)TimerSetTimeout(g_notificationTimer, 0, NSTACKX_FALSE);
1043     ResetNotificationConfig();
1044     DFINDER_LOGI(TAG, "caller stop send notifications, reset run cnt, target cnt all to 0");
1045 }
1046 
1047 static void CoapServiceNotificationTimerHandle(void *argument)
1048 {
1049     (void)argument;
1050     if (!IsCoapContextReady()) {
1051         DFINDER_LOGE(TAG, "coap context not ready, check nic status");
1052         return;
1053     }
1054     if (CoapPostServiceNotification() != NSTACKX_EOK) {
1055         DFINDER_LOGE(TAG, "failed when post service notification");
1056         goto L_ERR_NOTIFICATION;
1057     }
1058     DFINDER_LOGI(TAG, "the %hhu time for sending notification", g_notificationRunCnt + 1);
1059     uint16_t nextInterval = GetNextNotificationInterval(++g_notificationRunCnt);
1060     if (TimerSetTimeout(g_notificationTimer, nextInterval, NSTACKX_FALSE) != NSTACKX_EOK) {
1061         DFINDER_LOGE(TAG, "failed to set timer for service notification");
1062         goto L_ERR_NOTIFICATION;
1063     }
1064     return;
1065 L_ERR_NOTIFICATION:
1066     DFINDER_LOGE(TAG, "abort notification, tried %hhu request, now reset notification cnt to 0", g_notificationRunCnt);
1067     g_notificationRunCnt = 0;
1068 }
1069 
1070 static int32_t HndPostServiceNotificationEx(const coap_pdu_t *request)
1071 {
1072     size_t size = 0;
1073     const uint8_t *buf = NULL;
1074     if (coap_get_data(request, &size, &buf) == 0 || size == 0 || size > COAP_RXBUFFER_SIZE) {
1075         DFINDER_LOGE(TAG, "coap_get_data fail, size: %zu, coap rx buffer size: %d", size, COAP_RXBUFFER_SIZE);
1076         return NSTACKX_EFAILED;
1077     }
1078     NSTACKX_NotificationConfig *notification =
1079         (NSTACKX_NotificationConfig *)calloc(1, sizeof(NSTACKX_NotificationConfig));
1080     if (notification == NULL) {
1081         DFINDER_LOGE(TAG, "calloc for notification fail, size wanted: %zu", sizeof(NSTACKX_NotificationConfig));
1082         return NSTACKX_ENOMEM;
1083     }
1084     notification->msg = (char *)calloc(NSTACKX_MAX_NOTIFICATION_DATA_LEN, sizeof(char));
1085     if (notification->msg == NULL) {
1086         DFINDER_LOGE(TAG, "calloc for notification msg failed");
1087         free(notification);
1088         return NSTACKX_ENOMEM;
1089     }
1090     if (GetServiceNotificationInfo(buf, size, notification) != NSTACKX_EOK) {
1091         free(notification->msg);
1092         free(notification);
1093         return NSTACKX_EFAILED;
1094     }
1095     NotificationReceived(notification);
1096     free(notification->msg);
1097     free(notification);
1098     return NSTACKX_EOK;
1099 }
1100 
1101 static void HndPostServiceNotification(coap_resource_t *resource, coap_session_t *session,
1102     const coap_pdu_t *request, const coap_string_t *query, coap_pdu_t *response)
1103 {
1104     (void)resource;
1105     (void)query;
1106     (void)session;
1107     (void)response;
1108 
1109     if (request == NULL) {
1110         DFINDER_LOGW(TAG, "request pdu is null, return");
1111         return;
1112     }
1113 #ifdef DFINDER_SUPPORT_SET_SCREEN_STATUS
1114     if (!g_isScreenOn) {
1115         DFINDER_LOGD(TAG, "device screen is off, ignore pdu received");
1116         return;
1117     }
1118 #endif
1119     DFINDER_LOGI(TAG, "recv coap notification pdu mid: %d", coap_pdu_get_mid(request));
1120 
1121     if (HndPostServiceNotificationEx(request) != NSTACKX_EOK) {
1122         DFINDER_LOGE(TAG, " hnd post service notificatioin failed for pdu mid: %d", coap_pdu_get_mid(request));
1123     }
1124 }
1125 
1126 int32_t CoapInitResources(coap_context_t *ctx)
1127 {
1128     coap_resource_t *r =
1129         coap_resource_init(coap_make_str_const(COAP_DEVICE_DISCOVER_URI), g_resourceFlags);
1130     if (r == NULL) {
1131         DFINDER_LOGE(TAG, "coap resource init discover failed");
1132         return NSTACKX_ENOMEM;
1133     }
1134     coap_register_request_handler(r, COAP_REQUEST_POST, HndPostServiceDiscover);
1135     coap_resource_set_get_observable(r, NSTACKX_TRUE);
1136     coap_add_resource(ctx, r);
1137 
1138     coap_resource_t *msg =
1139         coap_resource_init(coap_make_str_const(COAP_SERVICE_MSG_URI), 0);
1140     if (msg == NULL) {
1141         DFINDER_LOGE(TAG, "coap resource init msg failed");
1142         (void)coap_delete_resource(ctx, r);
1143         return NSTACKX_ENOMEM;
1144     }
1145     coap_register_request_handler(msg, COAP_REQUEST_POST, HndPostServiceMsg);
1146     coap_add_resource(ctx, msg);
1147 
1148     coap_resource_t *notification = coap_resource_init(coap_make_str_const(COAP_SERVICE_NOTIFICATION_URI), 0);
1149     if (notification == NULL) {
1150         DFINDER_LOGE(TAG, "coap_resource_init for service notification failed");
1151         (void)coap_delete_resource(ctx, r);
1152         (void)coap_delete_resource(ctx, msg);
1153         return NSTACKX_ENOMEM;
1154     }
1155     coap_register_request_handler(notification, COAP_REQUEST_POST, HndPostServiceNotification);
1156     coap_add_resource(ctx, notification);
1157 
1158     return NSTACKX_EOK;
1159 }
1160 
1161 int32_t CoapDiscoverInit(EpollDesc epollfd)
1162 {
1163     if (g_recvRecountTimer == NULL) {
1164         g_recvRecountTimer = TimerStart(epollfd, COAP_RECV_COUNT_INTERVAL, NSTACKX_TRUE,
1165                                         CoapRecvRecountTimerHandle, NULL);
1166     }
1167     if (g_recvRecountTimer == NULL) {
1168         DFINDER_LOGE(TAG, "failed to start timer for receive discover message recount");
1169         return NSTACKX_EFAILED;
1170     }
1171 
1172     if (g_discoverTimer == NULL) {
1173         g_discoverTimer = TimerStart(epollfd, 0, NSTACKX_FALSE, CoapServiceDiscoverTimerHandle, NULL);
1174     }
1175     if (g_discoverTimer == NULL) {
1176         DFINDER_LOGE(TAG, "failed to start timer for service discover");
1177         TimerDelete(g_recvRecountTimer);
1178         g_recvRecountTimer = NULL;
1179         return NSTACKX_EFAILED;
1180     }
1181 
1182     if (g_notificationTimer == NULL) {
1183         g_notificationTimer = TimerStart(epollfd, 0, NSTACKX_FALSE, CoapServiceNotificationTimerHandle, NULL);
1184     }
1185     if (g_notificationTimer == NULL) {
1186         DFINDER_LOGE(TAG, "failed to start timer for service notification");
1187         TimerDelete(g_recvRecountTimer);
1188         g_recvRecountTimer = NULL;
1189         TimerDelete(g_discoverTimer);
1190         g_discoverTimer = NULL;
1191         return NSTACKX_EFAILED;
1192     }
1193 
1194     g_msgIdList = (MsgIdList *)calloc(1U, sizeof(MsgIdList));
1195     if (g_msgIdList == NULL) {
1196         DFINDER_LOGE(TAG, "message Id record list calloc error");
1197         TimerDelete(g_discoverTimer);
1198         g_discoverTimer = NULL;
1199         TimerDelete(g_recvRecountTimer);
1200         g_recvRecountTimer = NULL;
1201         TimerDelete(g_notificationTimer);
1202         g_notificationTimer = NULL;
1203         return NSTACKX_EFAILED;
1204     }
1205 
1206     g_msgIdList->startIdx = COAP_MAX_MSGID_RESERVE_NUM;
1207     g_msgIdList->endIdx = COAP_MAX_MSGID_RESERVE_NUM;
1208     g_userRequest = NSTACKX_FALSE;
1209     g_forceUpdate = NSTACKX_FALSE;
1210     g_recvDiscoverMsgNum = 0;
1211     g_subscribeCount = 0;
1212     g_discoverCount = 0;
1213     g_notificationRunCnt = 0;
1214     return NSTACKX_EOK;
1215 }
1216 
1217 void CoapDiscoverDeinit(void)
1218 {
1219     if (g_discoverTimer != NULL) {
1220         TimerDelete(g_discoverTimer);
1221         g_discoverTimer = NULL;
1222     }
1223     if (g_recvRecountTimer != NULL) {
1224         TimerDelete(g_recvRecountTimer);
1225         g_recvRecountTimer = NULL;
1226     }
1227     if (g_notificationTimer != NULL) {
1228         TimerDelete(g_notificationTimer);
1229         g_notificationTimer = NULL;
1230     }
1231     if (g_msgIdList != NULL) {
1232         free(g_msgIdList);
1233         g_msgIdList = NULL;
1234     }
1235     if (g_coapIntervalArr != NULL) {
1236         free(g_coapIntervalArr);
1237         g_coapIntervalArr = NULL;
1238     }
1239     ResetNotificationConfig();
1240 }
1241 
1242 void ResetCoapDiscoverTaskCount(uint8_t isBusy)
1243 {
1244     if (g_discoverTimer != NULL) {
1245         if (isBusy) {
1246             DFINDER_LOGI(TAG, "in busy state: g_discoverTimer task count %llu", g_discoverTimer->task.count);
1247         }
1248         g_discoverTimer->task.count = 0;
1249     }
1250     if (g_recvRecountTimer != NULL) {
1251         if (isBusy) {
1252             DFINDER_LOGI(TAG, "in busy state: g_recvRecountTimer task count %llu",
1253                          g_recvRecountTimer->task.count);
1254         }
1255         g_recvRecountTimer->task.count = 0;
1256     }
1257 }
1258 
1259 void SetCoapDiscoverType(CoapBroadcastType type)
1260 {
1261     g_coapDiscoverType = (uint32_t)type;
1262 }
1263 
1264 void SetCoapUserDiscoverInfo(uint32_t advCount, uint32_t advDuration)
1265 {
1266     g_coapUserMaxDiscoverCount = advCount;
1267     if (advCount != 0) {
1268         g_coapUserDiscoverInterval = advDuration / advCount;
1269     }
1270     DFINDER_LOGD(TAG, "SetCoapUserDiscoverInfo advCount %u, interval %u",
1271         g_coapUserMaxDiscoverCount, g_coapUserDiscoverInterval);
1272 }
1273 
1274 int32_t SetCoapDiscConfig(const DFinderDiscConfig *discConfig)
1275 {
1276     uint32_t *tmp = (uint32_t *)malloc(discConfig->intervalArrLen * sizeof(uint32_t));
1277     if (tmp != NULL) {
1278         if (g_coapIntervalArr != NULL) {
1279             free(g_coapIntervalArr);
1280         }
1281         g_coapIntervalArr = tmp;
1282         for (size_t i = 0; i < discConfig->intervalArrLen; ++i) {
1283             g_coapIntervalArr[i] = (discConfig->bcastInterval)[i];
1284         }
1285         // add 1: first broadcast starts immediately
1286         g_coapUserMaxDiscoverCount = discConfig->intervalArrLen + 1;
1287         return NSTACKX_EOK;
1288     }
1289     DFINDER_LOGE(TAG, "malloc for user define interval array failed");
1290     if (g_coapIntervalArr != NULL) {
1291         DFINDER_LOGD(TAG, "going to use last interval config");
1292         return NSTACKX_EOK;
1293     }
1294     DFINDER_LOGE(TAG, "failed to use last interval config");
1295     return NSTACKX_EFAILED;
1296 }
1297 
1298 static int32_t SendDiscoveryRspEx(CoapCtxType *ctx, const NSTACKX_ResponseSettings *responseSettings)
1299 {
1300     char remoteUrl[NSTACKX_MAX_URI_BUFFER_LENGTH] = {0};
1301     char host[NSTACKX_MAX_IP_STRING_LEN] = {0};
1302 
1303     if (SetLocalDeviceBusinessData(responseSettings->businessData, NSTACKX_TRUE) != NSTACKX_EOK) {
1304         return NSTACKX_EFAILED;
1305     }
1306     DFINDER_LOGD(TAG, "response settings with business type: %hu", responseSettings->businessType);
1307 
1308     if (strncpy_s(host, sizeof(host), responseSettings->remoteIp, strlen(responseSettings->remoteIp)) != EOK) {
1309         DFINDER_LOGE(TAG, "discoveryRsp remoteIp copy error");
1310         return NSTACKX_EFAILED;
1311     }
1312     if (sprintf_s(remoteUrl, sizeof(remoteUrl), "coap://%s/" COAP_DEVICE_DISCOVER_URI, host) < 0) {
1313         DFINDER_LOGE(TAG, "failed to get discoveryRsp remoteUrl");
1314         return NSTACKX_EFAILED;
1315     }
1316     IncreaseSequenceNumber(NSTACKX_FALSE);
1317     return CoapResponseService(ctx, remoteUrl, responseSettings->businessType);
1318 }
1319 
1320 void SendDiscoveryRsp(const NSTACKX_ResponseSettings *responseSettings)
1321 {
1322     CoapCtxType *ctx = LocalIfaceGetCoapCtx(responseSettings->localNetworkName);
1323     if (ctx == NULL) {
1324         DFINDER_LOGE(TAG, "local iface get coap context return null");
1325         IncStatistics(STATS_SEND_SD_RESPONSE_FAILED);
1326         return;
1327     }
1328 
1329     if (SendDiscoveryRspEx(ctx, responseSettings) != NSTACKX_EOK) {
1330         IncStatistics(STATS_SEND_SD_RESPONSE_FAILED);
1331     }
1332 }
1333 
1334 int32_t LocalizeNotificationInterval(const uint16_t *intervals, const uint8_t intervalLen)
1335 {
1336     uint16_t *tmp = (uint16_t *)calloc(intervalLen, sizeof(uint16_t));
1337     if (tmp != NULL) {
1338         if (g_notificationIntervals != NULL) {
1339             free(g_notificationIntervals);
1340         }
1341         g_notificationIntervals = tmp;
1342         for (size_t i = 0; i < intervalLen; ++i) {
1343             g_notificationIntervals[i] = intervals[i];
1344         }
1345         g_notificationTargetCnt = intervalLen;
1346         return NSTACKX_EOK;
1347     }
1348     DFINDER_LOGW(TAG, "calloc for notification intervals fail, interval len %hhu", intervalLen);
1349     if (g_notificationIntervals != NULL) {
1350         DFINDER_LOGW(TAG, "going to use last success notification config");
1351         return NSTACKX_EOK;
1352     }
1353     DFINDER_LOGE(TAG, "set notification intervals fail and can not use last success config");
1354     return NSTACKX_EFAILED;
1355 }
1356 
1357 static void CoapServiceNotificationFirstTime(void)
1358 {
1359     if (CoapPostServiceNotification() != NSTACKX_EOK) {
1360         DFINDER_LOGE(TAG, "failed to send service notification first time");
1361         return;
1362     }
1363 
1364     uint16_t nextInterval = GetNextNotificationInterval(++g_notificationRunCnt);
1365     if (TimerSetTimeout(g_notificationTimer, nextInterval, NSTACKX_FALSE) != NSTACKX_EOK) {
1366         DFINDER_LOGE(TAG, "failed to set timer when doing service notification");
1367         return;
1368     }
1369     DFINDER_LOGI(TAG, "first time for service notification");
1370 }
1371 
1372 void CoapServiceNotification(void)
1373 {
1374     if (!IsCoapContextReady()) {
1375         DFINDER_LOGW(TAG, "no coap ctx inited, please check nic info or reconnected");
1376         return;
1377     }
1378     if (g_notificationRunCnt != 0) {
1379         DFINDER_LOGI(TAG, "reset notification run cnt to 0, run cnt: %hhu, target cnt: %hhu",
1380             g_notificationRunCnt, g_notificationTargetCnt);
1381         g_notificationRunCnt = 0;
1382         (void)TimerSetTimeout(g_notificationTimer, 0, NSTACKX_FALSE);
1383     }
1384     CoapServiceNotificationFirstTime();
1385 }
1386