栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

软总线源码分析7:认证模块

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

软总线源码分析7:认证模块

根据上一章节对发现模块的分析,我们知道当发现了外部设备后,InnerDeviceFound会被调用,InnerDeviceFound函数会根据infoNode是否为内部节点,调用回调函数。

回想第4章节我们介绍组网模块的时候,组网会调用EnableCoapDisc函数将本地服务发布后,主动发现外部服务,EnableCoapDisc的源码如下:

static int32_t EnableCoapDisc(void)
{
    LOG_INFO("EnableCoapDisc begin");
    int32_t ret = DiscSetDiscoverCallback(MODULE_LNN, &g_discCb);
    if (ret != SOFTBUS_OK) {
        LOG_ERR("DiscSetDiscoverCallback error!");
        return SOFTBUS_ERR;
    }
    PublishInnerInfo publishInfo = {
        .publishId = LNN_PUBLISH_ID,
        .medium = COAP,
        .freq = HIGH,
        .capability = LNN_DISC_CAPABILITY,
        .capabilityData = (unsigned char *)LNN_DISC_CAPABILITY,
        .dataLen = strlen(LNN_DISC_CAPABILITY) + 1,
    };
    LOG_INFO("DiscStartScan!");
    ret = DiscStartScan(MODULE_LNN, &publishInfo);
    if (ret != SOFTBUS_OK) {
        LOG_ERR("DiscStartScan fail!");
        return SOFTBUS_ERR;
    }

    SubscribeInnerInfo subscribeInfo = {
        .subscribeId = LNN_SUBSCRIBE_ID,
        .medium = COAP,
        .freq = HIGH,
        .isSameAccount = false,
        .isWakeRemote = false,
        .capability = LNN_DISC_CAPABILITY,
        .capabilityData = (unsigned char *)LNN_DISC_CAPABILITY,
        .dataLen = strlen(LNN_DISC_CAPABILITY) + 1,
    };
    LOG_INFO("DiscStartAdvertise!");
    ret = DiscStartAdvertise(MODULE_LNN, &subscribeInfo);
    if (ret != SOFTBUS_OK) {
        LOG_ERR("DiscStartAdvertise fail!");
        return SOFTBUS_ERR;
    }
    return SOFTBUS_OK;
}

我们主要关心该函数的第一行,其将g_discCb挂载到本地,具体调用链不展开,总之在组网场景下,当发现外部设备后,InnerDeviceFound函数会调用g_discCb的OnDeviceFound函数指针进行处理,其函数名为DeviceFound,源码如下:

static void DeviceFound(const DeviceInfo *device)
{
    ConnectionAddr *para = NULL;
    if (device == NULL) {
        LOG_ERR("DeviceFound error!");
        return;
    }
    LOG_INFO("DeviceFound! type = %d", g_status.type);
    para = (ConnectionAddr *)SoftBusCalloc(sizeof(ConnectionAddr));
    if (para == NULL) {
        LOG_ERR("malloc init message fail");
        return;
    }
    para->type = g_status.type;
    para->info.ip.port = device->addr[0].port;
    if (strncpy_s(para->info.ip.ip, IP_STR_MAX_LEN, device->addr[0].addr, strlen(device->addr[0].addr)) != EOK) {
        LOG_ERR("STR ERROR!");
        SoftBusFree(para);
        return;
    }

    if (g_status.fsm != NULL) {
        LOG_INFO("PostMessageToFsm!");
        (void)LnnFsmRemoveMessage(g_status.fsm, FSM_MSG_TYPE_DISCOVERY_TIMEOUT);
        if (LnnFsmPostMessage(g_status.fsm, FSM_MSG_TYPE_JOIN_LNN, para) != SOFTBUS_OK) {
            LOG_ERR("LnnFsmPostMessage FSM_MSG_TYPE_JOIN_LNN error!");
            SoftBusFree(para);
        }
    } else {
        LOG_ERR("DeviceFound don't post to fsm!");
        SoftBusFree(para);
    }
    return;
}

该函数首先根据发现的设备信息,构造para地址信息,然后移除掉给状态机设置的超时定时器,然后向状态机提交FSM_MSG_TYPE_JOIN_LNN消息。

此时,该设备即向对端设备请求认证,这种场景下我们成本地发送认证消息的设备为客户端,对端接收认证消息的设备为服务端。

发送认证请求

状态机的机制已经在之前的章节介绍过了,因为当前状态机还在初始AUTH_INDEX状态下,因此该消息触发状态机的OnJoinLNNInAuth的函数。其源码如下:

