Files
communication_t2stack/nstackx_ctrl/core/nstackx_common.c
T
yexiaokang fb185021ee fix task->handle use-after-free
Signed-off-by: yexiaokang <yexiaokang3@huawei.com>
2026-01-19 19:56:53 +08:00

2438 lines
78 KiB
C

/*
* Copyright (C) 2021-2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "nstackx_common.h"
#include <securec.h>
#ifndef _WIN32
#include <pthread.h>
#include <semaphore.h>
#include <stdatomic.h>
#include <unistd.h>
#endif
#include "cJSON.h"
#ifndef DFINDER_USE_MINI_NSTACKX
#include <coap3/coap.h>
#endif
#include "coap_app.h"
#include "coap_discover.h"
#include "nstackx.h"
#include "nstackx_device.h"
#include "nstackx_epoll.h"
#include "nstackx_error.h"
#include "nstackx_event.h"
#include "nstackx_dfinder_log.h"
#include "nstackx_smartgenius.h"
#include "nstackx_timer.h"
#include "nstackx_util.h"
#include "nstackx_inet.h"
#include "json_payload.h"
#include "nstackx_statistics.h"
#include "nstackx_dfinder_hidump.h"
#include "nstackx_dfinder_hievent.h"
#include "nstackx_device_local.h"
#include "nstackx_device_remote.h"
#ifdef DFINDER_USE_MINI_NSTACKX
#include "cmsis_os2.h"
#include "ohos_init.h"
#define DFINDER_THREAD_STACK_SIZE (1024 * 32)
#endif
#define MAX_COAP_SERVICE_DATA_CNT 3
#define SINGLE_NIC_CNT 1
#define TAG "nStackXDFinder"
#define DFINDER_THREAD_NAME TAG
#define DFINDER_POST_EVENT_MAX_BLOCK_SECONDS 3
#define NSEC_TICKS_PER_SEC (1000000000)
enum {
NSTACKX_INIT_STATE_START = 0,
NSTACKX_INIT_STATE_ONGOING,
NSTACKX_INIT_STATE_DONE,
};
#ifdef DFINDER_USE_MINI_NSTACKX
static osThreadId_t g_threadId;
#else
static pthread_t g_tid;
#endif
static EpollDesc g_epollfd = INVALID_EPOLL_DESC;
static List g_eventNodeChain = {&(g_eventNodeChain), &(g_eventNodeChain)};
static uint8_t g_validTidFlag = NSTACKX_FALSE;
static uint8_t g_terminateFlag = NSTACKX_FALSE;
static pthread_mutex_t g_threadInitLock = PTHREAD_MUTEX_INITIALIZER;
static NSTACKX_Parameter g_parameter;
static atomic_uint_fast8_t g_nstackInitState = NSTACKX_INIT_STATE_START;
static atomic_uint_fast8_t g_nstackThreadInitState = NSTACKX_INIT_STATE_START;
static bool g_isNotifyPerDevice;
#define EVENT_COUNT_RATE_INTERVAL 2000 /* 2 SECONDS */
#define MAX_EVENT_PROCESS_NUM_PER_INTERVAL 700
#define MAX_CONTINUOUS_BUSY_INTERVAL_NUM 20
typedef struct {
uint32_t epollWaitTimeoutCount;
uint32_t epollWaitEventCount;
struct timespec measureBefore;
} EventProcessRatePara;
static EventProcessRatePara g_processRatePara;
static uint32_t g_continuousBusyIntervals;
static int32_t CheckDiscoverySettings(const NSTACKX_DiscoverySettings *discoverySettings);
static int32_t RegisterDeviceWithType(const NSTACKX_LocalDeviceInfoV2 *localDeviceInfo, int registerType);
bool GetIsNotifyPerDevice(void)
{
return g_isNotifyPerDevice;
}
#ifdef DFINDER_SUPPORT_COVERITY_TAINTED_SET
void Coverity_Tainted_Set(void *buf)
{
(void)buf;
}
#endif
List *GetEventNodeChain(void)
{
return &g_eventNodeChain;
}
EpollDesc GetEpollFD(void)
{
return g_epollfd;
}
void NotifyDFinderMsgRecver(DFinderMsgType msgType)
{
if (g_parameter.onDFinderMsgReceived != NULL) {
g_parameter.onDFinderMsgReceived(msgType);
}
}
int32_t ShouldAutoReplyUnicast(uint8_t businessType)
{
switch (businessType) {
case NSTACKX_BUSINESS_TYPE_SOFTBUS:
case NSTACKX_BUSINESS_TYPE_AUTONET:
case NSTACKX_BUSINESS_TYPE_STRATEGY:
return NSTACKX_FALSE;
case NSTACKX_BUSINESS_TYPE_NULL:
case NSTACKX_BUSINESS_TYPE_HICOM:
case NSTACKX_BUSINESS_TYPE_NEARBY:
default:
return NSTACKX_TRUE;
}
}
uint32_t GetDefaultDiscoverInterval(uint32_t discoverCount)
{
if (discoverCount < COAP_FIRST_DISCOVER_COUNT_RANGE) {
return COAP_FIRST_DISCOVER_INTERVAL;
} else if (discoverCount < COAP_SECOND_DISCOVER_COUNT_RANGE) {
return COAP_SECOND_DISCOVER_INTERVAL;
} else {
return COAP_LAST_DISCOVER_INTERVAL;
}
}
int32_t GetServiceDiscoverInfo(const uint8_t *buf, size_t size, struct DeviceInfo *deviceInfo, char **remoteUrlPtr)
{
uint8_t *newBuf = NULL;
if (size <= 0) {
DFINDER_LOGE(TAG, "buf size <= 0");
return NSTACKX_EFAILED;
}
if (buf[size - 1] != '\0') {
newBuf = (uint8_t *)calloc(size + 1, 1U);
if (newBuf == NULL) {
DFINDER_LOGE(TAG, "data is not end with 0 and new buf calloc error");
return NSTACKX_ENOMEM;
}
if (memcpy_s(newBuf, size + 1, buf, size) != EOK) {
DFINDER_LOGE(TAG, "data is not end with 0 and memcpy data error");
goto L_COAP_ERR;
}
DFINDER_LOGI(TAG, "data is not end with 0");
buf = newBuf;
}
if (ParseServiceDiscover(buf, deviceInfo, remoteUrlPtr) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "parse service discover error");
goto L_COAP_ERR;
}
if (newBuf != NULL) {
free(newBuf);
}
return NSTACKX_EOK;
L_COAP_ERR:
if (newBuf != NULL) {
free(newBuf);
}
return NSTACKX_EFAILED;
}
int32_t GetServiceNotificationInfo(const uint8_t *buf, size_t size, NSTACKX_NotificationConfig *notification)
{
uint8_t *newBuf = NULL;
if (buf[size - 1] != '\0') {
newBuf = (uint8_t *)calloc(size + 1, 1U);
if (newBuf == NULL) {
DFINDER_LOGE(TAG, "data is not end with 0 and new buf calloc error");
return NSTACKX_ENOMEM;
}
if (memcpy_s(newBuf, size + 1, buf, size) != EOK) {
DFINDER_LOGE(TAG, "data is not end with 0 and memcpy data error");
goto L_COAP_ERR;
}
DFINDER_LOGI(TAG, "data is not end with 0");
buf = newBuf;
}
if (ParseServiceNotification(buf, notification) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "parse service notification error");
goto L_COAP_ERR;
}
if (newBuf != NULL) {
free(newBuf);
}
return NSTACKX_EOK;
L_COAP_ERR:
if (newBuf != NULL) {
free(newBuf);
}
return NSTACKX_EFAILED;
}
static void ResetMainEpollTaskCount(uint8_t isBusy)
{
EpollTask *task = GetEpollTask(&g_eventNodeChain, g_epollfd);
if (task == NULL) {
return;
}
if (isBusy) {
DFINDER_LOGI(TAG, "in this busy interval: main epoll task count %llu", task->count);
}
task->count = 0;
}
static uint8_t IsBusyInterval(uint32_t eventCount, uint32_t timeMs)
{
uint8_t retFlag = NSTACKX_TRUE;
if ((uint64_t)eventCount * EVENT_COUNT_RATE_INTERVAL <
MAX_EVENT_PROCESS_NUM_PER_INTERVAL * (uint64_t)timeMs) {
retFlag = NSTACKX_FALSE;
}
ResetMainEpollTaskCount(retFlag);
ResetCoapSocketTaskCount(retFlag);
ResetCoapDiscoverTaskCount(retFlag);
ResetDeviceTaskCount(retFlag);
#ifndef DFINDER_USE_MINI_NSTACKX
ResetSmartGeniusTaskCount(retFlag);
#endif /* END OF DFINDER_USE_MINI_NSTACKX */
return retFlag;
}
static void CalculateEventProcessRate(void)
{
struct timespec now;
ClockGetTime(CLOCK_MONOTONIC, &now);
uint32_t measureElapse = GetTimeDiffMs(&now, &g_processRatePara.measureBefore);
if (measureElapse <= EVENT_COUNT_RATE_INTERVAL) {
return;
}
uint32_t totalCount = g_processRatePara.epollWaitEventCount + g_processRatePara.epollWaitTimeoutCount;
if (!IsBusyInterval(totalCount, measureElapse)) {
g_continuousBusyIntervals = 0;
} else {
DFINDER_LOGI(TAG, "main loop seems to be busy in the past interval. Timeout count %u, event count %u",
g_processRatePara.epollWaitTimeoutCount, g_processRatePara.epollWaitEventCount);
g_continuousBusyIntervals++;
if (g_continuousBusyIntervals >= MAX_CONTINUOUS_BUSY_INTERVAL_NUM) {
DFINDER_LOGE(TAG, "main loop seems to be busy in the past %u intervals. notify user to restart",
g_continuousBusyIntervals);
NotifyDFinderMsgRecver(DFINDER_ON_TOO_BUSY);
g_continuousBusyIntervals = 0;
}
}
g_processRatePara.epollWaitTimeoutCount = 0;
g_processRatePara.epollWaitEventCount = 0;
ClockGetTime(CLOCK_MONOTONIC, &g_processRatePara.measureBefore);
}
static void *NstackMainLoop(void *arg)
{
int32_t ret;
(void)arg;
(void)memset_s(&g_processRatePara, sizeof(g_processRatePara), 0, sizeof(g_processRatePara));
g_continuousBusyIntervals = 0;
ClockGetTime(CLOCK_MONOTONIC, &g_processRatePara.measureBefore);
#ifndef DFINDER_USE_MINI_NSTACKX
SetThreadName(DFINDER_THREAD_NAME);
#endif
while (g_terminateFlag == NSTACKX_FALSE) {
#ifndef DFINDER_USE_MINI_NSTACKX
uint32_t timeout = RegisterCoAPEpollTask(g_epollfd);
ret = EpollLoop(g_epollfd, timeout);
#else
ret = EpollLoop(g_epollfd, -1);
#endif /* END OF DFINDER_USE_MINI_NSTACKX */
if (ret == NSTACKX_EFAILED) {
IncStatistics(STATS_EPOLL_ERROR);
DFINDER_LOGE(TAG, "epoll loop failed");
#ifndef DFINDER_USE_MINI_NSTACKX
DeRegisterCoAPEpollTask();
#endif /* END OF DFINDER_USE_MINI_NSTACKX */
break;
} else if (ret == NSTACKX_ETIMEOUT) {
g_processRatePara.epollWaitTimeoutCount++;
} else if (ret > 0) {
g_processRatePara.epollWaitEventCount++;
} else {
/* do nothing */
}
CalculateEventProcessRate();
#ifndef DFINDER_USE_MINI_NSTACKX
DeRegisterCoAPEpollTask();
#endif /* END OF DFINDER_USE_MINI_NSTACKX */
}
return NULL;
}
EpollDesc GetMainLoopEpollFd(void)
{
return g_epollfd;
}
List *GetMainLoopEvendChain(void)
{
return &g_eventNodeChain;
}
static int32_t InternalInit(EpollDesc epollfd, uint32_t maxDeviceNum)
{
int32_t ret = EventModuleInit(&g_eventNodeChain, g_epollfd);
if (ret != NSTACKX_EOK) {
return ret;
}
ret = DeviceModuleInit(epollfd, maxDeviceNum);
if (ret != NSTACKX_EOK) {
return ret;
}
#ifdef _WIN32
ret = CoapThreadInit();
if (ret != NSTACKX_EOK) {
return ret;
}
#endif
ret = CoapDiscoverInit(epollfd);
if (ret != NSTACKX_EOK) {
return ret;
}
#ifndef DFINDER_USE_MINI_NSTACKX
ret = SmartGeniusInit(epollfd);
#endif /* END OF DFINDER_USE_MINI_NSTACKX */
return ret;
}
#ifdef DFINDER_USE_MINI_NSTACKX
static void ReportMainLoopStopInner(void *argument)
{
(void)argument;
DFINDER_LOGI(TAG, "receive message to stop main loop");
}
static void ReportMainLoopStop(void)
{
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_Ctrl is not initiated yet");
return;
}
if (PostEvent(&g_eventNodeChain, g_epollfd, ReportMainLoopStopInner, NULL) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "Failed to report mainloop stop!");
}
}
#endif
int32_t NSTACKX_ThreadInit(void)
{
if (g_nstackInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "nstack is not initiated foundation yet");
return NSTACKX_EFAILED;
}
if (PthreadMutexLock(&g_threadInitLock) != 0) {
DFINDER_LOGE(TAG, "Failed to lock");
return NSTACKX_EFAILED;
}
DFINDER_LOGI(TAG, "nstack begin init thread");
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_START) {
(void)PthreadMutexUnlock(&g_threadInitLock);
DFINDER_LOGI(TAG, "nstack init thread done");
return NSTACKX_EOK;
}
g_nstackThreadInitState = NSTACKX_INIT_STATE_ONGOING;
g_terminateFlag = NSTACKX_FALSE;
g_validTidFlag = NSTACKX_FALSE;
#ifndef DFINDER_USE_MINI_NSTACKX
int32_t ret = PthreadCreate(&g_tid, NULL, NstackMainLoop, NULL);
if (ret != 0) {
DFINDER_LOGE(TAG, "thread create failed");
g_terminateFlag = NSTACKX_TRUE;
(void)PthreadMutexUnlock(&g_threadInitLock);
return ret;
}
#else
osThreadAttr_t attr = {0};
attr.name = DFINDER_THREAD_NAME;
attr.stack_size = DFINDER_THREAD_STACK_SIZE;
// osPriorityNormal equals 24
attr.priority = osPriorityNormal;
g_threadId = osThreadNew((osThreadFunc_t)NstackMainLoop, NULL, &attr);
if (g_threadId == NULL) {
DFINDER_LOGE(TAG, "thread create failed with attribute settings");
g_terminateFlag = NSTACKX_TRUE;
(void)PthreadMutexUnlock(&g_threadInitLock);
return NSTACKX_EFAILED;
}
#endif
g_validTidFlag = NSTACKX_TRUE;
g_nstackThreadInitState = NSTACKX_INIT_STATE_DONE;
(void)PthreadMutexUnlock(&g_threadInitLock);
DFINDER_LOGI(TAG, "nstack init thread success");
return NSTACKX_EOK;
}
void NSTACKX_ThreadDeinit(void)
{
if (g_nstackThreadInitState == NSTACKX_INIT_STATE_START) {
return;
}
DFINDER_LOGI(TAG, "nstack begin deinit thread");
if (PthreadMutexLock(&g_threadInitLock) != 0) {
DFINDER_LOGE(TAG, "Failed to lock");
return;
}
if (g_validTidFlag) {
g_terminateFlag = NSTACKX_TRUE;
#ifndef DFINDER_USE_MINI_NSTACKX
PthreadJoin(g_tid, NULL);
#else
ReportMainLoopStop();
if (osThreadTerminate(g_threadId) != osOK) {
DFINDER_LOGE(TAG, "os thread terminate failed");
}
#endif
g_validTidFlag = NSTACKX_FALSE;
}
g_nstackThreadInitState = NSTACKX_INIT_STATE_START;
(void)PthreadMutexUnlock(&g_threadInitLock);
DFINDER_LOGI(TAG, "nstack deinit thread success");
}
#if !defined(DFINDER_USE_MINI_NSTACKX) && !defined(DFINDER_ENABLE_COAP_LOG)
static void CoapLogHandler(coap_log_t level, const char *message)
{
(void)level;
(void)message;
}
#endif
static void InitLogLevel(void)
{
// default log
SetLogLevel(NSTACKX_LOG_LEVEL_DEBUG);
// user defined log
#ifdef ENABLE_USER_LOG
SetDFinderLogLevel(DFINDER_LOG_LEVEL_DEBUG);
#endif
#ifndef DFINDER_USE_MINI_NSTACKX
// opensource libcoap log
#ifdef DFINDER_ENABLE_COAP_LOG
coap_set_log_level(COAP_LOG_DEBUG);
#else
coap_set_log_handler(CoapLogHandler);
#endif
#endif
}
static int32_t NstackxInitEx(const NSTACKX_Parameter *parameter, bool isNotifyPerDevice)
{
Coverity_Tainted_Set((void *)parameter);
int32_t ret;
if (g_nstackInitState != NSTACKX_INIT_STATE_START) {
return NSTACKX_EOK;
}
g_nstackInitState = NSTACKX_INIT_STATE_ONGOING;
cJSON_InitHooks(NULL);
InitLogLevel();
#ifdef NSTACKX_WITH_LITEOS
EpollEventPtrInit(); /* init g_epollEventPtrMutex g_epollEventPtrArray */
#endif
g_epollfd = CreateEpollDesc();
if (!IsEpollDescValid(g_epollfd)) {
DFINDER_LOGE(TAG, "epoll creat fail! errno: %d", errno);
g_nstackInitState = NSTACKX_INIT_STATE_START;
return NSTACKX_EFAILED;
}
DFINDER_LOGD(TAG, "nstack ctrl creat epollfd %d", REPRESENT_EPOLL_DESC(g_epollfd));
#ifdef DFINDER_SAVE_DEVICE_LIST
ret = InternalInit(g_epollfd, parameter != NULL ? parameter->maxDeviceNum : NSTACKX_DEFAULT_DEVICE_NUM);
#else
ret = InternalInit(g_epollfd, parameter != NULL ? parameter->maxDeviceNum : NSTACKX_MAX_DEVICE_NUM);
#endif
if (ret != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "internal init failed, ret=%d", ret);
goto L_ERR_INIT;
}
(void)memset_s(&g_parameter, sizeof(g_parameter), 0, sizeof(g_parameter));
if (parameter != NULL) {
(void)memcpy_s(&g_parameter, sizeof(g_parameter), parameter, sizeof(NSTACKX_Parameter));
}
#ifndef DFINDER_USE_MINI_NSTACKX
CoapInitSubscribeModuleInner(); /* initialize subscribe module number */
#endif /* END OF DFINDER_USE_MINI_NSTACKX */
g_isNotifyPerDevice = isNotifyPerDevice;
g_nstackInitState = NSTACKX_INIT_STATE_DONE;
DFINDER_LOGI(TAG, "DFinder init successfully");
return NSTACKX_EOK;
L_ERR_INIT:
NSTACKX_Deinit();
return ret;
}
int32_t NSTACKX_Init(const NSTACKX_Parameter *parameter)
{
return NstackxInitEx(parameter, false);
}
int32_t NSTACKX_InitV2(const NSTACKX_Parameter *parameter, bool isNotifyPerDevice)
{
return NstackxInitEx(parameter, isNotifyPerDevice);
}
void NSTACKX_Deinit(void)
{
if (g_nstackInitState == NSTACKX_INIT_STATE_START) {
return;
}
NSTACKX_ThreadDeinit();
#ifndef DFINDER_USE_MINI_NSTACKX
SmartGeniusClean();
#endif /* END OF DFINDER_USE_MINI_NSTACKX */
CoapDiscoverDeinit();
#ifdef _WIN32
CoapThreadDestroy();
#endif
DeviceModuleClean();
EventNodeChainClean(&g_eventNodeChain);
if (IsEpollDescValid(g_epollfd)) {
CloseEpollDesc(g_epollfd);
g_epollfd = INVALID_EPOLL_DESC;
}
ResetStatistics();
ResetEventFunc();
ResetSequenceNumber();
g_nstackInitState = NSTACKX_INIT_STATE_START;
DFINDER_LOGI(TAG, "deinit successfully");
}
static void DeviceDiscoverInner(void *argument)
{
if (!IsCoapContextReady()) {
DFINDER_LOGE(TAG, "no iface is ready, notify user with empty list");
NotifyDeviceFound(NULL, 0);
return;
}
(void)argument;
SetCoapDiscoverType(COAP_BROADCAST_TYPE_DEFAULT);
SetLocalDeviceBusinessType(NSTACKX_BUSINESS_TYPE_NULL);
CoapServiceDiscoverInner(INNER_DISCOVERY);
}
static void DeviceDiscoverInnerAn(void *argument)
{
(void)argument;
SetCoapDiscoverType(COAP_BROADCAST_TYPE_DEFAULT);
SetLocalDeviceBusinessType(NSTACKX_BUSINESS_TYPE_NULL);
CoapServiceDiscoverInnerAn(INNER_DISCOVERY);
}
static void DeviceDiscoverInnerConfigurable(void *argument)
{
NSTACKX_DiscoverySettings *discoverySettings = argument;
int32_t configResult = ConfigureDiscoverySettings(discoverySettings);
free(discoverySettings->businessData);
free(discoverySettings);
if (configResult != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "config discovery settings failed");
return;
}
CoapServiceDiscoverInnerConfigurable(INNER_DISCOVERY);
}
static void DiscConfig(void *argument)
{
DFinderDiscConfig *discConfig = argument;
uint8_t businessTypeLocal = GetLocalDeviceBusinessType();
if (discConfig->businessType != businessTypeLocal) {
DFINDER_LOGE(TAG, "business type is different, config: %hhu, local: %hhu",
discConfig->businessType, businessTypeLocal);
free(discConfig->businessData);
free(discConfig->bcastInterval);
free(discConfig);
return;
}
int32_t configResult = DiscConfigInner(discConfig);
free(discConfig->businessData);
free(discConfig->bcastInterval);
free(discConfig);
if (configResult != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "config for discover failed");
return;
}
CoapServiceDiscoverInnerConfigurable(INNER_DISCOVERY);
}
static void DeviceDiscoverStopInner(void *argument)
{
(void)argument;
CoapServiceDiscoverStopInner();
NotifyStatisticsEvent();
}
int32_t NSTACKX_StartDeviceFind(void)
{
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_Ctrl is not initiated yet");
return NSTACKX_EFAILED;
}
if (PostEvent(&g_eventNodeChain, g_epollfd, DeviceDiscoverInner, NULL) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "Failed to start device discover!");
return NSTACKX_EFAILED;
}
return NSTACKX_EOK;
}
int32_t NSTACKX_StartDeviceFindAn(uint8_t mode)
{
Coverity_Tainted_Set((void *)&mode);
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_Ctrl is not initiated yet");
return NSTACKX_EFAILED;
}
SetModeInfo(mode);
if (PostEvent(&g_eventNodeChain, g_epollfd, DeviceDiscoverInnerAn, NULL) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "Failed to start device discover!");
return NSTACKX_EFAILED;
}
return NSTACKX_EOK;
}
int32_t NSTACKX_StopDeviceFind(void)
{
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_Ctrl is not initiated yet");
return NSTACKX_EFAILED;
}
if (PostEvent(&g_eventNodeChain, g_epollfd, DeviceDiscoverStopInner, NULL) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "Failed to stop device discover!");
return NSTACKX_EFAILED;
}
return NSTACKX_EOK;
}
static int32_t CopyDiscoverySettings(NSTACKX_DiscoverySettings *dupDiscoverySettings,
const NSTACKX_DiscoverySettings *discoverySettings)
{
dupDiscoverySettings->businessType = discoverySettings->businessType;
dupDiscoverySettings->discoveryMode = discoverySettings->discoveryMode;
dupDiscoverySettings->length = discoverySettings->length;
if (discoverySettings->businessData != NULL) {
if (strncpy_s(dupDiscoverySettings->businessData, (dupDiscoverySettings->length + 1),
discoverySettings->businessData, discoverySettings->length) != EOK) {
DFINDER_LOGE(TAG, "businessData strncpy failed");
return NSTACKX_EINVAL;
}
}
dupDiscoverySettings->advertiseCount = discoverySettings->advertiseCount;
dupDiscoverySettings->advertiseDuration = discoverySettings->advertiseDuration;
return NSTACKX_EOK;
}
static int32_t CheckDiscoverySettings(const NSTACKX_DiscoverySettings *discoverySettings)
{
if (discoverySettings == NULL) {
DFINDER_LOGE(TAG, "Invalid discoverySettings info");
return NSTACKX_EINVAL;
}
if ((discoverySettings->businessData == NULL) && (discoverySettings->length != 0)) {
DFINDER_LOGE(TAG, "Invalid discoverySettings bData info");
return NSTACKX_EINVAL;
}
if (discoverySettings->length >= NSTACKX_MAX_BUSINESS_DATA_LEN) {
DFINDER_LOGE(TAG, "businessData length is too long");
return NSTACKX_EINVAL;
}
uint32_t advertiseCount = discoverySettings->advertiseCount;
uint32_t advertiseDuration = discoverySettings->advertiseDuration;
if ((advertiseCount == 0) && (advertiseDuration == 0)) {
return NSTACKX_EOK;
}
if ((advertiseCount < NSTACKX_MIN_ADVERTISE_COUNT) || (advertiseCount > NSTACKX_MAX_ADVERTISE_COUNT) ||
(advertiseDuration < NSTACKX_MIN_ADVERTISE_DURATION) || (advertiseDuration > NSTACKX_MAX_ADVERTISE_DURATION)) {
DFINDER_LOGE(TAG, "Invalid discoverySettings advertise info");
return NSTACKX_EINVAL;
}
return NSTACKX_EOK;
}
int32_t NSTACKX_StartDeviceDiscovery(const NSTACKX_DiscoverySettings *discoverySettings)
{
DFINDER_LOGI(TAG, "begin to NSTACKX_StartDeviceDiscovery!");
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_Ctrl is not initiated yet");
return NSTACKX_EFAILED;
}
if (CheckDiscoverySettings(discoverySettings) != NSTACKX_EOK) {
return NSTACKX_EINVAL;
}
NSTACKX_DiscoverySettings *dupDiscoverySettings = malloc(sizeof(NSTACKX_DiscoverySettings));
if (dupDiscoverySettings == NULL) {
DFINDER_LOGE(TAG, "malloc failed");
return NSTACKX_ENOMEM;
}
dupDiscoverySettings->businessData = (char *)calloc((discoverySettings->length + 1), sizeof(char));
if (dupDiscoverySettings->businessData == NULL) {
DFINDER_LOGE(TAG, "businessData calloc fail");
free(dupDiscoverySettings);
return NSTACKX_ENOMEM;
}
if (CopyDiscoverySettings(dupDiscoverySettings, discoverySettings) != NSTACKX_EOK) {
free(dupDiscoverySettings->businessData);
free(dupDiscoverySettings);
return NSTACKX_EINVAL;
}
if (PostEvent(&g_eventNodeChain, g_epollfd, DeviceDiscoverInnerConfigurable, dupDiscoverySettings) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "Failed to start device discover!");
free(dupDiscoverySettings->businessData);
free(dupDiscoverySettings);
return NSTACKX_EFAILED;
}
return NSTACKX_EOK;
}
static int32_t CopyDiscConfig(const DFinderDiscConfig *src, DFinderDiscConfig *dst)
{
dst->businessType = src->businessType;
dst->discoveryMode = src->discoveryMode;
dst->intervalArrLen = src->intervalArrLen;
for (size_t idx = 0; idx < dst->intervalArrLen; ++idx) {
(dst->bcastInterval)[idx] = (src->bcastInterval)[idx];
}
if (src->businessData != NULL) {
if (strncpy_s(dst->businessData, dst->businessDataLen, src->businessData, src->businessDataLen) != EOK) {
DFINDER_LOGE(TAG, "copy business data failed");
return NSTACKX_EFAILED;
}
}
return NSTACKX_EOK;
}
static int32_t CheckDiscInterval(uint32_t *intervalArr, uint32_t arrLen)
{
if (intervalArr == NULL || arrLen == 0) {
DFINDER_LOGE(TAG, "illegal param, arrlen: %ld", arrLen);
return NSTACKX_EINVAL;
}
// check interval values one by one
for (size_t i = 0; i < arrLen; ++i) {
if (intervalArr[i] < NSTACKX_MIN_ADVERTISE_INTERVAL || intervalArr[i] > NSTACKX_MAX_ADVERTISE_INTERVAL) {
DFINDER_LOGE(TAG, "invalid interval");
return NSTACKX_EINVAL;
}
}
return NSTACKX_EOK;
}
static int32_t CheckDiscConfig(const DFinderDiscConfig *discConfig)
{
if (discConfig == NULL) {
DFINDER_LOGE(TAG, "disc config passed in is null");
return NSTACKX_EINVAL;
}
// minus one for the first broadcast without interval
if (discConfig->bcastInterval == NULL || discConfig->intervalArrLen > (NSTACKX_MAX_ADVERTISE_COUNT - 1) ||
discConfig->intervalArrLen == 0) {
DFINDER_LOGE(TAG, "invalid broadcast interval params");
return NSTACKX_EINVAL;
}
if (CheckDiscInterval(discConfig->bcastInterval, discConfig->intervalArrLen) != NSTACKX_EOK) {
return NSTACKX_EINVAL;
}
if ((discConfig->businessData == NULL) && (discConfig->businessDataLen != 0)) {
DFINDER_LOGE(TAG, "invalid business data params");
return NSTACKX_EINVAL;
}
if (discConfig->businessDataLen >= NSTACKX_MAX_BUSINESS_DATA_LEN) {
DFINDER_LOGE(TAG, "business data is too long");
return NSTACKX_EINVAL;
}
return NSTACKX_EOK;
}
int32_t NSTACKX_StartDeviceDiscoveryWithConfig(const DFinderDiscConfig *discConfig)
{
DFINDER_LOGI(TAG, "dfinder start disc with config");
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "nstackx ctrl is not initialed yet");
return NSTACKX_EFAILED;
}
if (CheckDiscConfig(discConfig) != NSTACKX_EOK) {
return NSTACKX_EINVAL;
}
DFinderDiscConfig *dupDiscConfig = (DFinderDiscConfig *)malloc(sizeof(DFinderDiscConfig));
if (dupDiscConfig == NULL) {
DFINDER_LOGE(TAG, "malloc for duplicate disc config failed");
return NSTACKX_ENOMEM;
}
dupDiscConfig->bcastInterval = (uint32_t *)malloc(sizeof(uint32_t) * (discConfig->intervalArrLen));
if (dupDiscConfig->bcastInterval == NULL) {
DFINDER_LOGE(TAG, "malloc for duplicate broadcast interval failed");
free(dupDiscConfig);
return NSTACKX_ENOMEM;
}
dupDiscConfig->businessData = (char *)calloc((discConfig->businessDataLen + 1), sizeof(char));
if (dupDiscConfig->businessData == NULL) {
DFINDER_LOGE(TAG, "malloc for duplicate business data failed");
free(dupDiscConfig->bcastInterval);
free(dupDiscConfig);
return NSTACKX_ENOMEM;
}
// 1 to store the terminator
dupDiscConfig->businessDataLen = discConfig->businessDataLen + 1;
if (CopyDiscConfig(discConfig, dupDiscConfig) != NSTACKX_EOK) {
free(dupDiscConfig->businessData);
free(dupDiscConfig->bcastInterval);
free(dupDiscConfig);
return NSTACKX_EFAILED;
}
if (PostEvent(&g_eventNodeChain, g_epollfd, DiscConfig, dupDiscConfig) != NSTACKX_EOK) {
free(dupDiscConfig->businessData);
free(dupDiscConfig->bcastInterval);
free(dupDiscConfig);
return NSTACKX_EFAILED;
}
return NSTACKX_EOK;
}
#ifndef DFINDER_USE_MINI_NSTACKX
int32_t NSTACKX_SubscribeModule(void)
{
if (g_nstackInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_Ctrl is not initiated yet");
return NSTACKX_EFAILED;
}
CoapSubscribeModuleInner(INNER_DISCOVERY);
return NSTACKX_EOK;
}
int32_t NSTACKX_UnsubscribeModule(void)
{
if (g_nstackInitState != NSTACKX_INIT_STATE_DONE) {
return NSTACKX_EFAILED;
}
CoapUnsubscribeModuleInner(INNER_DISCOVERY);
return NSTACKX_EOK;
}
#endif /* END OF DFINDER_USE_MINI_NSTACKX */
static bool IsNetworkNameValid(const char *networkName, size_t len)
{
if (!StringHasEOF(networkName, len)) {
DFINDER_LOGE(TAG, "network name is not ended");
return NSTACKX_FALSE;
}
return NSTACKX_TRUE;
}
static bool IsIpAddressValid(const char *ipStr, size_t len)
{
if (!StringHasEOF(ipStr, len)) {
DFINDER_LOGE(TAG, "ip addr is not ended");
return NSTACKX_FALSE;
}
union InetAddr addr;
if (len != 0 && ipStr[0] != '\0' && InetGetAfType(ipStr, &addr) == AF_ERROR) {
DFINDER_LOGE(TAG, "invalid ip address");
return NSTACKX_FALSE;
}
return NSTACKX_TRUE;
}
static int32_t CheckInterfaceInfo(const NSTACKX_InterfaceInfo *ifaces, uint32_t count)
{
for (uint32_t i = 0; i < count; ++i) {
if (!IsNetworkNameValid(ifaces[i].networkName, sizeof(ifaces[i].networkName)) ||
!IsIpAddressValid(ifaces[i].networkIpAddr, sizeof(ifaces[i].networkIpAddr)) ||
!IsNetworkNameValid(ifaces[i].serviceData, sizeof(ifaces[i].serviceData))) {
DFINDER_LOGE(TAG, "invalid network name or ip address of No.%u local iface", i);
return NSTACKX_EINVAL;
}
}
return NSTACKX_EOK;
}
static int CheckLocalDeviceInfo(const NSTACKX_LocalDeviceInfo *localDeviceInfo)
{
if (g_nstackInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_Ctrl is not initiated yet");
return NSTACKX_EFAILED;
}
if (localDeviceInfo == NULL) {
DFINDER_LOGE(TAG, "Invalid local device info");
return NSTACKX_EINVAL;
}
if (!StringHasEOF(localDeviceInfo->deviceId, sizeof(localDeviceInfo->deviceId)) ||
!StringHasEOF(localDeviceInfo->name, sizeof(localDeviceInfo->name))) {
DFINDER_LOGE(TAG, "device id or device name is not ended");
return NSTACKX_EINVAL;
}
if (localDeviceInfo->ifNums > NSTACKX_MAX_LISTENED_NIF_NUM) {
DFINDER_LOGE(TAG, "invalid iface number %u", localDeviceInfo->ifNums);
return NSTACKX_EINVAL;
} else if (localDeviceInfo->ifNums == 0) {
if (!IsNetworkNameValid(localDeviceInfo->networkName, sizeof(localDeviceInfo->networkName)) ||
!IsIpAddressValid(localDeviceInfo->networkIpAddr, sizeof(localDeviceInfo->networkIpAddr))) {
DFINDER_LOGE(TAG, "invalid network name or ip address when iface number is 0");
return NSTACKX_EINVAL;
}
}
return NSTACKX_EOK;
}
static void DeviceInfoV2Init(NSTACKX_LocalDeviceInfoV2 *v2,
const NSTACKX_LocalDeviceInfo *localDeviceInfo, bool hasDeviceHash, uint64_t deviceHash)
{
v2->name = localDeviceInfo->name;
v2->deviceId = localDeviceInfo->deviceId;
v2->deviceType = localDeviceInfo->deviceType;
v2->businessType = localDeviceInfo->businessType;
v2->hasDeviceHash = hasDeviceHash;
v2->deviceHash = deviceHash;
}
static int32_t RegisterDeviceWithDeviceHash(const NSTACKX_LocalDeviceInfo *localDeviceInfo,
bool hasDeviceHash, uint64_t deviceHash)
{
int ret = CheckLocalDeviceInfo(localDeviceInfo);
if (ret != NSTACKX_EOK) {
return ret;
}
NSTACKX_LocalDeviceInfoV2 v2;
DeviceInfoV2Init(&v2, localDeviceInfo, hasDeviceHash, deviceHash);
NSTACKX_InterfaceInfo ifaceInfo;
(void)memset_s(&ifaceInfo, sizeof(ifaceInfo), 0, sizeof(ifaceInfo));
if (localDeviceInfo->ifNums == 0) {
if (strcpy_s(ifaceInfo.networkName, sizeof(ifaceInfo.networkName), localDeviceInfo->networkName) != EOK ||
strcpy_s(ifaceInfo.networkIpAddr, sizeof(ifaceInfo.networkIpAddr),
localDeviceInfo->networkIpAddr) != EOK) {
DFINDER_LOGE(TAG, "copy network name or ip addr failed");
return NSTACKX_EINVAL;
}
v2.localIfInfo = &ifaceInfo;
v2.ifNums = 1;
} else {
v2.localIfInfo = &localDeviceInfo->localIfInfo[0];
v2.ifNums = localDeviceInfo->ifNums;
}
return RegisterDeviceWithType(&v2, hasDeviceHash ? REGISTER_TYPE_UPDATE_SPECIFIED : REGISTER_TYPE_UPDATE_ALL);
}
int32_t NSTACKX_RegisterDevice(const NSTACKX_LocalDeviceInfo *localDeviceInfo)
{
Coverity_Tainted_Set((void *)localDeviceInfo);
DFINDER_LOGI(TAG, "begin to NSTACKX_RegisterDevice!");
return RegisterDeviceWithDeviceHash(localDeviceInfo, NSTACKX_FALSE, 0);
}
static void ConfigureLocalDeviceNameInner(void *argument)
{
char *localDevName = (char *)argument;
ConfigureLocalDeviceName(localDevName);
free(localDevName);
}
static void RegisterLocalDeviceHash(void *arg)
{
uint64_t hash = (uint64_t)(uintptr_t)arg;
SetLocalDeviceHash(hash);
}
static int32_t RegisterDeviceHashInner(uint64_t deviceHash)
{
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_DONE) {
SetLocalDeviceHash(deviceHash);
return NSTACKX_EOK;
}
if (PostEvent(&g_eventNodeChain, g_epollfd, RegisterLocalDeviceHash, (void *)deviceHash)) {
DFINDER_LOGE(TAG, "Failed to configure local device hash!");
return NSTACKX_EFAILED;
}
return NSTACKX_EOK;
}
int32_t NSTACKX_RegisterDeviceHash(uint64_t deviceHash)
{
if (g_nstackInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_CTRL is not initiated yet");
return NSTACKX_EFAILED;
}
return RegisterDeviceHashInner(deviceHash);
}
int32_t NSTACKX_RegisterDeviceName(const char *devName)
{
if (devName == NULL || devName[0] == '\0') {
DFINDER_LOGE(TAG, "register local device name is invalid");
return NSTACKX_EINVAL;
}
size_t len = strnlen(devName, NSTACKX_MAX_DEVICE_NAME_LEN);
if (len >= NSTACKX_MAX_DEVICE_NAME_LEN) {
DFINDER_LOGE(TAG, "devName len %zu is error", len);
return NSTACKX_EINVAL;
}
if (g_nstackInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_CTRL is not initiated yet");
return NSTACKX_EFAILED;
}
char *dupDevName = (char *)malloc(sizeof(char) * NSTACKX_MAX_DEVICE_NAME_LEN);
if (dupDevName == NULL) {
return NSTACKX_ENOMEM;
}
if (strncpy_s(dupDevName, NSTACKX_MAX_DEVICE_NAME_LEN, devName, len) != EOK) {
DFINDER_LOGE(TAG, "strncpy dupDevName failed");
free(dupDevName);
return NSTACKX_EFAILED;
}
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_DONE) {
ConfigureLocalDeviceNameInner((void *)dupDevName);
return NSTACKX_EOK;
}
if (PostEvent(&g_eventNodeChain, g_epollfd, ConfigureLocalDeviceNameInner, dupDevName) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "Failed to configure local device name!");
free(dupDevName);
return NSTACKX_EFAILED;
}
return NSTACKX_EOK;
}
int32_t NSTACKX_RegisterDeviceAn(const NSTACKX_LocalDeviceInfo *localDeviceInfo, uint64_t deviceHash)
{
Coverity_Tainted_Set((void *)localDeviceInfo);
Coverity_Tainted_Set((void *)&deviceHash);
DFINDER_LOGI(TAG, "begin to NSTACKX_RegisterDeviceAn!");
return RegisterDeviceWithDeviceHash(localDeviceInfo, NSTACKX_TRUE, deviceHash);
}
struct NSTACKX_Sem {
sem_t wait;
};
typedef void (*FreeArg)(void *arg);
struct PostEvtBlockArgs {
void *arg;
FreeArg cb;
EventHandle handle;
struct NSTACKX_Sem *sem;
};
static void NSTACKX_PostEventBlockHander(void *argument)
{
if (argument == NULL) {
return;
}
struct PostEvtBlockArgs *arg = (struct PostEvtBlockArgs *)argument;
if (arg->arg != NULL && arg->handle != NULL) {
arg->handle(arg->arg);
}
if (arg->sem != NULL) {
SemPost(&(arg->sem->wait));
DFINDER_LOGI(TAG, "post event is done");
}
if (arg->cb != NULL) {
arg->cb(arg->arg);
}
arg->arg = NULL;
free(arg);
}
static int32_t SemTimedWait(sem_t *sem, struct timespec expire)
{
struct timespec timeout;
if (clock_gettime(CLOCK_REALTIME, &timeout) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "clock_gettime fail");
return NSTACKX_EFAILED;
}
timeout.tv_sec += expire.tv_sec;
timeout.tv_nsec += expire.tv_nsec;
if (timeout.tv_nsec >= NSEC_TICKS_PER_SEC) {
timeout.tv_sec += 1;
timeout.tv_nsec -= NSEC_TICKS_PER_SEC;
}
int ret = sem_timedwait(sem, &timeout);
if (ret != 0) {
return NSTACKX_EFAILED;
}
return NSTACKX_EOK;
}
static int32_t NSTACKX_BlockEvtWaitFinish(struct PostEvtBlockArgs *arg, struct NSTACKX_Sem *sem)
{
int32_t ret = NSTACKX_EFAILED;
struct timespec expire = {
.tv_sec = DFINDER_POST_EVENT_MAX_BLOCK_SECONDS,
.tv_nsec = 0,
};
ret = SemTimedWait(&sem->wait, expire);
if (ret != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "sem wait failed errno %d", GetErrno());
} else {
DFINDER_LOGI(TAG, "sem wait success");
}
return ret;
}
static struct NSTACKX_Sem *NSTACKX_CreateSem(void)
{
struct NSTACKX_Sem *sem = (struct NSTACKX_Sem *)calloc(1U, sizeof(struct NSTACKX_Sem));
if (sem == NULL) {
DFINDER_LOGE(TAG, "calloc sem failed");
return NULL;
}
if (SemInit(&sem->wait, 0, 0)) {
DFINDER_LOGE(TAG, "Failed to init sem!");
free(sem);
return NULL;
}
return sem;
}
static void NSTACKX_FreeSem(void *arg)
{
if (arg == NULL) {
return;
}
struct NSTACKX_Sem *sem = (struct NSTACKX_Sem *)arg;
SemDestroy(&sem->wait);
free(sem);
DFINDER_LOGI(TAG, "free sem end");
}
static int32_t NSTACKX_PostEventBlock(EventHandle handle, void *arg, FreeArg cb)
{
struct PostEvtBlockArgs *blockEvtArg = (struct PostEvtBlockArgs *)calloc(1U, sizeof(struct PostEvtBlockArgs));
if (blockEvtArg == NULL) {
if (cb != NULL) {
cb(arg);
}
DFINDER_LOGE(TAG, "calloc failed");
return NSTACKX_EFAILED;
}
struct NSTACKX_Sem *sem = NSTACKX_CreateSem();
if (sem == NULL) {
if (cb != NULL) {
cb(arg);
}
free(blockEvtArg);
DFINDER_LOGE(TAG, "calloc sem failed");
return NSTACKX_EFAILED;
}
blockEvtArg->arg = arg;
blockEvtArg->cb = cb;
blockEvtArg->sem = sem;
blockEvtArg->handle = handle;
if (PostEvent(&g_eventNodeChain, g_epollfd,
NSTACKX_PostEventBlockHander, (void *)blockEvtArg) != NSTACKX_EOK) {
if (cb != NULL) {
cb(arg);
}
NSTACKX_FreeSem((void *)sem);
free(blockEvtArg);
DFINDER_LOGE(TAG, "PostEvent failed");
return NSTACKX_EFAILED;
}
if (NSTACKX_BlockEvtWaitFinish(blockEvtArg, sem) != NSTACKX_EOK) {
if (PostEvent(&g_eventNodeChain, g_epollfd, NSTACKX_FreeSem, (void*)sem) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "PostEvent failed");
NSTACKX_FreeSem((void *)sem);
return NSTACKX_EFAILED;
}
DFINDER_LOGE(TAG, "block wait failed");
return NSTACKX_EFAILED;
}
NSTACKX_FreeSem((void *)sem);
DFINDER_LOGI(TAG, "post event success");
return NSTACKX_EOK;
}
struct RegDeviceInfo {
NSTACKX_LocalDeviceInfoV2 *info;
int registerType;
int32_t err;
};
static void RegisterDeviceV2(void *arg)
{
struct RegDeviceInfo *regInfo = (struct RegDeviceInfo *)arg;
regInfo->err = RegisterLocalDeviceV2(regInfo->info, regInfo->registerType);
if (regInfo->err != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "register device failed");
}
}
#define NSTACKX_MAX_LOCAL_IFACE_NUM 10
static char *DeviceStrCreate(const char *str, uint32_t maxLen)
{
char *out = (char *)calloc(1u, maxLen);
if (out == NULL) {
return NULL;
}
if (strcpy_s(out, maxLen, str) != EOK) {
free(out);
return NULL;
}
return out;
}
static void RegisterInfoFree(NSTACKX_LocalDeviceInfoV2 *info)
{
if (info == NULL) {
return;
}
free((void *)info->name);
free((void *)info->deviceId);
free((void *)info->localIfInfo);
free(info);
}
static void RegisterDeviceFree(void *arg)
{
if (arg == NULL) {
return;
}
struct RegDeviceInfo *regInfo = (struct RegDeviceInfo *)arg;
RegisterInfoFree(regInfo->info);
regInfo->info = NULL;
free(regInfo);
}
static NSTACKX_LocalDeviceInfoV2 *RegisterInfoCreate(const NSTACKX_LocalDeviceInfoV2 *localDeviceInfo)
{
NSTACKX_LocalDeviceInfoV2 *infoV2 = (NSTACKX_LocalDeviceInfoV2 *)calloc(1u, sizeof(NSTACKX_LocalDeviceInfoV2));
if (infoV2 == NULL) {
DFINDER_LOGE(TAG, "calloc infov2 failed");
return NULL;
}
size_t len = strnlen(localDeviceInfo->deviceId, NSTACKX_MAX_DEVICE_ID_LEN);
if (len >= NSTACKX_MAX_DEVICE_ID_LEN) {
DFINDER_LOGE(TAG, "deviceId is error");
free(infoV2);
return NULL;
}
len = strnlen(localDeviceInfo->name, NSTACKX_MAX_DEVICE_NAME_LEN);
if (len >= NSTACKX_MAX_DEVICE_NAME_LEN) {
DFINDER_LOGE(TAG, "name is error");
free(infoV2);
return NULL;
}
infoV2->deviceId = DeviceStrCreate(localDeviceInfo->deviceId, NSTACKX_MAX_DEVICE_ID_LEN);
if (infoV2->deviceId == NULL) {
DFINDER_LOGE(TAG, "DeviceStrCreate deviceId is error");
RegisterInfoFree(infoV2);
return NULL;
}
infoV2->name = DeviceStrCreate(localDeviceInfo->name, NSTACKX_MAX_DEVICE_NAME_LEN);
if (infoV2->name == NULL) {
DFINDER_LOGE(TAG, "DeviceStrCreate name is error");
RegisterInfoFree(infoV2);
return NULL;
}
NSTACKX_InterfaceInfo *info = (NSTACKX_InterfaceInfo *)calloc(localDeviceInfo->ifNums,
sizeof(NSTACKX_InterfaceInfo));
if (info == NULL) {
DFINDER_LOGE(TAG, "calloc info is error");
RegisterInfoFree(infoV2);
return NULL;
}
(void)memcpy_s(info, localDeviceInfo->ifNums * sizeof(NSTACKX_InterfaceInfo),
localDeviceInfo->localIfInfo, localDeviceInfo->ifNums * sizeof(NSTACKX_InterfaceInfo));
infoV2->localIfInfo = info;
infoV2->businessType = localDeviceInfo->businessType;
infoV2->deviceHash = localDeviceInfo->deviceHash;
infoV2->deviceType = localDeviceInfo->deviceType;
infoV2->ifNums = localDeviceInfo->ifNums;
infoV2->hasDeviceHash = localDeviceInfo->hasDeviceHash;
return infoV2;
}
static struct RegDeviceInfo *RegisterDeviceCreate(const NSTACKX_LocalDeviceInfoV2 *localDeviceInfo, int registerType)
{
struct RegDeviceInfo *regInfo = (struct RegDeviceInfo *)calloc(1u, sizeof(struct RegDeviceInfo));
if (regInfo == NULL) {
DFINDER_LOGE(TAG, "calloc register info failed");
return NULL;
}
regInfo->info = RegisterInfoCreate(localDeviceInfo);
if (regInfo->info == NULL) {
DFINDER_LOGE(TAG, "calloc infov2 failed");
free(regInfo);
return NULL;
}
regInfo->registerType = registerType;
return regInfo;
}
static int32_t RegisterDeviceWithType(const NSTACKX_LocalDeviceInfoV2 *localDeviceInfo, int registerType)
{
if (localDeviceInfo == NULL || localDeviceInfo->name == NULL ||
localDeviceInfo->deviceId == NULL || localDeviceInfo->ifNums > NSTACKX_MAX_LOCAL_IFACE_NUM ||
(localDeviceInfo->ifNums != 0 && localDeviceInfo->localIfInfo == NULL) ||
CheckInterfaceInfo(localDeviceInfo->localIfInfo, localDeviceInfo->ifNums) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "invalid args");
return NSTACKX_EINVAL;
}
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_DONE) {
return (int32_t)RegisterLocalDeviceV2(localDeviceInfo, registerType);
}
struct RegDeviceInfo *regInfo = RegisterDeviceCreate(localDeviceInfo, registerType);
if (regInfo == NULL) {
DFINDER_LOGE(TAG, "Failed to create device info!");
return NSTACKX_EFAILED;
}
// The abnormal branch regInfo is released internally.
if (NSTACKX_PostEventBlock(RegisterDeviceV2, (void*)regInfo, RegisterDeviceFree) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "Failed to configure local device info!");
return NSTACKX_EBUSY;
}
return NSTACKX_EOK;
}
int32_t NSTACKX_RegisterDeviceV2(const NSTACKX_LocalDeviceInfoV2 *localDeviceInfo)
{
Coverity_Tainted_Set((void *)localDeviceInfo);
DFINDER_LOGI(TAG, "NSTACKX_RegisterDeviceV2 begin!");
if (g_nstackInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_Ctrl is not initiated yet");
return NSTACKX_EFAILED;
}
int registerType = (localDeviceInfo != NULL &&
localDeviceInfo->ifNums == SINGLE_NIC_CNT) ? REGISTER_TYPE_UPDATE_SPECIFIED : REGISTER_TYPE_UPDATE_ALL;
return RegisterDeviceWithType(localDeviceInfo, registerType);
}
typedef struct {
uint32_t capabilityBitmapNum;
uint32_t capabilityBitmap[NSTACKX_MAX_CAPABILITY_NUM];
} CapabilityProcessData;
static void RegisterCapabilityInner(void *argument)
{
CapabilityProcessData *capabilityData = argument;
(void)SetLocalDeviceCapability(capabilityData->capabilityBitmapNum, capabilityData->capabilityBitmap);
free(capabilityData);
}
static void SetFilterCapabilityInner(void *argument)
{
CapabilityProcessData *capabilityData = argument;
(void)SetFilterCapability(capabilityData->capabilityBitmapNum, capabilityData->capabilityBitmap);
free(capabilityData);
}
static int32_t NSTACKX_CapabilityHandle(uint32_t capabilityBitmapNum, uint32_t capabilityBitmap[], EventHandle handle)
{
Coverity_Tainted_Set((void *)&capabilityBitmapNum);
Coverity_Tainted_Set((void *)capabilityBitmap);
CapabilityProcessData *capabilityData = NULL;
if (g_nstackInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_Ctrl is not initiated yet");
return NSTACKX_EFAILED;
}
if (capabilityBitmapNum != 0 && capabilityBitmap == NULL) {
DFINDER_LOGE(TAG, "bitmap array is null");
return NSTACKX_EFAILED;
}
if (capabilityBitmapNum > NSTACKX_MAX_CAPABILITY_NUM) {
DFINDER_LOGE(TAG, "capabilityBitmapNum (%u) exceed max number", capabilityBitmapNum);
return NSTACKX_EINVAL;
}
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_DONE) {
if (handle == RegisterCapabilityInner) {
return (int32_t)SetLocalDeviceCapability(capabilityBitmapNum, capabilityBitmap);
}
if (handle == SetFilterCapabilityInner) {
return SetFilterCapability(capabilityBitmapNum, capabilityBitmap);
}
}
capabilityData = calloc(1U, sizeof(CapabilityProcessData));
if (capabilityData == NULL) {
return NSTACKX_ENOMEM;
}
if ((capabilityBitmapNum != 0) && memcpy_s(capabilityData->capabilityBitmap,
sizeof(capabilityData->capabilityBitmap), capabilityBitmap, capabilityBitmapNum * sizeof(uint32_t)) != EOK) {
free(capabilityData);
return NSTACKX_EINVAL;
}
capabilityData->capabilityBitmapNum = capabilityBitmapNum;
if (PostEvent(&g_eventNodeChain, g_epollfd, handle, capabilityData) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "Failed to register capability!");
free(capabilityData);
return NSTACKX_EFAILED;
}
return NSTACKX_EOK;
}
int32_t NSTACKX_RegisterCapability(uint32_t capabilityBitmapNum, uint32_t capabilityBitmap[])
{
DFINDER_LOGD(TAG, "begin to call NSTACKX_RegisterCapability");
return NSTACKX_CapabilityHandle(capabilityBitmapNum, capabilityBitmap, RegisterCapabilityInner);
}
int32_t NSTACKX_SetFilterCapability(uint32_t capabilityBitmapNum, uint32_t capabilityBitmap[])
{
DFINDER_LOGI(TAG, "Set Filter Capability");
return NSTACKX_CapabilityHandle(capabilityBitmapNum, capabilityBitmap, SetFilterCapabilityInner);
}
static void SetMaxDeviceNumInner(void *argument)
{
SetMaxDeviceNum((uint32_t)(uintptr_t)(argument));
}
int32_t NSTACKX_SetMaxDeviceNum(uint32_t maxDeviceNum)
{
if (g_nstackInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_Ctrl is not initiated yet");
return NSTACKX_EFAILED;
}
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_DONE) {
SetMaxDeviceNum(maxDeviceNum);
return NSTACKX_EOK;
}
if (NSTACKX_PostEventBlock(SetMaxDeviceNumInner, (void *)(uintptr_t)maxDeviceNum, NULL) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "Failed to set max device num!");
return NSTACKX_EFAILED;
}
return NSTACKX_EOK;
}
#ifdef DFINDER_SAVE_DEVICE_LIST
int32_t NSTACKX_SetDeviceListAgingTime(uint32_t agingTime)
{
if (g_nstackInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_Ctrl is not initiated yet");
return NSTACKX_EFAILED;
}
SetDeviceListAgingTime(agingTime);
return NSTACKX_EOK;
}
#else
int32_t NSTACKX_SetDeviceListAgingTime(uint32_t agingTime)
{
(void)agingTime;
DFINDER_LOGE(TAG, "device list not supported");
return NSTACKX_EFAILED;
}
#endif /* END OF DFINDER_SAVE_DEVICE_LIST */
int32_t NSTACKX_ScreenStatusChange(bool isScreenOn)
{
#ifdef DFINDER_SUPPORT_SET_SCREEN_STATUS
SetScreenStatus(isScreenOn);
DFINDER_LOGI(TAG, "set isScreenOn status %d", isScreenOn);
#else
(void)isScreenOn;
DFINDER_LOGI(TAG, "do not support set screen status");
#endif
return NSTACKX_EOK;
}
static void RegisterServiceDataInner(void *argument)
{
char *serviceData = argument;
if (SetLocalDeviceServiceData(serviceData) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "RegisterServiceData failed");
}
free(serviceData);
}
static bool RegisterServiceDataParamCheck(const struct NSTACKX_ServiceData *param, uint32_t cnt)
{
uint32_t i;
if (param == NULL) {
DFINDER_LOGE(TAG, "param is null");
return false;
}
if (cnt == 0 || cnt >= MAX_COAP_SERVICE_DATA_CNT) {
DFINDER_LOGE(TAG, "cnt is error");
return false;
}
for (i = 0; i < cnt; i++) {
size_t len = strnlen(param[i].serviceData, NSTACKX_MAX_SERVICE_DATA_LEN);
if (len == NSTACKX_MAX_SERVICE_DATA_LEN) {
DFINDER_LOGE(TAG, "param[%u] serviceData is error, no terminator", i);
return false;
}
len = strnlen(param[i].ip, NSTACKX_MAX_IP_STRING_LEN);
if (len == NSTACKX_MAX_IP_STRING_LEN) {
DFINDER_LOGE(TAG, "param[%u] ip is error, no terminator", i);
return false;
}
}
return true;
}
struct ServiceDataInfo {
struct NSTACKX_ServiceData *param;
uint32_t cnt;
int32_t err;
};
static void RegisterServiceDataV2(void *arg)
{
struct ServiceDataInfo *info = (struct ServiceDataInfo *)arg;
info->err = SetLocalDeviceServiceDataV2(info->param, info->cnt);
}
static struct ServiceDataInfo *ServiceDataV2Create(const struct NSTACKX_ServiceData *param,
uint32_t cnt)
{
struct ServiceDataInfo *info = (struct ServiceDataInfo *)calloc(1u, sizeof(struct ServiceDataInfo));
if (info == NULL) {
DFINDER_LOGE(TAG, "create info failed");
return NULL;
}
struct NSTACKX_ServiceData *data = (struct NSTACKX_ServiceData *)calloc(cnt, sizeof(struct NSTACKX_ServiceData));
if (data == NULL) {
free(info);
DFINDER_LOGE(TAG, "create data failed");
return NULL;
}
(void)memcpy_s(data, cnt * sizeof(struct NSTACKX_ServiceData),
param, cnt * sizeof(struct NSTACKX_ServiceData));
info->param = data;
info->cnt = cnt;
return info;
}
static void ServiceDataV2Free(void *arg)
{
if (arg == NULL) {
return;
}
struct ServiceDataInfo *info = (struct ServiceDataInfo *)arg;
free(info->param);
info->param = NULL;
free(info);
}
int32_t NSTACKX_RegisterServiceDataV2(const struct NSTACKX_ServiceData *param, uint32_t cnt)
{
DFINDER_LOGI(TAG, "begin to call NSTACKX_RegisterServiceDataV2");
if (!RegisterServiceDataParamCheck(param, cnt)) {
return NSTACKX_EINVAL;
}
if (g_nstackInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_Ctrl is not initiated yet");
return NSTACKX_EFAILED;
}
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_DONE) {
return SetLocalDeviceServiceDataV2(param, cnt);
}
struct ServiceDataInfo *info = ServiceDataV2Create(param, cnt);
if (info == NULL) {
DFINDER_LOGE(TAG, "create info failed");
return NSTACKX_EFAILED;
}
// The abnormal branch info is released internally.
if (NSTACKX_PostEventBlock(RegisterServiceDataV2, (void *)info, ServiceDataV2Free) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "Failed to register serviceDatav2!");
return NSTACKX_EFAILED;
}
return NSTACKX_EOK;
}
int32_t NSTACKX_RegisterServiceData(const char *serviceData)
{
Coverity_Tainted_Set((void *)serviceData);
DFINDER_LOGD(TAG, "begin to call NSTACKX_RegisterServiceData");
char *serviceDataTmp = NULL;
if (serviceData == NULL) {
DFINDER_LOGE(TAG, "serviceData is null");
return NSTACKX_EINVAL;
}
size_t len = strnlen(serviceData, NSTACKX_MAX_SERVICE_DATA_LEN);
if (len >= NSTACKX_MAX_SERVICE_DATA_LEN) {
DFINDER_LOGE(TAG, "serviceData len %zu is err", len);
return NSTACKX_EINVAL;
}
if (g_nstackInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_Ctrl is not initiated yet");
return NSTACKX_EFAILED;
}
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_DONE) {
return SetLocalDeviceServiceData(serviceData);
}
serviceDataTmp = calloc(1U, NSTACKX_MAX_SERVICE_DATA_LEN);
if (serviceDataTmp == NULL) {
return NSTACKX_ENOMEM;
}
if (strncpy_s(serviceDataTmp, NSTACKX_MAX_SERVICE_DATA_LEN, serviceData, len) != EOK) {
DFINDER_LOGE(TAG, "Failed to copy serviceData");
free(serviceDataTmp);
return NSTACKX_EINVAL;
}
if (PostEvent(&g_eventNodeChain, g_epollfd, RegisterServiceDataInner, serviceDataTmp) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "Failed to register serviceData!");
free(serviceDataTmp);
return NSTACKX_EFAILED;
}
return NSTACKX_EOK;
}
static void RegisterBusinessDataInner(void *argument)
{
DFINDER_LOGI(TAG, "Register Business Data Inner");
char *businessData = argument;
if (SetLocalDeviceBusinessData(businessData, NSTACKX_TRUE) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "RegisterBusinessData failed");
}
free(businessData);
}
int32_t NSTACKX_RegisterBusinessData(const char *businessData)
{
DFINDER_LOGI(TAG, "begin to call NSTACKX_RegisterBusinessData");
char *businessDataTmp = NULL;
if (businessData == NULL) {
DFINDER_LOGE(TAG, "businessData is null");
return NSTACKX_EINVAL;
}
size_t len = strnlen(businessData, NSTACKX_MAX_BUSINESS_DATA_LEN);
if (len >= NSTACKX_MAX_BUSINESS_DATA_LEN) {
DFINDER_LOGE(TAG, "businessData (%zu) exceed max number", len);
return NSTACKX_EINVAL;
}
if (g_nstackInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_Ctrl is not initiated yet");
return NSTACKX_EFAILED;
}
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_DONE) {
return (int32_t)SetLocalDeviceBusinessData(businessData, NSTACKX_TRUE);
}
businessDataTmp = calloc(1, NSTACKX_MAX_BUSINESS_DATA_LEN);
if (businessDataTmp == NULL) {
DFINDER_LOGE(TAG, "businessDataTmp is null");
return NSTACKX_ENOMEM;
}
if (strncpy_s(businessDataTmp, NSTACKX_MAX_BUSINESS_DATA_LEN, businessData, len) != EOK) {
DFINDER_LOGE(TAG, "Failed to copy businessData");
free(businessDataTmp);
return NSTACKX_EFAILED;
}
if (PostEvent(&g_eventNodeChain, g_epollfd, RegisterBusinessDataInner, businessDataTmp) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "Failed to register businessData!");
free(businessDataTmp);
return NSTACKX_EFAILED;
}
return NSTACKX_EOK;
}
#ifndef DFINDER_USE_MINI_NSTACKX
static void RegisterExtendServiceDataInner(void *argument)
{
char *extendServiceData = argument;
if (SetLocalDeviceExtendServiceData(extendServiceData) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "RegisterExtendServiceData failed");
}
free(extendServiceData);
}
#endif
int32_t NSTACKX_RegisterExtendServiceData(const char *extendServiceData)
{
#ifndef DFINDER_USE_MINI_NSTACKX
char *extendServiceDataTmp = NULL;
if (extendServiceData == NULL) {
DFINDER_LOGE(TAG, "extendServiceData is null");
return NSTACKX_EINVAL;
}
size_t len = strnlen(extendServiceData, NSTACKX_MAX_EXTEND_SERVICE_DATA_LEN);
if (len >= NSTACKX_MAX_EXTEND_SERVICE_DATA_LEN) {
DFINDER_LOGE(TAG, "extendServiceData len %zu is error", len);
return NSTACKX_EINVAL;
}
if (g_nstackInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_Ctrl is not initiated yet");
return NSTACKX_EFAILED;
}
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_DONE) {
return SetLocalDeviceExtendServiceData(extendServiceData);
}
extendServiceDataTmp = calloc(1, NSTACKX_MAX_EXTEND_SERVICE_DATA_LEN);
if (extendServiceDataTmp == NULL) {
return NSTACKX_ENOMEM;
}
if (strncpy_s(extendServiceDataTmp, NSTACKX_MAX_EXTEND_SERVICE_DATA_LEN, extendServiceData, len) != EOK) {
DFINDER_LOGE(TAG, "Failed to copy extendServiceData");
free(extendServiceDataTmp);
return NSTACKX_EINVAL;
}
if (PostEvent(&g_eventNodeChain, g_epollfd, RegisterExtendServiceDataInner, extendServiceDataTmp) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "Failed to register extendServiceData!");
free(extendServiceDataTmp);
return NSTACKX_EFAILED;
}
return NSTACKX_EOK;
#else
(void)extendServiceData;
DFINDER_LOGI(TAG, "NSTACKX_RegisterExtendServiceData not supported");
return NSTACKX_EOK;
#endif
}
#ifndef DFINDER_USE_MINI_NSTACKX
struct DirectMsgCtx {
MsgCtx msg;
const char *ipStr;
struct in_addr ip;
};
static void SendMsgDirectInner(void *arg)
{
struct DirectMsgCtx *msg = arg;
DFINDER_LOGD(TAG, "Enter WifiDirect send");
msg->msg.err = CoapSendServiceMsg(&msg->msg, msg->ipStr, &msg->ip);
SemPost(&msg->msg.wait);
}
static int32_t NSTACKX_SendMsgParamCheck(const char *moduleName, const char *deviceId, const uint8_t *data,
uint32_t len)
{
if (moduleName == NULL || strnlen(moduleName, NSTACKX_MAX_MODULE_NAME_LEN) > NSTACKX_MAX_MODULE_NAME_LEN) {
DFINDER_LOGE(TAG, "Invalid module name");
return NSTACKX_EINVAL;
}
if (deviceId == NULL || strnlen(deviceId, NSTACKX_MAX_DEVICE_ID_LEN) > NSTACKX_MAX_DEVICE_ID_LEN) {
DFINDER_LOGE(TAG, "Invalid device id");
return NSTACKX_EINVAL;
}
if (data == NULL || len == 0 || len > NSTACKX_MAX_SENDMSG_DATA_LEN) {
DFINDER_LOGE(TAG, "Null data to send");
return NSTACKX_EINVAL;
}
return NSTACKX_EOK;
}
static int MsgCtxInit(MsgCtx *msg, const char *moduleName, const char *deviceId, const uint8_t *data, uint32_t len)
{
if (SemInit(&msg->wait, 0, 0)) {
DFINDER_LOGE(TAG, "sem init fail");
return NSTACKX_EFAILED;
}
msg->deviceId = deviceId;
msg->moduleName = moduleName;
msg->data = data;
msg->len = len;
msg->err = NSTACKX_EOK;
return NSTACKX_EOK;
}
#endif
int32_t NSTACKX_SendMsgDirect(const char *moduleName, const char *deviceId, const uint8_t *data,
uint32_t len, const char *ipaddr, uint8_t type)
{
#ifndef DFINDER_USE_MINI_NSTACKX
int32_t ret = NSTACKX_EOK;
DFINDER_LOGD(TAG, "NSTACKX_SendMsgDirect");
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_Ctrl is not initiated yet");
return NSTACKX_EFAILED;
}
if (ipaddr == NULL) {
DFINDER_LOGE(TAG, "ipaddr needed");
return NSTACKX_EINVAL;
}
if (type > SERVER_TYPE_USB) {
DFINDER_LOGE(TAG, "invalid type %hhu", type);
return NSTACKX_EINVAL;
}
if (NSTACKX_SendMsgParamCheck(moduleName, deviceId, data, len) != NSTACKX_EOK) {
return NSTACKX_EINVAL;
}
struct DirectMsgCtx directMsg;
if (inet_pton(AF_INET, ipaddr, &directMsg.ip) != 1 || directMsg.ip.s_addr == 0) {
DFINDER_LOGE(TAG, "invalid ip addr");
return NSTACKX_EINVAL;
}
directMsg.ipStr = ipaddr;
directMsg.msg.type = type;
if (MsgCtxInit(&directMsg.msg, moduleName, deviceId, data, len) != NSTACKX_EOK) {
return NSTACKX_EFAILED;
}
if (PostEvent(&g_eventNodeChain, g_epollfd, SendMsgDirectInner, &directMsg) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "Failed to send msg");
ret = NSTACKX_EFAILED;
}
if (ret == NSTACKX_EOK) {
SemWait(&directMsg.msg.wait);
ret = directMsg.msg.err;
}
SemDestroy(&directMsg.msg.wait);
return ret;
#else
(void)moduleName;
(void)deviceId;
(void)data;
(void)len;
(void)ipaddr;
(void)type;
DFINDER_LOGI(TAG, "NSTACKX_SendMsgDirect not supported");
return NSTACKX_EFAILED;
#endif
}
#if defined(DFINDER_SAVE_DEVICE_LIST) && !defined(DFINDER_USE_MINI_NSTACKX)
static void SendMsgInner(void *arg)
{
MsgCtx *msg = arg;
const struct in_addr *remoteIp = GetRemoteDeviceIp(msg->deviceId);
if (remoteIp == NULL) {
DFINDER_LOGE(TAG, "no device found");
msg->err = NSTACKX_EINVAL;
} else {
char ipStr[INET_ADDRSTRLEN] = {0};
if (inet_ntop(AF_INET, remoteIp, ipStr, sizeof(ipStr)) != NULL) {
msg->err = CoapSendServiceMsg(msg, ipStr, remoteIp);
} else {
DFINDER_LOGE(TAG, "ip format failed");
}
}
SemPost(&msg->wait);
}
#endif
int32_t NSTACKX_SendMsg(const char *moduleName, const char *deviceId, const uint8_t *data, uint32_t len)
{
Coverity_Tainted_Set((void *)moduleName);
Coverity_Tainted_Set((void *)deviceId);
Coverity_Tainted_Set((void *)data);
Coverity_Tainted_Set((void *)&len);
#if defined(DFINDER_SAVE_DEVICE_LIST) && !defined(DFINDER_USE_MINI_NSTACKX)
int32_t ret = NSTACKX_EOK;
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_Ctrl is not initiated yet");
return NSTACKX_EFAILED;
}
if (NSTACKX_SendMsgParamCheck(moduleName, deviceId, data, len) != NSTACKX_EOK) {
return NSTACKX_EINVAL;
}
MsgCtx msg;
msg.type = INVALID_TYPE;
if (MsgCtxInit(&msg, moduleName, deviceId, data, len) != NSTACKX_EOK) {
return NSTACKX_EFAILED;
}
if (PostEvent(&g_eventNodeChain, g_epollfd, SendMsgInner, &msg) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "failed to send msg");
ret = NSTACKX_EFAILED;
}
if (ret == NSTACKX_EOK) {
SemWait(&msg.wait);
ret = msg.err;
}
SemDestroy(&msg.wait);
return ret;
#else
(void)moduleName;
(void)deviceId;
(void)data;
(void)len;
DFINDER_LOGI(TAG, "SendMsg not supported");
return NSTACKX_EFAILED;
#endif
}
static void SendDiscoveryRspInner(void *arg)
{
NSTACKX_ResponseSettings *responseSettings = arg;
SendDiscoveryRsp(responseSettings);
free(responseSettings->businessData);
free(responseSettings);
}
static int32_t CopyResponseSettings(NSTACKX_ResponseSettings *dupResponseSettings,
const NSTACKX_ResponseSettings *responseSettings)
{
dupResponseSettings->businessType = responseSettings->businessType;
dupResponseSettings->length = responseSettings->length;
if (responseSettings->businessData != NULL) {
if (strncpy_s(dupResponseSettings->businessData, (dupResponseSettings->length + 1),
responseSettings->businessData, responseSettings->length) != EOK) {
DFINDER_LOGE(TAG, "businessData strncpy failed");
return NSTACKX_EINVAL;
}
}
// strlen is check in CheckResponseSettings
if (strncpy_s(dupResponseSettings->localNetworkName, NSTACKX_MAX_INTERFACE_NAME_LEN,
responseSettings->localNetworkName, strlen(responseSettings->localNetworkName)) != EOK) {
DFINDER_LOGE(TAG, "localNetworkName strncpy failed");
return NSTACKX_EINVAL;
}
if (strncpy_s(dupResponseSettings->remoteIp, NSTACKX_MAX_IP_STRING_LEN,
responseSettings->remoteIp, strlen(responseSettings->remoteIp)) != EOK) {
DFINDER_LOGE(TAG, "remoteIp strncpy failed");
return NSTACKX_EINVAL;
}
return NSTACKX_EOK;
}
static int32_t CheckResponseSettings(const NSTACKX_ResponseSettings *responseSettings)
{
if (responseSettings == NULL) {
DFINDER_LOGE(TAG, "Invalid responseSettings info");
return NSTACKX_EINVAL;
}
if ((responseSettings->businessData == NULL) && (responseSettings->length != 0)) {
DFINDER_LOGE(TAG, "Invalid responseSettings bData info");
return NSTACKX_EINVAL;
}
if (responseSettings->length >= NSTACKX_MAX_BUSINESS_DATA_LEN) {
DFINDER_LOGE(TAG, "businessData length is too long");
return NSTACKX_EINVAL;
}
if (strnlen(responseSettings->localNetworkName, NSTACKX_MAX_INTERFACE_NAME_LEN) >=
NSTACKX_MAX_INTERFACE_NAME_LEN) {
DFINDER_LOGE(TAG, "businessData is error, no terminator");
return NSTACKX_EINVAL;
}
if (strnlen(responseSettings->remoteIp, NSTACKX_MAX_IP_STRING_LEN) >=
NSTACKX_MAX_IP_STRING_LEN) {
DFINDER_LOGE(TAG, "remoteIp is error, no terminator");
return NSTACKX_EINVAL;
}
return NSTACKX_EOK;
}
int32_t NSTACKX_SendDiscoveryRsp(const NSTACKX_ResponseSettings *responseSettings)
{
DFINDER_LOGI(TAG, "begin to NSTACKX_SendDiscoveryRsp!");
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_Ctrl is not initiated yet");
return NSTACKX_EFAILED;
}
if (CheckResponseSettings(responseSettings) != NSTACKX_EOK) {
return NSTACKX_EINVAL;
}
DFINDER_LOGI(TAG, "response settings, business type: %hu, local network name: %s",
responseSettings->businessType, responseSettings->localNetworkName);
NSTACKX_ResponseSettings *dupResponseSettings = malloc(sizeof(NSTACKX_ResponseSettings));
if (dupResponseSettings == NULL) {
DFINDER_LOGE(TAG, "malloc failed");
return NSTACKX_ENOMEM;
}
dupResponseSettings->businessData = (char *)calloc((responseSettings->length + 1), sizeof(char));
if (dupResponseSettings->businessData == NULL) {
DFINDER_LOGE(TAG, "businessData calloc failed");
free(dupResponseSettings);
return NSTACKX_ENOMEM;
}
if (CopyResponseSettings(dupResponseSettings, responseSettings) != NSTACKX_EOK) {
free(dupResponseSettings->businessData);
free(dupResponseSettings);
return NSTACKX_EINVAL;
}
if (PostEvent(&g_eventNodeChain, g_epollfd, SendDiscoveryRspInner, dupResponseSettings) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "Failed to send responseSettings info!");
free(dupResponseSettings->businessData);
free(dupResponseSettings);
return NSTACKX_EFAILED;
}
return NSTACKX_EOK;
}
#ifdef DFINDER_SAVE_DEVICE_LIST
static void GetDeviceListInner(void *argument)
{
GetDeviceListMessage *message = argument;
GetDeviceList(message->deviceList, message->deviceCountPtr, true);
SemPost(&message->wait);
}
#endif
int32_t NSTACKX_GetDeviceList(NSTACKX_DeviceInfo *deviceList, uint32_t *deviceCountPtr)
{
#ifdef DFINDER_SAVE_DEVICE_LIST
GetDeviceListMessage message = {
.deviceList = deviceList,
.deviceCountPtr = deviceCountPtr,
};
if (g_nstackInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_Ctrl is not initiated yet");
return NSTACKX_EFAILED;
}
if (deviceList == NULL || deviceCountPtr == NULL) {
DFINDER_LOGE(TAG, "Device list or count pointer is NULL");
return NSTACKX_EINVAL;
}
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_DONE) {
GetDeviceList(deviceList, deviceCountPtr, true);
return NSTACKX_EOK;
}
if (SemInit(&message.wait, 0, 0)) {
return NSTACKX_EFAILED;
}
if (PostEvent(&g_eventNodeChain, g_epollfd, GetDeviceListInner, &message) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "Failed to get device list");
SemDestroy(&message.wait);
return NSTACKX_EFAILED;
}
SemWait(&message.wait);
SemDestroy(&message.wait);
return NSTACKX_EOK;
#else
(void)deviceList;
(void)deviceCountPtr;
DFINDER_LOGE(TAG, "device list not supported");
return NSTACKX_EFAILED;
#endif /* END OF DFINDER_SAVE_DEVICE_LIST */
}
void NotifyDeviceListChanged(const NSTACKX_DeviceInfo *deviceList, uint32_t deviceCount)
{
if (g_parameter.onDeviceListChanged != NULL) {
DFINDER_LOGI(TAG, "notify callback: device list changed");
g_parameter.onDeviceListChanged(deviceList, deviceCount);
DFINDER_LOGI(TAG, "finish to notify device list changed");
} else {
DFINDER_LOGI(TAG, "notify callback: device list changed callback is null");
}
}
void NotifyDeviceFound(const NSTACKX_DeviceInfo *deviceList, uint32_t deviceCount)
{
if (g_parameter.onDeviceFound != NULL) {
DFINDER_LOGI(TAG, "notify callback: device found");
g_parameter.onDeviceFound(deviceList, deviceCount);
DFINDER_LOGI(TAG, "finish to notify device found");
} else {
DFINDER_LOGI(TAG, "notify callback: device found callback is null");
}
}
void NotificationReceived(const NSTACKX_NotificationConfig *notification)
{
if (g_parameter.onNotificationReceived != NULL) {
DFINDER_LOGI(TAG, "notify callback: notification received");
g_parameter.onNotificationReceived(notification);
DFINDER_LOGI(TAG, "finish to notify notification received");
} else {
DFINDER_LOGI(TAG, "notify callback: notification received callback is null");
}
}
#ifndef DFINDER_USE_MINI_NSTACKX
void NotifyMsgReceived(const char *moduleName, const char *deviceId, const uint8_t *data,
uint32_t len, const char *srcIp)
{
if (g_parameter.onMsgReceived != NULL) {
DFINDER_LOGI(TAG, "notify callback: message received, data length %u", len);
g_parameter.onMsgReceived(moduleName, deviceId, data, len, srcIp);
DFINDER_LOGI(TAG, "finish to notify msg received");
} else {
DFINDER_LOGI(TAG, "notify callback: message received callback is null");
}
}
int32_t NSTACKX_InitRestart(const NSTACKX_Parameter *parameter)
{
Coverity_Tainted_Set((void *)parameter);
#if defined(_WIN32) || defined(DFINDER_USE_MINI_NSTACKX)
DFINDER_LOGE(TAG, "do not support init restart");
(void)parameter;
return NSTACKX_EFAILED;
#else
DFINDER_LOGI(TAG, "NSTACKX_InitRestart");
int32_t ret = NSTACKX_Init(parameter);
if (ret == NSTACKX_EOK) {
if (PostEvent(&g_eventNodeChain, g_epollfd, DetectLocalIface, NULL) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "Failed to GetLocalNetworkInterface");
}
}
return ret;
#endif
}
static void DeviceDiscoverInnerRestart(void *argument)
{
(void)argument;
CoapServiceDiscoverInner(NSTACKX_FALSE);
}
void NSTACKX_StartDeviceFindRestart(void)
{
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_Ctrl is not initiated yet");
return;
}
DFINDER_LOGI(TAG, "start device find for restart");
if (PostEvent(&g_eventNodeChain, g_epollfd, DeviceDiscoverInnerRestart, NULL) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "Failed to start device discover!");
return;
}
return;
}
#endif /* END OF DFINDER_USE_MINI_NSTACKX */
#ifdef ENABLE_USER_LOG
int32_t NSTACKX_DFinderRegisterLog(DFinderLogCallback userLogCallback)
{
if (userLogCallback == NULL) {
DFINDER_LOGE(TAG, "logImpl null");
return NSTACKX_EFAILED;
}
int32_t ret = SetLogCallback(userLogCallback);
return ret;
}
#endif
#ifdef NSTACKX_DFINDER_HIDUMP
#define MAX_DUMP_ARGC 10
int NSTACKX_DFinderDump(const char **argv, uint32_t argc, void *softObj, DFinderDumpFunc dump)
{
if (g_nstackInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_Ctrl is not initiated yet");
return NSTACKX_EFAILED;
}
if (dump == NULL) {
DFINDER_LOGE(TAG, "dump is null");
return NSTACKX_EINVAL;
}
if (argc == 0 || argc > MAX_DUMP_ARGC) {
DFINDER_LOGE(TAG, "argc is invalid %u", argc);
return NSTACKX_EINVAL;
}
if (argv == NULL) {
DFINDER_LOGE(TAG, "argv is null");
return NSTACKX_EINVAL;
}
uint32_t i;
for (i = 0; i < argc; i++) {
if (argv[i] == NULL) {
DFINDER_LOGE(TAG, "argv[%u] is null", i);
return NSTACKX_EINVAL;
}
}
return DFinderDump(argv, argc, softObj, dump);
}
#else
int NSTACKX_DFinderDump(const char **argv, uint32_t argc, void *softObj, DFinderDumpFunc dump)
{
(void)argv;
(void)argc;
(void)softObj;
(void)dump;
DFINDER_LOGE(TAG, "unsupport dfinder dump");
return NSTACKX_NOTSUPPORT;
}
#endif
int NSTACKX_DFinderSetEventFunc(void *softobj, DFinderEventFunc func)
{
if (g_nstackInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "NSTACKX_Ctrl is not initiated yet");
return NSTACKX_EFAILED;
}
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_DONE) {
return SetEventFuncDirectly(softobj, func);
}
return SetEventFunc(softobj, func);
}
static int32_t CheckNotificationConfig(const NSTACKX_NotificationConfig *config)
{
if (config == NULL) {
DFINDER_LOGE(TAG, "notification config passed in is null");
return NSTACKX_EINVAL;
}
if (config->businessType >= NSTACKX_BUSINESS_TYPE_MAX) {
DFINDER_LOGE(TAG, "invalid business type %hhu in notification config", config->businessType);
return NSTACKX_EINVAL;
}
if (config->msg == NULL) {
DFINDER_LOGE(TAG, "msg in notification config is null");
return NSTACKX_EINVAL;
}
size_t len = strnlen(config->msg, NSTACKX_MAX_NOTIFICATION_DATA_LEN);
if (len >= NSTACKX_MAX_NOTIFICATION_DATA_LEN || len != config->msgLen || config->msgLen == 0) {
DFINDER_LOGE(TAG, "actual msg len %zu, msg len %zu in config", len, config->msgLen);
return NSTACKX_EINVAL;
}
// advertise count: [0, 100], first interval in intervalMs should be 0
if (config->intervalLen == 0 || config->intervalLen > NSTACKX_MAX_ADVERTISE_COUNT) {
DFINDER_LOGE(TAG, "invalid interval len %hhu in notification config, max support %d",
config->intervalLen, NSTACKX_MAX_ADVERTISE_COUNT);
return NSTACKX_EINVAL;
}
if (config->intervalsMs == NULL) {
DFINDER_LOGE(TAG, "broadcast intervals in notification config is null");
return NSTACKX_EINVAL;
}
// interval: [0 ms, 10000 ms]
if (config->intervalsMs[0] != 0) {
DFINDER_LOGE(TAG, "first interval should be 0 to indicate send notification immediately");
return NSTACKX_EINVAL;
}
for (size_t i = 1; i < config->intervalLen; ++i) {
if (config->intervalsMs[i] < NSTACKX_MIN_ADVERTISE_INTERVAL ||
config->intervalsMs[i] > NSTACKX_MAX_ADVERTISE_INTERVAL) {
DFINDER_LOGE(TAG, "invalid interval[%zu] = %hu, support max: %d min: %d",
i, config->intervalsMs[i], NSTACKX_MAX_ADVERTISE_INTERVAL, NSTACKX_MIN_ADVERTISE_INTERVAL);
return NSTACKX_EINVAL;
}
}
return NSTACKX_EOK;
}
static int32_t CopyNotificationConfig(NSTACKX_NotificationConfig *dst, const NSTACKX_NotificationConfig *src)
{
dst->businessType = src->businessType;
if (strncpy_s(dst->msg, src->msgLen + 1, src->msg, src->msgLen) != EOK) {
DFINDER_LOGE(TAG, "copy notification msg to duplicated one fail");
return NSTACKX_EFAILED;
}
dst->msgLen = src->msgLen;
for (size_t i = 0; i < src->intervalLen; ++i) {
(dst->intervalsMs)[i] = (src->intervalsMs)[i];
}
dst->intervalLen = src->intervalLen;
return NSTACKX_EOK;
}
static void NotificationInner(void *argument)
{
NSTACKX_NotificationConfig *config = (NSTACKX_NotificationConfig *)argument;
int32_t retMsg = LocalizeNotificationMsg(config->msg);
int32_t retInterval = LocalizeNotificationInterval(config->intervalsMs, config->intervalLen);
free(config->intervalsMs);
free(config->msg);
free(config);
if (retMsg != NSTACKX_EOK || retInterval != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "stop running service notification cause localize config fail");
return;
}
CoapServiceNotification();
}
int32_t NSTACKX_SendNotification(const NSTACKX_NotificationConfig *config)
{
DFINDER_LOGI(TAG, "begin to call NSTACKX_SendNotification");
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "dfinder not inited");
return NSTACKX_EFAILED;
}
if (CheckNotificationConfig(config) != NSTACKX_EOK) {
return NSTACKX_EINVAL;
}
NSTACKX_NotificationConfig *dupConfig = (NSTACKX_NotificationConfig *)calloc(1, sizeof(NSTACKX_NotificationConfig));
if (dupConfig == NULL) {
DFINDER_LOGE(TAG, "calloc for notification config fail, size wanted: %zu", sizeof(NSTACKX_NotificationConfig));
return NSTACKX_ENOMEM;
}
dupConfig->msg = (char *)calloc((config->msgLen + 1), sizeof(char));
if (dupConfig->msg == NULL) {
DFINDER_LOGE(TAG, "calloc for msg in notification fail, size wanted: %zu", config->msgLen + 1);
free(dupConfig);
return NSTACKX_ENOMEM;
}
dupConfig->intervalsMs = (uint16_t *)calloc(config->intervalLen, sizeof(uint16_t));
if (dupConfig->intervalsMs == NULL) {
DFINDER_LOGE(TAG, "calloc for intervals fail, size wanted: %zu", sizeof(uint16_t) * (config->intervalLen));
free(dupConfig->msg);
free(dupConfig);
return NSTACKX_ENOMEM;
}
if (CopyNotificationConfig(dupConfig, config) != NSTACKX_EOK) {
free(dupConfig->intervalsMs);
free(dupConfig->msg);
free(dupConfig);
return NSTACKX_EFAILED;
}
if (PostEvent(&g_eventNodeChain, g_epollfd, NotificationInner, dupConfig) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "post event failed to run notification inner");
free(dupConfig->intervalsMs);
free(dupConfig->msg);
free(dupConfig);
return NSTACKX_EFAILED;
}
return NSTACKX_EOK;
}
static void NotificationStop(void *argument)
{
(void)argument;
CoapServiceNotificationStop();
}
int32_t NSTACKX_StopSendNotification(uint8_t businessType)
{
DFINDER_LOGI(TAG, "begin to call NSTACKX_StopSendNotification, business type: %hhu", businessType);
if (g_nstackThreadInitState != NSTACKX_INIT_STATE_DONE) {
DFINDER_LOGE(TAG, "dfinder not inited");
return NSTACKX_EFAILED;
}
if (businessType >= NSTACKX_BUSINESS_TYPE_MAX) {
DFINDER_LOGE(TAG, "invalid business type %hhu to stop send notification", businessType);
return NSTACKX_EINVAL;
}
if (PostEvent(&g_eventNodeChain, g_epollfd, NotificationStop, NULL) != NSTACKX_EOK) {
DFINDER_LOGE(TAG, "post event failed to run stop device discover");
return NSTACKX_EFAILED;
}
return NSTACKX_EOK;
}