OpenHarmony分布式软总线流程分析v1.0丨1.被发现端,发布服务 原创 精华

丨张明亮丨
发布于 2021-6-26 08:20
浏览
12收藏

更新时间:2021年6月26日 @亮子力

这次的软总线流程分析字数太多,上传了好几次都失败了。所以我分成了2个部分。
1.被发现端,发布服务
2.开启软总线,建立连接

完整版可以下载文末的pdf。

@toc

源码目录:

主目录\foundation\communication\softbus_lite

├── authmanager【提供设备认证机制和设备知识库管理】
├── discovery【提供基于coap协议的设备发现机制】
├── interfaces
├── os_adapter【操作系统适配层】
├── trans_service【提供认证和数据传输通道】
└── BUILD.gn
通过BUILD.gn的分析,我们知道整个softbus_lite目录下的所有源码文件将被编译到一个动态库中。
其他依赖软总线的模块在编译的时候加上这个动态库的依赖就可以了。
例如:分布式调度子系统所在的foundation这个bin文件的编译就依赖这个动态库。

authmanager【提供设备认证机制和设备知识库管理】

当发现有请求时,调用ProcessDataEvent函数,收包,检验包头,根据数据包的类型确定不同的处理方式。类型主要包括以下三种:
MODULE_AUTH_SDK     加密数据类型
MODULE_TRUST_ENGINE 可信类型,直接进行数据传输
MODULE_CONNECTION  进行ip及设备认证

├── BUILD.gn
├── include
│   ├── auth_conn.h
│   ├── auth_interface.h
│   ├── bus_manager.h
│   ├── msg_get_deviceid.h
│   └── wifi_auth_manager.h
└── source
    ├── auth_conn.c【提供发送、接收、认证、获取秘钥功能】
    ├── auth_interface.c【管理各个会话节点、各个链接节点、各个秘钥节点,提供包括增删改查等功能】
    ├── bus_manager.c【主要通过deviceIp创建两个不同的listen,主要用来监听系统上有哪些device及新的device节点的创建;其中有两个回调函数OnConnectEvent和OnDataEvent,分别是用来处理设备节点的基本操作及节点数据的处理】
    ├── msg_get_deviceid.c【提供以cJSON格式获取各个设备的信息,包括设备id、链接信息、设备名、设备类型等】
    └── wifi_auth_manager.c【主要实现了连接管理和数据接收功能。连接管理包括连接的建立、断开及连接的查找。数据接收包括数据获取、包头及包长等的校验,并且为了简化包头数据读取,单独实现了对一个int型和一个long型数据的接收函数】

discovery【提供基于coap协议的设备发现机制】

├── BUILD.gn
├── coap【目录主要是负责COAP协议的部分】
│   ├── include
│   │   ├── coap_adapter.h
│   │   ├── coap_def.h
│   │   ├── coap_discover.h
│   │   ├── coap_socket.h
│   │   ├── json_payload.h
│   │   ├── nstackx_common.h
│   │   ├── nstackx_database.h
│   │   ├── nstackx_device.h
│   │   ├── nstackx_error.h
│   │   └── nstackx.h
│   └── source
│       ├── coap_adapter.c
│       ├── coap_discover.c【实现了基于COAP的设备发现功能】
│       ├── coap_socket.c
│       ├── json_payload.c
│       ├── nstackx_common.c
│       └── nstackx_device.c
└── discovery_service【基于coap协议实现了轻量设备端的服务发布的能力】
    ├── include
    │   ├── coap_service.h
    │   ├── common_info_manager.h
    │   └── discovery_error.h
    └── source
        ├── coap_service.c
        ├── common_info_manager.c
        └── discovery_service.c
        
discovery的实现前提是确保发现端设备与接收端设备在同一个局域网内且能互相收到对方的报文。大致流程是:

发现端设备,使用coap协议在局域网内发送广播;
接收端设备使用PublishService接口发布服务,接收端收到广播后,发送coap协议单播给发现端;
发现端设备收到报文会更新设备信息。

os_adapter【操作系统适配层】

├── include
│   └── os_adapter.h
└── source
    ├── L0
    │   └── os_adapter.c
    └── L1
        └── os_adapter.c

trans_service【提供认证和数据传输通道】