static int32_t OnJoinLNNInAuth(ConnectionAddr *addr)
{
    int32_t rc;
    ConnInfo *connInfo = &g_netBuilder.connInfo;
    ConnectOption option;

    if (addr == NULL) {
        return SOFTBUS_INVALID_PARAM;
    }
    if (ConvertAddrToOption(addr, &option) == false) {
        SoftBusFree(addr);
        return SOFTBUS_ERR;
    }

    if ((connInfo->flag & (CONN_INFO_FLAG_JOINING_ACTIVE |
        CONN_INFO_FLAG_JOINING_PASSIVE)) != 0) {
        if (LnnIsSameConnectionAddr(addr, &connInfo->addr) == true) {
            LOG_INFO("addr is same, waiting...");
            SoftBusFree(addr);
            return SOFTBUS_OK;
        }
        LOG_ERR("previous request is ongoing, reject it");
        LnnNotifyJoinResult(addr, NULL, SOFTBUS_ERR);
        SoftBusFree(addr);
        return SOFTBUS_OK;
    }
    LOG_INFO("begin a new join request");
    connInfo->addr = *addr;
    connInfo->flag |= CONN_INFO_FLAG_JOINING_ACTIVE;
    (void)AuthVerifyInit();
    LOG_INFO("hichain init ok....");
    rc = AuthVerifyDevice(LNN, &option);
    if (rc != SOFTBUS_OK) {
        CompleteJoinLNN(NULL, SOFTBUS_ERR);
        (void)AuthVerifyDeinit();
    } else {
        LnnFsmPostMessageDelay(&g_netBuilder.fsm, FSM_MSG_TYPE_JOIN_LNN_TIMEOUT,
            NULL, JOIN_LNN_TIMEOUT_LEN);
    }
    SoftBusFree(addr);
    LOG_INFO("rc = %d", rc);
    return rc;
}

OnJoinLNNInAuth首先将Addr转为Option,然后判断当前系统是否正在进行组网过程,如果是则直接返回。如果不是,则首先调用AuthVerifyInit初始化认证工作,然后调用AuthVerifyDevice进行认证处理,最后调用LnnFsmPostMessageDelay启动15S超时定时器。

认证处理初始化

AuthVerifyInit的源码如下:

int32_t AuthVerifyInit(void)
{
    if (HichainServiceInit() != SOFTBUS_OK) {
        LOG_ERR("HichainServiceInit failed");
        return SOFTBUS_ERR;
    }
    return SOFTBUS_OK;
}

该函数即调用了HichainServiceInit,其源码如下:

static int32_t HichainServiceInit(void)
{
    if (InitDeviceAuthService() != 0) {
        LOG_ERR("auth InitDeviceAuthService failed");
        return SOFTBUS_ERR;
    }
    g_hichainGaInstance = GetGaInstance();
    if (g_hichainGaInstance == NULL) {
        LOG_ERR("auth GetGaInstance failed");
        return SOFTBUS_ERR;
    }
    g_hichainGmInstance = GetGmInstance();
    if (g_hichainGmInstance == NULL) {
        LOG_ERR("auth GetGmInstance failed");
        return SOFTBUS_ERR;
    }
    (void)memset_s(&g_hichainCallback, sizeof(DeviceAuthCallback), 0, sizeof(DeviceAuthCallback));
    g_hichainCallback.onTransmit = AuthOnTransmit;
    g_hichainCallback.onSessionKeyReturned = AuthOnSessionKeyReturned;
    g_hichainCallback.onFinish = AuthOnFinish;
    g_hichainCallback.onError = AuthOnError;
    g_hichainCallback.onRequest = AuthOnRequest;

    (void)memset_s(&g_hichainListener, sizeof(DataChangeListener), 0, sizeof(DataChangeListener));
    g_hichainListener.onDeviceNotTrusted = AuthOnDeviceNotTrusted;
    if (g_hichainGmInstance->regDataChangeListener(AUTH_APPID, &g_hichainListener) != 0) {
        LOG_ERR("auth RegDataChangeListener failed");
        return SOFTBUS_ERR;
    }
    return SOFTBUS_OK;
}

该函数首先调用InitDeviceAuthService完成认证服务的初始化工作,然后初始化群组认证管理实例g_hichainGaInstance,群组管理实例g_hichainGmInstance和认证回调实例g_hichainCallback,并在最后注册监听器。

初始化的细节不展开介绍,感兴趣可以对其自行分析。 

