赞
踩
本文简单介绍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可用来发送和接收数据。
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; }
向会话对端发送字节数据,实际上是调用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"}, };
即设备在局域网内发布上述的服务,这些服务就能被发现和调用。其本质就是将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、注册设备信息到softbus int 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;
WifiEventTrigger()是一个回调函数,他的执行环境是线程CoapWifiEventThread(待会解释)。当连接到wifi后,CoapWifiEventThread就会调用WifiEventTrigger(),其参数para=1,表示连接到wifi。表示网络已连接,那么就可用开始软总线。
//WIFI事件回调 state=1:UPDATE_IP_EVENT void 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; } }
coapInit()最终是调用CoapInitDiscovery() 来建立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到remoteIp static 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中的信息,这样对端就了解了局域网内有什么设备。
上一节的WifiEventTrigger()中,在连接到wifi后,会启动软总线,创建软总线运行所需的资源:
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;
}
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); } }
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_baseLister static 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; }
重要的结构体,负责认证的连接
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赋值给对应的AuthConn void 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); }
当软总线建立与设备的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; }
完成设备认证,其过程是:对端设备发送数据给本地的安全子系统的设备认证模块,设备认证模块负责处理数据,判断是否通过认证。
这里数据传输的方式就是使用 就是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; } }
处理可信设备
//处理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或deviceid void 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 static 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; }
OnModuleMessageReceived()函数处理的是什么逻辑?
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。