它主要封装了socket、cJSON、线程锁接口,实现了用户的创建、监听、会话管理,以及设备、指令、数据等信息的获取,最终提供加密和解密传输两种传输通道。
├── BUILD.gn
├── include
│   ├── libdistbus
│   │   ├── auth_conn_manager.h
│   │   └── tcp_session_manager.h
│   └── utils
│       ├── aes_gcm.h
│       ├── comm_defs.h
│       ├── data_bus_error.h
│       ├── message.h
│       └── tcp_socket.h
└── source
    ├── libdistbus
    │   ├── auth_conn_manager.c		【用户创建,监听,连接等服务管理】
    │   ├── tcp_session.c			【会话管理】
    │   ├── tcp_session.h
    │   ├── tcp_session_manager.c
    │   ├── trans_lock.c			【互斥锁初始化以及互斥锁资源获取与释放】
    │   └── trans_lock.h
    └── utils
        ├── aes_gcm.c		【提供加密传输和解密传输接口】
        ├── message.c		【用于获取以cJSON格式管理的设备(包括设备名、设备类型、设备ID等)、指令、数据、会话(包括用户端口、会话端口等)等信息】
        └── tcp_socket.c	【端口号管理以及数据传输管理】

一、如何初始化软总线

调用软总线模块并不复杂,需要准备2个结构体就可以召唤神龙,简称StartBus()。以下我们以Hi3861为例写一个简单的例子。

static void InitSoftbus(void)
{printf(">>>>>%s:%d:%s()\n",__FILE__,__LINE__,__FUNCTION__);
    static PublishInfo g_publishInfo = {
        .capabilityData = (unsigned char *)"1",
        .capability = "ddmpCapability",
        .dataLen = 1,
        .publishId = 1,
        .mode = DISCOVER_MODE_ACTIVE,
        .medium = COAP,
        .freq = MID,
    };
    static IPublishCallback g_publishCallback = {
        .onPublishSuccess = OnSuccess,
        .onPublishFail = OnFail,
    };

    int ret = PublishService(g_demoModuleName, &g_publishInfo, &g_publishCallback);
    if (ret != 0) {
        printf("PublishService err\n");
    }
    sleep(5);
    ret = CreateSessionServer(g_demoModuleName, g_demoSessionName, &g_sessionCallback);
    if (ret != 0) {
        printf("CreateSessionServer err\n");
    }
    printf("InitSoftbus ok\n");
}

一、被发现端,发布服务。【discovery目录】

在分布式软总线子系统中,设备分为发现端和被发现端。这里我们使用手机作为发现端,Hi3861开发板发布服务,作为被发现端。

发布服务主要是通过PublishService()这个函数,相关的代码在:主目录\foundation\communication\softbus_lite\discovery_service文件夹下。

如果设备要发布软总线服务,就需要调用下面这个函数。

