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