blob: 35d74bd06c844fdf57ef9ac97ba233bb8f9b012a [file] [log] [blame]
/*
* Copyright (c) 2023 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "DeviceScanner.h"
using namespace chip;
using namespace chip::Dnssd;
#if CONFIG_NETWORK_LAYER_BLE
using namespace chip::Ble;
constexpr char kBleKey[] = "BLE";
#endif // CONFIG_NETWORK_LAYER_BLE
CHIP_ERROR DeviceScanner::Start()
{
mDiscoveredResults.clear();
#if CONFIG_NETWORK_LAYER_BLE
ReturnErrorOnFailure(DeviceLayer::PlatformMgrImpl().StartBleScan(this));
#endif // CONFIG_NETWORK_LAYER_BLE
ReturnErrorOnFailure(chip::Dnssd::Resolver::Instance().Init(DeviceLayer::UDPEndPointManager()));
char serviceName[kMaxCommissionableServiceNameSize];
auto filter = DiscoveryFilterType::kNone;
ReturnErrorOnFailure(MakeServiceTypeName(serviceName, sizeof(serviceName), filter, DiscoveryType::kCommissionableNode));
return ChipDnssdBrowse(serviceName, DnssdServiceProtocol::kDnssdProtocolUdp, Inet::IPAddressType::kAny,
Inet::InterfaceId::Null(), this);
}
CHIP_ERROR DeviceScanner::Stop()
{
#if CONFIG_NETWORK_LAYER_BLE
ReturnErrorOnFailure(DeviceLayer::PlatformMgrImpl().StopBleScan());
#endif // CONFIG_NETWORK_LAYER_BLE
return ChipDnssdStopBrowse(this);
}
void DeviceScanner::OnNodeDiscovered(const DiscoveredNodeData & nodeData)
{
auto & commissionData = nodeData.commissionData;
auto discriminator = commissionData.longDiscriminator;
auto vendorId = static_cast<VendorId>(commissionData.vendorId);
auto productId = commissionData.productId;
ChipLogProgress(chipTool, "OnNodeDiscovered (MDNS): discriminator: %u, vendorId: %u, productId: %u", discriminator, vendorId,
productId);
auto & resolutionData = nodeData.resolutionData;
auto & instanceData = mDiscoveredResults[commissionData.instanceName];
auto & interfaceData = instanceData[resolutionData.interfaceId.GetPlatformInterface()];
for (size_t i = 0; i < resolutionData.numIPs; i++)
{
auto params = Controller::SetUpCodePairerParameters(resolutionData, i);
DeviceScannerResult result = { params, vendorId, productId, discriminator, chip::MakeOptional(resolutionData) };
interfaceData.push_back(result);
}
nodeData.LogDetail();
}
void DeviceScanner::OnBrowseAdd(chip::Dnssd::DnssdService service)
{
ChipLogProgress(chipTool, "OnBrowseAdd: %s", service.mName);
LogErrorOnFailure(ChipDnssdResolve(&service, service.mInterface, this));
auto & instanceData = mDiscoveredResults[service.mName];
auto & interfaceData = instanceData[service.mInterface.GetPlatformInterface()];
(void) interfaceData;
}
void DeviceScanner::OnBrowseRemove(chip::Dnssd::DnssdService service)
{
ChipLogProgress(chipTool, "OnBrowseRemove: %s", service.mName);
auto & instanceData = mDiscoveredResults[service.mName];
auto & interfaceData = instanceData[service.mInterface.GetPlatformInterface()];
// Check if the interface data has been resolved already, otherwise, just inform the
// back end that we may not need it anymore.
if (interfaceData.size() == 0)
{
ChipDnssdResolveNoLongerNeeded(service.mName);
}
// Delete the interface placeholder.
instanceData.erase(service.mInterface.GetPlatformInterface());
// If there is nothing else to resolve for the given instance name, just remove it
// too.
if (instanceData.size() == 0)
{
mDiscoveredResults.erase(service.mName);
}
}
void DeviceScanner::OnBrowseStop(CHIP_ERROR error)
{
ChipLogProgress(chipTool, "OnBrowseStop: %" CHIP_ERROR_FORMAT, error.Format());
for (auto & instance : mDiscoveredResults)
{
for (auto & interface : instance.second)
{
if (interface.second.size() == 0)
{
ChipDnssdResolveNoLongerNeeded(instance.first.c_str());
}
}
}
}
#if CONFIG_NETWORK_LAYER_BLE
void DeviceScanner::OnBleScanAdd(BLE_CONNECTION_OBJECT connObj, const ChipBLEDeviceIdentificationInfo & info)
{
auto discriminator = info.GetDeviceDiscriminator();
auto vendorId = static_cast<VendorId>(info.GetVendorId());
auto productId = info.GetProductId();
ChipLogProgress(chipTool, "OnBleScanAdd (BLE): %p, discriminator: %u, vendorId: %u, productId: %u", connObj, discriminator,
vendorId, productId);
auto params = Controller::SetUpCodePairerParameters(connObj, false /* connected */);
DeviceScannerResult result = { params, vendorId, productId, discriminator };
auto & instanceData = mDiscoveredResults[kBleKey];
auto & interfaceData = instanceData[chip::Inet::InterfaceId::Null().GetPlatformInterface()];
interfaceData.push_back(result);
}
void DeviceScanner::OnBleScanRemove(BLE_CONNECTION_OBJECT connObj)
{
ChipLogProgress(chipTool, "OnBleScanRemove: %p", connObj);
auto & instanceData = mDiscoveredResults[kBleKey];
auto & interfaceData = instanceData[chip::Inet::InterfaceId::Null().GetPlatformInterface()];
interfaceData.erase(std::remove_if(interfaceData.begin(), interfaceData.end(),
[connObj](const DeviceScannerResult & result) {
return result.mParams.HasDiscoveredObject() &&
result.mParams.GetDiscoveredObject() == connObj;
}),
interfaceData.end());
if (interfaceData.size() == 0)
{
instanceData.clear();
mDiscoveredResults.erase(kBleKey);
}
}
#endif // CONFIG_NETWORK_LAYER_BLE
CHIP_ERROR DeviceScanner::Get(uint16_t index, RendezvousParameters & params)
{
uint16_t currentIndex = 0;
for (auto & instance : mDiscoveredResults)
{
for (auto & interface : instance.second)
{
for (auto & result : interface.second)
{
if (currentIndex == index)
{
params = result.mParams;
return CHIP_NO_ERROR;
}
currentIndex++;
}
}
}
return CHIP_ERROR_NOT_FOUND;
}
CHIP_ERROR DeviceScanner::Get(uint16_t index, Dnssd::CommonResolutionData & resolutionData)
{
uint16_t currentIndex = 0;
for (auto & instance : mDiscoveredResults)
{
for (auto & interface : instance.second)
{
for (auto & result : interface.second)
{
if (currentIndex == index && result.mResolutionData.HasValue())
{
resolutionData = result.mResolutionData.Value();
return CHIP_NO_ERROR;
}
currentIndex++;
}
}
}
return CHIP_ERROR_NOT_FOUND;
}
void DeviceScanner::Log() const
{
auto resultsCount = mDiscoveredResults.size();
VerifyOrReturn(resultsCount > 0, ChipLogProgress(chipTool, "No device discovered."));
[[maybe_unused]] uint16_t index = 0;
for (auto & instance : mDiscoveredResults)
{
ChipLogProgress(chipTool, "Instance Name: %s ", instance.first.c_str());
for (auto & interface : instance.second)
{
for (auto & result : interface.second)
{
char addr[Transport::PeerAddress::kMaxToStringSize];
result.mParams.GetPeerAddress().ToString(addr);
ChipLogProgress(chipTool, "\t %u - Discriminator: %u - Vendor: %u - Product: %u - %s", index, result.mDiscriminator,
result.mVendorId, result.mProductId, addr);
index++;
}
}
}
}
DeviceScanner & GetDeviceScanner()
{
static DeviceScanner scanner;
return scanner;
}