Skip to content

Commit a578416

Browse files
[python/mdns] Add "resolve" command for operational discovery (#5025)
* [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.
1 parent fc666df commit a578416

19 files changed

+595
-112
lines changed

src/controller/BUILD.gn

+3
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,16 @@ static_library("controller") {
3131
"CHIPDeviceController.h",
3232
"CHIPDeviceController_deprecated.cpp",
3333
"CHIPDeviceController_deprecated.h",
34+
"DeviceAddressUpdater.cpp",
35+
"DeviceAddressUpdater.h",
3436
]
3537

3638
cflags = [ "-Wconversion" ]
3739

3840
public_deps = [
3941
"${chip_root}/src/app",
4042
"${chip_root}/src/lib/core",
43+
"${chip_root}/src/lib/mdns",
4144
"${chip_root}/src/lib/support",
4245
"${chip_root}/src/messaging",
4346
"${chip_root}/src/platform",

src/controller/CHIPDevice.cpp

+18-1
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,22 @@ CHIP_ERROR Device::OpenPairingWindow(uint32_t timeout, PairingWindowOption optio
292292
return CHIP_NO_ERROR;
293293
}
294294

295+
CHIP_ERROR Device::UpdateAddress(const Transport::PeerAddress & addr)
296+
{
297+
bool didLoad;
298+
299+
VerifyOrReturnError(addr.GetTransportType() == Transport::Type::kUdp, CHIP_ERROR_INVALID_ADDRESS);
300+
ReturnErrorOnFailure(LoadSecureSessionParametersIfNeeded(didLoad));
301+
302+
Transport::PeerConnectionState * connectionState = mSessionManager->GetPeerConnectionState(mSecureSession);
303+
VerifyOrReturnError(connectionState != nullptr, CHIP_ERROR_INCORRECT_STATE);
304+
305+
mDeviceUdpAddress = addr;
306+
connectionState->SetPeerAddress(addr);
307+
308+
return CHIP_NO_ERROR;
309+
}
310+
295311
CHIP_ERROR Device::LoadSecureSessionParameters(ResetTransport resetNeeded)
296312
{
297313
CHIP_ERROR err = CHIP_NO_ERROR;
@@ -330,12 +346,13 @@ CHIP_ERROR Device::LoadSecureSessionParameters(ResetTransport resetNeeded)
330346
return err;
331347
}
332348

333-
bool Device::GetIpAddress(Inet::IPAddress & addr) const
349+
bool Device::GetAddress(Inet::IPAddress & addr, uint16_t & port) const
334350
{
335351
if (mState == ConnectionState::NotConnected)
336352
return false;
337353

338354
addr = mDeviceUdpAddress.GetIPAddress();
355+
port = mDeviceUdpAddress.GetPort();
339356
return true;
340357
}
341358

src/controller/CHIPDevice.h

+18-5
Original file line numberDiff line numberDiff line change
@@ -119,14 +119,14 @@ class DLL_EXPORT Device
119119
app::CommandSender * GetCommandSender() { return mCommandSender; }
120120

121121
/**
122-
* @brief
123-
* Get the IP address assigned to the device.
122+
* @brief Get the IP address and port assigned to the device.
124123
*
125-
* @param[out] addr The reference to the IP address.
124+
* @param[out] addr IP address of the device.
125+
* @param[out] port Port number of the device.
126126
*
127-
* @return true, if the IP address was filled in the out parameter, false otherwise
127+
* @return true, if the IP address and port were filled in the out parameters, false otherwise
128128
*/
129-
bool GetIpAddress(Inet::IPAddress & addr) const;
129+
bool GetAddress(Inet::IPAddress & addr, uint16_t & port) const;
130130

131131
/**
132132
* @brief
@@ -261,6 +261,19 @@ class DLL_EXPORT Device
261261
*/
262262
CHIP_ERROR OpenPairingWindow(uint32_t timeout, PairingWindowOption option, SetupPayload & setupPayload);
263263

264+
/**
265+
* @brief
266+
* Update address of the device.
267+
*
268+
* This function will set new IP address and port of the device. Since the device settings might
269+
* have been moved from RAM to the persistent storage, the function will load the device settings
270+
* first, before making the changes.
271+
*
272+
* @param[in] addr Address of the device to be set.
273+
*
274+
* @return CHIP_NO_ERROR if the address has been updated, an error code otherwise.
275+
*/
276+
CHIP_ERROR UpdateAddress(const Transport::PeerAddress & addr);
264277
/**
265278
* @brief
266279
* Return whether the current device object is actively associated with a paired CHIP

src/controller/CHIPDeviceController_deprecated.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,8 @@ bool ChipDeviceController::GetIpAddress(Inet::IPAddress & addr)
177177
if (mDevice == nullptr)
178178
InitDevice();
179179

180-
return mDevice != nullptr && mDevice->GetIpAddress(addr);
180+
uint16_t port;
181+
return mDevice != nullptr && mDevice->GetAddress(addr, port);
181182
}
182183

183184
CHIP_ERROR ChipDeviceController::DisconnectDevice()
+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
*
3+
* Copyright (c) 2021 Project CHIP Authors
4+
* All rights reserved.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#include "DeviceAddressUpdater.h"
20+
21+
#include <controller/CHIPDeviceController.h>
22+
#include <support/ReturnMacros.h>
23+
24+
namespace chip {
25+
namespace Controller {
26+
27+
CHIP_ERROR DeviceAddressUpdater::Init(DeviceController * controller, DeviceAddressUpdateDelegate * delegate)
28+
{
29+
VerifyOrReturnError(mController == nullptr, CHIP_ERROR_INCORRECT_STATE);
30+
VerifyOrReturnError(mDelegate == nullptr, CHIP_ERROR_INCORRECT_STATE);
31+
32+
mController = controller;
33+
mDelegate = delegate;
34+
35+
return CHIP_NO_ERROR;
36+
}
37+
38+
void DeviceAddressUpdater::OnNodeIdResolved(NodeId nodeId, const Mdns::ResolvedNodeData & nodeData)
39+
{
40+
CHIP_ERROR error = CHIP_NO_ERROR;
41+
Device * device = nullptr;
42+
43+
VerifyOrExit(nodeData.mAddress.Type() != Inet::kIPAddressType_Any, error = CHIP_ERROR_INVALID_ADDRESS);
44+
VerifyOrExit(mController != nullptr, error = CHIP_ERROR_INCORRECT_STATE);
45+
SuccessOrExit(error = mController->GetDevice(nodeId, &device));
46+
47+
device->UpdateAddress(Transport::PeerAddress::UDP(nodeData.mAddress, nodeData.mPort, nodeData.mInterfaceId));
48+
49+
exit:
50+
if (mDelegate != nullptr)
51+
{
52+
mDelegate->OnAddressUpdateComplete(nodeId, error);
53+
}
54+
}
55+
56+
void DeviceAddressUpdater::OnNodeIdResolutionFailed(NodeId nodeId, CHIP_ERROR error)
57+
{
58+
if (mDelegate != nullptr)
59+
{
60+
mDelegate->OnAddressUpdateComplete(nodeId, error);
61+
}
62+
}
63+
64+
} // namespace Controller
65+
} // namespace chip

src/controller/DeviceAddressUpdater.h

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
*
3+
* Copyright (c) 2021 Project CHIP Authors
4+
* All rights reserved.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#pragma once
20+
21+
#include <mdns/Resolver.h>
22+
#include <support/DLLUtil.h>
23+
#include <transport/raw/MessageHeader.h>
24+
25+
namespace chip {
26+
namespace Controller {
27+
28+
class DeviceController;
29+
30+
/// Callbacks for CHIP device address resolution
31+
class DLL_EXPORT DeviceAddressUpdateDelegate
32+
{
33+
public:
34+
virtual ~DeviceAddressUpdateDelegate() {}
35+
virtual void OnAddressUpdateComplete(NodeId nodeId, CHIP_ERROR error) = 0;
36+
};
37+
38+
/// Class for updating CHIP devices' addresses based on responses from mDNS Resolver
39+
class DLL_EXPORT DeviceAddressUpdater : public Mdns::ResolverDelegate
40+
{
41+
public:
42+
CHIP_ERROR Init(DeviceController * controller, DeviceAddressUpdateDelegate * delegate = nullptr);
43+
44+
private:
45+
// Mdns::ResolverDelegate Implementation
46+
void OnNodeIdResolved(NodeId nodeId, const Mdns::ResolvedNodeData & nodeData) override;
47+
void OnNodeIdResolutionFailed(NodeId nodeId, CHIP_ERROR error) override;
48+
49+
DeviceController * mController = nullptr;
50+
DeviceAddressUpdateDelegate * mDelegate = nullptr;
51+
};
52+
53+
} // namespace Controller
54+
} // namespace chip

src/controller/python/BUILD.gn

+2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ shared_library("ChipDeviceCtrl") {
3939
sources = [
4040
"ChipDeviceController-ClusterCommands.cpp",
4141
"ChipDeviceController-ScriptBinding.cpp",
42+
"ChipDeviceController-ScriptDeviceAddressUpdateDelegate.cpp",
43+
"ChipDeviceController-ScriptDeviceAddressUpdateDelegate.h",
4244
"ChipDeviceController-ScriptDevicePairingDelegate.cpp",
4345
"ChipDeviceController-ScriptDevicePairingDelegate.h",
4446
"ChipDeviceController-StorageDelegate.cpp",

src/controller/python/ChipDeviceController-ScriptBinding.cpp

+73-6
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
#include <errno.h>
2929
#include <fcntl.h>
30+
#include <memory>
3031
#include <stdio.h>
3132
#include <stdlib.h>
3233
#include <sys/time.h>
@@ -38,13 +39,16 @@
3839
#include <inttypes.h>
3940
#include <net/if.h>
4041

42+
#include "ChipDeviceController-ScriptDeviceAddressUpdateDelegate.h"
4143
#include "ChipDeviceController-ScriptDevicePairingDelegate.h"
4244
#include "ChipDeviceController-StorageDelegate.h"
4345

4446
#include <app/CommandSender.h>
4547
#include <app/InteractionModelEngine.h>
4648
#include <controller/CHIPDevice.h>
4749
#include <controller/CHIPDeviceController.h>
50+
#include <controller/DeviceAddressUpdater.h>
51+
#include <mdns/Resolver.h>
4852
#include <support/CHIPMem.h>
4953
#include <support/CodeUtils.h>
5054
#include <support/DLLUtil.h>
@@ -63,6 +67,7 @@ typedef void (*LogMessageFunct)(uint64_t time, uint64_t timeUS, const char * mod
6367
namespace {
6468
chip::Controller::PythonPersistentStorageDelegate sStorageDelegate;
6569
chip::Controller::ScriptDevicePairingDelegate sPairingDelegate;
70+
chip::Controller::ScriptDeviceAddressUpdateDelegate sDeviceAddressUpdateDelegate;
6671
} // namespace
6772

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

7479
extern "C" {
7580
CHIP_ERROR pychip_DeviceController_NewDeviceController(chip::Controller::DeviceCommissioner ** outDevCtrl,
81+
chip::Controller::DeviceAddressUpdater ** outAddressUpdater,
7682
chip::NodeId localDeviceId);
77-
CHIP_ERROR pychip_DeviceController_DeleteDeviceController(chip::Controller::DeviceCommissioner * devCtrl);
83+
CHIP_ERROR pychip_DeviceController_DeleteDeviceController(chip::Controller::DeviceCommissioner * devCtrl,
84+
chip::Controller::DeviceAddressUpdater * addressUpdater);
85+
CHIP_ERROR
86+
pychip_DeviceController_GetAddressAndPort(chip::Controller::DeviceCommissioner * devCtrl, chip::NodeId nodeId, char * outAddress,
87+
uint64_t maxAddressLen, uint16_t * outPort);
7888

7989
// Rendezvous
8090
CHIP_ERROR pychip_DeviceController_ConnectBLE(chip::Controller::DeviceCommissioner * devCtrl, uint16_t discriminator,
@@ -89,11 +99,18 @@ pychip_ScriptDevicePairingDelegate_SetWifiCredential(chip::Controller::DeviceCom
8999
CHIP_ERROR
90100
pychip_ScriptDevicePairingDelegate_SetThreadCredential(chip::Controller::DeviceCommissioner * devCtrl, int channel, int panId,
91101
const char * masterKey);
92-
93102
CHIP_ERROR
94103
pychip_ScriptDevicePairingDelegate_SetKeyExchangeCallback(chip::Controller::DeviceCommissioner * devCtrl,
95104
chip::Controller::DevicePairingDelegate_OnPairingCompleteFunct callback);
96105

106+
// Discovery
107+
CHIP_ERROR pychip_DeviceAddressUpdater_New(chip::Controller::DeviceAddressUpdater ** outAddressUpdater,
108+
chip::Controller::DeviceCommissioner * devCtrl);
109+
void pychip_DeviceAddressUpdater_Delete(chip::Controller::DeviceAddressUpdater * addressUpdater);
110+
void pychip_ScriptDeviceAddressUpdateDelegate_SetOnAddressUpdateComplete(
111+
chip::Controller::DeviceAddressUpdateDelegate_OnUpdateComplete callback);
112+
CHIP_ERROR pychip_Resolver_ResolveNode(uint64_t fabricid, chip::NodeId nodeid);
113+
97114
uint8_t pychip_DeviceController_GetLogFilter();
98115
void pychip_DeviceController_SetLogFilter(uint8_t category);
99116

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

110127
CHIP_ERROR pychip_DeviceController_NewDeviceController(chip::Controller::DeviceCommissioner ** outDevCtrl,
128+
chip::Controller::DeviceAddressUpdater ** outAddressUpdater,
111129
chip::NodeId localDeviceId)
112130
{
113131
CHIP_ERROR err = CHIP_NO_ERROR;
@@ -123,21 +141,37 @@ CHIP_ERROR pychip_DeviceController_NewDeviceController(chip::Controller::DeviceC
123141
SuccessOrExit(err = (*outDevCtrl)->ServiceEvents());
124142

125143
exit:
126-
if (err != CHIP_NO_ERROR && *outDevCtrl != NULL)
144+
if (err != CHIP_NO_ERROR && *outAddressUpdater != NULL)
127145
{
128-
delete *outDevCtrl;
129-
*outDevCtrl = NULL;
146+
delete *outAddressUpdater;
147+
*outAddressUpdater = NULL;
130148
}
149+
131150
return err;
132151
}
133152

134-
CHIP_ERROR pychip_DeviceController_DeleteDeviceController(chip::Controller::DeviceCommissioner * devCtrl)
153+
CHIP_ERROR pychip_DeviceController_DeleteDeviceController(chip::Controller::DeviceCommissioner * devCtrl,
154+
chip::Controller::DeviceAddressUpdater * addressUpdater)
135155
{
136156
if (devCtrl != NULL)
137157
{
138158
devCtrl->Shutdown();
139159
delete devCtrl;
140160
}
161+
162+
return CHIP_NO_ERROR;
163+
}
164+
165+
CHIP_ERROR pychip_DeviceController_GetAddressAndPort(chip::Controller::DeviceCommissioner * devCtrl, chip::NodeId nodeId,
166+
char * outAddress, uint64_t maxAddressLen, uint16_t * outPort)
167+
{
168+
Device * device;
169+
ReturnErrorOnFailure(devCtrl->GetDevice(nodeId, &device));
170+
171+
Inet::IPAddress address;
172+
VerifyOrReturnError(device->GetAddress(address, *outPort), CHIP_ERROR_INCORRECT_STATE);
173+
VerifyOrReturnError(address.ToString(outAddress, maxAddressLen), CHIP_ERROR_BUFFER_TOO_SMALL);
174+
141175
return CHIP_NO_ERROR;
142176
}
143177

@@ -237,6 +271,39 @@ pychip_ScriptDevicePairingDelegate_SetKeyExchangeCallback(chip::Controller::Devi
237271
return CHIP_NO_ERROR;
238272
}
239273

274+
CHIP_ERROR pychip_DeviceAddressUpdater_New(chip::Controller::DeviceAddressUpdater ** outAddressUpdater,
275+
chip::Controller::DeviceCommissioner * devCtrl)
276+
{
277+
auto addressUpdater = std::make_unique<chip::Controller::DeviceAddressUpdater>();
278+
279+
VerifyOrReturnError(addressUpdater.get() != nullptr, CHIP_ERROR_NO_MEMORY);
280+
ReturnErrorOnFailure(addressUpdater->Init(devCtrl, &sDeviceAddressUpdateDelegate));
281+
ReturnErrorOnFailure(Mdns::Resolver::Instance().SetResolverDelegate(addressUpdater.get()));
282+
283+
*outAddressUpdater = addressUpdater.release();
284+
return CHIP_NO_ERROR;
285+
}
286+
287+
void pychip_DeviceAddressUpdater_Delete(chip::Controller::DeviceAddressUpdater * addressUpdater)
288+
{
289+
if (addressUpdater != nullptr)
290+
{
291+
Mdns::Resolver::Instance().SetResolverDelegate(nullptr);
292+
delete addressUpdater;
293+
}
294+
}
295+
296+
void pychip_ScriptDeviceAddressUpdateDelegate_SetOnAddressUpdateComplete(
297+
chip::Controller::DeviceAddressUpdateDelegate_OnUpdateComplete callback)
298+
{
299+
sDeviceAddressUpdateDelegate.SetOnAddressUpdateComplete(callback);
300+
}
301+
302+
CHIP_ERROR pychip_Resolver_ResolveNode(uint64_t fabricid, chip::NodeId nodeid)
303+
{
304+
return Mdns::Resolver::Instance().ResolveNodeId(nodeid, fabricid, Inet::kIPAddressType_Any);
305+
}
306+
240307
CHIP_ERROR pychip_Stack_Init()
241308
{
242309
CHIP_ERROR err = CHIP_NO_ERROR;

0 commit comments

Comments
 (0)