Skip to content

Commit

Permalink
[python/mdns] Add "resolve" command for operational discovery (#5025)
Browse files Browse the repository at this point in the history
* [mdns] Add Resolver interface

Expose the mDNS resolver functionality implemented for
Avahi/Linux using a new Resolver interface.

* [mdns] Fix build with chip_mdns_advertiser="platform"

* [mdns/python] Add command to resolve address of a CHIP device

Add DeviceAddressUpdater class which updates device
addresses in the device controller based on responses from
mDNS resolver. A result of an update/resolution request
can be passed to an optional DeviceAddressUpdateDelegate.

Add "resolve <fabricid> <nodeid>" command to the Python
CHIP controller. Usage:
1. Build CHIP with chip_mdns_advertiser="platform" argument.
2. Start Python CHIP controller.
3. Pair a CHIP device using "connect -ble" command.
4. Resolve the node ID using "resolve <fabricid> <nodeid>".

Note that Thread devices currently don't support the DNS-SD
service registration, but one can still test the new command
by registering the necessary services manually, e.g.

avahi-publish-address test-host.local. fd11:22::1 &
avahi-publish-publish-service -H test-host.local \
    <fabricid-hex>-<nodeid-hex> _chip._tcp 11097

* [mdns] Fix improper global object initialization order.

On Linux, DiscoveryImplPlatform constructor refers to
MdnsAvahi global object which may not yet be initialized.
Some refactoring in the code is required to come up with
a better solution, but for now make sure that
DiscoveryImplPlatform is not initialized prior to MdnsAvahi.

* [mdns] Apply code review comments

Also, fix updating the device address in the device
controller as previously the connection state wasn't
updated.
  • Loading branch information
Damian-Nordic authored Mar 5, 2021
1 parent fc666df commit a578416
Show file tree
Hide file tree
Showing 19 changed files with 595 additions and 112 deletions.
3 changes: 3 additions & 0 deletions src/controller/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,16 @@ static_library("controller") {
"CHIPDeviceController.h",
"CHIPDeviceController_deprecated.cpp",
"CHIPDeviceController_deprecated.h",
"DeviceAddressUpdater.cpp",
"DeviceAddressUpdater.h",
]

cflags = [ "-Wconversion" ]

public_deps = [
"${chip_root}/src/app",
"${chip_root}/src/lib/core",
"${chip_root}/src/lib/mdns",
"${chip_root}/src/lib/support",
"${chip_root}/src/messaging",
"${chip_root}/src/platform",
Expand Down
19 changes: 18 additions & 1 deletion src/controller/CHIPDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,22 @@ CHIP_ERROR Device::OpenPairingWindow(uint32_t timeout, PairingWindowOption optio
return CHIP_NO_ERROR;
}

CHIP_ERROR Device::UpdateAddress(const Transport::PeerAddress & addr)
{
bool didLoad;

VerifyOrReturnError(addr.GetTransportType() == Transport::Type::kUdp, CHIP_ERROR_INVALID_ADDRESS);
ReturnErrorOnFailure(LoadSecureSessionParametersIfNeeded(didLoad));

Transport::PeerConnectionState * connectionState = mSessionManager->GetPeerConnectionState(mSecureSession);
VerifyOrReturnError(connectionState != nullptr, CHIP_ERROR_INCORRECT_STATE);

mDeviceUdpAddress = addr;
connectionState->SetPeerAddress(addr);

return CHIP_NO_ERROR;
}

CHIP_ERROR Device::LoadSecureSessionParameters(ResetTransport resetNeeded)
{
CHIP_ERROR err = CHIP_NO_ERROR;
Expand Down Expand Up @@ -330,12 +346,13 @@ CHIP_ERROR Device::LoadSecureSessionParameters(ResetTransport resetNeeded)
return err;
}

bool Device::GetIpAddress(Inet::IPAddress & addr) const
bool Device::GetAddress(Inet::IPAddress & addr, uint16_t & port) const
{
if (mState == ConnectionState::NotConnected)
return false;

addr = mDeviceUdpAddress.GetIPAddress();
port = mDeviceUdpAddress.GetPort();
return true;
}

Expand Down
23 changes: 18 additions & 5 deletions src/controller/CHIPDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,14 @@ class DLL_EXPORT Device
app::CommandSender * GetCommandSender() { return mCommandSender; }

/**
* @brief
* Get the IP address assigned to the device.
* @brief Get the IP address and port assigned to the device.
*
* @param[out] addr The reference to the IP address.
* @param[out] addr IP address of the device.
* @param[out] port Port number of the device.
*
* @return true, if the IP address was filled in the out parameter, false otherwise
* @return true, if the IP address and port were filled in the out parameters, false otherwise
*/
bool GetIpAddress(Inet::IPAddress & addr) const;
bool GetAddress(Inet::IPAddress & addr, uint16_t & port) const;

/**
* @brief
Expand Down Expand Up @@ -261,6 +261,19 @@ class DLL_EXPORT Device
*/
CHIP_ERROR OpenPairingWindow(uint32_t timeout, PairingWindowOption option, SetupPayload & setupPayload);

/**
* @brief
* Update address of the device.
*
* This function will set new IP address and port of the device. Since the device settings might
* have been moved from RAM to the persistent storage, the function will load the device settings
* first, before making the changes.
*
* @param[in] addr Address of the device to be set.
*
* @return CHIP_NO_ERROR if the address has been updated, an error code otherwise.
*/
CHIP_ERROR UpdateAddress(const Transport::PeerAddress & addr);
/**
* @brief
* Return whether the current device object is actively associated with a paired CHIP
Expand Down
3 changes: 2 additions & 1 deletion src/controller/CHIPDeviceController_deprecated.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,8 @@ bool ChipDeviceController::GetIpAddress(Inet::IPAddress & addr)
if (mDevice == nullptr)
InitDevice();

return mDevice != nullptr && mDevice->GetIpAddress(addr);
uint16_t port;
return mDevice != nullptr && mDevice->GetAddress(addr, port);
}

CHIP_ERROR ChipDeviceController::DisconnectDevice()
Expand Down
65 changes: 65 additions & 0 deletions src/controller/DeviceAddressUpdater.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
*
* Copyright (c) 2021 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 "DeviceAddressUpdater.h"

#include <controller/CHIPDeviceController.h>
#include <support/ReturnMacros.h>

namespace chip {
namespace Controller {

CHIP_ERROR DeviceAddressUpdater::Init(DeviceController * controller, DeviceAddressUpdateDelegate * delegate)
{
VerifyOrReturnError(mController == nullptr, CHIP_ERROR_INCORRECT_STATE);
VerifyOrReturnError(mDelegate == nullptr, CHIP_ERROR_INCORRECT_STATE);

mController = controller;
mDelegate = delegate;

return CHIP_NO_ERROR;
}

void DeviceAddressUpdater::OnNodeIdResolved(NodeId nodeId, const Mdns::ResolvedNodeData & nodeData)
{
CHIP_ERROR error = CHIP_NO_ERROR;
Device * device = nullptr;

VerifyOrExit(nodeData.mAddress.Type() != Inet::kIPAddressType_Any, error = CHIP_ERROR_INVALID_ADDRESS);
VerifyOrExit(mController != nullptr, error = CHIP_ERROR_INCORRECT_STATE);
SuccessOrExit(error = mController->GetDevice(nodeId, &device));

device->UpdateAddress(Transport::PeerAddress::UDP(nodeData.mAddress, nodeData.mPort, nodeData.mInterfaceId));

exit:
if (mDelegate != nullptr)
{
mDelegate->OnAddressUpdateComplete(nodeId, error);
}
}

void DeviceAddressUpdater::OnNodeIdResolutionFailed(NodeId nodeId, CHIP_ERROR error)
{
if (mDelegate != nullptr)
{
mDelegate->OnAddressUpdateComplete(nodeId, error);
}
}

} // namespace Controller
} // namespace chip
54 changes: 54 additions & 0 deletions src/controller/DeviceAddressUpdater.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
*
* Copyright (c) 2021 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.
*/

#pragma once

#include <mdns/Resolver.h>
#include <support/DLLUtil.h>
#include <transport/raw/MessageHeader.h>

namespace chip {
namespace Controller {

class DeviceController;

/// Callbacks for CHIP device address resolution
class DLL_EXPORT DeviceAddressUpdateDelegate
{
public:
virtual ~DeviceAddressUpdateDelegate() {}
virtual void OnAddressUpdateComplete(NodeId nodeId, CHIP_ERROR error) = 0;
};

/// Class for updating CHIP devices' addresses based on responses from mDNS Resolver
class DLL_EXPORT DeviceAddressUpdater : public Mdns::ResolverDelegate
{
public:
CHIP_ERROR Init(DeviceController * controller, DeviceAddressUpdateDelegate * delegate = nullptr);

private:
// Mdns::ResolverDelegate Implementation
void OnNodeIdResolved(NodeId nodeId, const Mdns::ResolvedNodeData & nodeData) override;
void OnNodeIdResolutionFailed(NodeId nodeId, CHIP_ERROR error) override;

DeviceController * mController = nullptr;
DeviceAddressUpdateDelegate * mDelegate = nullptr;
};

} // namespace Controller
} // namespace chip
2 changes: 2 additions & 0 deletions src/controller/python/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ shared_library("ChipDeviceCtrl") {
sources = [
"ChipDeviceController-ClusterCommands.cpp",
"ChipDeviceController-ScriptBinding.cpp",
"ChipDeviceController-ScriptDeviceAddressUpdateDelegate.cpp",
"ChipDeviceController-ScriptDeviceAddressUpdateDelegate.h",
"ChipDeviceController-ScriptDevicePairingDelegate.cpp",
"ChipDeviceController-ScriptDevicePairingDelegate.h",
"ChipDeviceController-StorageDelegate.cpp",
Expand Down
79 changes: 73 additions & 6 deletions src/controller/python/ChipDeviceController-ScriptBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#include <errno.h>
#include <fcntl.h>
#include <memory>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
Expand All @@ -38,13 +39,16 @@
#include <inttypes.h>
#include <net/if.h>

#include "ChipDeviceController-ScriptDeviceAddressUpdateDelegate.h"
#include "ChipDeviceController-ScriptDevicePairingDelegate.h"
#include "ChipDeviceController-StorageDelegate.h"

#include <app/CommandSender.h>
#include <app/InteractionModelEngine.h>
#include <controller/CHIPDevice.h>
#include <controller/CHIPDeviceController.h>
#include <controller/DeviceAddressUpdater.h>
#include <mdns/Resolver.h>
#include <support/CHIPMem.h>
#include <support/CodeUtils.h>
#include <support/DLLUtil.h>
Expand All @@ -63,6 +67,7 @@ typedef void (*LogMessageFunct)(uint64_t time, uint64_t timeUS, const char * mod
namespace {
chip::Controller::PythonPersistentStorageDelegate sStorageDelegate;
chip::Controller::ScriptDevicePairingDelegate sPairingDelegate;
chip::Controller::ScriptDeviceAddressUpdateDelegate sDeviceAddressUpdateDelegate;
} // namespace

// NOTE: Remote device ID is in sync with the echo server device id
Expand All @@ -73,8 +78,13 @@ chip::NodeId kRemoteDeviceId = chip::kTestDeviceNodeId;

extern "C" {
CHIP_ERROR pychip_DeviceController_NewDeviceController(chip::Controller::DeviceCommissioner ** outDevCtrl,
chip::Controller::DeviceAddressUpdater ** outAddressUpdater,
chip::NodeId localDeviceId);
CHIP_ERROR pychip_DeviceController_DeleteDeviceController(chip::Controller::DeviceCommissioner * devCtrl);
CHIP_ERROR pychip_DeviceController_DeleteDeviceController(chip::Controller::DeviceCommissioner * devCtrl,
chip::Controller::DeviceAddressUpdater * addressUpdater);
CHIP_ERROR
pychip_DeviceController_GetAddressAndPort(chip::Controller::DeviceCommissioner * devCtrl, chip::NodeId nodeId, char * outAddress,
uint64_t maxAddressLen, uint16_t * outPort);

// Rendezvous
CHIP_ERROR pychip_DeviceController_ConnectBLE(chip::Controller::DeviceCommissioner * devCtrl, uint16_t discriminator,
Expand All @@ -89,11 +99,18 @@ pychip_ScriptDevicePairingDelegate_SetWifiCredential(chip::Controller::DeviceCom
CHIP_ERROR
pychip_ScriptDevicePairingDelegate_SetThreadCredential(chip::Controller::DeviceCommissioner * devCtrl, int channel, int panId,
const char * masterKey);

CHIP_ERROR
pychip_ScriptDevicePairingDelegate_SetKeyExchangeCallback(chip::Controller::DeviceCommissioner * devCtrl,
chip::Controller::DevicePairingDelegate_OnPairingCompleteFunct callback);

// Discovery
CHIP_ERROR pychip_DeviceAddressUpdater_New(chip::Controller::DeviceAddressUpdater ** outAddressUpdater,
chip::Controller::DeviceCommissioner * devCtrl);
void pychip_DeviceAddressUpdater_Delete(chip::Controller::DeviceAddressUpdater * addressUpdater);
void pychip_ScriptDeviceAddressUpdateDelegate_SetOnAddressUpdateComplete(
chip::Controller::DeviceAddressUpdateDelegate_OnUpdateComplete callback);
CHIP_ERROR pychip_Resolver_ResolveNode(uint64_t fabricid, chip::NodeId nodeid);

uint8_t pychip_DeviceController_GetLogFilter();
void pychip_DeviceController_SetLogFilter(uint8_t category);

Expand All @@ -108,6 +125,7 @@ CHIP_ERROR pychip_GetDeviceByNodeId(chip::Controller::DeviceCommissioner * devCt
}

CHIP_ERROR pychip_DeviceController_NewDeviceController(chip::Controller::DeviceCommissioner ** outDevCtrl,
chip::Controller::DeviceAddressUpdater ** outAddressUpdater,
chip::NodeId localDeviceId)
{
CHIP_ERROR err = CHIP_NO_ERROR;
Expand All @@ -123,21 +141,37 @@ CHIP_ERROR pychip_DeviceController_NewDeviceController(chip::Controller::DeviceC
SuccessOrExit(err = (*outDevCtrl)->ServiceEvents());

exit:
if (err != CHIP_NO_ERROR && *outDevCtrl != NULL)
if (err != CHIP_NO_ERROR && *outAddressUpdater != NULL)
{
delete *outDevCtrl;
*outDevCtrl = NULL;
delete *outAddressUpdater;
*outAddressUpdater = NULL;
}

return err;
}

CHIP_ERROR pychip_DeviceController_DeleteDeviceController(chip::Controller::DeviceCommissioner * devCtrl)
CHIP_ERROR pychip_DeviceController_DeleteDeviceController(chip::Controller::DeviceCommissioner * devCtrl,
chip::Controller::DeviceAddressUpdater * addressUpdater)
{
if (devCtrl != NULL)
{
devCtrl->Shutdown();
delete devCtrl;
}

return CHIP_NO_ERROR;
}

CHIP_ERROR pychip_DeviceController_GetAddressAndPort(chip::Controller::DeviceCommissioner * devCtrl, chip::NodeId nodeId,
char * outAddress, uint64_t maxAddressLen, uint16_t * outPort)
{
Device * device;
ReturnErrorOnFailure(devCtrl->GetDevice(nodeId, &device));

Inet::IPAddress address;
VerifyOrReturnError(device->GetAddress(address, *outPort), CHIP_ERROR_INCORRECT_STATE);
VerifyOrReturnError(address.ToString(outAddress, maxAddressLen), CHIP_ERROR_BUFFER_TOO_SMALL);

return CHIP_NO_ERROR;
}

Expand Down Expand Up @@ -237,6 +271,39 @@ pychip_ScriptDevicePairingDelegate_SetKeyExchangeCallback(chip::Controller::Devi
return CHIP_NO_ERROR;
}

CHIP_ERROR pychip_DeviceAddressUpdater_New(chip::Controller::DeviceAddressUpdater ** outAddressUpdater,
chip::Controller::DeviceCommissioner * devCtrl)
{
auto addressUpdater = std::make_unique<chip::Controller::DeviceAddressUpdater>();

VerifyOrReturnError(addressUpdater.get() != nullptr, CHIP_ERROR_NO_MEMORY);
ReturnErrorOnFailure(addressUpdater->Init(devCtrl, &sDeviceAddressUpdateDelegate));
ReturnErrorOnFailure(Mdns::Resolver::Instance().SetResolverDelegate(addressUpdater.get()));

*outAddressUpdater = addressUpdater.release();
return CHIP_NO_ERROR;
}

void pychip_DeviceAddressUpdater_Delete(chip::Controller::DeviceAddressUpdater * addressUpdater)
{
if (addressUpdater != nullptr)
{
Mdns::Resolver::Instance().SetResolverDelegate(nullptr);
delete addressUpdater;
}
}

void pychip_ScriptDeviceAddressUpdateDelegate_SetOnAddressUpdateComplete(
chip::Controller::DeviceAddressUpdateDelegate_OnUpdateComplete callback)
{
sDeviceAddressUpdateDelegate.SetOnAddressUpdateComplete(callback);
}

CHIP_ERROR pychip_Resolver_ResolveNode(uint64_t fabricid, chip::NodeId nodeid)
{
return Mdns::Resolver::Instance().ResolveNodeId(nodeid, fabricid, Inet::kIPAddressType_Any);
}

CHIP_ERROR pychip_Stack_Init()
{
CHIP_ERROR err = CHIP_NO_ERROR;
Expand Down
Loading

0 comments on commit a578416

Please sign in to comment.