//moduleName:调用模块名
//info:PublishInfo结构体
//cb:发布成功或者失败的回调函数
int PublishService(const char *moduleName, const struct PublishInfo *info, const struct IPublishCallback *cb)
{printf(">>>>>%s:%d:%s()[soft bus init start]\n",__FILE__,__LINE__,__FUNCTION__);
    //许可检查,首先将检查是否有发布权限。这里调用的os_adapter【操作系统适配层】相关部分。
    if (SoftBusCheckPermission(SOFTBUS_PERMISSION) != 0 || info == NULL || cb == NULL) {
        SOFTBUS_PRINT("[DISCOVERY] PublishService invalid para(info or cb)\n");
        return ERROR_INVALID;
    }

    //参数有效性检查,检查了一些发布参数的合法性,其次确认发布协议是不是COAP。
    if (moduleName == NULL || strlen(moduleName) >= MAX_PACKAGE_NAME || info->publishId <= 0 ||
        info->dataLen > MAX_CAPABILITY_DATA_LEN) {
        SOFTBUS_PRINT("[DISCOVERY] PublishService invliad para\n");
        PublishCallback(info->publishId, PUBLISH_FAIL_REASON_PARAMETER_INVALID, NULL, cb);
        return ERROR_INVALID;
    }//如果参数检查失败,调用PublishCallback()来回调cb里面的失败回调函数
    if (info->medium != COAP) {
        PublishCallback(info->publishId, PUBLISH_FAIL_REASON_NOT_SUPPORT_MEDIUM, NULL, cb);
        return ERROR_INVALID;
    }

    //用g_discoveryMutex防止多个设备对外发布服务产生的冲突
    if (g_discoveryMutex == NULL) {
        g_discoveryMutex = MutexInit();
        if (g_discoveryMutex == NULL) {
            PublishCallback(info->publishId, PUBLISH_FAIL_REASON_UNKNOWN, NULL, cb);
            return ERROR_FAIL;
        }
    }
    MutexLock(g_discoveryMutex);//解除互斥锁
    
    //InitService()这个函数比较重要。参考1.初始化InitService()发现服务
    if (InitService() != ERROR_SUCCESS) {
        SOFTBUS_PRINT("[DISCOVERY] PublishService InitService fail\n");
        PublishCallback(info->publishId, PUBLISH_FAIL_REASON_UNKNOWN, NULL, cb);
        MutexUnlock(g_discoveryMutex);
        return ERROR_FAIL;
    }

    //AddPublishModule()函数,参考2.模块增加到g_publishModule
    PublishModule *findModule = AddPublishModule(moduleName, info);
    if (findModule == NULL) {
        SOFTBUS_PRINT("[DISCOVERY] PublishService AddPublishModule fail\n");
        PublishCallback(info->publishId, PUBLISH_FAIL_REASON_UNKNOWN, NULL, cb);
        MutexUnlock(g_discoveryMutex);
        return ERROR_FAIL;
    }

    //注册COAP服务,参考3.CoapRegisterDefualtService()
    int ret = ERROR_SUCCESS;
    if (info->capability == NULL || info->capabilityData == NULL) {
        (void)CoapRegisterDefualtService();
    } else {
        ret = DoRegistService(info->medium);
    }
    
    MutexUnlock(g_discoveryMutex);

    //这个PublishCallback()就很简单了,上面出现好多次了,初始化成功或者失败的回调函数。
    if (ret != ERROR_SUCCESS) {
        PublishCallback(info->publishId, PUBLISH_FAIL_REASON_UNKNOWN, findModule, cb);
        return ERROR_FAIL;
    } else {
        PublishCallback(info->publishId, ERROR_SUCCESS, findModule, cb);
        return ERROR_SUCCESS;
    }
}

1.初始化InitService()发现服务

Z:\harmony110\foundation\communication\softbus_lite\discovery\discovery_service\source\discovery_service.c
int InitService(void)
{
    if (g_isServiceInit != 0) {//全局变量g_isServiceInit:确认服务是否启动。如果其他模块启动过,那么直接返回成功。
        return ERROR_SUCCESS;
    }

    //初始化g_deviceInfo结构体。参考1.1.初始化g_deviceInfo结构体,相关文件【common_info_manager.c】
    if (InitCommonManager() != 0) {
        DeinitService();
        return ERROR_FAIL;
    }
	
    //分配内存,参考:1.2.初始化全局g_publishModule和g_capabilityData
    g_publishModule = calloc(1, sizeof(PublishModule) * MAX_MODULE_COUNT);
    if (g_publishModule == NULL) {
        DeinitService();
        return ERROR_NOMEMORY;
    }
    g_capabilityData = calloc(1, MAX_SERVICE_DATA_LEN);
    if (g_capabilityData == NULL) {
        DeinitService();
        return ERROR_NOMEMORY;
    }
	//软总线注册第一个监听函数WifiEventTrigger(),当接入网络时trigger
    //注册wifi Callback,将WifiEventTrigger()↓函数,赋值给全局变量g_wifiCallback,参考b.COAP初始化wifi事件
    RegisterWifiCallback(WifiEventTrigger);
    
    //COAP初始化。参考1.3.初始化COAP协议服务,相关文件【coap_service.c】
    int ret = CoapInit();
    if (ret != ERROR_SUCCESS) {
        SOFTBUS_PRINT("[DISCOVERY] InitService CoapInit fail\n");
        DeinitService();
        return ret;
    }printf(">>>>>%s:%d[Register WifiEventTring()]\n",__FILE__,__LINE__);//添加打印调试
    
    //COAP写入消息队列,这样会触发上面↑消息回调函数,WifiEventTrigger(),这个函数比较重要,TODO 1.4.
    CoapWriteMsgQueue(UPDATE_IP_EVENT);
    
    //COAP注册设备信息
    ret = CoapRegisterDeviceInfo();
    if (ret != ERROR_SUCCESS) {
        SOFTBUS_PRINT("[DISCOVERY] InitService CoapRegisterDeviceInfo fail\n");
        DeinitService();
        return ret;
    }
    
    g_isServiceInit = 1;
    SOFTBUS_PRINT("[DISCOVERY] InitService ok\n");
    return ERROR_SUCCESS;
}

