当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