Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / lib / mdns / Discovery_ImplPlatform.cpp
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *
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
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 #include "Discovery_ImplPlatform.h"
19
20 #include <inttypes.h>
21
22 #include "ServiceNaming.h"
23 #include "lib/core/CHIPSafeCasts.h"
24 #include "lib/mdns/platform/Mdns.h"
25 #include "lib/support/logging/CHIPLogging.h"
26 #include "platform/CHIPDeviceConfig.h"
27 #include "platform/CHIPDeviceLayer.h"
28 #include "setup_payload/AdditionalDataPayloadGenerator.h"
29 #include "support/CodeUtils.h"
30 #include "support/ErrorStr.h"
31 #include "support/RandUtils.h"
32
33 namespace {
34
35 uint8_t HexToInt(char c)
36 {
37     if ('0' <= c && c <= '9')
38     {
39         return static_cast<uint8_t>(c - '0');
40     }
41     else if ('a' <= c && c <= 'f')
42     {
43         return static_cast<uint8_t>(0x0a + c - 'a');
44     }
45     else if ('A' <= c && c <= 'F')
46     {
47         return static_cast<uint8_t>(0x0a + c - 'A');
48     }
49
50     return UINT8_MAX;
51 }
52
53 constexpr uint64_t kUndefinedNodeId = 0;
54
55 } // namespace
56
57 namespace chip {
58 namespace Mdns {
59
60 DiscoveryImplPlatform DiscoveryImplPlatform::sManager;
61
62 DiscoveryImplPlatform::DiscoveryImplPlatform() = default;
63
64 CHIP_ERROR DiscoveryImplPlatform::Init()
65 {
66     if (!mMdnsInitialized)
67     {
68         ReturnErrorOnFailure(ChipMdnsInit(HandleMdnsInit, HandleMdnsError, this));
69         mCommissionInstanceName = GetRandU64();
70         mMdnsInitialized        = true;
71     }
72
73     return CHIP_NO_ERROR;
74 }
75
76 CHIP_ERROR DiscoveryImplPlatform::Start(Inet::InetLayer * inetLayer, uint16_t port)
77 {
78     ReturnErrorOnFailure(Init());
79
80     CHIP_ERROR error = ChipMdnsStopPublish();
81
82     if (error != CHIP_NO_ERROR)
83     {
84         ChipLogError(Discovery, "Failed to initialize platform mdns: %s", ErrorStr(error));
85     }
86
87     error = SetupHostname();
88     if (error != CHIP_NO_ERROR)
89     {
90         ChipLogError(Discovery, "Failed to setup mdns hostname: %s", ErrorStr(error));
91     }
92
93     return error;
94 }
95
96 void DiscoveryImplPlatform::HandleMdnsInit(void * context, CHIP_ERROR initError)
97 {
98     DiscoveryImplPlatform * publisher = static_cast<DiscoveryImplPlatform *>(context);
99
100     if (initError == CHIP_NO_ERROR)
101     {
102         publisher->mMdnsInitialized = true;
103     }
104     else
105     {
106         ChipLogError(Discovery, "mDNS initialization failed with %s", chip::ErrorStr(initError));
107         publisher->mMdnsInitialized = false;
108     }
109 }
110
111 void DiscoveryImplPlatform::HandleMdnsError(void * context, CHIP_ERROR error)
112 {
113     DiscoveryImplPlatform * publisher = static_cast<DiscoveryImplPlatform *>(context);
114     if (error == CHIP_ERROR_FORCED_RESET)
115     {
116         if (publisher->mIsOperationalPublishing)
117         {
118             publisher->Advertise(publisher->mOperationalAdvertisingParams);
119         }
120         if (publisher->mIsCommissionalPublishing)
121         {
122             publisher->Advertise(publisher->mCommissioningdvertisingParams);
123         }
124     }
125     else
126     {
127         ChipLogError(Discovery, "mDNS error: %s", chip::ErrorStr(error));
128     }
129 }
130
131 #if CHIP_ENABLE_ROTATING_DEVICE_ID
132 CHIP_ERROR DiscoveryImplPlatform::GenerateRotatingDeviceId(char rotatingDeviceIdHexBuffer[], size_t & rotatingDeviceIdHexBufferSize)
133 {
134     CHIP_ERROR error = CHIP_NO_ERROR;
135     char serialNumber[chip::DeviceLayer::ConfigurationManager::kMaxSerialNumberLength + 1];
136     size_t serialNumberSize  = 0;
137     uint16_t lifetimeCounter = 0;
138     SuccessOrExit(error =
139                       chip::DeviceLayer::ConfigurationMgr().GetSerialNumber(serialNumber, sizeof(serialNumber), serialNumberSize));
140     SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetLifetimeCounter(lifetimeCounter));
141     SuccessOrExit(error = AdditionalDataPayloadGenerator().generateRotatingDeviceId(
142                       lifetimeCounter, serialNumber, serialNumberSize, rotatingDeviceIdHexBuffer, rotatingDeviceIdHexBufferSize,
143                       rotatingDeviceIdHexBufferSize));
144 exit:
145     return error;
146 }
147 #endif
148
149 CHIP_ERROR DiscoveryImplPlatform::SetupHostname()
150 {
151 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
152     static char hostname[17]; // Hostname is 64-bit EUI-64 expressed as a 16-character hexadecimal string.
153     uint8_t eui64[8];
154     chip::DeviceLayer::ThreadStackMgr().GetFactoryAssignedEUI64(eui64);
155     snprintf(hostname, sizeof(hostname), "%02X%02X%02X%02X%02X%02X%02X%02X", eui64[0], eui64[1], eui64[2], eui64[3], eui64[4],
156              eui64[5], eui64[6], eui64[7]);
157 #else
158     uint8_t mac[6];    // 6 byte wifi mac
159     char hostname[13]; // Hostname will be the hex representation of mac.
160
161     ReturnErrorOnFailure(chip::DeviceLayer::ConfigurationMgr().GetPrimaryWiFiMACAddress(mac));
162     for (size_t i = 0; i < sizeof(mac); i++)
163     {
164         snprintf(&hostname[i * 2], sizeof(hostname) - i * 2, "%02X", mac[i]);
165     }
166 #endif
167
168     ReturnErrorOnFailure(ChipMdnsSetHostname(hostname));
169
170     return CHIP_NO_ERROR;
171 }
172
173 CHIP_ERROR DiscoveryImplPlatform::Advertise(const CommissionAdvertisingParameters & params)
174 {
175     CHIP_ERROR error = CHIP_NO_ERROR;
176     MdnsService service;
177     char discriminatorBuf[6];
178     char vendorProductBuf[12];
179     char pairingInstrBuf[128];
180     TextEntry textEntries[4];
181     size_t textEntrySize = 0;
182     char shortDiscriminatorSubtype[6];
183     char longDiscriminatorSubtype[8];
184     char vendorSubType[8];
185     const char * subTypes[3];
186     size_t subTypeSize = 0;
187 #if CHIP_ENABLE_ROTATING_DEVICE_ID
188     char rotatingDeviceIdHexBuffer[RotatingDeviceId::kHexMaxLength];
189     size_t rotatingDeviceIdHexBufferSize = 0;
190 #endif
191
192     if (!mMdnsInitialized)
193     {
194         return CHIP_ERROR_INCORRECT_STATE;
195     }
196     snprintf(service.mName, sizeof(service.mName), "%016" PRIX64, mCommissionInstanceName);
197     if (params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissioning)
198     {
199         strncpy(service.mType, "_chipc", sizeof(service.mType));
200     }
201     else
202     {
203         strncpy(service.mType, "_chipd", sizeof(service.mType));
204     }
205     service.mProtocol = MdnsServiceProtocol::kMdnsProtocolUdp;
206
207     snprintf(discriminatorBuf, sizeof(discriminatorBuf), "%04u", params.GetLongDiscriminator());
208     textEntries[textEntrySize++] = { "D", reinterpret_cast<const uint8_t *>(discriminatorBuf),
209                                      strnlen(discriminatorBuf, sizeof(discriminatorBuf)) };
210     if (params.GetVendorId().HasValue())
211     {
212         if (params.GetProductId().HasValue())
213         {
214             snprintf(vendorProductBuf, sizeof(vendorProductBuf), "%u+%u", params.GetVendorId().Value(),
215                      params.GetProductId().Value());
216         }
217         else
218         {
219             snprintf(vendorProductBuf, sizeof(vendorProductBuf), "%u", params.GetVendorId().Value());
220         }
221         textEntries[textEntrySize++] = { "VP", reinterpret_cast<const uint8_t *>(vendorProductBuf),
222                                          strnlen(vendorProductBuf, sizeof(vendorProductBuf)) };
223     }
224 #if CHIP_ENABLE_ROTATING_DEVICE_ID
225     if (textEntrySize < ArraySize(textEntries))
226     {
227         ReturnErrorOnFailure(GenerateRotatingDeviceId(rotatingDeviceIdHexBuffer, rotatingDeviceIdHexBufferSize));
228         // Rotating Device ID
229
230         textEntries[textEntrySize++] = { "RI", Uint8::from_const_char(rotatingDeviceIdHexBuffer), rotatingDeviceIdHexBufferSize };
231     }
232     else
233     {
234         return CHIP_ERROR_INVALID_LIST_LENGTH;
235     }
236 #endif
237     if (params.GetPairingHint().HasValue() && params.GetPairingInstr().HasValue())
238     {
239         snprintf(pairingInstrBuf, sizeof(pairingInstrBuf), "%s+%u", params.GetPairingInstr().Value(),
240                  params.GetPairingHint().Value());
241         textEntries[textEntrySize++] = { "P", reinterpret_cast<const uint8_t *>(pairingInstrBuf),
242                                          strnlen(pairingInstrBuf, sizeof(pairingInstrBuf)) };
243     }
244
245     snprintf(shortDiscriminatorSubtype, sizeof(shortDiscriminatorSubtype), "_S%03u", params.GetShortDiscriminator());
246     subTypes[subTypeSize++] = shortDiscriminatorSubtype;
247     snprintf(longDiscriminatorSubtype, sizeof(longDiscriminatorSubtype), "_L%04u", params.GetLongDiscriminator());
248     subTypes[subTypeSize++] = longDiscriminatorSubtype;
249     if (params.GetVendorId().HasValue())
250     {
251         snprintf(vendorSubType, sizeof(vendorSubType), "_V%u", params.GetVendorId().Value());
252         subTypes[subTypeSize++] = vendorSubType;
253     }
254
255     service.mTextEntries   = textEntries;
256     service.mTextEntrySize = textEntrySize;
257     service.mPort          = CHIP_PORT;
258     service.mInterface     = INET_NULL_INTERFACEID;
259     service.mSubTypes      = subTypes;
260     service.mSubTypeSize   = subTypeSize;
261     service.mAddressType   = Inet::kIPAddressType_Any;
262     error                  = ChipMdnsPublishService(&service);
263
264     return error;
265 }
266
267 CHIP_ERROR DiscoveryImplPlatform::Advertise(const OperationalAdvertisingParameters & params)
268 {
269     MdnsService service;
270     CHIP_ERROR error = CHIP_NO_ERROR;
271
272     mOperationalAdvertisingParams = params;
273     // TODO: There may be multilple device/fabrid ids after multi-admin.
274
275     ReturnErrorOnFailure(MakeInstanceName(service.mName, sizeof(service.mName), params.GetFabricId(), params.GetNodeId()));
276     strncpy(service.mType, "_chip", sizeof(service.mType));
277     service.mProtocol      = MdnsServiceProtocol::kMdnsProtocolTcp;
278     service.mPort          = CHIP_PORT;
279     service.mTextEntries   = nullptr;
280     service.mTextEntrySize = 0;
281     service.mInterface     = INET_NULL_INTERFACEID;
282     service.mAddressType   = Inet::kIPAddressType_Any;
283     error                  = ChipMdnsPublishService(&service);
284
285     return error;
286 }
287
288 CHIP_ERROR DiscoveryImplPlatform::StopPublishDevice()
289 {
290     mIsOperationalPublishing  = false;
291     mIsCommissionalPublishing = false;
292     return ChipMdnsStopPublish();
293 }
294
295 CHIP_ERROR DiscoveryImplPlatform::SetResolverDelegate(ResolverDelegate * delegate)
296 {
297     VerifyOrReturnError(delegate == nullptr || mResolverDelegate == nullptr, CHIP_ERROR_INCORRECT_STATE);
298     mResolverDelegate = delegate;
299     return CHIP_NO_ERROR;
300 }
301
302 CHIP_ERROR DiscoveryImplPlatform::ResolveNodeId(uint64_t nodeId, uint64_t fabricId, Inet::IPAddressType type)
303 {
304     ReturnErrorOnFailure(Init());
305
306     MdnsService service;
307
308     ReturnErrorOnFailure(MakeInstanceName(service.mName, sizeof(service.mName), fabricId, nodeId));
309     strncpy(service.mType, "_chip", sizeof(service.mType));
310     service.mProtocol    = MdnsServiceProtocol::kMdnsProtocolTcp;
311     service.mAddressType = type;
312     return ChipMdnsResolve(&service, INET_NULL_INTERFACEID, HandleNodeIdResolve, this);
313 }
314
315 void DiscoveryImplPlatform::HandleNodeIdResolve(void * context, MdnsService * result, CHIP_ERROR error)
316 {
317     DiscoveryImplPlatform * mgr = static_cast<DiscoveryImplPlatform *>(context);
318
319     if (mgr->mResolverDelegate == nullptr)
320     {
321         return;
322     }
323
324     if (error != CHIP_NO_ERROR)
325     {
326         ChipLogError(Discovery, "Node ID resolved failed with %s", chip::ErrorStr(error));
327         mgr->mResolverDelegate->OnNodeIdResolutionFailed(kUndefinedNodeId, error);
328         return;
329     }
330
331     if (result == nullptr)
332     {
333         ChipLogError(Discovery, "Node ID resolve not found");
334         mgr->mResolverDelegate->OnNodeIdResolutionFailed(kUndefinedNodeId, CHIP_ERROR_UNKNOWN_RESOURCE_ID);
335         return;
336     }
337
338     // Parse '%x-%x' from the name
339     uint64_t nodeId       = 0;
340     bool deliminatorFound = false;
341
342     for (size_t i = 0; i < sizeof(result->mName) && result->mName[i] != 0; i++)
343     {
344         if (result->mName[i] == '-')
345         {
346             deliminatorFound = true;
347             break;
348         }
349         else
350         {
351             uint8_t val = HexToInt(result->mName[i]);
352
353             if (val == UINT8_MAX)
354             {
355                 break;
356             }
357             else
358             {
359                 nodeId = nodeId * 16 + val;
360             }
361         }
362     }
363
364     ResolvedNodeData nodeData;
365     nodeData.mInterfaceId = result->mInterface;
366     nodeData.mAddress     = result->mAddress.ValueOr({});
367     nodeData.mPort        = result->mPort;
368
369     if (deliminatorFound)
370     {
371         ChipLogProgress(Discovery, "Node ID resolved for %" PRIX64, nodeId);
372         mgr->mResolverDelegate->OnNodeIdResolved(nodeId, nodeData);
373     }
374     else
375     {
376         ChipLogProgress(Discovery, "Invalid service entry from node %" PRIX64, nodeId);
377         mgr->mResolverDelegate->OnNodeIdResolved(kUndefinedNodeId, nodeData);
378     }
379 }
380
381 DiscoveryImplPlatform & DiscoveryImplPlatform::GetInstance()
382 {
383     return sManager;
384 }
385
386 ServiceAdvertiser & chip::Mdns::ServiceAdvertiser::Instance()
387 {
388     return DiscoveryImplPlatform::GetInstance();
389 }
390
391 Resolver & chip::Mdns::Resolver::Instance()
392 {
393     return DiscoveryImplPlatform::GetInstance();
394 }
395
396 } // namespace Mdns
397 } // namespace chip