1.1.初始化g_deviceInfo结构体

Z:\harmony110\foundation\communication\softbus_lite\discovery\discovery_service\source\common_info_manager.c
    
int InitCommonManager(void)
{
    if (InitLocalDeviceInfo() != 0) { //初始化本地设备信息
        SOFTBUS_PRINT("[DISCOVERY] InitCommonManager fail\n");
        return ERROR_FAIL;
    }
    return ERROR_SUCCESS;
}
================================================================================================
int InitLocalDeviceInfo(void) //初始化本地设备信息
{
    char deviceId[DEVICEID_MAX_NUM] = {0};

    if (g_deviceInfo != NULL) { //初始化一个g_deviceInfo的结构体。包含本地设备的各种信息。
        memset_s(g_deviceInfo, sizeof(DeviceInfo), 0, sizeof(DeviceInfo));
    } else {
        g_deviceInfo = (DeviceInfo *)calloc(1, sizeof(DeviceInfo));
        if (g_deviceInfo == NULL) {
            return ERROR_FAIL;
        }
    }

    g_deviceInfo->devicePort = -1;		//默认,g_deviceInfo.设备端口-1
    g_deviceInfo->isAccountTrusted = 1; //默认,g_deviceInfo.账户是可信的

    unsigned int ret;
    //从文件获取设备id,这个函数还有好几层,就不继续深挖了。大体就是从DEVICE_ID_FILE文件中读取。
    //#define DEVICE_ID_FILE   "/storage/data/softbus/deviceid"
    ret = GetDeviceIdFromFile(deviceId, MAX_VALUE_SIZE);
    if (ret != ERROR_SUCCESS) {
        SOFTBUS_PRINT("[DISCOVERY] Get device fail\n");
        return ERROR_FAIL;
    }

#if defined(__LITEOS_M__) || defined(__LITEOS_RISCV__) //g_deviceInfo.设备的类型,目前分为L0和L1
    g_deviceInfo->deviceType = L0;
    ret = (unsigned int)strcpy_s(g_deviceInfo->deviceName, sizeof(g_deviceInfo->deviceName), L0_DEVICE_NAME);
#else
    g_deviceInfo->deviceType = L1;
    ret = (unsigned int)strcpy_s(g_deviceInfo->deviceName, sizeof(g_deviceInfo->deviceName), L1_DEVICE_NAME);
#endif

    ret |= (unsigned int)strcpy_s(g_deviceInfo->deviceId, sizeof(g_deviceInfo->deviceId), deviceId);//g_deviceInfo.设备id
    ret |= (unsigned int)strcpy_s(g_deviceInfo->version, sizeof(g_deviceInfo->version), "1.0.0");//g_deviceInfo.版本号
    if (ret != 0) {
        return ERROR_FAIL;
    }

    SOFTBUS_PRINT("[DISCOVERY] InitLocalDeviceInfo ok\n");
    return ERROR_SUCCESS;
}

1.2.初始化全局g_publishModule和g_capabilityData

Z:\harmony110\foundation\communication\softbus_lite\discovery\discovery_service\source\discovery_service.c
//首先,discovery_service.c开头定义了这两个全局变量。

PublishModule *g_publishModule = NULL;	//存放发布的模块
char *g_capabilityData = NULL;			//能力描述数据

typedef struct {
    char package[MAX_PACKAGE_NAME];
    int publishId;
    unsigned short medium;
    unsigned short capabilityBitmap;
    char *capabilityData;
    unsigned short dataLength;
    unsigned short used;
} PublishModule;//发布模块结构体

//初始化InitService()发现服务后,会将模块注册到全局变量g_publishModule中,服务注册到g_capabilityData中。

1.3.初始化COAP协议服务

