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