软总线源码分析4: 接口解析之组网

当A端通过PublishService发布服务,B端通过调用StartDiscovery查找对应的服务后,A端或者B端根据对端设备的MAC地址,便可以发布组网请求。

组网请求的函数为JoinLNN,其源码如下所示:

int32_t JoinLNN(const char *pkgName, ConnectionAddr *target, OnJoinLNNResult cb)
{
    int32_t rc;
    SoftBusList *list = NULL;

    if (pkgName == NULL || target == NULL || cb == NULL) {
        LOG_ERR("fail : params are NULL!");
        return SOFTBUS_INVALID_PARAM;
    }
    if (InitSoftBus(pkgName) != SOFTBUS_OK) {
        LOG_ERR("fail: init softbus");
        return SOFTBUS_ERR;
    }
    list = g_busCenterClient.joinLNNCbList;
    if (list == NULL) {
        LOG_ERR("fail : join lnn cb list = NULL!");
        return SOFTBUS_ERR;
    }
    if (pthread_mutex_lock(&g_busCenterClient.lock) != 0) {
        LOG_ERR("fail: lock join lnn cb list in join");
    }
    rc = SOFTBUS_ERR;
    do {
        if (FindJoinLNNCbItem(target, cb) != NULL) {
            LOG_ERR("fail : join request already exist");
            break;
        }
        rc = GetServerProvideInterface()->joinLNN(target, sizeof(*target));
        if (rc != SOFTBUS_OK) {
            LOG_ERR("fail : request join lnn");
        } else {
            rc = AddJoinLNNCbItem(target, cb);
        }
    } while (false);
    if (pthread_mutex_unlock(&g_busCenterClient.lock) != 0) {
        LOG_ERR("fail: unlock join lnn cb list in join");
    }
    return rc;
}

JoinLNN源码主要做了两件事:1. 调用本地的joinLNN接口发起组网请求;2.成功后调用函数AddJoinLNNCbItem将组网结果添加到本地维护的列表中。

其中AddJoinLNNCbItem的源码比较简单,即将组网成功后的target信息和cb回调保存在本地g_busCenterClient的joinLNNCbList列表中,因此不展开。我们主要分析joinLNN接口。

与PublishService和StartDiscovery的IPC通信过程一致:1. joinLNN获取SoftBusServerProxy对象,调用其JoinLNN方法,该方法填写参数请求发送到服务端进程。2. 服务端解析参数后调用SoftBusServer的JoinLNN方法。3. JoinLNN调用LnnIpcServerJoin完成相应的处理。

LnnIpcServerJoin源码如下:

int32_t LnnIpcServerJoin(const char *pkgName, void *addr, uint32_t addrTypeLen)
{
    if (CheckBusCenterPermission(pkgName) != true) {
        LOG_ERR("ServerJoinLNN no permission!");
        return SOFTBUS_PERMISSION_DENIED;
    }
    ConnectionAddr *connAddr = (ConnectionAddr *)addr;

    (void)addrTypeLen;
    if (pkgName == nullptr || connAddr == nullptr) {
        LOG_ERR("parameters are nullptr!\n");
        return SOFTBUS_ERR;
    }
    std::lock_guard<std::mutex> autoLock(g_lock);
    if (IsRepeatJoinLNNRequest(pkgName, connAddr)) {
        LOG_ERR("repeat join lnn request from: %s", pkgName);
        return SOFTBUS_ERR;
    }
    int32_t ret = LnnServerJoin(connAddr);
    if (ret == SOFTBUS_OK) {
        ret = AddJoinLNNInfo(pkgName, connAddr);
    }
    return ret;
}

其逻辑也比较简单,即调用LnnServerJoin发起组网请求,请求成功后调用AddJoinLNNInfo将组网信息添加到本地。

LnnServerJoin的源码如下所示:

int32_t LnnServerJoin(ConnectionAddr *addr)
{
    LOG_INFO("LnnServerJoin enter!");
    if (addr == NULL || addr->type < CONNECTION_ADDR_WLAN || addr->type > CONNECTION_ADDR_ETH) {
        LOG_ERR("para error!");
        return SOFTBUS_ERR;
    }
    if (g_netBuilder.isInit == false) {
        LOG_ERR("no init");
        return SOFTBUS_ERR;
    }

    uint32_t cap = 0;
    if (ConvertTypeToNetCap(addr->type, &cap) != SOFTBUS_OK) {
        LOG_ERR("ConvertTypeToNetCap error!");
        return SOFTBUS_ERR;
    }
    if (LnnSetLocalNumInfo(NUM_KEY_NET_CAP, (int32_t)cap) != SOFTBUS_OK) {
        LOG_ERR("LnnSetLocalNumInfo error!");
        return SOFTBUS_ERR;
    }

    if (g_netBuilder.hook[addr->type] != NULL) {
        LOG_INFO("LnnServerJoin enter hook");
        return g_netBuilder.hook[addr->type]->preprocess(addr, &g_netBuilder.fsm, NETWORK_TYPE_ACTIVE);
    }
    return ConnTypeDefaultHook(addr);
}

其将组网请求的连接类型转换为cap描述的Bitmap并保存后,调用g_netBuilder对应的preprocess钩子函数,最后调用函数ConnTypeDefaultHook完成相应的处理。

一、IpPreprocess

g_netBuilder.hook[addr->type]->preprocess在组网服务初始化中注册,其源码如下:

static ConnTypeHook g_hook = {
    .preprocess = IpPreprocess,
    .shutdown = IpShutdown,
};

void LnnInitIpHook(void)
{
    LnnRegisterConnTypeHook(CONNECTION_ADDR_WLAN, &g_hook);
    LnnRegisterConnTypeHook(CONNECTION_ADDR_ETH, &g_hook);
    if (UpdateLocalIp(CONNECTION_ADDR_ETH) == SOFTBUS_OK) {
        LOG_INFO("update eth ip success");
        return;
    }
    if (UpdateLocalIp(CONNECTION_ADDR_WLAN) == SOFTBUS_OK) {
        LOG_INFO("update wlan ip success");
    }
}

所以可知g_netBuilder.hook[addr->type]->preprocess指向的函数指针即为IpPreprocess,其源码如下所示:

static int32_t IpPreprocess(const ConnectionAddr *addr, FsmStateMachine *fsm, NetworkType networkType)
{
    if (addr == NULL || fsm == NULL) {
        LOG_ERR("para error!");
        return SOFTBUS_ERR;
    }
    ConnectionAddrType type = addr->type;

    if (UpdateLocalIp(type) != SOFTBUS_OK) {
        LOG_ERR("UpdateLocalIp fail!");
        return SOFTBUS_ERR;
    }
    if (OpenIpLink() != SOFTBUS_OK) {
        LOG_ERR("OpenIpLink fail!");
        return SOFTBUS_ERR;
    }
    if (networkType == NETWORK_TYPE_ACTIVE) {
        ConnectionAddrType *para = (ConnectionAddrType *)SoftBusCalloc(sizeof(ConnectionAddrType));
        if (para == NULL) {
            LOG_ERR("malloc init message fail");
            return SOFTBUS_ERR;
        }
        *para = type;
        if (LnnFsmPostMessageDelay(fsm, FSM_MSG_TYPE_DISCOVERY_TIMEOUT, para, JOIN_DISCOVERY_TIMEOUT_LEN)
            != SOFTBUS_OK) {
            SoftBusFree(para);
            return SOFTBUS_ERR;
        }
    }
    if (EnableCoapDisc() != SOFTBUS_OK) {
        LOG_ERR("EnableCoapDisc fail!");
        return SOFTBUS_ERR;
    }

    LOG_INFO("IpPreprocess ok!");
    g_status.fsm = fsm;
    g_status.type = type;
    return SOFTBUS_OK;
}

IpPreprocess主要分为四部分:1.更新本地IP地址;2.打开IP连接;3.如果是主动组网,则延迟1分钟后向状态机发送超时消息;4.打开COAP发现服务。

1.更新本地IP

UpdateLocalIp的源码如下所示:

static int32_t UpdateLocalIp(ConnectionAddrType type)
{
    char ipAddr[IP_MAX_LEN] = {0};
    char ifName[NET_IF_NAME_LEN] = {0};
    IfInfo info = {
        .ifName = ifName,
        .ifNameLen = NET_IF_NAME_LEN,
    };
    int32_t r
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值