Z:\harmony110\foundation\communication\softbus_lite\discovery\discovery_service\source\coap_service.c
int CoapInit(void)
{
    int ret = NSTACKX_Init();
    if (ret != 0) {
        SOFTBUS_PRINT("[DISCOVERY] CoapInit NSTACKX_Init fail\n");
        return ERROR_FAIL;
    }
    return ERROR_SUCCESS;
}
================================================================================================
Z:\harmony110\foundation\communication\softbus_lite\discovery\coap\source\nstackx_common.c
int NSTACKX_Init()
{
    int ret;
    if (g_nstackInitState != NSTACKX_INIT_STATE_START) {
        return NSTACKX_EOK;
    }

    g_nstackInitState = NSTACKX_INIT_STATE_ONGOING;
    cJSON_InitHooks(NULL);

    ret = CoapInitDiscovery(); //启动COAP端口监听
    if (ret != NSTACKX_EOK) {
        goto L_ERR_INIT;
    }
    g_nstackInitState = NSTACKX_INIT_STATE_DONE;
    return NSTACKX_EOK;

L_ERR_INIT:
    ret = NSTACKX_Deinit();
    if (ret != NSTACKX_EOK) {
        SOFTBUS_PRINT("[DISCOVERY] deinit fail\n");
    }
    return NSTACKX_EFAILED;
}
================================================================================================
Z:\harmony110\foundation\communication\softbus_lite\discovery\coap\source\coap_discover.c
int CoapInitDiscovery(void)
{    
    int ret = CoapInitSocket();	//参考a.COAP初始化Socket //启动监听端口
    if (ret != NSTACKX_EOK) {
        SOFTBUS_PRINT("[DISCOVERY] Init socket fail\n");
        return ret;
    }

    ret = CoapInitWifiEvent();	//参考b.COAP初始化wifi事件
    if (ret != NSTACKX_EOK) {
        SOFTBUS_PRINT("[DISCOVERY] Init wifi event fail\n");
        return ret;
    }
#if defined(__LITEOS_A__)
    ret = CreateQueryIpThread();
    if (ret != NSTACKX_EOK) {
        SOFTBUS_PRINT("[DISCOVERY] Init query Ip fail\n");
        return ret;
    }
#endif
    if (CreateMsgQueThread() != NSTACKX_EOK) {
        return NSTACKX_EFAILED;
    }
    
    return CreateCoapListenThread();	//参考c.创建COAP监听线程
}
================================================================================================

a.COAP初始化Socket

//这个函数跳转到了coap【目录主要是负责COAP协议的部分】
Z:\harmony110\foundation\communication\softbus_lite\discovery\coap\source\coap_socket.c
int CoapInitSocket(void)
{
    if (g_serverFd >= 0) {
        return NSTACKX_EOK;
    }
    struct sockaddr_in sockAddr;
    (void)memset_s(&sockAddr, sizeof(sockAddr), 0, sizeof(sockAddr));
    sockAddr.sin_port = htons(COAP_DEFAULT_PORT);
    g_serverFd = CoapCreateUdpServer(&sockAddr);	//创建一个udp服务器,这个socket赋值给g_serverFd
    if (g_serverFd < 0) {
        return NSTACKX_OVERFLOW;
    }
    COAP_SoftBusInitMsgId();
    return NSTACKX_EOK;
}
================================================================================================
int CoapCreateUdpServer(const struct sockaddr_in *sockAddr)	//创建一个udp服务器
{
    if (sockAddr == NULL) {
        return NSTACKX_EINVAL;
    }

    struct sockaddr_in localAddr;
    socklen_t len = sizeof(localAddr);
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0) {
        return NSTACKX_OVERFLOW;
    }

    (void)memset_s(&localAddr, sizeof(localAddr), 0, sizeof(localAddr));
    localAddr.sin_family = AF_INET;				//结构体sockaddr_in.sin_family = 2
    localAddr.sin_port = sockAddr->sin_port;	//结构体sockaddr_in.sin_port = 5684,定义在coap_socket.h
    if (sockAddr->sin_addr.s_addr != 0) {
        localAddr.sin_addr.s_addr = sockAddr->sin_addr.s_addr;	//测试发现这里执行的是else
    } else {
        localAddr.sin_addr.s_addr = htonl(INADDR_ANY);	//结构体sockaddr_in.sin_addr.s_addr = 0 打印测试结果是0
    }

    if (bind(sockfd, (struct sockaddr *)&localAddr, len) == -1) {	//创建一个socket,然后用bind()绑定到指定的IP+PORT
        CloseSocket(&sockfd);
        return NSTACKX_EFAILED;
    }

    if (getsockname(sockfd, (struct sockaddr *)&localAddr, &len) == -1) {	//获取套接字名称
        CloseSocket(&sockfd);
        return NSTACKX_EFAILED;
    }
    return sockfd;
}

b.COAP初始化wifi事件

//基本原理就是,像wifi_lite注册事件回调函数
//最终调用调用WifiEventTrigger()函数
Z:\harmony110\foundation\communication\softbus_lite\discovery\coap\source\coap_discover.c
int CoapInitWifiEvent(void)
{
    SOFTBUS_PRINT("[DISCOVERY] CoapInitWifiEvent\n");
    unsigned int ret;
    if (g_wifiQueueId == -1) {
        ret = CreateMsgQue("/wifiQue",		//创建一个消息队列
            WIFI_QUEUE_SIZE, (unsigned int*)&g_wifiQueueId,
            0, sizeof(AddressEventHandler));
        if (ret != 0) {
            SOFTBUS_PRINT("[DISCOVERY]CreateMsgQue fail\n");
            (void)CoapDeinitWifiEvent();
            return ret;
        }

#if defined(__LITEOS_M__) || defined(__LITEOS_RISCV__)
        g_coapEventHandler.OnWifiConnectionChanged = CoapConnectionChangedHandler;//参考下面解析
        WifiErrorCode error = RegisterWifiEvent(&g_coapEventHandler);	//注册wifi事件,全局变量g_coapEventHandler
        if (error != WIFI_SUCCESS) {
            SOFTBUS_PRINT("[DISCOVERY]RegisterWifiEvent fail, error:%d\n", error);
            (void)CoapDeinitWifiEvent();
            g_wifiQueueId = -1;
            return error;
        }
#endif
    }
    return NSTACKX_EOK;
}
================================================================================================
#if defined(__LITEOS_M__) || defined(__LITEOS_RISCV__)
static void CoapConnectionChangedHandler(int state, WifiLinkedInfo* info)
{
    (void)info;
    CoapWriteMsgQueue(state);//参考下面解析
}
================================================================================================
void CoapWriteMsgQueue(int state)
{
    SOFTBUS_PRINT("[DISCOVERY] CoapWriteMsgQueue\n");
    AddressEventHandler handler;
    handler.handler = CoapHandleWifiEvent;//参考下面解析
    handler.state = state;
    /* while a new event coming, it must stop the previous loop 当一个新的事件出现时,它必须停止之前的循环 */
    g_queryIpFlag = 0;
    (void)WriteMsgQue(g_wifiQueueId, &handler, sizeof(AddressEventHandler));
}
================================================================================================
void CoapHandleWifiEvent(unsigned int para)
{
    if (g_wifiCallback != NULL) {	//g_wifiCallback在int InitService(void){RegisterWifiCallback(WifiEventTrigger);}
        g_wifiCallback(para);		//WifiEventTrigger()
    }
}

c.创建COAP监听线程, HandleReadEvent()

