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 "nstackx_device_local.h"
17 #include <securec.h>
18 #include "nstackx_dfinder_hidump.h"
19 #include "nstackx_error.h"
20 #include "nstackx_dev.h"
21 #include "nstackx_dfinder_log.h"
22 #include "nstackx_statistics.h"
23 #include "nstackx_timer.h"
24 #include "nstackx_util.h"
25 #include "nstackx_device_remote.h"
26 #include "nstackx_list.h"
27
28 #define TAG "LOCALDEVICE"
29 enum {
30 IFACE_STATE_READY,
31 IFACE_STATE_DESTROYING,
32 IFACE_STATE_CREATING,
33 };
34
35 struct LocalIface {
36 List node;
37
38 char ifname[NSTACKX_MAX_INTERFACE_NAME_LEN];
39 char ipStr[NSTACKX_MAX_IP_STRING_LEN];
40 struct in_addr ip;
41
42 uint8_t type;
43 uint8_t state;
44 uint8_t createCount;
45 struct timespec updateTime;
46
47 Timer *timer;
48 CoapCtxType *ctx;
49 };
50
51 typedef struct LocalDevice_ {
52 DeviceInfo deviceInfo;
53
54 List readyList[IFACE_TYPE_MAX];
55 List creatingList;
56 List destroyList;
57
58 Timer *timer;
59 bool inited;
60 } LocalDevice;
61
62 static LocalDevice g_localDevice;
63
64 #define LOCAL_DEVICE_OFFLINE_DEFERRED_DURATION 5000 /* Defer local device offline event, 5 seconds */
65
66 #define NSTACKX_DEFAULT_DEVICE_NAME "nStack Device"
67
68 #define IFACE_COAP_CTX_INIT_MAX_RETRY_TIMES 4
69 static const uint32_t g_ifaceCoapCtxRetryBackoffList[IFACE_COAP_CTX_INIT_MAX_RETRY_TIMES] = { 10, 15, 25, 100 };
70
71 static pthread_mutex_t g_capabilityLock = PTHREAD_MUTEX_INITIALIZER;
72 static pthread_mutex_t g_serviceDataLock = PTHREAD_MUTEX_INITIALIZER;
73 static pthread_mutex_t g_businessDataLock = PTHREAD_MUTEX_INITIALIZER;
74 static pthread_mutex_t g_extendServiceDataLock = PTHREAD_MUTEX_INITIALIZER;
75 static pthread_mutex_t g_deviceInfoLock = PTHREAD_MUTEX_INITIALIZER;
76
LocalDeviceTimeout(void * data)77 static void LocalDeviceTimeout(void *data)
78 {
79 (void)data;
80
81 struct timespec cur;
82 ClockGetTime(CLOCK_MONOTONIC, &cur);
83
84 uint32_t nextTimeout = 0;
85 List *pos = NULL;
86 List *tmp = NULL;
87 LIST_FOR_EACH_SAFE(pos, tmp, &g_localDevice.destroyList) {
88 struct LocalIface *iface = (struct LocalIface *)pos;
89 uint32_t diff = GetTimeDiffMs(&cur, &iface->updateTime);
90 if (diff < LOCAL_DEVICE_OFFLINE_DEFERRED_DURATION) {
91 nextTimeout = LOCAL_DEVICE_OFFLINE_DEFERRED_DURATION - diff;
92 break;
93 }
94
95 DestroyLocalIface(iface, NSTACKX_FALSE);
96 }
97
98 if (nextTimeout != 0) {
99 DFINDER_LOGD(TAG, "start offline timer again, timeout %u", nextTimeout);
100 (void)TimerSetTimeout(g_localDevice.timer, nextTimeout, NSTACKX_FALSE);
101 }
102 }
103
LocalDeviceDeinit(void)104 void LocalDeviceDeinit(void)
105 {
106 if (!g_localDevice.inited) {
107 DFINDER_LOGW(TAG, "local device not inited");
108 return;
109 }
110
111 List *pos = NULL;
112 List *tmp = NULL;
113 int i;
114 for (i = 0; i < IFACE_TYPE_MAX; i++) {
115 LIST_FOR_EACH_SAFE(pos, tmp, &g_localDevice.readyList[i]) {
116 DestroyLocalIface((struct LocalIface *)pos, NSTACKX_TRUE);
117 }
118 }
119
120 LIST_FOR_EACH_SAFE(pos, tmp, &g_localDevice.destroyList) {
121 DestroyLocalIface((struct LocalIface *)pos, NSTACKX_TRUE);
122 }
123
124 LIST_FOR_EACH_SAFE(pos, tmp, &g_localDevice.creatingList) {
125 DestroyLocalIface((struct LocalIface *)pos, NSTACKX_TRUE);
126 }
127
128 if (g_localDevice.timer != NULL) {
129 TimerDelete(g_localDevice.timer);
130 g_localDevice.timer = NULL;
131 }
132
133 g_localDevice.inited = NSTACKX_FALSE;
134 }
135
LocalDeviceInit(EpollDesc epollfd)136 int LocalDeviceInit(EpollDesc epollfd)
137 {
138 (void)memset_s(&g_localDevice, sizeof(g_localDevice), 0, sizeof(g_localDevice));
139 g_localDevice.timer = TimerStart(epollfd, 0, NSTACKX_FALSE, LocalDeviceTimeout, NULL);
140 if (g_localDevice.timer == NULL) {
141 DFINDER_LOGE(TAG, "timer init failed");
142 return NSTACKX_EFAILED;
143 }
144
145 int i;
146 for (i = 0; i < IFACE_TYPE_MAX; i++) {
147 ListInitHead(&g_localDevice.readyList[i]);
148 }
149
150 ListInitHead(&g_localDevice.destroyList);
151 ListInitHead(&g_localDevice.creatingList);
152 g_localDevice.inited = NSTACKX_TRUE;
153
154 return NSTACKX_EOK;
155 }
156
ResetLocalDeviceTaskCount(uint8_t isBusy)157 void ResetLocalDeviceTaskCount(uint8_t isBusy)
158 {
159 if (g_localDevice.timer != NULL) {
160 if (isBusy) {
161 DFINDER_LOGI(TAG, "in this busy interval: offline deferred timer task count %llu",
162 g_localDevice.timer->task.count);
163 }
164 g_localDevice.timer->task.count = 0;
165 }
166 }
167
LocalIfaceChangeState(struct LocalIface * iface,List * targetList,uint8_t state)168 static inline void LocalIfaceChangeState(struct LocalIface *iface, List *targetList, uint8_t state)
169 {
170 DFINDER_LOGI(TAG, "iface %s state change: %hhu -> %hhu", iface->ifname, iface->state, state);
171 ListRemoveNode(&iface->node);
172 iface->state = state;
173 ListInsertTail(targetList, &iface->node);
174 }
175
LocalIfaceCreateContextTimeout(void * arg)176 static void LocalIfaceCreateContextTimeout(void *arg)
177 {
178 struct LocalIface *iface = (struct LocalIface *)arg;
179 DFINDER_LOGD(TAG, "iface %s create context for %u times", iface->ifname, iface->createCount);
180 iface->ctx = CoapServerInit(&iface->ip, (void *)iface);
181 if (iface->ctx != NULL) {
182 DFINDER_LOGD(TAG, "iface %s create coap context success", iface->ifname);
183 TimerDelete(iface->timer);
184 iface->timer = NULL;
185 LocalIfaceChangeState(iface, &g_localDevice.readyList[iface->type], IFACE_STATE_READY);
186 return;
187 }
188
189 if (iface->createCount >= IFACE_COAP_CTX_INIT_MAX_RETRY_TIMES) {
190 DFINDER_LOGE(TAG, "create context retry reach max times %hhu", iface->createCount);
191 DestroyLocalIface(iface, NSTACKX_FALSE);
192 return;
193 }
194
195 (void)TimerSetTimeout(iface->timer, g_ifaceCoapCtxRetryBackoffList[iface->createCount], NSTACKX_FALSE);
196 iface->createCount++;
197 }
198
NeedCreateSynchronously(uint8_t ifaceType)199 static inline bool NeedCreateSynchronously(uint8_t ifaceType)
200 {
201 return ifaceType < IFACE_TYPE_P2P;
202 }
203
LocalIfaceInit(struct LocalIface * iface,const char * ifname,const struct in_addr * ip,const char * ipStr)204 static int LocalIfaceInit(struct LocalIface *iface, const char *ifname, const struct in_addr *ip, const char *ipStr)
205 {
206 DFINDER_LOGI(TAG, "trying to bring up interface %s", ifname);
207
208 if (strcpy_s(iface->ifname, sizeof(iface->ifname), ifname) != EOK) {
209 DFINDER_LOGE(TAG, "copy ifname %s failed", ifname);
210 return NSTACKX_EFAILED;
211 }
212 if (strcpy_s(iface->ipStr, sizeof(iface->ipStr), ipStr) != EOK) {
213 DFINDER_LOGE(TAG, "copy ip string failed");
214 return NSTACKX_EFAILED;
215 }
216 iface->type = GetIfaceType(ifname);
217 iface->ip.s_addr = ip->s_addr;
218
219 if (NeedCreateSynchronously(iface->type)) {
220 iface->ctx = CoapServerInit(ip, (void *)iface);
221 if (iface->ctx == NULL) {
222 DFINDER_LOGE(TAG, "create coap context failed");
223 IncStatistics(STATS_CREATE_SERVER_FAILED);
224 return NSTACKX_EFAILED;
225 }
226 iface->state = IFACE_STATE_READY;
227 ListInsertTail(&g_localDevice.readyList[iface->type], &iface->node);
228 } else {
229 iface->timer = TimerStart(GetEpollFD(), g_ifaceCoapCtxRetryBackoffList[0],
230 NSTACKX_FALSE, LocalIfaceCreateContextTimeout, iface);
231 if (iface->timer == NULL) {
232 DFINDER_LOGE(TAG, "iface %s create timer to create context async failed", iface->ifname);
233 return NSTACKX_EFAILED;
234 }
235 iface->createCount = 1;
236 iface->state = IFACE_STATE_CREATING;
237 ListInsertTail(&g_localDevice.creatingList, &iface->node);
238 }
239
240 return NSTACKX_EOK;
241 }
242
CreateLocalIface(const char * ifname,const struct in_addr * ip,const char * ipStr)243 static struct LocalIface *CreateLocalIface(const char *ifname, const struct in_addr *ip, const char *ipStr)
244 {
245 struct LocalIface *iface = calloc(1, sizeof(struct LocalIface));
246 if (iface == NULL) {
247 DFINDER_LOGE(TAG, "alloc falied");
248 return NULL;
249 }
250
251 if (LocalIfaceInit(iface, ifname, ip, ipStr) != NSTACKX_EOK) {
252 DFINDER_LOGE(TAG, "local iface init failed");
253 free(iface);
254 return NULL;
255 }
256
257 return iface;
258 }
259
DestroyLocalIface(struct LocalIface * iface,bool moduleDeinit)260 void DestroyLocalIface(struct LocalIface *iface, bool moduleDeinit)
261 {
262 DFINDER_LOGI(TAG, "destroy iface %s, type: %hhu state: %hhu", iface->ifname, iface->type, iface->state);
263
264 #ifdef DFINDER_SAVE_DEVICE_LIST
265 DestroyRxIfaceByIfname(iface->ifname);
266 #endif
267
268 if (iface->ctx != NULL) {
269 CoapServerDestroy(iface->ctx, moduleDeinit);
270 }
271 ListRemoveNode(&iface->node);
272 if (iface->timer != NULL) {
273 TimerDelete(iface->timer);
274 }
275 free(iface);
276 }
277
GetLocalIface(List * head,const char * ifname,const struct in_addr * ip)278 static struct LocalIface *GetLocalIface(List *head, const char *ifname, const struct in_addr *ip)
279 {
280 List *pos = NULL;
281 LIST_FOR_EACH(pos, head) {
282 struct LocalIface *iface = (struct LocalIface *)pos;
283 DFINDER_LOGD(TAG, "local ifname: %s, ifname: %s", iface->ifname, ifname);
284 if (strcmp(iface->ifname, ifname) == 0 && (ip == NULL || ip->s_addr == iface->ip.s_addr)) {
285 return iface;
286 }
287 }
288
289 return NULL;
290 }
291
GetActiveLocalIface(const char * ifname)292 static struct LocalIface *GetActiveLocalIface(const char *ifname)
293 {
294 uint8_t type = GetIfaceType(ifname);
295 struct LocalIface *iface = GetLocalIface(&g_localDevice.readyList[type], ifname, NULL);
296 if (iface == NULL) {
297 iface = GetLocalIface(&g_localDevice.creatingList, ifname, NULL);
298 }
299
300 return iface;
301 }
302
AddToDestroyList(struct LocalIface * iface)303 static void AddToDestroyList(struct LocalIface *iface)
304 {
305 if (iface->state != IFACE_STATE_DESTROYING) {
306 if (ListIsEmpty(&g_localDevice.destroyList)) {
307 (void)TimerSetTimeout(g_localDevice.timer, LOCAL_DEVICE_OFFLINE_DEFERRED_DURATION, NSTACKX_FALSE);
308 DFINDER_LOGD(TAG, "iface %s start offline timer", iface->ifname);
309 }
310 LocalIfaceChangeState(iface, &g_localDevice.destroyList, IFACE_STATE_DESTROYING);
311 ClockGetTime(CLOCK_MONOTONIC, &iface->updateTime);
312 if (iface->timer != NULL) {
313 (void)TimerSetTimeout(iface->timer, 0, NSTACKX_FALSE);
314 iface->createCount = 0;
315 }
316 }
317 }
318
AddLocalIface(const char * ifname,const struct in_addr * ip)319 int AddLocalIface(const char *ifname, const struct in_addr *ip)
320 {
321 struct LocalIface *iface = GetActiveLocalIface(ifname);
322 if (iface == NULL) {
323 iface = GetLocalIface(&g_localDevice.destroyList, ifname, ip);
324 if (iface != NULL) {
325 DFINDER_LOGW(TAG, "iface %s is in destroying", ifname);
326 LocalIfaceChangeState(iface, &g_localDevice.readyList[iface->type], IFACE_STATE_READY);
327 return NSTACKX_EOK;
328 }
329 } else {
330 if (iface->ip.s_addr == ip->s_addr) {
331 DFINDER_LOGW(TAG, "iface %s already existed", ifname);
332 return NSTACKX_EOK;
333 }
334
335 AddToDestroyList(iface);
336 }
337
338 char ipStr[INET_ADDRSTRLEN] = {0};
339 if (inet_ntop(AF_INET, ip, ipStr, sizeof(ipStr)) == NULL) {
340 DFINDER_LOGE(TAG, "ip to string failed");
341 return NSTACKX_EFAILED;
342 }
343
344 iface = CreateLocalIface(ifname, ip, ipStr);
345 return (iface == NULL) ? NSTACKX_EFAILED : NSTACKX_EOK;
346 }
347
RemoveLocalIface(const char * ifname)348 void RemoveLocalIface(const char *ifname)
349 {
350 struct LocalIface *iface = GetActiveLocalIface(ifname);
351 if (iface == NULL) {
352 DFINDER_LOGW(TAG, "iface %s not found when deleting iface", ifname);
353 return;
354 }
355
356 AddToDestroyList(iface);
357 }
358
RemoveAllLocalIfaceOfList(List * list)359 static void RemoveAllLocalIfaceOfList(List *list)
360 {
361 List *pos = NULL;
362 List *tmp = NULL;
363 LIST_FOR_EACH_SAFE(pos, tmp, list) {
364 AddToDestroyList((struct LocalIface *)pos);
365 }
366 }
367
RemoveAllLocalIface(void)368 static void RemoveAllLocalIface(void)
369 {
370 uint8_t i;
371 for (i = IFACE_TYPE_ETH; i < IFACE_TYPE_MAX; i++) {
372 RemoveAllLocalIfaceOfList(&g_localDevice.readyList[i]);
373 }
374
375 RemoveAllLocalIfaceOfList(&g_localDevice.creatingList);
376 }
377
RemoveSpecifiedLocalIface(const NSTACKX_InterfaceInfo * ifInfo,uint32_t ifNums)378 static inline void RemoveSpecifiedLocalIface(const NSTACKX_InterfaceInfo *ifInfo, uint32_t ifNums)
379 {
380 uint32_t i;
381 for (i = 0; i < ifNums; ++i) {
382 RemoveLocalIface(ifInfo[i].networkName);
383 }
384 }
385
AddLocalIfaceIpChanged(const NSTACKX_InterfaceInfo * ifInfo,uint32_t ifNums)386 static int AddLocalIfaceIpChanged(const NSTACKX_InterfaceInfo *ifInfo, uint32_t ifNums)
387 {
388 uint8_t ifaceType = IFACE_TYPE_MAX;
389 uint32_t i;
390 for (i = 0; i < ifNums; ++i) {
391 if (ifInfo->networkName[0] == '\0' || ifInfo->networkIpAddr[0] == '\0') {
392 DFINDER_LOGI(TAG, "skip empty network name or ip addr");
393 continue;
394 }
395
396 struct in_addr ip;
397 if (inet_pton(AF_INET, ifInfo[i].networkIpAddr, &ip) != 1) {
398 DFINDER_LOGE(TAG, "invalid ip addr of iface %u", ifInfo[i].networkName);
399 return NSTACKX_EFAILED;
400 }
401
402 if (ip.s_addr == 0) {
403 DFINDER_LOGI(TAG, "skip ip with any");
404 continue;
405 }
406
407 if (AddLocalIface(ifInfo[i].networkName, &ip) != NSTACKX_EOK) {
408 DFINDER_LOGE(TAG, "create local iface %s failed", ifInfo[i].networkName);
409 return NSTACKX_EFAILED;
410 }
411
412 uint8_t curIfaceType = GetIfaceType(ifInfo[i].networkName);
413 if (curIfaceType < ifaceType) { /* storge the highest priority interface name */
414 if (strcpy_s(g_localDevice.deviceInfo.networkName, sizeof(g_localDevice.deviceInfo.networkName),
415 ifInfo[i].networkName) != EOK) {
416 DFINDER_LOGE(TAG, "copy ifname %s failed", ifInfo[i].networkName);
417 return NSTACKX_EFAILED;
418 }
419 ifaceType = curIfaceType;
420 }
421 }
422
423 return NSTACKX_EOK;
424 }
425
CopyDeviceInfoV2(const NSTACKX_LocalDeviceInfoV2 * devInfo)426 static int CopyDeviceInfoV2(const NSTACKX_LocalDeviceInfoV2 *devInfo)
427 {
428 if (strcpy_s(g_localDevice.deviceInfo.deviceId, sizeof(g_localDevice.deviceInfo.deviceId),
429 devInfo->deviceId) != EOK) {
430 DFINDER_LOGE(TAG, "copy device id failed");
431 return NSTACKX_EFAILED;
432 }
433
434 if (devInfo->name[0] == '\0') {
435 DFINDER_LOGW(TAG, "Invalid device name. Will use default name");
436 (void)strcpy_s(g_localDevice.deviceInfo.deviceName,
437 sizeof(g_localDevice.deviceInfo.deviceName), NSTACKX_DEFAULT_DEVICE_NAME);
438 } else {
439 if (strcpy_s(g_localDevice.deviceInfo.deviceName,
440 sizeof(g_localDevice.deviceInfo.deviceName), devInfo->name) != EOK) {
441 DFINDER_LOGE(TAG, "copy device name %s failed", devInfo->name);
442 return NSTACKX_EFAILED;
443 }
444 }
445
446 g_localDevice.deviceInfo.deviceType = devInfo->deviceType;
447 g_localDevice.deviceInfo.businessType = devInfo->businessType;
448 if (devInfo->hasDeviceHash) {
449 SetLocalDeviceHash(devInfo->deviceHash);
450 }
451
452 return NSTACKX_EOK;
453 }
454
RegisterLocalDeviceV2(const NSTACKX_LocalDeviceInfoV2 * devInfo,int registerType)455 int RegisterLocalDeviceV2(const NSTACKX_LocalDeviceInfoV2 *devInfo, int registerType)
456 {
457 if (PthreadMutexLock(&g_deviceInfoLock) != 0) {
458 DFINDER_LOGE(TAG, "failed to lock");
459 return NSTACKX_EFAILED;
460 }
461 if (registerType == REGISTER_TYPE_UPDATE_ALL) {
462 RemoveAllLocalIface();
463 } else {
464 RemoveSpecifiedLocalIface(devInfo->localIfInfo, devInfo->ifNums);
465 }
466
467 if (CopyDeviceInfoV2(devInfo) != NSTACKX_EOK) {
468 if (PthreadMutexUnlock(&g_deviceInfoLock) != 0) {
469 DFINDER_LOGE(TAG, "failed to unlock");
470 }
471 return NSTACKX_EFAILED;
472 }
473
474 if (AddLocalIfaceIpChanged(devInfo->localIfInfo, devInfo->ifNums) != NSTACKX_EOK) {
475 if (registerType == REGISTER_TYPE_UPDATE_ALL) {
476 RemoveAllLocalIface(); /* maybe some ifaces is added, so remove all ifaces again */
477 }
478 if (PthreadMutexUnlock(&g_deviceInfoLock) != 0) {
479 DFINDER_LOGE(TAG, "failed to unlock");
480 }
481 return NSTACKX_EFAILED;
482 }
483 if (PthreadMutexUnlock(&g_deviceInfoLock) != 0) {
484 DFINDER_LOGE(TAG, "failed to unlock");
485 return NSTACKX_EFAILED;
486 }
487
488 return NSTACKX_EOK;
489 }
490
ConfigureLocalDeviceName(const char * localDeviceName)491 void ConfigureLocalDeviceName(const char *localDeviceName)
492 {
493 char backupDevName[NSTACKX_MAX_DEVICE_NAME_LEN] = {0};
494 if (memcpy_s(backupDevName, sizeof(backupDevName), g_localDevice.deviceInfo.deviceName,
495 sizeof(g_localDevice.deviceInfo.deviceName)) != EOK) {
496 DFINDER_LOGE(TAG, "backup local device name failed!");
497 return;
498 }
499 if (strncpy_s(g_localDevice.deviceInfo.deviceName, NSTACKX_MAX_DEVICE_NAME_LEN,
500 localDeviceName, NSTACKX_MAX_DEVICE_NAME_LEN - 1) != EOK) {
501 DFINDER_LOGW(TAG, "copy local device failed, will use current name");
502 if (strcpy_s(g_localDevice.deviceInfo.deviceName, NSTACKX_MAX_DEVICE_NAME_LEN, backupDevName) != EOK) {
503 DFINDER_LOGE(TAG, "config device name failed and cannot restore!");
504 }
505 }
506 }
507
SetLocalDeviceHash(uint64_t deviceHash)508 void SetLocalDeviceHash(uint64_t deviceHash)
509 {
510 (void)memset_s(g_localDevice.deviceInfo.deviceHash, sizeof(g_localDevice.deviceInfo.deviceHash),
511 0, sizeof(g_localDevice.deviceInfo.deviceHash));
512 if (sprintf_s(g_localDevice.deviceInfo.deviceHash, DEVICE_HASH_LEN,
513 "%ju", deviceHash) == -1) {
514 DFINDER_LOGE(TAG, "set device hash error");
515 }
516 }
517
SetLocalDeviceCapability(uint32_t capabilityBitmapNum,uint32_t capabilityBitmap[])518 int SetLocalDeviceCapability(uint32_t capabilityBitmapNum, uint32_t capabilityBitmap[])
519 {
520 if (PthreadMutexLock(&g_capabilityLock) != 0) {
521 DFINDER_LOGE(TAG, "failed to lock");
522 return NSTACKX_EFAILED;
523 }
524 (void)memset_s(g_localDevice.deviceInfo.capabilityBitmap, sizeof(g_localDevice.deviceInfo.capabilityBitmap),
525 0, sizeof(g_localDevice.deviceInfo.capabilityBitmap));
526 g_localDevice.deviceInfo.capabilityBitmapNum = 0;
527
528 if (capabilityBitmapNum > 0) {
529 if (memcpy_s(g_localDevice.deviceInfo.capabilityBitmap, sizeof(g_localDevice.deviceInfo.capabilityBitmap),
530 capabilityBitmap, sizeof(uint32_t) * capabilityBitmapNum) != EOK) {
531 DFINDER_LOGE(TAG, "capabilityBitmap copy error");
532 if (PthreadMutexUnlock(&g_capabilityLock) != 0) {
533 DFINDER_LOGE(TAG, "failed to unlock");
534 }
535 return NSTACKX_EFAILED;
536 }
537 }
538
539 g_localDevice.deviceInfo.capabilityBitmapNum = capabilityBitmapNum;
540 if (PthreadMutexUnlock(&g_capabilityLock) != 0) {
541 DFINDER_LOGE(TAG, "failed to unlock");
542 return NSTACKX_EFAILED;
543 }
544 return NSTACKX_EOK;
545 }
546
SetLocalDeviceServiceData(const char * serviceData)547 int32_t SetLocalDeviceServiceData(const char *serviceData)
548 {
549 if (PthreadMutexLock(&g_serviceDataLock) != 0) {
550 DFINDER_LOGE(TAG, "failed to lock");
551 return NSTACKX_EFAILED;
552 }
553 if (strcpy_s(g_localDevice.deviceInfo.serviceData, NSTACKX_MAX_SERVICE_DATA_LEN, serviceData) != EOK) {
554 DFINDER_LOGE(TAG, "serviceData copy error");
555 if (PthreadMutexUnlock(&g_serviceDataLock) != 0) {
556 DFINDER_LOGE(TAG, "failed to unlock");
557 }
558 return NSTACKX_EFAILED;
559 }
560 if (PthreadMutexUnlock(&g_serviceDataLock) != 0) {
561 DFINDER_LOGE(TAG, "failed to unlock");
562 return NSTACKX_EFAILED;
563 }
564 return NSTACKX_EOK;
565 }
566
SetLocalDeviceBusinessType(uint8_t businessType)567 void SetLocalDeviceBusinessType(uint8_t businessType)
568 {
569 g_localDevice.deviceInfo.businessType = businessType;
570 }
571
GetLocalDeviceBusinessType(void)572 uint8_t GetLocalDeviceBusinessType(void)
573 {
574 return g_localDevice.deviceInfo.businessType;
575 }
576
SetLocalDeviceBusinessData(const char * data,bool unicast)577 int SetLocalDeviceBusinessData(const char *data, bool unicast)
578 {
579 if (PthreadMutexLock(&g_businessDataLock) != 0) {
580 DFINDER_LOGE(TAG, "failed to lock");
581 return NSTACKX_EFAILED;
582 }
583 int ret = EOK;
584 if (unicast) {
585 ret = strcpy_s(g_localDevice.deviceInfo.businessData.businessDataUnicast,
586 NSTACKX_MAX_BUSINESS_DATA_LEN, data);
587 } else {
588 ret = strcpy_s(g_localDevice.deviceInfo.businessData.businessDataBroadcast,
589 NSTACKX_MAX_BUSINESS_DATA_LEN, data);
590 }
591
592 if (ret != EOK) {
593 DFINDER_LOGE(TAG, "businessData copy error, unicast: %d", unicast);
594 if (PthreadMutexUnlock(&g_businessDataLock) != 0) {
595 DFINDER_LOGE(TAG, "failed to unlock");
596 }
597 return NSTACKX_EFAILED;
598 }
599
600 if (PthreadMutexUnlock(&g_businessDataLock) != 0) {
601 DFINDER_LOGE(TAG, "failed to unlock");
602 return NSTACKX_EFAILED;
603 }
604
605 return NSTACKX_EOK;
606 }
607
LocalizeNotificationMsg(const char * msg)608 int32_t LocalizeNotificationMsg(const char *msg)
609 {
610 if (strcpy_s(g_localDevice.deviceInfo.notification, NSTACKX_MAX_NOTIFICATION_DATA_LEN, msg) != EOK) {
611 DFINDER_LOGE(TAG, "copy notification msg to local dev failed");
612 return NSTACKX_EFAILED;
613 }
614 return NSTACKX_EOK;
615 }
616
GetLocalDeviceMode(void)617 uint8_t GetLocalDeviceMode(void)
618 {
619 return g_localDevice.deviceInfo.mode;
620 }
621
SetLocalDeviceMode(uint8_t mode)622 void SetLocalDeviceMode(uint8_t mode)
623 {
624 g_localDevice.deviceInfo.mode = mode;
625 }
626
627 #ifndef DFINDER_USE_MINI_NSTACKX
SetLocalDeviceExtendServiceData(const char * extendServiceData)628 int32_t SetLocalDeviceExtendServiceData(const char *extendServiceData)
629 {
630 if (PthreadMutexLock(&g_extendServiceDataLock) != 0) {
631 DFINDER_LOGE(TAG, "failed to lock");
632 return NSTACKX_EFAILED;
633 }
634 if (strcpy_s(g_localDevice.deviceInfo.extendServiceData, NSTACKX_MAX_EXTEND_SERVICE_DATA_LEN,
635 extendServiceData) != EOK) {
636 DFINDER_LOGE(TAG, "extendServiceData copy error");
637 if (PthreadMutexUnlock(&g_extendServiceDataLock) != 0) {
638 DFINDER_LOGE(TAG, "failed to unlock");
639 }
640 return NSTACKX_EFAILED;
641 }
642 if (PthreadMutexUnlock(&g_extendServiceDataLock) != 0) {
643 DFINDER_LOGE(TAG, "failed to unlock");
644 return NSTACKX_EFAILED;
645 }
646 return NSTACKX_EOK;
647 }
648
649 #ifndef _WIN32
DetectLocalIface(void * arg)650 void DetectLocalIface(void *arg)
651 {
652 struct ifconf ifc;
653 struct ifreq req[INTERFACE_MAX];
654 int fd = GetInterfaceList(&ifc, req, sizeof(req));
655 if (fd < 0) {
656 DFINDER_LOGE(TAG, "get iface list failed");
657 return;
658 }
659
660 int interfaceNum = ifc.ifc_len / (int)sizeof(struct ifreq);
661 for (int i = 0; i < interfaceNum && i < INTERFACE_MAX; i++) {
662 /* get IP of this interface */
663 int state = GetInterfaceIP(fd, &req[i]);
664 if (state == NSTACKX_EFAILED) {
665 (void)close(fd);
666 return;
667 } else if (state == NSTACKX_EINVAL) {
668 continue;
669 }
670
671 uint8_t ifaceType = GetIfaceType(req[i].ifr_name);
672 if (ifaceType > IFACE_TYPE_WLAN) {
673 DFINDER_LOGI(TAG, "skip iface %s", req[i].ifr_name);
674 continue;
675 }
676
677 struct in_addr *ip = &((struct sockaddr_in *)&req[i].ifr_addr)->sin_addr;
678 if (req[i].ifr_addr.sa_family != AF_INET || ip->s_addr == 0) {
679 DFINDER_LOGD(TAG, "iface %s is not ipv4 or ip is any", req[i].ifr_name);
680 continue;
681 }
682
683 DFINDER_LOGI(TAG, "try to add new iface %s", req[i].ifr_name);
684 (void)AddLocalIface(req[i].ifr_name, ip);
685 }
686 (void)close(fd);
687
688 (void)arg;
689 }
690 #endif /* _WIN32 */
691
692 #endif /* END OF DFINDER_USE_MINI_NSTACKX */
693
GetBroadcastIp(const struct LocalIface * iface,char * ipStr,size_t ipStrLen)694 int GetBroadcastIp(const struct LocalIface *iface, char *ipStr, size_t ipStrLen)
695 {
696 #ifdef _WIN32
697 return GetIfBroadcastAddr(&iface->ip, ipStr, ipStrLen);
698 #else
699 return GetIfBroadcastIp(iface->ifname, ipStr, ipStrLen);
700 #endif
701 }
702
GetLocalDeviceId(void)703 const char *GetLocalDeviceId(void)
704 {
705 return g_localDevice.deviceInfo.deviceId;
706 }
707
GetLocalDeviceInfo(void)708 DeviceInfo *GetLocalDeviceInfo(void)
709 {
710 return &g_localDevice.deviceInfo;
711 }
712
GetLocalDeviceNetworkName(void)713 const char *GetLocalDeviceNetworkName(void)
714 {
715 return g_localDevice.deviceInfo.networkName;
716 }
717
GetLocalIfaceIp(const struct LocalIface * iface)718 const struct in_addr *GetLocalIfaceIp(const struct LocalIface *iface)
719 {
720 return &iface->ip;
721 }
722
GetLocalIfaceIpStr(const struct LocalIface * iface)723 const char *GetLocalIfaceIpStr(const struct LocalIface *iface)
724 {
725 return iface->ipStr;
726 }
727
GetLocalIfaceName(const struct LocalIface * iface)728 const char *GetLocalIfaceName(const struct LocalIface *iface)
729 {
730 return iface->ifname;
731 }
732
LocalIfaceGetCoapCtx(const char * ifname)733 CoapCtxType *LocalIfaceGetCoapCtx(const char *ifname)
734 {
735 int i;
736 for (i = 0; i < IFACE_TYPE_MAX; i++) {
737 List *pos = NULL;
738 LIST_FOR_EACH(pos, &g_localDevice.readyList[i]) {
739 struct LocalIface *iface = (struct LocalIface *)pos;
740 if (strcmp(iface->ifname, ifname) != 0) {
741 continue;
742 }
743
744 return iface->ctx;
745 }
746 }
747
748 return NULL;
749 }
750
751 #ifdef _WIN32
GetLocalIfaceByLocalIp(const struct in_addr * ip)752 static struct LocalIface *GetLocalIfaceByLocalIp(const struct in_addr *ip)
753 {
754 int i;
755 for (i = 0; i < IFACE_TYPE_MAX; i++) {
756 List *pos = NULL;
757 LIST_FOR_EACH(pos, &g_localDevice.readyList[i]) {
758 struct LocalIface *iface = (struct LocalIface *)pos;
759 if (iface->ip.s_addr != ip->s_addr) {
760 continue;
761 }
762
763 return iface;
764 }
765 }
766
767 return NULL;
768 }
769 #endif
770
771 #ifndef DFINDER_USE_MINI_NSTACKX
IfaceTypeIsMatch(uint8_t ifaceType,uint8_t serverType)772 static inline bool IfaceTypeIsMatch(uint8_t ifaceType, uint8_t serverType)
773 {
774 return serverType == INVALID_TYPE ||
775 (serverType == SERVER_TYPE_WLANORETH && (ifaceType == IFACE_TYPE_ETH || ifaceType == IFACE_TYPE_WLAN)) ||
776 (serverType == SERVER_TYPE_P2P && ifaceType == IFACE_TYPE_P2P) ||
777 (serverType == SERVER_TYPE_USB && ifaceType == IFACE_TYPE_USB);
778 }
779
LocalIfaceGetCoapCtxByRemoteIp(const struct in_addr * remoteIp,uint8_t serverType)780 CoapCtxType *LocalIfaceGetCoapCtxByRemoteIp(const struct in_addr *remoteIp, uint8_t serverType)
781 {
782 struct LocalIface *iface = NULL;
783 struct sockaddr_in addr;
784 addr.sin_addr.s_addr = remoteIp->s_addr;
785 #ifdef _WIN32
786 InterfaceInfo localDev;
787 (void)memset_s(&localDev, sizeof(InterfaceInfo), 0, sizeof(InterfaceInfo));
788 if (GetTargetAdapter(&addr, &localDev) != NSTACKX_EOK) {
789 DFINDER_LOGE(TAG, "get target adapter failed");
790 return NULL;
791 }
792 struct in_addr localIp = { .s_addr = localDev.ipAddr };
793 iface = GetLocalIfaceByLocalIp(&localIp);
794 #else
795 struct ifreq req;
796 (void)memset_s(&req, sizeof(struct ifreq), 0, sizeof(struct ifreq));
797 if (GetTargetInterface(&addr, &req) != NSTACKX_EOK) {
798 DFINDER_LOGE(TAG, "get target interface failed");
799 return NULL;
800 }
801
802 uint8_t ifaceType = GetIfaceType(req.ifr_ifrn.ifrn_name);
803 DFINDER_LOGD(TAG, "ifaceType: %hhu", ifaceType);
804 iface = GetLocalIface(&g_localDevice.readyList[ifaceType], req.ifr_ifrn.ifrn_name, NULL);
805 #endif
806 if (iface == NULL) {
807 DFINDER_LOGE(TAG, "can not find iface");
808 return NULL;
809 }
810
811 if (!IfaceTypeIsMatch(iface->type, serverType)) {
812 DFINDER_LOGE(TAG, "type not match, iface type: %hhu, server type: %hhu", iface->type, serverType);
813 return NULL;
814 }
815
816 return iface->ctx;
817 }
818 #endif
819
820 #ifdef NSTACKX_DFINDER_HIDUMP
LocalIfaceDump(char * buf,size_t size)821 int LocalIfaceDump(char *buf, size_t size)
822 {
823 List *pos = NULL;
824 struct LocalIface *iface = NULL;
825 int ret;
826 size_t index = 0;
827 int i;
828 for (i = 0; i < IFACE_TYPE_MAX; i++) {
829 LIST_FOR_EACH(pos, &g_localDevice.readyList[i]) {
830 iface = (struct LocalIface *)pos;
831 ret = DFinderDumpIface(buf + index, size - index, iface->ifname, &iface->ip, iface->state);
832 if (ret < 0 || (uint32_t)ret > size - index) {
833 return NSTACKX_EFAILED;
834 }
835
836 index += (uint32_t)ret;
837 }
838 }
839
840 LIST_FOR_EACH(pos, &g_localDevice.creatingList) {
841 iface = (struct LocalIface *)pos;
842 ret = DFinderDumpIface(buf + index, size - index, iface->ifname, &iface->ip, iface->state);
843 if (ret < 0 || (uint32_t)ret > size - index) {
844 return NSTACKX_EFAILED;
845 }
846
847 index += (uint32_t)ret;
848 }
849
850 LIST_FOR_EACH(pos, &g_localDevice.destroyList) {
851 iface = (struct LocalIface *)pos;
852 ret = DFinderDumpIface(buf + index, size - index, iface->ifname, &iface->ip, iface->state);
853 if (ret < 0 || (uint32_t)ret > size - index) {
854 return NSTACKX_EFAILED;
855 }
856
857 index += (uint32_t)ret;
858 }
859
860 return index;
861 }
862 #endif
863