OpenHarmony分布式软总线流程分析v1.0丨2.开启软总线,建立连接 原创 精华
丨张明亮丨
发布于 2021-6-26 08:25
浏览
21收藏
更新时间:2021年6月26日 @亮子力
这次的软总线流程分析字数太多,上传了好几次都失败了。所以我分成了2个部分。
1.被发现端,发布服务
2.开启软总线,建立连接
完整版可以下载文末的pdf。
@toc
二、当接入网络,触发WifiEventTrigger(),开启软总线
Z:\harmony110\foundation\communication\softbus_lite\discovery\discovery_service\source\discovery_service.c
void WifiEventTrigger(unsigned int para)
{
DeviceInfo *localDev = GetCommonDeviceInfo();
if (localDev == NULL) {
return;
}
int ret;
if (para) {
char wifiIp[MAX_DEV_IP_LEN] = {0};
CoapGetIp(wifiIp, MAX_DEV_IP_LEN, 0); //参考1.获取本设备ip
if (strcmp(wifiIp, "0.0.0.0") == 0) {
SOFTBUS_PRINT("[DISCOVERY] WifiEventTrigger new event interupt.\n");
return;
}
ret = memcpy_s(localDev->deviceIp, sizeof(localDev->deviceIp), wifiIp, sizeof(wifiIp));
} else {
ret = memset_s(localDev->deviceIp, sizeof(localDev->deviceIp), 0, sizeof(localDev->deviceIp));
}
if (ret != ERROR_SUCCESS) {
return;
}
if (BusManager(para) != ERROR_SUCCESS) { //参考2.BusManager()启动软总线
SOFTBUS_PRINT("[DISCOVERY] WifiEventTrigger StartBusManager(%d) fail\n", para);
return;
}
if (CoapRegisterDeviceInfo() != ERROR_SUCCESS) {
SOFTBUS_PRINT("[DISCOVERY] WifiEventTrigger CoapRegisterDeviceInfo fail\n");
return;
}
if (DoRegistService(COAP) != ERROR_SUCCESS) {
SOFTBUS_PRINT("[DISCOVERY] WifiEventTrigger DoRegistService fail\n");
return;
}
}
1.获取本设备ip
Z:\harmony110\foundation\communication\softbus_lite\discovery\coap\source\coap_discover.c
//通过CoapGetIp()循环获取本地设备wifi连接后的IP地址,并放入到deviceInfo->deviceIp中。后续会使用。
void CoapGetIp(char *ip, int length, int finite)
{
if (ip == NULL || length != NSTACKX_MAX_IP_STRING_LEN) {
return;
}
g_queryIpFlag = 1;
int count = finite ? GET_IP_TIMES : GET_IP_INFINITE;
while (g_queryIpFlag) {
CoapGetWifiIp(ip, length);//获取ip方式根据内核不同,会有多个方式
if (CheckIpIsValid(ip, strlen(ip)) == 0) {
break;
}
if (count == 0) {
break;
}
count--;
usleep(TEN_MS); //#define TEN_MS (10 * 1000)//usleep 10ms,每次获取IP间隔10ms
}
return;
}
2.BusManager()启动软总线
Z:\harmony110\foundation\communication\softbus_lite\authmanager\source\bus_manager.c
int BusManager(unsigned int startFlag)
{
if (startFlag == 1) {
return StartBus();
} else {
return StopBus();
}
}
==============================================================================
int StartBus(void)
{
if (g_busStartFlag == 1) {
return 0;
}
DeviceInfo *info = GetCommonDeviceInfo();
if (info == NULL) {
return ERROR_FAIL;
}
g_baseLister.onConnectEvent = OnConnectEvent; //当存在新连接时调用此函数
g_baseLister.onDataEvent = OnDataEvent; //当存在新数据时调用此函数
//StartListener()函数负责为认证模块提供通道完成初始化
int authPort = StartListener(&g_baseLister, info->deviceIp); //参考:2.1.启动侦听
if (authPort < 0) {
SOFTBUS_PRINT("[AUTH] StartBus StartListener fail\n");
return ERROR_FAIL;
}
info->devicePort = authPort;
//StartSession()函数负责初始化业务的session管理
int sessionPort = StartSession(info->deviceIp); //参考:2.2.启动会话
if (sessionPort < 0) {
SOFTBUS_PRINT("[AUTH] StartBus StartSession fail\n");
StopListener();
return ERROR_FAIL;
}
AuthMngInit(authPort, sessionPort);
g_busStartFlag = 1;
SOFTBUS_PRINT("[AUTH] StartBus ok\n");
return 0;
}
==============================================================================
//回调函数的处理
//trans_service模块的使用者设置的回调函数将在存在新连接、和新数据时被调用
//比如认证模块通过以下函数完成认证动作:OnConnectEvent()函数中完成对新连接的处理, OnDataEvent()函数中完成对新数据的处理。
int OnConnectEvent(int fd, const char *ip)
ProcessConnectEvent(fd, ip);
return 0;
}
int OnDataEvent(int fd)
ProcessDataEvent(fd);
return 0;
}
2.1.启动监听,StartListener(),监听与发现端建立连接
StartListener()函数的底层存在对应不同版本平台的适配函数,这印证了鸿蒙OS各部分解耦的模块化设计思想,针对不同的硬件设备,组合成最适合该设备的OS。比如创建线程时采用了统一的static void WaitProcess(void)函数,而其内部封装了不同底层API的适配代码。
Z:\harmony110\foundation\communication\softbus_lite\trans_service\source\libdistbus\auth_conn_manager.c
//StartListener()函数负责为认证模块提供通道完成初始化
//该函数主要是创建了一个WaitProcess 的线程,该线程用于对g_maxFd 所代表的文件描述符利用select 函数进行监控,若返回值大于0,则调用ProcessAuthData 函数。该函数完成对建立的链接的数据进行收发,并对收到的数据进行处理的工作,两个处理事件的函数分别是onConnectEvent和onDataEvent,即前面注册的两个回调函数。其中onConnectEvent 函数主要是为新建立连接的设备创建AuthConnNode 类型的节点,并将其加入链表中;onDataEvent 函数是对AuthConnNode节点中的数据成员进行内存分配及对数据进行处理。
#if defined(__LITEOS_M__) || defined(__LITEOS_RISCV__)
int StartListener(BaseListener *callback, const char *ip) // *callback,回调函数
{
if (callback == NULL || ip == NULL) {
return -DBE_BAD_PARAM;
}
g_callback = callback;
//InitListenFd()函数完成监听TCP socket的创建和监听,其中IP地址和端口号由上层调用者指定。
int rc = InitListenFd(ip, SESSIONPORT); //
if (rc != DBE_SUCCESS) {
return -DBE_BAD_PARAM;
}
osThreadAttr_t attr;
attr.name = "trans_auth_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 = osPriorityNormal5; // LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO -> cmsis prio
//osThreadNew()在不同平台上会有不同的实现,在LITEOS_A和Linux平台上, osThreadNew()会调用兼容POSIX的pthread_create()完成线程的创建
g_uwTskLoID = osThreadNew((osThreadFunc_t)WaitProcess, NULL, &attr);//监听新连接和数据WaitProcess(void)
if (NULL == g_uwTskLoID) {
SOFTBUS_PRINT("[TRANS] StartListener task create fail\n");
return -1;
}
SOFTBUS_PRINT("[TRANS] StartListener ok\n");
return GetSockPort(g_listenFd);
}
==============================================================================
static void WaitProcess(void)//监听新连接和数据WaitProcess(void)
{
SOFTBUS_PRINT("[TRANS] WaitProcess begin\n");
fd_set readSet;
fd_set exceptfds;
while (1) {//WaitProcess()使用忙等方式,调用select()来监听listenFd和数据g_dataFd的信息,如果监听到有数据可读,则进入ProcessAuthData来处理。
FD_ZERO(&readSet);
FD_ZERO(&exceptfds);
FD_SET(g_listenFd, &readSet);
if (g_dataFd >= 0) {
FD_SET(g_dataFd, &readSet);
FD_SET(g_dataFd, &exceptfds);
}
int ret = select(g_maxFd + 1, &readSet, NULL, &exceptfds, NULL);//监听g_listenFd和数据g_dataFd的信息
if (ret > 0) {//如果监听到有数据可读,则进入ProcessAuthData来处理。
if (!ProcessAuthData(g_listenFd, &readSet)) {//【重要的监听】参考:
SOFTBUS_PRINT("[TRANS] WaitProcess ProcessAuthData fail\n");
StopListener();
break;
}
} else if (ret < 0) {//如果发现g_dataFd有异常信息,则将其关闭。其中g_dataFd是由listenFd监听到连接时创建的socket。
if (errno == EINTR || (g_dataFd > 0 && FD_ISSET(g_dataFd, &exceptfds))) {
SOFTBUS_PRINT("[TRANS] errno == EINTR or g_dataFd is in exceptfds set.\n");
CloseAuthSessionFd(g_dataFd);
continue;
}
SOFTBUS_PRINT("[TRANS] WaitProcess select fail, stop listener\n");
StopListener();
break;
}
}
}
2.2.启动会话,StartSession()
//StartSession()函数负责初始化业务的session管理
//StartSession 该函数只有一个参数,即const char *ip,也就是一个IP,和StartListener函数中的IP 是一样的。该函数是为全局变量g_sessionMgr 申请空间及初始化,然后根据所给的参数创建socket 文件描述符并监听,之后通过调用StartSelectLoop 函数创建SelectSessionLoop 的线程,该线程将socket 文件描述符加入集合,并调用select 函数进行监控,若函数的返回值大于0,则调用ProcessData 函数,该函数有两个分支,若socket 未创建session则为其创建session;若已创建session,则处理其数据部分
Z:\harmony110\foundation\communication\softbus_lite\authmanager\source\bus_manager.c
int StartSession(const char *ip)
{
int port = CreateTcpSessionMgr(true, ip);
return port;
}
==============================================================================
Z:\harmony110\foundation\communication\softbus_lite\trans_service\source\libdistbus\tcp_session_manager.c
int CreateTcpSessionMgr(bool asServer, const char* localIp)
{
if (localIp == NULL) {
return TRANS_FAILED;
}
if (InitTcpMgrLock() != 0 || GetTcpMgrLock() != 0) {
return TRANS_FAILED;
}
int ret = InitGSessionMgr();
if (ReleaseTcpMgrLock() != 0 || ret != 0) {
FreeSessionMgr();
return TRANS_FAILED;
}
g_sessionMgr->asServer = asServer;//该函数是为全局变量g_sessionMgr 申请空间及初始化
int listenFd = OpenTcpServer(localIp, DEFAULT_TRANS_PORT);
if (listenFd < 0) {
SOFTBUS_PRINT("[TRANS] CreateTcpSessionMgr OpenTcpServer fail\n");
FreeSessionMgr();
return TRANS_FAILED;
}
int rc = listen(listenFd, LISTEN_BACKLOG);//然后根据所给的参数创建socket 文件描述符并监听
if (rc != 0) {
SOFTBUS_PRINT("[TRANS] CreateTcpSessionMgr listen fail\n");
CloseSession(listenFd);
FreeSessionMgr();
return TRANS_FAILED;
}
g_sessionMgr->listenFd = listenFd;
signal(SIGPIPE, SIG_IGN);
if (StartSelectLoop(g_sessionMgr) != 0) {//之后通过调用StartSelectLoop 函数创建SelectSessionLoop 的线程
SOFTBUS_PRINT("[TRANS] CreateTcpSessionMgr StartSelectLoop fail\n");
CloseSession(listenFd);
FreeSessionMgr();
return TRANS_FAILED;
}
return GetSockPort(listenFd);
}
==============================================================================
Z:\harmony110\foundation\communication\softbus_lite\trans_service\source\libdistbus\tcp_session_manager.c
#if defined(__LITEOS_M__) || defined(__LITEOS_RISCV__)
int StartSelectLoop(TcpSessionMgr *tsm)
{
if (tsm == NULL) {
return TRANS_FAILED;
}
if (tsm->isSelectLoopRunning) {
return 0;
}
osThreadId_t sessionLoopTaskId;
osThreadAttr_t attr;
attr.name = "trans_session_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 = osPriorityNormal5; // LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO -> cmsis prio
//该线程将socket 文件描述符加入集合,并调用select 函数进行监控,
sessionLoopTaskId = osThreadNew((osThreadFunc_t)SelectSessionLoop, (void *)tsm, &attr);
if (NULL == sessionLoopTaskId) {
SOFTBUS_PRINT("[TRANS] StartSelectLoop TaskCreate fail\n");
return TRANS_FAILED;
}
return 0;
}
==============================================================================
Z:\harmony110\foundation\communication\softbus_lite\trans_service\source\libdistbus\tcp_session_manager.c
static void SelectSessionLoop(TcpSessionMgr *tsm)
{
if (tsm == NULL) {
return;
}
SOFTBUS_PRINT("[TRANS] SelectSessionLoop begin\n");
tsm->isSelectLoopRunning = true;
while (true) {
fd_set readfds;
fd_set exceptfds;
int maxFd = InitSelectList(tsm, &readfds, &exceptfds);
if (maxFd < 0) {
break;
}
errno = 0;
int ret = select(maxFd + 1, &readfds, NULL, &exceptfds, NULL);
if (ret < 0) {
SOFTBUS_PRINT("RemoveExceptSessionFd\r\n");
if (errno == EINTR || RemoveExceptSessionFd(tsm, &exceptfds) == 0) {
continue;
}
SOFTBUS_PRINT("[TRANS] SelectSessionLoop close all Session\n");
CloseAllSession(tsm);
break;
} else if (ret == 0) {
continue;
} else {//若函数的返回值大于0,则调用ProcessData 函数,
ProcessData(tsm, &readfds);
}
}
tsm->isSelectLoopRunning = false;
}
==============================================================================
Z:\harmony110\foundation\communication\softbus_lite\trans_service\source\libdistbus\tcp_session_manager.c
static void ProcessData(TcpSessionMgr *tsm, fd_set *rfds)
{
if (tsm == NULL || tsm->listenFd == -1) {
return;
}
//该函数有两个分支,若socket 未创建session则为其创建session;若已创建session,则处理其数据部分
if (FD_ISSET(tsm->listenFd, rfds)) {
ProcessConnection(tsm);
return;
}
ProcessSesssionData(tsm, rfds);
}
总结:
当软总线启动后,就会开始监听新连接,OnConnectEvent()函数中完成对新连接的处理, OnDataEvent()函数中完成对新数据的处理。
三、当发现端(比如手机)发送广播
当鸿蒙手机开启锁屏后,会在局域网内发送UDP广播,当开发板(服务端)检测到广播会调用下面的函数。
1.当检测到局域网内UDP广播包,HandleReadEvent()
Z:\harmony110\foundation\communication\softbus_lite\discovery\coap\source\coap_discover.c
static void HandleReadEvent(int fd)
{
int socketFd = fd;
unsigned char *recvBuffer = calloc(1, COAP_MAX_PDU_SIZE + 1);
if (recvBuffer == NULL) {
return;
}
ssize_t nRead;
nRead = CoapSocketRecv(socketFd, recvBuffer, COAP_MAX_PDU_SIZE);//这个函数读取socket的内容
if ((nRead == 0) || (nRead < 0 && errno != EAGAIN &&
errno != EWOULDBLOCK && errno != EINTR)) {
free(recvBuffer);
return;
}
COAP_Packet decodePacket;
(void)memset_s(&decodePacket, sizeof(COAP_Packet), 0, sizeof(COAP_Packet));
decodePacket.protocol = COAP_UDP;
COAP_SoftBusDecode(&decodePacket, recvBuffer, nRead);//然后调用COAP_SoftBusDecode来解码
PostServiceDiscover(&decodePacket);//解码后的报文由PostServiceDiscover来处理,参考下面解析
free(recvBuffer);
}
==============================================================================
void PostServiceDiscover(const COAP_Packet *pkt)
{
char *remoteUrl = NULL;
DeviceInfo deviceInfo;
if (pkt == NULL) {
return;
}
(void)memset_s(&deviceInfo, sizeof(deviceInfo), 0, sizeof(deviceInfo));
//关于GetServiceDiscoverInfo()这个解包函数暂时不深挖了,TODO
if (GetServiceDiscoverInfo(pkt->payload.buffer, pkt->payload.len, &deviceInfo, &remoteUrl) != NSTACKX_EOK) {
return;
}
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));
printf(">>>>>%s:%d\nremoteUrl:%s\nwifiIpAddr:%s\n",__FILE__,__LINE__,remoteUrl,wifiIpAddr);//添加打印调试
if (remoteUrl != NULL) {
CoapResponseService(pkt, remoteUrl, wifiIpAddr);//通过解析到的手机(发现端)的地址,应答服务
free(remoteUrl);
}
}
==============================================================================
static int CoapResponseService(const COAP_Packet *pkt, const char* remoteUrl, const char* remoteIp)
{
int ret;
CoapRequest coapRequest;
(void)memset_s(&coapRequest, sizeof(coapRequest), 0, sizeof(coapRequest));
coapRequest.remoteUrl = remoteUrl;
coapRequest.remoteIp = remoteIp;
char *payload = PrepareServiceDiscover();
if (payload == NULL) {
return NSTACKX_EFAILED;
}
printf(">>>>>%s:%d\npayload:%s\n",__FILE__,__LINE__,payload);//添加打印调试
COAP_ReadWriteBuffer sndPktBuff = {0};
sndPktBuff.readWriteBuf = calloc(1, COAP_MAX_PDU_SIZE);
if (sndPktBuff.readWriteBuf == NULL) {
free(payload);
return NSTACKX_EFAILED;
}
sndPktBuff.size = COAP_MAX_PDU_SIZE;
sndPktBuff.len = 0;
ret = BuildSendPkt(pkt, remoteIp, payload, &sndPktBuff);//构建要发回的包
free(payload);
if (ret != DISCOVERY_ERR_SUCCESS) {
free(sndPktBuff.readWriteBuf);
sndPktBuff.readWriteBuf = NULL;
return ret;
}
coapRequest.data = sndPktBuff.readWriteBuf;
coapRequest.dataLength = sndPktBuff.len;
ret = CoapSendRequest(&coapRequest); //发送
free(sndPktBuff.readWriteBuf);
sndPktBuff.readWriteBuf = NULL;
return ret;
}
2.当检测到新连接,ProcessAuthData()
Z:\harmony110\foundation\communication\softbus_lite\trans_service\source\libdistbus\auth_conn_manager.c:85
//无论是新连接请求,还是已有连接中有数据到来,均会进入本函数。
static bool ProcessAuthData(int listenFd, const fd_set *readSet)
{
if (readSet == NULL || g_callback == NULL || g_callback->onConnectEvent == NULL ||
g_callback->onDataEvent == NULL) {
return false;
}
if (FD_ISSET(listenFd, readSet)) {//判断是否是listenFd上存在消息
struct sockaddr_in addrClient = {0};
socklen_t addrLen = sizeof(addrClient);
//如果是,则说明当前存在新的连接,这时调用accept()完成链接创建,新创建的socket的fd被存储在g_dataFd中,
g_dataFd = accept(listenFd, (struct sockaddr *)(&addrClient), &addrLen);
if (g_dataFd < 0) {
CloseAuthSessionFd(listenFd);
return false;
}
RefreshMaxFd(g_dataFd);
//同时调用g_callback->onConnectEvent通知认证模块有新的连接事件发生,并将新创建的fd和client的IP地址告知认证模块。
//与此同时,创建g_dataFd时候需要刷新g_maxFd,以保证在WaitProcess()中的下一次select()操作时中,会监听到g_dataFd上的事件。
if (g_callback->onConnectEvent(g_dataFd, inet_ntoa(addrClient.sin_addr)) != 0) { //参考下面解析OnConnectEvent()
CloseAuthSessionFd(g_dataFd);
}
}
//如果FD_ISSET()判断出g_dataFd上存在消息,则说明已完成握手的连接向本节点发送了数据,
if (g_dataFd > 0 && FD_ISSET(g_dataFd, readSet)) { //参考下面解析OnDataEvent()
g_callback->onDataEvent(g_dataFd);//这时函数回调g_callback->onDataEvent(),把控制权返回给调用者,以处理接收到的数据。
}
return true;
}
==============================================================================
Z:\harmony110\foundation\communication\softbus_lite\authmanager\source\bus_manager.c
int OnConnectEvent(int fd, const char *ip)
{
ProcessConnectEvent(fd, ip); //2.1当建立新连接
return 0;
}
int OnDataEvent(int fd)
{
ProcessDataEvent(fd); //2.2当接收到新数据
return 0;
}
2.1当建立新连接,OnConnectEvent()
Z:\harmony110\foundation\communication\softbus_lite\authmanager\source\wifi_auth_manager.c:192行
void ProcessConnectEvent(int fd, const char *ip)
{
SOFTBUS_PRINT("[AUTH] ProcessConnectEvent fd = %d\n", fd);
AuthConn *aconn = FindAuthConnByFd(fd); //通过fd查找验证连接
aconn = calloc(1, sizeof(AuthConn)); //? 系统声明吗?
int ret = strcpy_s(aconn->deviceIp, sizeof(aconn->deviceIp), ip);//字符串复制函数
aconn->fd = fd;
ret = AddAuthConnToList(aconn);//添加认证连接到列表
}
Z:\harmony110\foundation\communication\softbus_lite\authmanager\source\wifi_auth_manager.c:554
这个函数被调用3次??
数据事件进程
void ProcessDataEvent(int fd)
{
SOFTBUS_PRINT("[AUTH] ProcessDataEvent fd = %d\n", fd);
AuthConn *conn = FindAuthConnByFd(fd); //通过fd查找验证连接
if (conn->db.buf == NULL) {
conn->db.buf = (char *)malloc(DEFAULT_BUF_SIZE);
if (conn->db.buf == NULL) {
return;
}
(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;
int rc = AuthConnRecv(fd, buf, used, size - used, 0);
if (rc == 0) {
return;
} else if (rc < 0) {
CloseConn(conn);
return;
}
used += rc;
int processed = ProcessPackets(conn, buf, size, used); //参考下面解析1
if (processed > 0) {
used -= processed;
if (used != 0) {
if (memmove_s(buf, processed, buf, used) != EOK) {
CloseConn(conn);
return;
}
}
} else if (processed < 0) {
CloseConn(conn);
return;
}
db->used = used;
SOFTBUS_PRINT("[AUTH] ProcessDataEvent ok\n");
}
1.\Z:\harmony110\foundation\communication\softbus_lite\authmanager\source\wifi_auth_manager.c:527行
static int ProcessPackets(AuthConn *conn, const char *buf, int size, int used)
{
int processed = 0;
while (processed + PACKET_HEAD_SIZE < used) {
Packet *pkt = ParsePacketHead(buf, processed, used - processed, size);//参考下面解析1
int len = pkt->dataLen;//将解析完包的大小,赋值给len
processed += PACKET_HEAD_SIZE;//+24
OnDataReceived(conn, pkt, buf + processed);//参考下面解析2
processed += len;
free(pkt);
pkt = NULL;
}
return processed;
}
1.\Z:\harmony110\foundation\communication\softbus_lite\authmanager\source\wifi_auth_manager.c:485行
//解析包头,这个函数返回一个packet的结构体
static Packet *ParsePacketHead(const char *buf, int offset, int len, int size)
{
unsigned int identifier = GetIntFromBuf(buf, offset); //1.从buf获取识别码
offset += DEFAULT_INT_LEN; //将偏移量+4
int module = GetIntFromBuf(buf, offset);//2.从buf获取module
offset += DEFAULT_INT_LEN;//将偏移量+4
long long seq = 0;
if (GetLongFromBuf(buf, offset, &seq) != 0) {//3.从buf获取序列号
return NULL;
}
offset += DEFAULT_LONG_LEN;//将偏移量+4
int flags = GetIntFromBuf(buf, offset);//4.从buf获取标志位
offset += DEFAULT_INT_LEN;//将偏移量+4
int dataLen = GetIntFromBuf(buf, offset);//5.从buf获取数据长度
SOFTBUS_PRINT("[AUTH] ParsePacketHead module=%d, seq=%lld, flags=%d, datalen=%d\n", module, seq, flags, dataLen);
Packet *packet = (Packet *)malloc(sizeof(Packet));
packet->module = module;
packet->seq = seq;
packet->flags = flags;
packet->dataLen = dataLen;
return packet;
}
2.\Z:\harmony110\foundation\communication\softbus_lite\authmanager\source\wifi_auth_manager.c:446行
static void OnDataReceived(AuthConn *conn, const Packet *pkt, const char *data)
{
SOFTBUS_PRINT("[AUTH] OnDataReceived\n"); //数据接收
if ((pkt->module > MODULE_HICHAIN) && (pkt->module <= MODULE_AUTH_SDK)) {
//接收数据的认证接口函数,参考解析1
AuthInterfaceOnDataReceived(conn, pkt->module, pkt->seq, data, pkt->dataLen);
return;
}
cJSON *msg = DecryptMessage(pkt->module, data, pkt->dataLen);
if (msg == NULL) {
SOFTBUS_PRINT("[AUTH] OnDataReceived DecryptMessage fail\n");
return;
}
OnModuleMessageReceived(conn, pkt->module, pkt->flags, pkt->seq, msg);
cJSON_Delete(msg);
msg = NULL;
}
Z:\harmony110\foundation\communication\softbus_lite\authmanager\source\auth_interface.c
void AuthInterfaceOnDataReceived(const AuthConn *conn, int module, long long seqId, const char *data, int dataLen)
{
SOFTBUS_PRINT("[AUTH] AuthInterfaceOnDataReceived begin\n");
if (AuthSessionMapInit() != 0) { //认证会话初始化
return;
}
AuthSession *auth = AuthGetAuthSessionBySeqId(seqId);//身份验证-通过序列ID获取验证会话
if (auth == NULL) {
auth = AuthGetNewAuthSession(conn, seqId, g_authSessionId);//身份验证-获取新的验证会话
if (auth == NULL) {
return;
}
++g_authSessionId;
}
switch (module) {
case MODULE_AUTH_SDK:
AuthProcessReceivedData(auth->sessionId, data, dataLen);//身份验证线程接收数据
break;
default:
break;
}
return;
}
2.2当接收到新数据,OnDataEvent()
Z:\harmony110\foundation\communication\softbus_lite\authmanager\source\wifi_auth_manager.c
void ProcessDataEvent(int fd)
{
SOFTBUS_PRINT("[AUTH] ProcessDataEvent fd = %d\n", fd);
AuthConn *conn = FindAuthConnByFd(fd);
if (conn == NULL) {
SOFTBUS_PRINT("ProcessDataEvent get authConn fail\n");
return;
}
if (conn->db.buf == NULL) {
conn->db.buf = (char *)malloc(DEFAULT_BUF_SIZE);
if (conn->db.buf == NULL) {
return;
}
(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;
printf(">>>>>%s:%d\nbuf:%s\n",__FILE__,__LINE__,buf);
int rc = AuthConnRecv(fd, buf, used, size - used, 0);//认证连接的返回信息
if (rc == 0) {
return;
} else if (rc < 0) {
CloseConn(conn);
return;
}
used += rc;
int processed = ProcessPackets(conn, buf, size, used);//对收到的包处理
if (processed > 0) {
used -= processed;
if (used != 0) {
if (memmove_s(buf, processed, buf, used) != EOK) {
CloseConn(conn);
return;
}
}
} else if (processed < 0) {
CloseConn(conn);
return;
}
db->used = used;
SOFTBUS_PRINT("[AUTH] ProcessDataEvent ok\n");
}
==============================================================================
Z:\harmony110\foundation\communication\softbus_lite\authmanager\source\auth_conn.c
int AuthConnRecv(int fd, char *buf, int offset, int count, int timeout)
{
if ((buf == NULL) || (offset < 0) || (count <= 0) || (offset + count <= 0)) {
return -1;
}
return TcpRecvData(fd, buf + offset, count, timeout);
}
==============================================================================
Z:\harmony110\foundation\communication\softbus_lite\trans_service\source\utils\tcp_socket.c
int TcpRecvData(int fd, char *buf, int len, int timeout)
{
return TcpRecvMessages(fd, buf, len, timeout, 0);
}
==============================================================================
Z:\harmony110\foundation\communication\softbus_lite\trans_service\source\utils\tcp_socket.c
static int32_t TcpRecvMessages(int fd, char *buf, uint32_t len, int timeout, int flags)
{printf(">>>>>%s:%d:%s()\n",__FILE__,__LINE__,__FUNCTION__);
if (fd < 0 || buf == NULL || len == 0 || timeout < 0) {
return -1;
}
printf(">>>>>%s:%d\nfd:%d,len:%d,flags:%d\nTcpRecvMessages:buf:%s\n",__FILE__,__LINE__,fd,len,flags,buf);
errno = 0;
int32_t rc = recv(fd, buf, len, flags);
printf(">>>>>%s:%d\nfd:%d,len:%d,flags:%d,rc:%d\nTcpRecvMessages:buf:%s\n",__FILE__,__LINE__,fd,len,flags,rc,buf);
if ((rc == -1) && (errno == EAGAIN)) {
rc = 0;
} else if (rc <= 0) {
rc = -1;//rc = -1; //这里rc = -1,程序在这里跳出了,但是却找不到int32_t rc = recv(fd, buf, len, flags);的来源
}
return rc;
}
//通过添加2条打印信息发现,经过recv(fd, buf, len, flags)之后,buf有了数据,这数据来自手机端,并加密了。关于recv()打开下面文件
//Z:\harmony110\device\hisilicon\hispark_pegasus\sdk_liteos\third_party\lwip_sack\include\lwip\sockets.h:1589
//在函数的描述里可以看做,这里的recv()是作为API提供的,所以只能挖到这里了。
auth.设备认证机制
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型数据的接收函数】
reference:
©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
分类
OpenHarmony分布式软总线流程分析v1.0.pdf 634.37K 965次下载
已于2021-6-27 19:42:20修改
赞
14
收藏 21
回复
相关推荐
膜拜研究底层的大佬。看了一下代码,好像是C代码比较多,C++的输出符比较少。所以openharmony底层是C吗🤔
嗯 基本都是C实现的😄
我的菜~
另,请教一下,有没有让华为手机直接与Hi3516/Hi3861开发板进行交互的办法?
我本地的Hi3516/Hi3861开发板,publish服务之后,华为手机打开超级终端搜索设备时,开发板都能收到广播信息:
#coap_listen_task#:: HandleReadEvent(UDP ServerSocket Event), serverFd[0]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[coap_discover] HandleReadEvent Begin:
HandleReadEvent [3-1] CoapSocketRecv() 391 Bytes to recvBuffer
HandleReadEvent [3-2] COAP_SoftBusDecode(recvBuffer to decodePacket): COAP_UDP
HandleReadEvent [3-3] PostServiceDiscover(decodePacket): ResponseService
decodePacket:
protocol[COAP_UDP]
token [0:(null)]
payload [354:{"deviceId":"{\"UDID\":\"E36AD77903F.............02983\"}","devicename":"HUAWEI Mate 40E","hicomversion":"3.1.0.0","mode":1,"deviceHash":"285...........3123","serviceData":"port:41215","extendServiceDat
[coap_discover] HandleReadEvent End.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
我不懂APP上的开发,所以是直接在系统服务层上搞的,不知道怎么响应发现端的广播。
我和你想法一样,最后发现要连接华为手机的软总线需要认证。
有个recv()函数是作为API提供的,而这里获取不到,就没法接入,或许这以后是商业部分。
那岂不是连不上了
连接成功了吗?
可以连接,但是认证失败。
如果是华为的开发板是不是会省去认证这个环节,好像华为自己的开发板是不需要认证这一层程序的。
是在Hi3516和Hi3861上测试的
膜拜大佬,请教个问题,现在2.0里面的dsoftbus和softbus_lite的区别是什么?是不是dsoftbus是发现端的代码,而softbus_lite是被发现端(轻量级设备)的代码?
那要自己编译一个rom才能构建一个完整iot网络?
大神有在openharmony3.0上试看看吗?
softbus_lite应该是临时的,后面的能力会收编进dsoftbus中