//创建了CoapReadHandle线程,处理COAP_DEFAULT_PORT端口上的UDP socket的数据(也就是基于COAP协议的discover广播消息)
Z:\harmony110\foundation\communication\softbus_lite\discovery\coap\source\coap_discover.c
int CreateCoapListenThread(void)
{
    g_terminalFlag = 1;

#if defined(__LITEOS_M__) || defined(__LITEOS_RISCV__)
    if (g_coapTaskId != NULL) {
        return NSTACKX_EOK;
    }

    osThreadAttr_t attr;			//创建一个osThreadAttr_t结构体
    attr.name = "coap_listen_task";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
    attr.priority = osPriorityNormal4; // COAP_DEFAULT_PRIO -> cmsis prio
	//新建一个系统线程,全局变量g_coapTaskId
    g_coapTaskId = osThreadNew((osThreadFunc_t)CoapReadHandle, NULL, &attr);	//参考下面解析CoapReadHandle
    if (g_coapTaskId == NULL) {
        g_terminalFlag = 0;
        SOFTBUS_PRINT("[DISCOVERY] create task fail\n");
        return NSTACKX_EFAILED;
    }
#else
    if (g_coapTaskId != -1) {
        return NSTACKX_EOK;
    }

    ThreadAttr attr = {"coap_listen_task", 0x800, 20, 0, 0};
    int error = CreateThread((Runnable)CoapReadHandle, NULL, &attr, (unsigned int *)&g_coapTaskId);
    if (error != 0) {
        g_terminalFlag = 0;
        SOFTBUS_PRINT("[DISCOVERY] create task fail\n");
        return NSTACKX_EFAILED;
    }
#endif
    return NSTACKX_EOK;
}
================================================================================================
#define TIME_MICRO_SEC 10000
static void CoapReadHandle(unsigned int uwParam1, unsigned int uwParam2, unsigned int uwParam3, unsigned int uwParam4)
{
    (void)uwParam1;
    (void)uwParam2;
    (void)uwParam3;
    (void)uwParam4;
    int ret;
    fd_set readSet;
    int serverFd = GetCoapServerSocket();
    SOFTBUS_PRINT("[DISCOVERY] CoapReadHandle coin select begin\n");
    while (g_terminalFlag) {
        FD_ZERO(&readSet);
        FD_SET(serverFd, &readSet);
        //通过调用select实现了异步通讯
        ret = select(serverFd + 1, &readSet, NULL, NULL, NULL);
        if (ret > 0) {
            if (FD_ISSET(serverFd, &readSet)) {
                //在端口监听到包是通过HandleReadEvent函数来处理,在这个函数中对收到的数据包进行处理
                HandleReadEvent(serverFd);//参考【三、当发现端(比如手机)发送广播】
            }
        } else {
            SOFTBUS_PRINT("[DISCOVERY]ret:%d,error:%d\n", ret, errno);
        }
    }
    SOFTBUS_PRINT("[DISCOVERY] CoapReadHandle exit\n");
}

2.模块增加到g_publishModule

//g_publishModule是啥,要参考上面解析过的:1.2.初始化全局g_publishModule和g_capabilityData
//传入参数有PublishInfo *info,g_publishModule大部分内容继承PublishInfo
//而PublishInfo结构体的内容,是最早调用PublishService()就需要提供的参数
//通俗讲就是将加入软总线的模块名和它的信息,添加到系统g_publishModule中。
PublishModule *AddPublishModule(const char *packageName, const PublishInfo *info)
{
    //验证参数
    if (packageName == NULL || g_publishModule == NULL || info == NULL) {
        return NULL;
    }
    if (info->dataLen > MAX_SERVICE_DATA_LEN) {
        return NULL;
    }
    if (FindExistModule(packageName, info->publishId) != NULL) {
        return NULL;
    }
    if (FindFreeModule() == NULL) {
        return NULL;
    }
    
    //
    int ret;
    for (int i = 0; i < MAX_MODULE_COUNT; i++) {  //#define MAX_MODULE_COUNT 3
        if (g_publishModule[i].used == 1) {
            continue;
        }

        if (ParseCapability(info->capability, &g_publishModule[i].capabilityBitmap)) {
            return NULL;
        }

        g_publishModule[i].used = 1;
        g_publishModule[i].capabilityData = calloc(1, info->dataLen + 1);
        if (g_publishModule[i].capabilityData == NULL) {
            memset_s(&g_publishModule[i], sizeof(g_publishModule[i]), 0, sizeof(g_publishModule[i]));
            return NULL;
        }
        g_publishModule[i].dataLength = info->dataLen + 1;
        ret = memcpy_s(g_publishModule[i].capabilityData,
                       g_publishModule[i].dataLength,
                       info->capabilityData, info->dataLen);
        if (ret != 0) {
            free(g_publishModule[i].capabilityData);
            g_publishModule[i].capabilityData = NULL;
            memset_s(&g_publishModule[i], sizeof(g_publishModule[i]), 0, sizeof(g_publishModule[i]));
            return NULL;
        }
        g_publishModule[i].medium = info->medium;
        g_publishModule[i].publishId = info->publishId;
        ret = memcpy_s(g_publishModule[i].package, MAX_PACKAGE_NAME, packageName, strlen(packageName));
        if (ret != 0) {
            free(g_publishModule[i].capabilityData);
            g_publishModule[i].capabilityData = NULL;
            memset_s(&g_publishModule[i], sizeof(g_publishModule[i]), 0, sizeof(g_publishModule[i]));
            return NULL;
        }
        return &g_publishModule[i];
    }
    return NULL;
}

