当前位置: 首页 > 工具软件 > AuthManager > 使用案例 >

OpenHarmony源码分析之分布式软总线:authmanager模块(1)/设备认证连接管理

田玉韵
2023-12-01

一、 概述

authmanager模块是鸿蒙为设备提供认证机制的模块。模块内的主要处理过程包括报文的接收、解密、再次封装、加密、发送的步骤。本文重点介绍当有设备发起身份认证连接请求时,系统是如何管理的。处理过程主要集中在wifi_auth_manager.c文件中。

二、 源码分析

  1. 当有设备发起连接请求时,首先在trans_service模块建立socket连接,主要在函数 ProcessAuthData() 中实现:
/*
函数功能: 处理listenFd的事件调用accept建立连接生成通信描述符g_dataFd,或者处理g_dataFd的通信事件
函数参数:监听描述符listenFd,可读描述符集合
函数返回值:成功返回true,失败返回false
详细:
*/
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;
    }
	//如果有设备发起连接,响应listenFd事件,accept建立socket连接,然后调用回调函数onConnectEvent处理连接事件
    if (FD_ISSET(listenFd, readSet)) {
        struct sockaddr_in addrClient = {0};
        socklen_t addrLen = sizeof(addrClient);
		//建立socket连接
        g_dataFd = accept(listenFd, (struct sockaddr *)(&addrClient), &addrLen);
        if (g_dataFd < 0) {//accept函数执行出错
            CloseAuthSessionFd(listenFd);
            return false;
        }
        //更新最大描述符值,因为后续需要为select函数提供最大描述符值,select函数需要获得监听集合中所有文件描述符的范围
        RefreshMaxFd(g_dataFd);
        //响应新连接事件
        if (g_callback->onConnectEvent(g_dataFd, inet_ntoa(addrClient.sin_addr)) != 0) {
            CloseAuthSessionFd(g_dataFd);
        }
    }
	//如果接收到设备发送的可读数据,响应g_dataFd的事件,调用回调函数onDataEvent处理数据传输事件
    if (g_dataFd > 0 && FD_ISSET(g_dataFd, readSet)) {
        g_callback->onDataEvent(g_dataFd);//响应通信新数据事件
    }

    return true;
}

  1. 为处理新连接,调用 onConnectEvent() 函数,在该函数中又调用了 ProcessConnectEvent() 函数,此函数才是真正的处理连接函数:
/*
函数功能:处理设备建立新socket连接事件
函数参数:
    fd:通信fd
    ip:请求连接的设备IP地址字符串
函数返回值:0
详细:
*/
int OnConnectEvent(int fd, const char *ip)
{
    ProcessConnectEvent(fd, ip);//处理建立新socket连接事件
    return 0;
}

/*
函数功能:处理设备建立新socket连接事件
函数参数:
    fd:用于通信的套接字fd
    ip:请求连接的设备IP地址字符串
函数返回值:无
详细:
*/
void ProcessConnectEvent(int fd, const char *ip)
{
    SOFTBUS_PRINT("[AUTH] ProcessConnectEvent fd = %d\n", fd);
    if (fd < 0 || ip == NULL) {
        return;
    }

    AuthConn *aconn = FindAuthConnByFd(fd);//通过fd查找认证连接链表中是否已存在该设备
    if (aconn != NULL) {
        CloseConn(aconn);
        return;
    }

    //若不存在,则添加到设备认证连接链表中
    aconn = calloc(1, sizeof(AuthConn));//新建一个待认证设备连接信息体
    if (aconn == NULL) {
        return;
    }

    int ret = strcpy_s(aconn->deviceIp, sizeof(aconn->deviceIp), ip);//赋值设备IP
    if (ret != EOK) {
        free(aconn);
        aconn = NULL;
        return;
    }
    aconn->fd = fd;//赋值与该设备通信的套接字描述符

    ret = AddAuthConnToList(aconn);//将aconn连接添加到已建立socket连接设备链表中
    if (ret != 0) {
        AuthConnClose(aconn);
        free(aconn);
        aconn = NULL;
        return;
    }

    SOFTBUS_PRINT("[AUTH] ProcessConnectEvent ok\n");
}
  1. 在函数 ProcessConnectEvent() 中,首先判断在全局认证设备链表中是否已存在该设备:
/*
函数功能:查找该连接的套接字fd是否已在设备链表中
函数参数:
    fd:建立连接的套接字fd
函数返回值:
    若该设备已存在则返回设备连接信息,若不存在则返回NULL
详细:
*/
static AuthConn* FindAuthConnByFd(int fd)
{
    if (g_fdMap == NULL) {
        return NULL;
    }

    AuthConnNode *node = NULL;
    List *pos = NULL;
    List *tmp = NULL;
	//遍历g_fdMap链表,该链表只存储认证连接设备节点地址
    LIST_FOR_EACH_SAFE(pos, tmp, g_fdMap) {
        node = (AuthConnNode*)pos;
        if (node->aconn == NULL) {
            continue;
        }
        if (node->aconn->fd == fd) {//若该设备已存在,则返回该设备的连接信息
            return node->aconn;
        }
    }

    return NULL;
}
  1. 若该设备不存在,则将其添加到设备认证连接链表中:
/*
函数功能:将当前已建立连接设备信息添加到已建立连接设备链表中
函数参数:
    aconn:当前连接的设备连接信息结构体地址
函数返回值:
    成功:返回0
    失败:返回-1
详细:
*/
static int AddAuthConnToList(AuthConn *aconn)
{
    if (aconn == NULL) {
        return -1;
    }
    if (g_fdMap == NULL) {//如果认证连接链表未初始化,就申请空间并初始化
        g_fdMap = calloc(1, sizeof(List));
        if (g_fdMap == NULL) {
            return -1;
        }
        ListInitHead(g_fdMap);//初始化已建立连接设备的双向链表头指针
    }

    if (ListLength(g_fdMap) >= AUTH_CONN_MAX_NUM) {//不允许超过最大连接设备数量32
        return -1;
    }
    AuthConnNode *node = calloc(1, sizeof(AuthConnNode));//申请设备节点内存
    if (node == NULL) {
        return -1;
    }

    node->aconn = aconn;
    ListInsertTail(g_fdMap, &node->head);//将新节点插入到链表末尾

    SOFTBUS_PRINT("[AUTH] AddAuthConnToList add new node(%d) ok\n", aconn->fd);
    return 0;
}

void ListInitHead(List *head)//初始化头指针
{
    head->next = head;
    head->prev = head;
}

/*
函数功能:将新增节点插入双向链表末尾
函数参数:head      链表头指针;node    新增节点指针
函数返回值:无
详细:
*/
void ListInsertTail(List *head, List *node)//将新增节点插入双向链表末尾
{
    node->prev = head->prev;
    node->prev->next = node;
    node->next = head;
    head->prev = node;
}
  1. 本模块涉及的关键数据结构:
/*用于管理连接设备的双向链表结构*/
typedef struct List {//双向链表
    struct List *prev;
    struct List *next;
} List;

static List *g_fdMap = NULL;//全局已建立连接设备双向链表头指针

/*AuthConn结构体用于保存已建立socket连接的身份认证设备的基本信息以及状态信息*/
typedef struct AuthConn {
    int fd;//通信套接字描述符
    char authId[MAX_AUTH_ID_LEN];//身份认证id
    char deviceId[MAX_DEV_ID_LEN];//设备id
    char deviceIp[MAX_DEV_IP_LEN];//设备IP
    int busVersion;//总线版本
    int authPort;//认证通道端口
    int sessionPort;//会话通道端口
    int authState;//认证状态
    int onlineState;//设备在线状态
    DataBuffer db;//数据缓冲区
} AuthConn;

/*设备身份认证连接节点*/
typedef struct AuthConnNode {
    List head;//头指针
    AuthConn *aconn;//设备连接信息
} AuthConnNode;

至此,设备发起新连接的处理结束。

 类似资料: