3 * Copyright (c) 2020 Project CHIP Authors
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #include "DiscoveryManager.h"
22 #include "lib/mdns/platform/Mdns.h"
23 #include "lib/support/logging/CHIPLogging.h"
24 #include "platform/CHIPDeviceConfig.h"
25 #include "platform/CHIPDeviceLayer.h"
26 #include "support/CodeUtils.h"
27 #include "support/ErrorStr.h"
28 #include "support/RandUtils.h"
34 uint8_t HexToInt(char c)
36 if ('0' <= c && c <= '9')
38 return static_cast<uint8_t>(c - '0');
40 else if ('a' <= c && c <= 'f')
42 return static_cast<uint8_t>(0x0a + c - 'a');
44 else if ('A' <= c && c <= 'F')
46 return static_cast<uint8_t>(0x0a + c - 'A');
52 constexpr uint64_t kUndefinedNodeId = 0;
60 DiscoveryManager DiscoveryManager::sManager;
62 CHIP_ERROR DiscoveryManager::Init()
67 mUnprovisionedInstanceName = GetRandU64();
68 SuccessOrExit(error = ChipMdnsInit(HandleMdnsInit, HandleMdnsError, this));
73 #endif // CHIP_ENABLE_MDNS
76 void DiscoveryManager::HandleMdnsInit(void * context, CHIP_ERROR initError)
79 DiscoveryManager * publisher = static_cast<DiscoveryManager *>(context);
81 if (initError == CHIP_NO_ERROR)
83 publisher->mMdnsInitialized = true;
87 ChipLogError(Discovery, "mDNS initialization failed with %s", chip::ErrorStr(initError));
89 #endif // CHIP_ENABLE_MDNS
92 void DiscoveryManager::HandleMdnsError(void * context, CHIP_ERROR error)
95 DiscoveryManager * publisher = static_cast<DiscoveryManager *>(context);
96 if (error == CHIP_ERROR_FORCED_RESET && publisher->mIsPublishing)
98 publisher->StartPublishDevice();
102 ChipLogError(Discovery, "mDNS error: %s", chip::ErrorStr(error));
104 #endif // CHIP_ENABLE_MDNS
107 CHIP_ERROR DiscoveryManager::StartPublishDevice(chip::Inet::IPAddressType addressType, chip::Inet::InterfaceId interface)
112 // TODO: after multi-admin is decided we may need to publish both _chipc._udp and _chip._tcp service
115 SuccessOrExit(error = SetupHostname());
117 else if (chip::DeviceLayer::ConfigurationMgr().IsFullyProvisioned() != mIsPublishingProvisionedDevice)
119 SuccessOrExit(error = StopPublishDevice());
120 // Set hostname again in case the mac address changes when shifting from soft-AP to station
121 SuccessOrExit(error = SetupHostname());
123 mIsPublishingProvisionedDevice = chip::DeviceLayer::ConfigurationMgr().IsFullyProvisioned();
125 if (mIsPublishingProvisionedDevice)
127 error = PublishProvisionedDevice(addressType, interface);
131 error = PublishUnprovisionedDevice(addressType, interface);
133 mIsPublishing = true;
137 return CHIP_ERROR_NOT_IMPLEMENTED;
138 #endif // CHIP_ENABLE_MDNS
141 CHIP_ERROR DiscoveryManager::SetupHostname()
144 uint8_t mac[6]; // 6 byte wifi mac
145 char hostname[13]; // Hostname will be the hex representation of mac.
148 SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetPrimaryWiFiMACAddress(mac));
149 for (size_t i = 0; i < sizeof(mac); i++)
151 snprintf(&hostname[i * 2], sizeof(hostname) - i * 2, "%02X", mac[i]);
153 SuccessOrExit(error = ChipMdnsSetHostname(hostname));
158 return CHIP_ERROR_NOT_IMPLEMENTED;
159 #endif // CHIP_ENABLE_MDNS
162 CHIP_ERROR DiscoveryManager::PublishUnprovisionedDevice(chip::Inet::IPAddressType addressType, chip::Inet::InterfaceId interface)
165 CHIP_ERROR error = CHIP_NO_ERROR;
167 uint16_t discriminator;
170 char discriminatorBuf[5]; // hex representation of 16-bit discriminator
171 char vendorProductBuf[10]; // "FFFF+FFFF"
172 // TODO: The text entry will be updated in the spec, update accordingly.
173 TextEntry entries[2] = {
175 { "VP", nullptr, 0 },
178 VerifyOrExit(mMdnsInitialized, error = CHIP_ERROR_INCORRECT_STATE);
179 ChipLogProgress(Discovery, "setup mdns service");
180 SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetSetupDiscriminator(discriminator));
181 snprintf(service.mName, sizeof(service.mName), "%016" PRIX64, mUnprovisionedInstanceName);
182 strncpy(service.mType, "_chipc", sizeof(service.mType));
183 service.mProtocol = MdnsServiceProtocol::kMdnsProtocolUdp;
184 SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetVendorId(vendorID));
185 SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetProductId(productID));
186 snprintf(discriminatorBuf, sizeof(discriminatorBuf), "%04X", discriminator);
187 snprintf(vendorProductBuf, sizeof(vendorProductBuf), "%04X+%04X", vendorID, productID);
188 entries[0].mData = reinterpret_cast<const uint8_t *>(discriminatorBuf);
189 entries[0].mDataSize = strnlen(discriminatorBuf, sizeof(discriminatorBuf));
190 entries[1].mData = reinterpret_cast<const uint8_t *>(vendorProductBuf);
191 entries[1].mDataSize = strnlen(discriminatorBuf, sizeof(vendorProductBuf));
192 service.mTextEntryies = entries;
193 service.mTextEntrySize = sizeof(entries) / sizeof(TextEntry);
194 service.mPort = CHIP_PORT;
195 service.mInterface = interface;
196 service.mAddressType = addressType;
197 error = ChipMdnsPublishService(&service);
202 return CHIP_ERROR_NOT_IMPLEMENTED;
203 #endif // CHIP_ENABLE_MDNS
206 CHIP_ERROR DiscoveryManager::PublishProvisionedDevice(chip::Inet::IPAddressType addressType, chip::Inet::InterfaceId interface)
212 CHIP_ERROR error = CHIP_NO_ERROR;
214 // TODO: There may be multilple device/fabrid ids after multi-admin.
215 SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetFabricId(fabricId));
216 SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetDeviceId(deviceId));
217 snprintf(service.mName, sizeof(service.mName), "%" PRIX64 "-%" PRIX64, deviceId, fabricId);
218 strncpy(service.mType, "_chip", sizeof(service.mType));
219 service.mProtocol = MdnsServiceProtocol::kMdnsProtocolTcp;
220 service.mPort = CHIP_PORT;
221 service.mTextEntryies = nullptr;
222 service.mTextEntrySize = 0;
223 service.mInterface = interface;
224 service.mAddressType = addressType;
225 error = ChipMdnsPublishService(&service);
230 return CHIP_ERROR_NOT_IMPLEMENTED;
231 #endif // CHIP_ENABLE_MDNS
234 CHIP_ERROR DiscoveryManager::StopPublishDevice()
237 mIsPublishing = false;
238 return ChipMdnsStopPublish();
240 return CHIP_ERROR_NOT_IMPLEMENTED;
241 #endif // CHIP_ENABLE_MDNS
244 CHIP_ERROR DiscoveryManager::RegisterResolveDelegate(ResolveDelegate * delegate)
246 if (mResolveDelegate != nullptr)
248 return CHIP_ERROR_INCORRECT_STATE;
252 mResolveDelegate = delegate;
253 return CHIP_NO_ERROR;
257 CHIP_ERROR DiscoveryManager::ResolveNodeId(uint64_t nodeId, uint64_t fabricId, Inet::IPAddressType type)
262 snprintf(service.mName, sizeof(service.mName), "%" PRIX64 "-%" PRIX64, nodeId, fabricId);
263 strncpy(service.mType, "_chip", sizeof(service.mType));
264 service.mProtocol = MdnsServiceProtocol::kMdnsProtocolTcp;
265 service.mAddressType = type;
266 return ChipMdnsResolve(&service, INET_NULL_INTERFACEID, HandleNodeIdResolve, this);
268 return CHIP_ERROR_NOT_IMPLEMENTED;
269 #endif // CHIP_ENABLE_MDNS
272 void DiscoveryManager::HandleNodeIdResolve(void * context, MdnsService * result, CHIP_ERROR error)
275 DiscoveryManager * mgr = static_cast<DiscoveryManager *>(context);
277 if (mgr->mResolveDelegate == nullptr)
281 if (error != CHIP_NO_ERROR)
283 ChipLogError(Discovery, "Node ID resolved failed with %s", chip::ErrorStr(error));
284 mgr->mResolveDelegate->HandleNodeIdResolve(error, kUndefinedNodeId, MdnsService{});
286 else if (result == nullptr)
288 ChipLogError(Discovery, "Node ID resolve not found");
289 mgr->mResolveDelegate->HandleNodeIdResolve(CHIP_ERROR_UNKNOWN_RESOURCE_ID, kUndefinedNodeId, MdnsService{});
293 // Parse '%x-%x' from the name
295 bool deliminatorFound = false;
297 for (size_t i = 0; i < sizeof(result->mName) && result->mName[i] != 0; i++)
299 if (result->mName[i] == '-')
301 deliminatorFound = true;
306 uint8_t val = HexToInt(result->mName[i]);
308 if (val == UINT8_MAX)
314 nodeId = nodeId * 16 + val;
319 if (deliminatorFound)
321 ChipLogProgress(Discovery, "Node ID resolved for %" PRIX64, nodeId);
322 mgr->mResolveDelegate->HandleNodeIdResolve(error, nodeId, *result);
326 ChipLogProgress(Discovery, "Invalid service entry from node %" PRIX64, nodeId);
327 mgr->mResolveDelegate->HandleNodeIdResolve(error, kUndefinedNodeId, *result);
330 #endif // CHIP_ENABLE_MDNS