3.CoapRegisterDefualtService()

Z:\harmony110\foundation\communication\softbus_lite\discovery\discovery_service\source\coap_service.c

int CoapRegisterDefualtService(void)
{
    DeviceInfo *info = GetCommonDeviceInfo(); //info继承全局变量g_deviceInfo结构体
    if (info == NULL) {
        return ERROR_FAIL;
    }

    char serviceData[MAX_DEFAULT_SERVICE_DATA_LEN] = {0};
    if (sprintf_s(serviceData, sizeof(serviceData), "port:%d", info->devicePort) == -1) {
        return ERROR_FAIL;
    }

    return NSTACKX_RegisterServiceData(serviceData);
}
==============================================================================
Z:\harmony110\foundation\communication\softbus_lite\discovery\coap\source\nstackx_common.c

int NSTACKX_RegisterServiceData(const char* serviceData)
{
    if (serviceData == NULL) {
        return NSTACKX_EINVAL;
    }

    if (g_nstackInitState != NSTACKX_INIT_STATE_DONE) {
        return NSTACKX_EFAILED;
    }
    unsigned int serviceLen = strlen(serviceData);
    if (serviceLen >= NSTACKX_MAX_SERVICE_DATA_LEN) {
        return NSTACKX_EINVAL;
    }

    if (RegisterServiceData(serviceData, serviceLen + 1) != NSTACKX_EOK) {
        return NSTACKX_EINVAL;
    }
    return NSTACKX_EOK;
}
==============================================================================
Z:\harmony110\foundation\communication\softbus_lite\discovery\coap\source\nstackx_device.c

int RegisterServiceData(const char* serviceData, int length)
{
    if (serviceData == NULL) {
        return NSTACKX_EINVAL;
    }

    (void)memset_s(g_localDeviceInfo.serviceData, sizeof(g_localDeviceInfo.serviceData),
        0, sizeof(g_localDeviceInfo.serviceData));
    if (strcpy_s(g_localDeviceInfo.serviceData, NSTACKX_MAX_SERVICE_DATA_LEN, serviceData) != EOK)  {
        return NSTACKX_EFAILED;
    }

    (void)length;
    return NSTACKX_EOK;
}
==============================================================================
Z:\harmony110\foundation\communication\softbus_lite\discovery\coap\source\nstackx_device.c

int RegisterServiceData(const char* serviceData, int length)
{
    if (serviceData == NULL) {
        return NSTACKX_EINVAL;
    }

    (void)memset_s(g_localDeviceInfo.serviceData, sizeof(g_localDeviceInfo.serviceData),
        0, sizeof(g_localDeviceInfo.serviceData));
    if (strcpy_s(g_localDeviceInfo.serviceData, NSTACKX_MAX_SERVICE_DATA_LEN, serviceData) != EOK)  {
        return NSTACKX_EFAILED;
    }

    (void)length;
    return NSTACKX_EOK;
}

总结:

通过模块信息注册发布服务后,系统会产生2个线程,1个监听网络,另一个监听局域网内UDP的发现端请求。

接入网络执行【二、当接入网络,触发WifiEventTrigger(),开启软总线】

监听到UDP广播【三、当发现端(比如手机)发送广播】

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
OpenHarmony分布式软总线流程分析v1.0.pdf 634.37K 953次下载
已于2021-6-27 19:42:44修改
7
收藏 12
回复
举报
2条回复
按时间正序
/
按时间倒序
mb609898e2cfb86
mb609898e2cfb86

感谢楼主分享代码

回复
2021-6-28 11:24:11
笔架鱼052
笔架鱼052

您好, 看了您的博文,  其中关于 L0 设备端用作被发现端的代码, 您这边方便提供一下地址吗? 还是调用如下 PublishService CreateSessionServer 接口之后 发现和认证就 没问题了?

回复
2022-1-24 15:32:44
回复
    相关推荐