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