设备认证

AuthVerifyDevice的源码如下所示:

int32_t AuthVerifyDevice(AuthModuleId moduleId, const ConnectOption *option)
{
    if (option == NULL) {
        LOG_ERR("invalid parameter");
        return SOFTBUS_INVALID_PARAM;
    }
    if (pthread_mutex_lock(&g_authLock) != 0) {
        LOG_ERR("lock mutex failed");
        return SOFTBUS_ERR;
    }
    if (IsNeedVerify(option) == false) {
        (void)pthread_mutex_unlock(&g_authLock);
        LOG_INFO("there is no need to verify!");
        return SOFTBUS_AUTH_VERIFIED;
    }
    if (IsDeviceAuthingNow(option) == true) {
        (void)pthread_mutex_unlock(&g_authLock);
        LOG_ERR("authentication between two devices is in progress, please verify later");
        return SOFTBUS_AUTH_VERIFYING;
    }
    (void)pthread_mutex_unlock(&g_authLock);
    if (g_hichainGaInstance == NULL || g_hichainGmInstance == NULL) {
        LOG_ERR("need to call AuthVerifyInit!");
        return SOFTBUS_ERR;
    }
    if (HandleVerifyDevice(moduleId, option) != SOFTBUS_OK) {
        LOG_ERR("auth HandleVerifyDevice failed");
        return SOFTBUS_ERR;
    }
    return SOFTBUS_OK;
}

该函数首先调用IsNeedVerify判断目标设备的IP地址是否需要进行认证,然后调用IsDeviceAuthingNow判断目标设备是否正在进行认证处理,如果都没有,则调用HandleVerifyDevice对设备进行认证处理。HandleVerifyDevice的源码如下:

static int32_t HandleVerifyDevice(AuthModuleId moduleId, const ConnectOption *option)
{
    if (pthread_mutex_lock(&g_authLock) != 0) {
        LOG_ERR("lock mutex failed");
        return SOFTBUS_ERR;
    }
    AuthManager *auth = (AuthManager *)SoftBusMalloc(sizeof(AuthManager));
    if (auth == NULL) {
        LOG_ERR("SoftBusMalloc failed");
        (void)pthread_mutex_unlock(&g_authLock);
        return SOFTBUS_ERR;
    }
    (void)memset_s(auth, sizeof(AuthManager), 0, sizeof(AuthManager));
    if (InitNewAuthManager(auth, moduleId, option) != SOFTBUS_OK) {
        LOG_ERR("auth InitNewAuthManager failed");
        (void)pthread_mutex_unlock(&g_authLock);
        SoftBusFree(auth);
        return SOFTBUS_ERR;
    }
    (void)pthread_mutex_unlock(&g_authLock);

    if (option->type == CONNECT_TCP) {
        if (HandleIpVerifyDevice(auth, option) != SOFTBUS_OK) {
            LOG_ERR("HandleIpVerifyDevice failed");
            DeleteAuth(auth);
            return SOFTBUS_ERR;
        }
    } else if (option->type == CONNECT_BR) {
        if (ConnConnectDevice(option, auth->requestId, &g_connResult) != SOFTBUS_OK) {
            LOG_ERR("auth ConnConnectDevice failed");
            DeleteAuth(auth);
            return SOFTBUS_ERR;
        }
    } else {
        LOG_ERR("auth conn type %d is not support", option->type);
        DeleteAuth(auth);
        return SOFTBUS_ERR;
    }
    if (EventInLooper(auth->authId) != SOFTBUS_OK) {
        LOG_ERR("auth EventInLooper failed");
        DeleteAuth(auth);
        return SOFTBUS_ERR;
    }
    LOG_INFO("start authentication process, authId is %lld", auth->authId);
    return SOFTBUS_OK;
}

该函数主要分为三步:

  1. 初始化AuthManager,并将其插入到g_authClientHead列表尾节点;
  2. 根据组网连接的类型,选择对应的认证方法。如果是IP类型,则调用HandleIpVerifyDevice进行认证,如果是BR类型,则调用ConnConnectDevice进行认证。
  3. 调用EventInLooper设置超时定时器,10S后若认证还未成功就进行超时处理

其中第1步和第3步比较简单,我们对第2步以IP链接为例,对HandleIpVerifyDevice函数展开分析,其源码如下:

