继上一章节分析完PublishService接口后,本章节我们开始分析StartDiscovery接口。
StartDiscovery接口
根据g_discCoapFuncInterface的接口可以知道,当为主动发现时,调用CoapStartAdvertise函数,当为被动发现时,调用CoapSubscribe函数完成对应的处理。下面我们分别介绍这两种实现:
CoapStartAdvertise
CoapStartAdvertise的源码如下所示:
static int32_t CoapStartAdvertise(const SubscribeOption *option)
{
if (option == NULL || g_subscribeMgr == NULL) {
return SOFTBUS_INVALID_PARAM;
}
if (pthread_mutex_lock(&(g_subscribeMgr->lock)) != 0) {
LOG_ERR("pthread mutex lock failed.");
return SOFTBUS_LOCK_ERR;
}
if (RegisterAllCapBitmap(CAPABILITY_NUM, option->capabilityBitmap, g_subscribeMgr, MAX_CAP_NUM) != SOFTBUS_OK) {
(void)pthread_mutex_unlock(&(g_subscribeMgr->lock));
LOG_ERR("merge discovery capability failed.");
return SOFTBUS_DISCOVER_COAP_MERGE_CAP_FAIL;
}
if (g_subscribeMgr->isUpdate) {
if (DiscCoapSetFilterCapability(CAPABILITY_NUM, g_subscribeMgr->allCap) != SOFTBUS_OK) {
(void)pthread_mutex_unlock(&(g_subscribeMgr->lock));
LOG_ERR("set all filter capability to dfinder failed.");
return SOFTBUS_DISCOVER_COAP_SET_FILTER_CAP_FAIL;
}
}
if (DiscCoapStopDiscovery() != SOFTBUS_OK) {
(void)pthread_mutex_unlock(&(g_subscribeMgr->lock));
LOG_ERR("coap stop discovery failed.");
return SOFTBUS_DISCOVER_COAP_STOP_DISCOVER_FAIL;
}
if (DiscCoapStartDiscovery(ACTIVE_DISCOVERY) != SOFTBUS_OK) {
(void)pthread_mutex_unlock(&(g_subscribeMgr->lock));
LOG_ERR("coap start advertise failed.");
return SOFTBUS_DISCOVER_COAP_START_DISCOVER_FAIL;
}
(void)pthread_mutex_unlock(&(g_subscribeMgr->lock));
LOG_INFO("coap start active discovery.");
return SOFTBUS_OK;
}
该函数主要做了四件事:
- 调用RegisterAllCapBitmap将能力注册到g_subscribeMgr中。
- 调用DiscCoapSetFilterCapability将能力保存到本地的g_filterCapabilityBitmap中。
- 调用DiscCoapStopDiscovery停止上一轮的发现处理。
- 调用DiscCoapStartDiscovery完成发现处理。
RegisterAllCapBitmap函数和DiscCoapSetFilterCapability函数比较简单,因此不展开介绍。我们主要对DiscCoapStopDiscovery函数和DiscCoapStartDiscovery函数展开。
DiscCoapStopDiscovery
DiscCoapStopDiscovery调用NSTACKX_StopDeviceFind函数,该函数使用PostEvent提交一个事件,其handle为DeviceDiscoverStopInner函数,该函数最终调用CoapServiceDiscoverStopInner函数完成处理,其源码如下:
void CoapServiceDiscoverStopInner(void)
{
TimerSetTimeout(g_discoverTimer, 0, NSTACKX_FALSE);
CoapServiceDiscoverStop();
LOGI(TAG, "device discover stopped");
}
该函数首先调用TimerSetTimeout关闭掉上一轮发现设置的定时器,然后调用CoapServiceDiscoverStop函数,CoapServiceDiscoverStop的源码如下:
static void CoapServiceDiscoverStop(void)
{
g_discoverCount = 0;
g_forceUpdate = NSTACKX_FALSE;
SetModeInfo(DISCOVER_MODE);
ClearDevices(GetDeviceDBBackup());
LOGW(TAG, "clear device list backup");
/* Can call PostDeviceFindWrapper() to notify user if needed. */
g_userRequest = NSTACKX_FALSE;
}
该函数也比较简单,即清除掉各种标志和设备列表备份中的记录。
DiscCoapStartDiscovery
停止上一轮的发现处理之后,便调用DiscCoapStartDiscovery函数进行发现处理,该函数我们在上一章节介绍CoapPublish时介绍过,该函数在StartDiscovery调用的情况下,根据传入的参数,调用NSTACKX_StartDeviceFind函数。NSTACKX_StartDeviceFind函数使用PostEvent提交一个事件,其处理的handle为DeviceDiscoverInner函数,其源码如下:
static void DeviceDiscoverInner(void *argument)
{
(void)argument;
CoapServiceDiscoverInner(INNER_DISCOVERY);
/* If both Wifi AP and BLE are disabled, we should also notify user, with empty list. */
if (!IsWifiApConnected()) {
NotifyDeviceFound(NULL, 0);
}
}
该函数首先调用CoapServiceDiscoverInner进行发现的处理,然后判断如果当前设备的Wifi和Ble都没有打开的话,则通知用户发现的设备为空。
CoapServiceDiscoverInner的源码如下:
void CoapServiceDiscoverInner(uint8_t userRequest)
{
uint32_t discoverInterval;
if (!IsWifiApConnected() || g_context == NULL) {
return;
}
if (userRequest) {
g_userRequest = NSTACKX_TRUE;
g_forceUpdate = NSTACKX_TRUE;
}
if (g_coapDiscoverTargetCount > 0 && g_discoverCount >= g_coapDiscoverTargetCount) {
g_discoverCount = 0;
SetModeInfo(DISCOVER_MODE);
ClearDevices(GetDeviceDBBackup());
LOGW(TAG, "clear device list backup");
TimerSetTimeout(g_discoverTimer, 0, NSTACKX_FALSE);
}
if (g_discoverCount) {
/* Service discover is ongoing, return. */
return;
} else {
/* First discover */
if (BackupDeviceDB() != NSTACKX_EOK) {
LOGE(TAG, "backup device list fail");
return;
}
ClearDevices(GetDeviceDB());
LOGW(TAG, "clear device list");
g_coapDiscoverTargetCount = g_coapMaxDiscoverCount;
}
SetModeInfo(DISCOVER_MODE);
if (CoapPostServiceDiscover() != NSTACKX_EOK) {
LOGE(TAG, "failed to post service discover request");
return;
}
discoverInterval = GetDiscoverInterval(g_discoverCount);
if (TimerSetTimeout(g_discoverTimer, discoverInterval, NSTACKX_FALSE) != NSTACKX_EOK) {
LOGE(TAG, "failed to set timer for service discover");
return;
}
++g_discoverCount;
LOGI(TAG, "the first time for device discover.");
return;
}
因为g_discoverCount在CoapServiceDiscoverStop函数中置0,因此CoapServiceDiscoverInner首先调用BackupDeviceDB,将g_deviceList中的设备内容备份到g_deviceListBackup中;然后清除掉当前g_deviceList中发现的设备;最后调用CoapPostServiceDiscover完成发现处理,并设置定时器超时门限。
CoapPostServiceDiscover的源码我们在上一章节CoapPublish中介绍过,即组一条广播报文将消息发送出去,因此本章不展开。
上一章节的CoapPublish中,调用CoapServiceDiscoverInnerAn函数时,也会在最后设置一个定时器和对应的超时门限,那么这个定时器的作用是什么呢?
我们可以看一下CoapDiscoverInit中,创建g_discoverTimer定时器的处理。CoapDiscoverInit调用TimerStart函数为g_discoverTimer创建了一个定时器,其对应的超时处理函数为CoapServiceDiscoverTimerHandle,源码如下:
static void CoapServiceDiscoverTimerHandle(void *argument)
{
uint32_t discoverInterval;
(void)argument;
if (g_discoverCount >= g_coapDiscoverTargetCount || !IsWifiApConnected()) {
/* Discover done, or wifi AP disconnected. */
CoapServiceDiscoverStop();
return;
}
if (CoapPostServiceDiscover() != NSTACKX_EOK) {
LOGE(TAG, "failed to post service discover request");
goto L_ERR_SERVICE_DISCOVER;
}
LOGI(TAG, "the %d times for device discover.", g_discoverCount + 1);
/* Restart timer */
discoverInterval = GetDiscoverInterval(g_discoverCount);
++g_discoverCount;
if (TimerSetTimeout(g_discoverTimer, discoverInterval, NSTACKX_FALSE) != NSTACKX_EOK) {
LOGE(TAG, "failed to set timer for service discover");
goto L_ERR_SERVICE_DISCOVER;
}
return;
L_ERR_SERVICE_DISCOVER:
/* Abort service discover by not starting timer. */
LOGE(TAG, "abort service discover, have tried %u request", g_discoverCount);
/* Reset g_discoverCount to allow new request from user. */
g_discoverCount = 0;
return;
}
该函数处理也很简单,即判断g_discoverCount是否超过了g_coapDiscoverTargetCount(该值被设为默认值12),如果没超过则继续调用CoapPostServiceDiscover对外广播,若已超过则直接返回。
因此我们知道发现的处理会对外广播最多12次COAP报文,并且会根据当前的次数调用GetDiscoverInterval调整时间,前两次间隔100ms,第3次和第4次间隔300ms,后面每次间隔500ms。
CoapSubscribe
CoapSubscribe