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