int32_t HandleIpVerifyDevice(AuthManager *auth, const ConnectOption *option)
{
    if (auth == NULL || option == NULL) {
        LOG_ERR("invalid parameter");
        return SOFTBUS_ERR;
    }
    char localIp[IP_MAX_LEN] = {0};
    if (LnnGetLocalStrInfo(STRING_KEY_WLAN_IP, localIp, IP_MAX_LEN) != SOFTBUS_OK) {
        LOG_ERR("auth get local ip failed");
        return SOFTBUS_ERR;
    }
    int fd = OpenTcpClientSocket(option->info.ipOption.ip, localIp, option->info.ipOption.port);
    if (fd < 0) {
        LOG_ERR("auth OpenTcpClientSocket failed");
        return SOFTBUS_ERR;
    }
    auth->fd = fd;
    if (AddTrigger(AUTH, fd, RW_TRIGGER) != SOFTBUS_OK) {
        LOG_ERR("auth AddTrigger failed");
        return SOFTBUS_ERR;
    }
    if (AuthSyncDeviceUuid(auth) != SOFTBUS_OK) {
        LOG_ERR("AuthSyncDeviceUuid failed");
        return SOFTBUS_ERR;
    }
    return SOFTBUS_OK;
}

该函数主要处理分为三步:

  1. 获取本地的IP后,调用OpenTcpClientSocket函数创建一个Socket,连接到对端设备的IP地址和端口
  2. 调用AddTrigger将该Socket的描述符fd添加到g_listenerList的info中。
  3. 调用AuthSyncDeviceUuid填写认证的消息报文后,将该消息发送出去。

该函数比较简单,因此不展开介绍。

接收认证请求消息 接收消息的触发链

在之前的章节里,我们介绍了组网处理的过程中,IpPreprocess函数会调用OpenAuthServer在本地创建一个接收socket并绑定到本地IP上。然后创建一个线程池并向其中的线程中提交一个Job,该Job的处理函数为SelectThread,源码如下:

static int32_t SelectThread(const SoftbusListenerNode *node)
{
    if (node == NULL) {
        return SOFTBUS_INVALID_PARAM;
    }
    ListenerModule module = node->module;
    if (CheckModule(node->module) != SOFTBUS_OK) {
        return SOFTBUS_INVALID_PARAM;
    }
    if (pthread_mutex_lock(&g_listenerList[module].lock) != 0) {
        LOG_ERR("lock failed");
        return SOFTBUS_LOCK_ERR;
    }
    SoftbusBaseListenerInfo *listenerInfo = g_listenerList[module].info;
    if (listenerInfo == NULL || listenerInfo->status != LISTENER_RUNNING) {
        pthread_mutex_unlock(&g_listenerList[module].lock);
        return SOFTBUS_ERR;
    }
    fd_set readSet;
    fd_set writeSet;
    fd_set exceptSet;
    if (SetSelect(module, &readSet, &writeSet, &exceptSet) != SOFTBUS_OK) {
        LOG_ERR("select failed with invalid listener");
        pthread_mutex_unlock(&g_listenerList[module].lock);
        return SOFTBUS_ERR;
    }
    int32_t nEvents = select(listenerInfo->maxFd + 1, &readSet, &writeSet,
        &exceptSet, &listenerInfo->tv);
    if (nEvents < 0) {
        LOG_ERR("select failed, errno=%d", errno);
        pthread_mutex_unlock(&g_listenerList[module].lock);
        return SOFTBUS_TCP_SOCKET_ERR;
    } else if (nEvents == 0) {
        pthread_mutex_unlock(&g_listenerList[module].lock);
        return SOFTBUS_OK;
    } else {
        ProcessData(module, &readSet, &writeSet, &exceptSet);
        pthread_mutex_unlock(&g_listenerList[module].lock);
        return SOFTBUS_OK;
    }
}

SelectThread首先设置要进行监听的各个读写连接套接字,然后对各个连接套接字进行Select调用,若发现有数据要接收,则调用ProcessData进行处理。

ProcessData又会调用OnEvent,OnEvent最终调用认证模块注册的onDataEvent回调函数进行处理,其函数为AuthOnDataEvent。

消息接收处理

AuthOnDataEvent首先从连接套接字中调用recv()函数,获取发送端发送的数据后,调用AuthIpOnDataReceived函数进行处理,其源码如下:

static void AuthIpOnDataReceived(int32_t fd, const ConnPktHead *head, char *data, int len)
{
    if (head == NULL || data == NULL) {
        LOG_ERR("invalid parameter");
        return;
    }
    AuthManager *auth = NULL;
    auth = AuthGetManagerByFd(fd);
    if (auth == NULL || auth->authId != head->seq) {
        LOG_ERR("ip get auth failed");
        return;
    }
    LOG_INFO("auth ip data module is %d", head->module);
    switch (head->module) {
        case MODULE_TRUST_ENGINE: {
            HandleReceiveDeviceId(auth, (uint8_t *)data);
            break;
        }
        case MODULE_AUTH_SDK: {
            HandleReceiveAuthData(auth, head->module, (uint8_t *)data, head->len);
            break;
        }
        case MODULE_AUTH_CONNECTION: {
            AuthHandlePeerSyncDeviceInfo(auth, (uint8_t *)data, head->len);
            break;
        }
        default: {
            LOG_ERR("unknown data type");
            break;
        }
    }
}

因为在发送端组包时,我们填写的内容为MODULE_TRUST_ENGINE,因此该函数调用HandleReceiveDeviceId进行处理,其源码如下:

​void HandleReceiveDeviceId(AuthManager *auth, uint8_t *data)
{
    if (auth == NULL || data == NULL) {
        LOG_ERR("invalid parameter");
        return;
    }
    if (AuthUnpackDeviceInfo(auth, data) != SOFTBUS_OK) {
        LOG_ERR("AuthUnpackDeviceInfo failed");
        HandleAuthFail(auth);
        return;
    }
    if (auth->side == SERVER_SIDE_FLAG) {
        if (AuthSyncDeviceUuid(auth) != SOFTBUS_OK) {
            HandleAuthFail(auth);
        }
        return;
    }
    if (auth->status == AUTH_PASSED) {
        LOG_INFO("auth pass, no need to call verify again");
        return;
    }
    VerifyDeviceDevLvl(auth);
}

​

该函数首先调用AuthUnpackDeviceInfo对接收的data进行解析,然后由于接收端的side为SERVER_SIDE_FLAG,因此该函数会调用AuthSyncDeviceUuid向对端返回认证消息。

发送端接收到返回消息

发送端接收到返回消息后,其处理方式与上一节的接收端接收消息处理一致。在HandleReceiveDeviceId函数中,由于发送端的side为CLIENT_SIDE_FLAG,因此该函数解析完返回数据后,调用VerifyDeviceDevLvl进行认证处理。

VerifyDeviceDevLvl又会调用StartAuth进行认证处理,其源码如下:

static void StartAuth(AuthManager *auth, char *groupId, bool isDeviceLevel, bool isClient)
{
    (void)groupId;
    char *authParams = NULL;
    if (isDeviceLevel) {
        authParams = AuthGenDeviceLevelParam(auth, isClient);
    } else {
        LOG_ERR("not supported session level");
        return;
    }
    if (authParams == NULL) {
        LOG_ERR("generate auth param failed");
        return;
    }
    if (auth->hichain->authDevice(auth->authId, authParams, &g_hichainCallback) != 0) {
        LOG_ERR("authDevice failed");
        HandleAuthFail(auth);
        return;
    }
    cJSON_free(authParams);
}

该函数首先将AuthManager转换为一条Json消息,然后调用authDevice回调函数,其钩子为AuthDevice,源码如下:

static int32_t AuthDevice(int64_t authReqId, const char *authParams, const DeviceAuthCallback *gaCallback)
{
    LOGI("Begin AuthDevice.");
    if (authParams == NULL) {
        LOGE("The input auth params is null!");
        return HC_ERR_INVALID_PARAMS;
    }
    if (g_taskThread == NULL) {
        LOGE("The task thread is null!");
        return HC_ERR_SERVICE_NEED_RESTART;
    }
    CJson *jsonParams = CreateJsonFromString(authParams);
    if (jsonParams == NULL) {
        LOGE("Create json from params failed!");
        return HC_ERR_JSON_FAIL;
    }
    AuthDeviceTask *task = (AuthDeviceTask *)HcMalloc(sizeof(AuthDeviceTask), 0);
    if (task == NULL) {
        FreeJson(jsonParams);
        LOGE("Failed to allocate memory for task!");
        return HC_ERR_ALLOC_MEMORY;
    }
    if (!InitAuthDeviceTask(task, authReqId, jsonParams, gaCallback)) {
        LOGE("Failed to init task!");
        FreeJson(jsonParams);
        HcFree(task);
        return HC_ERR_INIT_TASK_FAIL;
    }
    g_taskThread->pushTask(g_taskThread, (HcTaskBase*)task);
    LOGI("Push AuthDevice task successfully.");
    return HC_SUCCESS;
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/926257.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号