> 文档中心 > OpenHarmony 软总线lite 源码分析

OpenHarmony 软总线lite 源码分析

文章目录

    • 软总线
    • 一、会话传输
      • 1.1、CreateSessionServer
      • 1.2、SendBytes
    • 二、设备发现
      • 2.1、发布服务
        • 2.1.1、wifi事件
        • 2.1.2、coap服务器
      • 2.2、软总线
        • 2.2.1、SelectSessionLoop
        • 2.2.2、WaitProcess
        • 2.2.3、OnConnectEvent
        • 2.2.4、OnDataEvent
          • AuthInterfaceOnDataReceived
          • OnModuleMessageReceived
    • 问题待解决
        • hichain的认证过程
        • tcp server 连接过程

软总线

本文简单介绍softbus_lite的部分实现。代码来自openharmony 3.0 foundation/commucation/softbus_lite。

softbus_lite是L0和L1设备所采用的软总线的实现,相比于标准设备的dsoftbus,功能有所减少。例如softbus_lite只实现被动接收Session连接的功能,无法主动发起session连接以及发现服务。

softbus_lite更多的应用场景是作为边缘设备,通过在局域网内发布服务,等待标准设备的订阅。

一、会话传输

L0,L1系统属于lite系统,无法主动打开session,只能创建session server,然后等待远程设备来打开会话。在会话回调函数中,可获取会话id。通过session id可用来发送和接收数据

1.1、CreateSessionServer

CreateSessionServer:session server的作用只是用来管理listenerMap,即监听的功能,回调函数的执行。

struct ISessionListener {//当会话被打开时回调,sessionId表示本地会话id,也就是tcp连接的句柄,发送和接收数据时会使用到    int (*onSessionOpened)(int sessionId);    void (*onSessionClosed)(int sessionId);//接受到会话的数据    void (*onBytesReceived)(int sessionId, const void *data, unsigned int dataLen);};//创建g_sessionMgr,保存参数信息到全局数组int CreateSessionServer(const char* moduleName, const char* sessionName, struct ISessionListener *listener){    int ret = CreateSessionServerInner(moduleName, sessionName, listener);}//将listener保存到全局数组static int CreateSessionServerInner(const char* moduleName, const char* sessionName, struct ISessionListener *listener){    //创建g_sessionMgr    if (g_sessionMgr == NULL && InitGSessionMgr() != 0) { return TRANS_FAILED;    }    //在serverListenerMap中找一个空位置    int findIndex = -1;    for (int i = 0; i < MAX_SESSION_SERVER_NUM; i++) { if (g_sessionMgr->serverListenerMap[i] == NULL) {     findIndex = i;     break; }    }    if (findIndex >= 0 && findIndex < MAX_SESSION_SERVER_NUM) { g_sessionMgr->serverListenerMap[findIndex] = calloc(1, sizeof(SessionListenerMap)); //把参数信息保存到数组 SessionListenerMap *listenerMap = g_sessionMgr->serverListenerMap[findIndex]; if (strncpy_s(listenerMap->sessionName, NAME_LENGTH, sessionName, strlen(sessionName)) ||     strncpy_s(listenerMap->moduleName, NAME_LENGTH, moduleName, strlen(moduleName))) {     free(listenerMap);     listenerMap = NULL;     return TRANS_FAILED; }//把回调函数保存到全局数组 listenerMap->listener = listener;    }    return 0;}

1.2、SendBytes

向会话对端发送字节数据,实际上是调用socket接口 进行发送。

sessionfd就是通过回调函数获取到的sessionid,其实就是tcp端口的句柄。

int SendBytes(int sessionfd, const unsigned char *buf, unsigned int size){    //获取session    TcpSession *session = GetSessionById(sessionfd);    //打包数据到cipherBuf    char *cipherBuf = (char *)TransPackBytes(session, buf, size, &cipherLen);    int32_t bytes = 0;    fd_set writefds;    FD_ZERO(&writefds);    FD_SET(sessionfd, &writefds);    struct timeval msTimeout;    //设置超时时间    msTimeout.tv_sec = DEFAULT_TIMEOUT / ONE_SEC;    msTimeout.tv_usec = (DEFAULT_TIMEOUT % ONE_SEC) * ONE_SEC;    //阻塞等待socket就绪    int err = select(sessionfd + 1, NULL, &writefds, NULL, &msTimeout);//使用socket发送数据    while (FD_ISSET(sessionfd, &writefds) && bytes < (int32_t)cipherLen && (sessionfd) >= 0) { errno = 0; int32_t rc = send(sessionfd, cipherBuf + bytes, cipherLen - bytes, 0); if ((rc == -1) && (errno == EAGAIN)) {     continue; } else if (rc <= 0) {     if (bytes == 0) {  bytes = -1;     }     break; } bytes += rc;    }    free(cipherBuf);    return 0;}

二、设备发现

用户使用发现功能来自动发现周围的OpenHarmony设备时,需要保证发现端设备与被发现端设备在同一个局域网内,并且互相能收到对方以下流程的报文。

1)发现端设备,发起discover请求后,使用coap协议在局域网内发送广播。(2)被发现端设备使用PublishService接口发布服务,接收端收到广播后,发送coap协议单播给发现端。(3)发现端设备收到报文会更新设备信息。    

设备发现的最终目的就是发现局域网内的设备,更新周围的设备id。

目前L0、L1系统,也就是lite系统,不支持作为发现端。只能作为被发现端。通过使用PublishService接口发布服务,就能被标准设备发现。

发现服务的工作原理是这样的:

  • 首先由本地A设备,远程B设备。A设备调用PublishService发布服务,会创建一个udp服务器,监听一个广播端口。

  • B设备调用StartDiscovery开始发现设备,会创建一个udp客户端,向局域网广播。(B是L2设备)

  • A收到B的广播消息后,创建一个udp客户端,给B发送响应消息,响应消息中包含A的设备信息。

  • B收到响应后,会执行回调函数,函数参数就是A的设备信息。

  • B接下来可对A进行会话连接等。

下面的结构体表示服务提供的设备信息:这个信息会一直传递到对端设备

/** * @brief 发送给对端的本地设备信息 */typedef struct PublishInfo {    //服务id,如何确定?    int publishId;    //L0,L1设备只能是DISCOVER_MODE_PASSIVE 被动发现    int mode;    //协议:COAP协议    ExchangeMedium medium;    //报文发送频率    ExchangeFreq freq;    /** 服务发布的能力. 见下文 */    const char *capability;    /** 服务的数据。见下文 */    unsigned char *capabilityData;    /** Maximum length of the capability data for service publishing (2 bytes) */    unsigned int dataLen;} PublishInfo;
/** * @brief 服务的能力枚举,具体是什么意思? */typedef enum {    /** MeeTime */    HICALL_CAPABILITY_BITMAP = 0,    /** Video reverse connection in the smart domain */    PROFILE_CAPABILITY_BITMAP = 1,    /** Gallery in Vision */    HOMEVISIONPIC_CAPABILITY_BITMAP = 2,    /** cast+ */    CASTPLUS_CAPABILITY_BITMAP,    /** Input method in Vision */    AA_CAPABILITY_BITMAP,    /** Device virtualization tool package */    DVKIT_CAPABILITY_BITMAP,    /** Distributed middleware */    DDMP_CAPABILITY_BITMAP} DataBitMap;//将服务的能力和字符串绑定static const CapabilityMap g_capabilityMap[] = {    {HICALL_CAPABILITY_BITMAP, (char *)"hicall"},    {PROFILE_CAPABILITY_BITMAP, (char *)"profile"},    {CASTPLUS_CAPABILITY_BITMAP, (char *)"castPlus"},    {HOMEVISIONPIC_CAPABILITY_BITMAP, (char *)"homevisionPic"},    {AA_CAPABILITY_BITMAP, (char *)"aaCapability"},    {DVKIT_CAPABILITY_BITMAP, (char *)"dvKit"},    {DDMP_CAPABILITY_BITMAP, (char *)"ddmpCapability"},};

2.1、发布服务

即设备在局域网内发布上述的服务,这些服务就能被发现和调用。其本质就是将PublishInfo保存到全局变量中,并创建coap server监听端口,等待服务被发现和调用。当收到发现报文时,将PublishInfo里的信息通过coap报文,发送给发现者。

PublishService用于发布服务,代码如下:

int PublishService(const char *moduleName, const struct PublishInfo *info, const struct IPublishCallback *cb){    //检查是否有软总线权限    if (SoftBusCheckPermission(SOFTBUS_PERMISSION) != 0 || info == NULL || cb == NULL) { return ERROR_INVALID;    }    //初始化全局服务    if (InitService() != ERROR_SUCCESS) { return ERROR_FAIL;    }    //初始化module    PublishModule *findModule = AddPublishModule(moduleName, info);    //设置全局变量    if (info->capability == NULL || info->capabilityData == NULL) { (void)CoapRegisterDefualtService();    } else { ret = DoRegistService(info->medium);    }    //执行用户回调函数    if (ret != ERROR_SUCCESS) { PublishCallback(info->publishId, PUBLISH_FAIL_REASON_UNKNOWN, findModule, cb); return ERROR_FAIL;    } else { //call back PublishCallback(info->publishId, ERROR_SUCCESS, findModule, cb); return ERROR_SUCCESS;    }}

初始化全局服务,是主要的初始化代码:

//初始化服务:初始化设备信息ip地址、注册wifi回调函数、coap初始化。在连接到wifi后,启动soft bus、注册设备信息到softbusint InitService(void){//初始化 g_deviceInfo、g_publishModule、g_capabilityData、g_wifiCallback等全局变量    InitCommonManager();    g_publishModule = calloc(1, sizeof(PublishModule) * MAX_MODULE_COUNT);    g_capabilityData = calloc(1, MAX_SERVICE_DATA_LEN);    //注册wifi事件回调函数,具体见下文    RegisterWifiCallback(WifiEventTrigger);    //初始化coap服务器,处理coap报文逻辑    int ret = CoapInit();    //给wifi队列写入消息,本质是使能WifiEventTrigger()函数    CoapWriteMsgQueue(UPDATE_IP_EVENT);    //设置设备信息    ret = CoapRegisterDeviceInfo();    return ERROR_SUCCESS;}

在整个发现服务流程中,以下全局变量经常使用到,有必要简单的了解下

//全局模块 对应一个上层的应用typedef struct {    char package[MAX_PACKAGE_NAME];//上层应用packagename    int publishId;    unsigned short medium;    unsigned short capabilityBitmap;    char *capabilityData;    unsigned short dataLength;    unsigned short used;} PublishModule;g_publishModule;char *g_capabilityData = NULL;//设备信息typedef struct DeviceInfo {    char deviceName[MAX_DEV_NAME_LEN];    char deviceId[MAX_DEV_ID_LEN];    char deviceIp[MAX_DEV_IP_LEN];    char version[MAX_DEV_VERSION_LEN];    char softwareVersion[MAX_SOFTWARE_VERSION_LEN];//软件版本    char networkName[MAX_DEV_NETWORK_LEN];    int deviceType;    int devicePort;    NetworkState networkState;    int isAccountTrusted;} DeviceInfo;g_deviceInfo;

2.1.1、wifi事件

WifiEventTrigger()是一个回调函数,他的执行环境是线程CoapWifiEventThread(待会解释)。当连接到wifi后,CoapWifiEventThread就会调用WifiEventTrigger(),其参数para=1,表示连接到wifi。表示网络已连接,那么就可用开始软总线。

//WIFI事件回调 state=1:UPDATE_IP_EVENTvoid WifiEventTrigger(unsigned int para){    DeviceInfo *localDev = GetCommonDeviceInfo();    //para=state=1 连接上wifi    if (para) { //获取ip char wifiIp[MAX_DEV_IP_LEN] = {0}; CoapGetIp(wifiIp, MAX_DEV_IP_LEN, 0); if (strcmp(wifiIp, "0.0.0.0") == 0) {     return; } ret = memcpy_s(localDev->deviceIp, sizeof(localDev->deviceIp), wifiIp, sizeof(wifiIp));    } else { //清除ip,断开网络连接 ret = memset_s(localDev->deviceIp, sizeof(localDev->deviceIp), 0, sizeof(localDev->deviceIp));    }    //开启软总线    if (BusManager(para) != ERROR_SUCCESS) { return;    }    //初始化本地设备信息    if (CoapRegisterDeviceInfo() != ERROR_SUCCESS) { return;    }    //注册capablity 和 g_capabilityData 到nstackx     if (DoRegistService(COAP) != ERROR_SUCCESS) { return;    }}

2.1.2、coap服务器

coapInit()最终是调用CoapInitDiscovery() 来建立coap协议所需的资源:

  • udp server:用于监听coap报文
  • wifi消息队列:缓存wifi状态消息
  • CoapWifiEventThread:处理wifi消息队列
  • CreateCoapListenThread:处理coap报文交互逻辑
//初始化coap协议所需资源int CoapInitDiscovery(void){    //建立udp server 监听5684端口(coap协议默认端口)    int ret = CoapInitSocket();    //创建wifi消息队列    ret = CoapInitWifiEvent();    //创建 CoapWifiEventThread 线程    if (CreateMsgQueThread() != NSTACKX_EOK) { return NSTACKX_EFAILED;    }    //创建CoapReadHandle 线程    return CreateCoapListenThread();}

CoapWifiEventThread线程:其本质内容就是执行wifi事件回调函数。

//处理wifi队列的消息void CoapWifiEventThread(unsigned int uwParam1, unsigned int uwParam2, unsigned int uwParam3, unsigned int uwParam4){    g_wifiTaskStart = 1;    while (g_wifiTaskStart) { //读取队列消息的消息: handler(WifiEventTrigger) ret = ReadMsgQue(g_wifiQueueId, &handle, &readSize); if ((ret == 0) && (readSize == sizeof(AddressEventHandler))) {     if (handle.handler == NULL) {  continue;     }     //执行回调函数(WifiEventTrigger)     handle.handler(handle.state); }    }}

CoapReadHandle:读取udp server接收的数据,并处理数据。

static void CoapReadHandle(unsigned int uwParam1, unsigned int uwParam2, unsigned int uwParam3, unsigned int uwParam4){    //获取之间创建的udp server    int serverFd = GetCoapServerSocket();    while (g_terminalFlag) { FD_ZERO(&readSet); FD_SET(serverFd, &readSet); //读取udp server接收的数据 ret = select(serverFd + 1, &readSet, NULL, NULL, NULL); if (ret > 0) {     if (FD_ISSET(serverFd, &readSet)) {  //处理接收数据  HandleReadEvent(serverFd);     } } else {     SOFTBUS_PRINT("[DISCOVERY]ret:%d,error:%d\n", ret, errno); }    }}

处理udp server数据的代码:

//处理udp数据报事件static void HandleReadEvent(int fd){    int socketFd = fd;    unsigned char *recvBuffer = calloc(1, COAP_MAX_PDU_SIZE + 1);    ssize_t nRead;    //读取coap报文    nRead = CoapSocketRecv(socketFd, recvBuffer, COAP_MAX_PDU_SIZE);    COAP_Packet decodePacket;    (void)memset_s(&decodePacket, sizeof(COAP_Packet), 0, sizeof(COAP_Packet));    decodePacket.protocol = COAP_UDP;    //解析coap报文的数据,封装成decodePacket    COAP_SoftBusDecode(&decodePacket, recvBuffer, nRead);    //响应远程发现者    PostServiceDiscover(&decodePacket);    free(recvBuffer);}

响应的内容是什么?具体来看PostServiceDiscover():

从对端发来的coap报文中,可解析出对端的ip地址和url,然后将本地设备信息和对端地址组成coap报文,发送给对端

//给远程设备发送响应void PostServiceDiscover(const COAP_Packet *pkt){    char *remoteUrl = NULL;    //从pkt中,可获取对端设备的ip等信息,封装成deviceinfo    DeviceInfo deviceInfo;    (void)memset_s(&deviceInfo, sizeof(deviceInfo), 0, sizeof(deviceInfo));    //解析pkt->payload.buffer数据到deviceInfo    if (GetServiceDiscoverInfo(pkt->payload.buffer, pkt->payload.len, &deviceInfo, &remoteUrl) != NSTACKX_EOK) { return;    }    //获取对端的ip地址    char wifiIpAddr[NSTACKX_MAX_IP_STRING_LEN];    (void)memset_s(wifiIpAddr, sizeof(wifiIpAddr), 0, sizeof(wifiIpAddr));    (void)inet_ntop(AF_INET, &deviceInfo.netChannelInfo.wifiApInfo.ip, wifiIpAddr, sizeof(wifiIpAddr));    if (remoteUrl != NULL) { //利用deviceinfo,发送coap报文给对端 CoapResponseService(pkt, remoteUrl, wifiIpAddr); free(remoteUrl);    }}//发送CoapRequest到remoteIpstatic int CoapResponseService(const COAP_Packet *pkt, const char* remoteUrl, const char* remoteIp){    int ret;    //初始化CoapRequest    CoapRequest coapRequest;    coapRequest.remoteUrl = remoteUrl;  //资源地址    coapRequest.remoteIp = remoteIp;    //ip地址    //payload包含了本地设备的信息    char *payload = PrepareServiceDiscover();    //以下就是构建coapRequest    COAP_ReadWriteBuffer sndPktBuff = {0};    sndPktBuff.readWriteBuf = calloc(1, COAP_MAX_PDU_SIZE);    sndPktBuff.size = COAP_MAX_PDU_SIZE;    sndPktBuff.len = 0;    //根据pkt和ip构建coap报文sndPktBuff    ret = BuildSendPkt(pkt, remoteIp, payload, &sndPktBuff);    free(payload);    coapRequest.data = sndPktBuff.readWriteBuf;    coapRequest.dataLength = sndPktBuff.len;    //创建udp客户端并发送coap报文    ret = CoapSendRequest(&coapRequest);    free(sndPktBuff.readWriteBuf);    sndPktBuff.readWriteBuf = NULL;    return ret;}

payload的内容就是设备信息,其json格式如下:

  {    "deviceId":[device ID, string],    "deviceName":[device name, string],    "type": [device type, number],    "version":[hicom version, string],    "wlanIp":[WLAN IP address, string],    "capabilityBitmap":[bitmap, bitmap, bitmap, ...]    "coapUri":[coap uri for discover, string]   <-- optional. When present, means it's broadcast request.  }

对端在收到这个消息后,就可以会触发回调函数:该函数在dsoftbus中定义

void (*OnDeviceFound)(const DeviceInfo *device);

该函数的参数device中就包含了payload中的信息,这样对端就了解了局域网内有什么设备。

2.2、软总线

上一节的WifiEventTrigger()中,在连接到wifi后,会启动软总线,创建软总线运行所需的资源:

  • 回调函数OnConnectEvent:初始化认证相关的结构体
  • 回调函数OnDataEvent:认证数据的处理逻辑(详)
  • WaitProcess线程:读取g_listenFd,执行回调函数,处理软总线的事务
  • SelectSessionLoop线程:处理tcp session的事务
  • AuthManager:设备认证事务
int StartBus(void){//设置软总线的回调函数    g_baseLister.onConnectEvent = OnConnectEvent;    g_baseLister.onDataEvent = OnDataEvent;    //创建 tcp server、WaitProcess线程 用于执行回调函数    int authPort = StartListener(&g_baseLister, info->deviceIp);    //创建tcp server、SelectSessionLoop线程、用于实现session的回调    int sessionPort = StartSession(info->deviceIp);    //保存两个tcp server的端口    AuthMngInit(authPort, sessionPort);    g_busStartFlag = 1;}

2.2.1、SelectSessionLoop

SelectSessionLoop线程:监听所有session的数据,并处理这些数据。

session是一个建立在tcp传输上的概念,创建一个session的过程如下:

首先A创建一个tcp server,监听连接。B与A建立TCP连接,能够正常传输TCP数据。接着发送特定的TCP数据,建立session连接。所以这里涉及到了两个连接,一个是tcp层的,一个session层的连接。tcp 层的连接建立完成后可以初始化session结构体,其实现在ProcessConnection().Session层的连接在ProcessSesssionData()中完成。

static void SelectSessionLoop(TcpSessionMgr *tsm){    tsm->isSelectLoopRunning = true;    while (true) { fd_set readfds;//用于读取数据 fd_set exceptfds; //等待readfds的消息 int ret = select(maxFd + 1, &readfds, NULL, &exceptfds, NULL);     //处理数据     ProcessData(tsm, &readfds);    }    tsm->isSelectLoopRunning = false;}//处理session数据static void ProcessData(TcpSessionMgr *tsm, fd_set *rfds){    //listenFd的消息,则表示需要创建tcp session连接    if (FD_ISSET(tsm->listenFd, rfds)) { ProcessConnection(tsm); return;    }    //否则,是tcp session数据    ProcessSesssionData(tsm, rfds);}

ProcessConnection:完成tcp连接,并初始化session结构体,方便下一阶段建立session使用。

static void ProcessConnection(TcpSessionMgr *tsm){    //建立tcp 连接    int cfd = accept(tsm->listenFd, (struct sockaddr *)&addr, &addrLen);    //创建tcp session    TcpSession *session = CreateTcpSession();    //把authConn的deivceid复制到session    AuthConn* authConn = GetOnLineAuthConnByIp(inet_ntoa(addr.sin_addr));    if (authConn != NULL && strncpy_s(session->deviceId, MAX_DEV_ID_LEN, authConn->deviceId, strlen(authConn->deviceId)) != 0) { SOFTBUS_PRINT("[TRANS] Error on copy deviceId of session."); free(session); CloseSession(cfd); return;    }    //把tcp连接添加session    session->fd = cfd;    //把session给sessionmgr管理    int result = AddSession(tsm, session);    return;}

ProcessSesssionData:初始化完成session后,接收到session数据。有两种session数据类型,一种是请求建立session,一种是正常的session数据。

static void ProcessSesssionData(const TcpSessionMgr *tsm, const fd_set *rfds){    //遍历所有的tcp session,找到fd对应的session    for (int i = 0; i < MAX_SESSION_SUM_NUM; i++) { if (tsm->sessionMap_[i] != NULL && tsm->sessionMap_[i]->fd != -1 &&     FD_ISSET(tsm->sessionMap_[i]->fd, rfds) > 0) {     //处理对应session数据     if (!OnProcessDataAvailable(tsm->sessionMap_[i])) {  return;     } }    }}//处理tcp session的数据static bool OnProcessDataAvailable(TcpSession *session){    //name是softbus_Lite_unknown 说明是对方发起session连接请求    if (strcmp(session->sessionName, "softbus_Lite_unknown") == 0) { //处理session连接请求,响应请求,执行回调函数onSessionOpened bool isSuccess = HandleRequestMsg(session); if (!isSuccess) {     CloseSession(session->fd); } return isSuccess;    } else { //已经建立了session 正常接收数据 unsigned char* buf = calloc(1, RECIVED_BUFF_SIZE); SessionListenerMap *sessionListener = GetSessionListenerByName(session->sessionName,     strlen(session->sessionName)); if (sessionListener != NULL && sessionListener->listener != NULL) {     //读取session数据     int recvLen = TcpSessionRecv(session, (char *)buf, RECIVED_BUFF_SIZE, 0);     //执行session的回调函数,处理 接收数据     sessionListener->listener->onBytesReceived(session->fd, buf, recvLen);     free(buf);     return true; } free(buf);    }}

2.2.2、WaitProcess

WaitProcess线程,他的任务是监听g_listenFd,并处理软总线上的回调函数。

//等待建立socket,并回调成功建立static void WaitProcess(void){    while (1) {//等待g_listenFd 的数据 int ret = select(g_maxFd + 1, &readSet, NULL, &readSet, NULL); if (ret > 0) {      //处理g_listenFd的数据     if (!ProcessAuthData(g_listenFd, &readSet)) {  StopListener();  break;     } }    }}//处理softbus数据 建立socket 回调g_baseListerstatic bool ProcessAuthData(int listenFd, const fd_set *readSet){    //listenFd是否在readSet,即listenFd是否有数据    if (FD_ISSET(listenFd, readSet)) { struct sockaddr_in addrClient = {0}; socklen_t addrLen = sizeof(addrClient); //建立tcp连接 g_dataFd = accept(listenFd, (struct sockaddr *)(&addrClient), &addrLen); //更新g_dataFd RefreshMaxFd(g_dataFd); //执行回调函数: 连接成功 OnConnectEvent if (g_callback->onConnectEvent(g_dataFd, inet_ntoa(addrClient.sin_addr)) != 0) {     CloseAuthSessionFd(g_dataFd); }    }    //执行回调函数:数据接收 OnDataEvent    if (g_dataFd > 0 && FD_ISSET(g_dataFd, readSet)) { g_callback->onDataEvent(g_dataFd);    }    return true;}

2.2.3、OnConnectEvent

重要的结构体,负责认证的连接

typedef struct AuthConn {    int fd;    char authId[MAX_AUTH_ID_LEN];//?    char deviceId[MAX_DEV_ID_LEN];    char deviceIp[MAX_DEV_IP_LEN];    int busVersion;    int authPort;//软总线上的认证tcp端口    int sessionPort;//软总线上的session端口    int authState;    int onlineState;    DataBuffer db;} AuthConn;

软总线在收到连接事件后,回调OnDataEvent(),设置aconn对象的ip和fd。aconn会在OnDataEvent()中大放异彩

//将fd、ip赋值给对应的AuthConnvoid ProcessConnectEvent(int fd, const char *ip){    SOFTBUS_PRINT("[AUTH] ProcessConnectEvent fd = %d\n", fd);    if (fd < 0 || ip == NULL) { return;    }    //获取 aconn,若不为NULL,说明已经认证过了    AuthConn *aconn = FindAuthConnByFd(fd);    if (aconn != NULL) { CloseConn(aconn); return;    }//还未认证,设置aconn    aconn = calloc(1, sizeof(AuthConn));    //复制ip、fd给aconn    int ret = strcpy_s(aconn->deviceIp, sizeof(aconn->deviceIp), ip); aconn->fd = fd;    //把 aconn 添加到 g_fdMap 数组    ret = AddAuthConnToList(aconn);}

2.2.4、OnDataEvent

当软总线建立与设备的authconn后就可进行认证,具体的方式是:

//从tcp端口读取数据包,并解析void ProcessDataEvent(int fd){    //获取authconn    AuthConn *conn = FindAuthConnByFd(fd);    //申请buf    if (conn->db.buf == NULL) { conn->db.buf = (char *)malloc(DEFAULT_BUF_SIZE); (void)memset_s(conn->db.buf, DEFAULT_BUF_SIZE, 0, DEFAULT_BUF_SIZE); conn->db.size = DEFAULT_BUF_SIZE; conn->db.used = 0;    }    DataBuffer *db = &conn->db;    char *buf = db->buf;    int used = db->used;    int size = db->size;    //接收认证数据到buf    int rc = AuthConnRecv(fd, buf, used, size - used, 0);    used += rc;    //解析tcp包头,处理包内信息    int processed = ProcessPackets(conn, buf, size, used);    db->used = used;}

ProcessPackets:根据module参数对软总线的数据分支处理

//解析tcp包头,处理包内信息static int ProcessPackets(AuthConn *conn, const char *buf, int size, int used){    int processed = 0;    while (processed + PACKET_HEAD_SIZE < used) { //将buf首部数据转换成packet Packet *pkt = ParsePacketHead(buf, processed, used - processed, size); //有效数据长度 int len = pkt->dataLen; //处理了buf的首部数据  processed += PACKET_HEAD_SIZE; //处理payload数据 OnDataReceived(conn, pkt, buf + processed); processed += len; free(pkt); pkt = NULL;    }    return processed;}//分支处理对端发来的认证数据static void OnDataReceived(AuthConn *conn, const Packet *pkt, const char *data){    //module == MODULE_AUTH_SDK    if ((pkt->module > MODULE_HICHAIN) && (pkt->module <= MODULE_AUTH_SDK)) { //建立AuthSession,处理认证逻辑 AuthInterfaceOnDataReceived(conn, pkt->module, pkt->seq, data, pkt->dataLen); return;    }    cJSON *msg = DecryptMessage(pkt->module, data, pkt->dataLen);    //建立连接或完成认证    OnModuleMessageReceived(conn, pkt->module, pkt->flags, pkt->seq, msg);    cJSON_Delete(msg);    msg = NULL;}
AuthInterfaceOnDataReceived

完成设备认证,其过程是:对端设备发送数据给本地的安全子系统的设备认证模块,设备认证模块负责处理数据,判断是否通过认证。

这里数据传输的方式就是使用 就是session

module的定义

#define MODULE_NONE 0#define MODULE_TRUST_ENGINE 1    //可信类型,直接进行数据传输#define MODULE_HICHAIN 2#define MODULE_AUTH_SDK 3    //加密数据类型#define MODULE_HICHAIN_SYNC 4#define MODULE_CONNECTION 5//进行ip及设备认证#define MODULE_SESSION 6#define MODULE_SMART_COMM 7#define MODULE_AUTH_CHANNEL 8#define MODULE_AUTH_MSG 9
//建立认证session,处理认证逻辑void AuthInterfaceOnDataReceived(const AuthConn *conn, int module, long long seqId, const char *data, int dataLen){    //创建authsession数组,authsession是一个会话,负责认证逻辑    if (AuthSessionMapInit() != 0) { return;    }    //初始化指定auth session    AuthSession *auth = AuthGetAuthSessionBySeqId(seqId);    if (auth == NULL) { //获取失败,将conn添加到g_authSessionMap auth = AuthGetNewAuthSession(conn, seqId, g_authSessionId); ++g_authSessionId;    }    //对不同模组使用不同认证方式    switch (module) { case MODULE_AUTH_SDK:     //使用hichain处理auth数据     AuthProcessReceivedData(auth->sessionId, data, dataLen);     break;    }    return;}//调用安全子系统的设备认证模块,来完成对端设备的数据的认证static void AuthProcessReceivedData(uint32_t sessionId, const char *data, int dataLen){ if (g_hcHandle == NULL) { //初始化hichain,hichain是设备认证模块要使用的对象 if (AuthInitHiChain(sessionId) != 0) {     AuthDelAuthSessionBySessionId(sessionId);     return; }    }    struct uint8_buff request = {(uint8_t *)data, dataLen, dataLen};    //把数据传递给安全认证子系统,处理的结果会通过回调函数反馈    if (receive_data(g_hcHandle, &request) != HC_OK) { return;    }}
OnModuleMessageReceived

处理可信设备

//处理module消息static void OnModuleMessageReceived(AuthConn *conn, int module, int flags, long long seq, const cJSON *msg){    switch (module) { //可信类型,能直接进行数据传输 case MODULE_TRUST_ENGINE: {     if (((unsigned int)flags & FLAG_REPLY) == 0) {  //通过发送本地deviceid 使通道建立?  OnMsgOpenChannelReq(conn, seq, msg);     }     break; } //连接类型,需要进行ip及设备认证 case MODULE_CONNECTION: {     OnMessageReceived(conn, seq, msg);     break; }    }    return;}//验证设备的ip或deviceidvoid OnMessageReceived(AuthConn *conn, long long seq, const cJSON *msg){    cJSON *codeJson = cJSON_GetObjectItem(msg, "CODE");    int code = codeJson->valueint;    //回复对端    switch (code) { case CODE_VERIIFY_IP: {     OnVerifyIp(conn, seq, msg);     break; } case CODE_VERIFY_DEVID: {     OnVerifyDeviceId(conn, seq, msg);     break; }    }}

问题待解决

hichain的认证过程

hichain的认证目前没有找到文档,只能通过源码,猜测以下内容:初始化hichain所需要的对象,软总线作为一个媒介,在hichain和对端设备之间传递数据。

//初始化hichainstatic int AuthInitHiChain(uint32_t sessionId){    struct session_identity serverIdentity = { sessionId, {AUTH_DEFAULT_ID_LEN, AUTH_DEFAULT_ID}, {AUTH_DEFAULT_ID_LEN, AUTH_DEFAULT_ID}, 0    };    //定义设备认证回调函数,会在安全子系统中得到执行     struct hc_call_back hiChainCallback = { AuthOnTransmit,  //发送hichain的数据 AuthGetProtocolParams,  //获取会话id AuthSetSessionKey,      //保存hc_session_key AuthSetServiceResult,   //认证结果回调 AuthConfirmReceiveRequest    };    //获取hichain,HC_ACCESSORY表示本地是附属设备,收超级终端控制    g_hcHandle = get_instance(&serverIdentity, HC_ACCESSORY, &hiChainCallback);    return 0;}

tcp server 连接过程

OnModuleMessageReceived()函数处理的是什么逻辑?