Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / platform / Tizen / MdnsImpl.cpp
1 /*
2  *
3  *    Copyright (c) 2021 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 #include "MdnsImpl.h"
18
19 #include "MdnsError.h"
20
21 #include <cstdio>
22 #include <sstream>
23 #include <string.h>
24 #include <algorithm>
25
26 #include <platform/CHIPDeviceLayer.h>
27 #include <support/CHIPMem.h>
28 #include <support/CodeUtils.h>
29 #include <support/SafeInt.h>
30 #include <support/logging/CHIPLogging.h>
31
32 using namespace chip::Mdns;
33
34 namespace {
35
36 constexpr const char * kLocalDomain = "local.";
37 constexpr const char * kProtocolTcp = "._tcp";
38 constexpr const char * kProtocolUdp = "._udp";
39 constexpr uint8_t kMdnsKeyMaxSize   = 32;
40
41 bool IsSupportedProtocol(MdnsServiceProtocol protocol)
42 {
43     return (protocol == MdnsServiceProtocol::kMdnsProtocolUdp) || (protocol == MdnsServiceProtocol::kMdnsProtocolTcp);
44 }
45
46 uint32_t GetInterfaceId(chip::Inet::InterfaceId interfaceId)
47 {
48     return INET_NULL_INTERFACEID ? 0 : interfaceId;
49 }
50
51 std::string GetFullType(const char * type, MdnsServiceProtocol protocol)
52 {
53     std::ostringstream typeBuilder;
54     typeBuilder << type;
55     typeBuilder << (protocol == MdnsServiceProtocol::kMdnsProtocolUdp ? kProtocolUdp : kProtocolTcp);
56     return typeBuilder.str();
57 }
58
59 } // namespace
60
61 namespace chip {
62 namespace Mdns {
63
64 MdnsContexts MdnsContexts::sInstance;
65
66 void MdnsContexts::Delete(GenericContext * context)
67 {
68     if (context->type == ContextType::GetAddrInfo)
69     {
70         GetAddrInfoContext * addrInfoContext = reinterpret_cast<GetAddrInfoContext *>(context);
71         std::vector<TextEntry>::iterator textEntry;
72         for (textEntry = addrInfoContext->textEntries.begin(); textEntry != addrInfoContext->textEntries.end(); textEntry++)
73         {
74             free(const_cast<char *>(textEntry->mKey));
75             free(const_cast<uint8_t *>(textEntry->mData));
76         }
77     }
78
79     DNSServiceRefDeallocate(context->serviceRef);
80     chip::Platform::Delete(context);
81 }
82
83 MdnsContexts::~MdnsContexts()
84 {
85     std::vector<GenericContext *>::const_iterator iter = mContexts.cbegin();
86     while (iter != mContexts.cend())
87     {
88         Delete(*iter);
89         mContexts.erase(iter);
90     }
91 }
92
93 CHIP_ERROR MdnsContexts::Add(GenericContext * context, DNSServiceRef sdRef)
94 {
95     VerifyOrReturnError(context != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
96     VerifyOrReturnError(sdRef != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
97
98     context->serviceRef = sdRef;
99     mContexts.push_back(context);
100
101     return CHIP_NO_ERROR;
102 }
103
104 CHIP_ERROR MdnsContexts::Remove(GenericContext * context)
105 {
106     bool found = false;
107
108     std::vector<GenericContext *>::const_iterator iter = mContexts.cbegin();
109     while (iter != mContexts.cend())
110     {
111         if (*iter != context)
112         {
113             iter++;
114             continue;
115         }
116
117         Delete(*iter);
118         mContexts.erase(iter);
119         found = true;
120         break;
121     }
122
123     return found ? CHIP_NO_ERROR : CHIP_ERROR_KEY_NOT_FOUND;
124 }
125
126 CHIP_ERROR MdnsContexts::Removes(ContextType type)
127 {
128     bool found = false;
129
130     std::vector<GenericContext *>::const_iterator iter = mContexts.cbegin();
131     while (iter != mContexts.cend())
132     {
133         if ((*iter)->type != type)
134         {
135             iter++;
136             continue;
137         }
138
139         Delete(*iter);
140         mContexts.erase(iter);
141         found = true;
142     }
143
144     return found ? CHIP_NO_ERROR : CHIP_ERROR_KEY_NOT_FOUND;
145 }
146
147 CHIP_ERROR MdnsContexts::Get(ContextType type, GenericContext * context)
148 {
149     bool found = false;
150     std::vector<GenericContext *>::iterator iter;
151
152     for (iter = mContexts.begin(); iter != mContexts.end(); iter++)
153     {
154         if ((*iter)->type == type)
155         {
156             context = *iter;
157             if (context != nullptr)
158                 found   = true;
159
160             break;
161         }
162     }
163
164     return found ? CHIP_NO_ERROR : CHIP_ERROR_KEY_NOT_FOUND;
165 }
166
167 void MdnsContexts::PrepareSelect(fd_set & readFdSet, fd_set & writeFdSet, fd_set & errorFdSet, int & maxFd, timeval & timeout)
168 {
169     std::vector<DNSServiceRef> serviceRefs(mContexts.size());
170     std::transform(mContexts.begin(), mContexts.end(), serviceRefs.begin(),
171                    [](GenericContext * context) { return context->serviceRef; });
172
173     std::vector<DNSServiceRef>::iterator iter;
174     for (iter = serviceRefs.begin(); iter != serviceRefs.end(); iter++)
175     {
176         int fd = DNSServiceRefSockFD(*iter);
177         FD_SET(fd, &readFdSet);
178         if (maxFd < fd)
179         {
180             maxFd = fd;
181         }
182     }
183 }
184
185 void MdnsContexts::HandleSelectResult(fd_set & readFdSet, fd_set & writeFdSet, fd_set & errorFdSet)
186 {
187     std::vector<DNSServiceRef> serviceRefs(mContexts.size());
188     std::transform(mContexts.begin(), mContexts.end(), serviceRefs.begin(),
189                    [](GenericContext * context) { return context->serviceRef; });
190
191     std::vector<DNSServiceRef>::iterator iter;
192     for (iter = serviceRefs.begin(); iter != serviceRefs.end(); iter++)
193     {
194         int fd = DNSServiceRefSockFD(*iter);
195         if (FD_ISSET(fd, &readFdSet))
196         {
197             DNSServiceProcessResult(*iter);
198         }
199     }
200 }
201
202 CHIP_ERROR PopulateTextRecord(TXTRecordRef * record, char * buffer, uint16_t bufferLen, TextEntry * textEntries,
203                               size_t textEntrySize)
204 {
205     VerifyOrReturnError(textEntrySize <= kMdnsTextMaxSize, CHIP_ERROR_INVALID_ARGUMENT);
206
207     DNSServiceErrorType err;
208     TXTRecordCreate(record, bufferLen, buffer);
209
210     for (size_t i = 0; i < textEntrySize; i++)
211     {
212         TextEntry entry = textEntries[i];
213         VerifyOrReturnError(chip::CanCastTo<uint8_t>(entry.mDataSize), CHIP_ERROR_INVALID_ARGUMENT);
214
215         err = TXTRecordSetValue(record, entry.mKey, static_cast<uint8_t>(entry.mDataSize), entry.mData);
216         VerifyOrReturnError(err == kDNSServiceErr_NoError, CHIP_ERROR_INVALID_ARGUMENT);
217     }
218
219     return CHIP_NO_ERROR;
220 }
221
222 bool CheckForSuccess(GenericContext * context, const char * name, DNSServiceErrorType err, bool useCallback = false)
223 {
224     if (context == nullptr)
225     {
226         ChipLogError(DeviceLayer, "%s (%s)", name, "Mdns context is null.");
227         return false;
228     }
229
230     if (kDNSServiceErr_NoError != err)
231     {
232         ChipLogError(DeviceLayer, "%s (%s)", name, Error::ToString(err));
233
234         if (useCallback)
235         {
236             switch (context->type)
237             {
238             case ContextType::Register:
239                 // Nothing special to do. Maybe ChipMdnsPublishService should take a callback ?
240                 break;
241             case ContextType::Browse: {
242                 BrowseContext * browseContext = reinterpret_cast<BrowseContext *>(context);
243                 browseContext->callback(browseContext->context, nullptr, 0, CHIP_ERROR_INTERNAL);
244                 break;
245             }
246             case ContextType::Resolve: {
247                 ResolveContext * resolveContext = reinterpret_cast<ResolveContext *>(context);
248                 resolveContext->callback(resolveContext->context, nullptr, CHIP_ERROR_INTERNAL);
249                 break;
250             }
251             case ContextType::GetAddrInfo: {
252                 GetAddrInfoContext * resolveContext = reinterpret_cast<GetAddrInfoContext *>(context);
253                 resolveContext->callback(resolveContext->context, nullptr, CHIP_ERROR_INTERNAL);
254                 break;
255             }
256             }
257         }
258
259         if (CHIP_ERROR_KEY_NOT_FOUND == MdnsContexts::GetInstance().Remove(context))
260         {
261             chip::Platform::Delete(context);
262         }
263
264         return false;
265     }
266
267     return true;
268 }
269
270 static void OnRegister(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType err, const char * name, const char * type,
271                        const char * domain, void * context)
272 {
273     RegisterContext * sdCtx = reinterpret_cast<RegisterContext *>(context);
274     VerifyOrReturn(CheckForSuccess(sdCtx, __func__, err));
275
276     ChipLogDetail(DeviceLayer, "Mdns: %s name: %s, type: %s, domain: %s, flags: %d", __func__, name, type, domain, flags);
277 };
278
279 CHIP_ERROR Register(uint32_t interfaceId, const char * type, const char * name, uint16_t port, TXTRecordRef * recordRef)
280 {
281     DNSServiceErrorType err;
282     DNSServiceRef sdRef;
283     RegisterContext * sdCtx = nullptr;
284
285     uint16_t recordLen          = TXTRecordGetLength(recordRef);
286     const void * recordBytesPtr = TXTRecordGetBytesPtr(recordRef);
287
288     if (CHIP_NO_ERROR == MdnsContexts::GetInstance().Get(ContextType::Register, sdCtx))
289     {
290         err = DNSServiceUpdateRecord(sdCtx->serviceRef, NULL, 0 /* flags */, recordLen, recordBytesPtr, 0 /* ttl */);
291         TXTRecordDeallocate(recordRef);
292         VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err), CHIP_ERROR_INTERNAL);
293         return CHIP_NO_ERROR;
294     }
295
296     sdCtx = chip::Platform::New<RegisterContext>(nullptr);
297     err   = DNSServiceRegister(&sdRef, 0 /* flags */, interfaceId, name, type, kLocalDomain, NULL, port, recordLen, recordBytesPtr,
298                              OnRegister, sdCtx);
299     TXTRecordDeallocate(recordRef);
300
301     VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err), CHIP_ERROR_INTERNAL);
302
303     return MdnsContexts::GetInstance().Add(sdCtx, sdRef);
304 }
305
306 void OnBrowseAdd(BrowseContext * context, const char * name, const char * type, const char * domain, uint32_t interfaceId)
307 {
308     ChipLogDetail(DeviceLayer, "Mdns: %s  name: %s, type: %s, domain: %s, interface: %d", __func__, name, type, domain,
309                   interfaceId);
310
311     VerifyOrReturn(strcmp(kLocalDomain, domain) == 0);
312
313     char * tokens  = strdup(type);
314     char * regtype = strtok(tokens, ".");
315     free(tokens);
316
317     MdnsService service = {};
318     service.mInterface  = interfaceId;
319     service.mProtocol   = context->protocol;
320
321     strncpy(service.mName, name, sizeof(service.mName));
322     service.mName[kMdnsNameMaxSize] = 0;
323
324     strncpy(service.mType, regtype, sizeof(service.mType));
325     service.mType[kMdnsTypeMaxSize] = 0;
326
327     context->services.push_back(service);
328 }
329
330 void OnBrowseRemove(BrowseContext * context, const char * name, const char * type, const char * domain, uint32_t interfaceId)
331 {
332     ChipLogDetail(DeviceLayer, "Mdns: %s  name: %s, type: %s, domain: %s, interface: %d", __func__, name, type, domain,
333                   interfaceId);
334
335     VerifyOrReturn(strcmp(kLocalDomain, domain) == 0);
336
337     std::remove_if(context->services.begin(), context->services.end(), [name, type, interfaceId](const MdnsService & service) {
338         return strcmp(name, service.mName) == 0 && type == GetFullType(service.mType, service.mProtocol) &&
339             service.mInterface == interfaceId;
340     });
341 }
342
343 static void OnBrowse(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceId, DNSServiceErrorType err, const char * name,
344                      const char * type, const char * domain, void * context)
345 {
346     BrowseContext * sdCtx = reinterpret_cast<BrowseContext *>(context);
347     VerifyOrReturn(CheckForSuccess(sdCtx, __func__, err, true));
348
349     (flags & kDNSServiceFlagsAdd) ? OnBrowseAdd(sdCtx, name, type, domain, interfaceId)
350                                   : OnBrowseRemove(sdCtx, name, type, domain, interfaceId);
351
352     if (!(flags & kDNSServiceFlagsMoreComing))
353     {
354         sdCtx->callback(sdCtx->context, sdCtx->services.data(), sdCtx->services.size(), CHIP_NO_ERROR);
355         MdnsContexts::GetInstance().Remove(sdCtx);
356     }
357 }
358
359 CHIP_ERROR Browse(void * context, MdnsBrowseCallback callback, uint32_t interfaceId, const char * type,
360                   MdnsServiceProtocol protocol)
361 {
362     DNSServiceErrorType err;
363     DNSServiceRef sdRef;
364     BrowseContext * sdCtx;
365
366     sdCtx = chip::Platform::New<BrowseContext>(context, callback, protocol);
367     err   = DNSServiceBrowse(&sdRef, 0 /* flags */, interfaceId, type, kLocalDomain, OnBrowse, sdCtx);
368     VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err), CHIP_ERROR_INTERNAL);
369
370     return MdnsContexts::GetInstance().Add(sdCtx, sdRef);
371 }
372
373 static void OnGetAddrInfo(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceId, DNSServiceErrorType err,
374                           const char * hostname, const struct sockaddr * address, uint32_t ttl, void * context)
375 {
376     GetAddrInfoContext * sdCtx = reinterpret_cast<GetAddrInfoContext *>(context);
377     VerifyOrReturn(CheckForSuccess(sdCtx, __func__, err, true));
378
379     ChipLogDetail(DeviceLayer, "Mdns: %s hostname:%s", __func__, hostname);
380
381     MdnsService service    = {};
382     service.mPort          = sdCtx->port;
383     service.mTextEntries   = sdCtx->textEntries.empty() ? nullptr : sdCtx->textEntries.data();
384     service.mTextEntrySize = sdCtx->textEntries.empty() ? 0 : sdCtx->textEntries.size();
385     service.mAddress.SetValue(chip::Inet::IPAddress::FromSockAddr(*address));
386
387     sdCtx->callback(sdCtx->context, &service, CHIP_NO_ERROR);
388     MdnsContexts::GetInstance().Remove(sdCtx);
389 }
390
391 CHIP_ERROR GetAddrInfo(void * context, MdnsResolveCallback callback, uint32_t interfaceId, const char * hostname, uint16_t port,
392                        uint16_t txtLen, const unsigned char * txtRecord)
393 {
394     DNSServiceErrorType err;
395     DNSServiceRef sdRef;
396     GetAddrInfoContext * sdCtx;
397
398     sdCtx = chip::Platform::New<GetAddrInfoContext>(context, callback, port);
399
400     char key[kMdnsKeyMaxSize];
401     char value[kMdnsTextMaxSize];
402     uint8_t valueLen;
403     const void * valuePtr;
404
405     uint16_t recordCount = TXTRecordGetCount(txtLen, txtRecord);
406     for (uint16_t i = 0; i < recordCount; i++)
407     {
408         err = TXTRecordGetItemAtIndex(txtLen, txtRecord, i, kMdnsKeyMaxSize, key, &valueLen, &valuePtr);
409         VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err, true), CHIP_ERROR_INTERNAL);
410
411         strncpy(value, reinterpret_cast<const char *>(valuePtr), valueLen);
412         value[valueLen] = 0;
413
414         sdCtx->textEntries.push_back(TextEntry{ strdup(key), reinterpret_cast<const uint8_t *>(strdup(value)), valueLen });
415     }
416
417     err = DNSServiceGetAddrInfo(&sdRef, 0 /* flags */, interfaceId, kDNSServiceProtocol_IPv4, hostname, OnGetAddrInfo, sdCtx);
418     VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err, true), CHIP_ERROR_INTERNAL);
419
420     return MdnsContexts::GetInstance().Add(sdCtx, sdRef);
421 }
422
423 static void OnResolve(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceId, DNSServiceErrorType err,
424                       const char * fullname, const char * hostname, uint16_t port, uint16_t txtLen, const unsigned char * txtRecord,
425                       void * context)
426 {
427     ResolveContext * sdCtx = reinterpret_cast<ResolveContext *>(context);
428     VerifyOrReturn(CheckForSuccess(sdCtx, __func__, err, true));
429
430     GetAddrInfo(sdCtx->context, sdCtx->callback, interfaceId, hostname, port, txtLen, txtRecord);
431     MdnsContexts::GetInstance().Remove(sdCtx);
432 }
433
434 CHIP_ERROR Resolve(void * context, MdnsResolveCallback callback, uint32_t interfaceId, const char * type, const char * name)
435 {
436     DNSServiceErrorType err;
437     DNSServiceRef sdRef;
438     ResolveContext * sdCtx;
439
440     sdCtx = chip::Platform::New<ResolveContext>(context, callback);
441     err   = DNSServiceResolve(&sdRef, 0 /* flags */, interfaceId, name, type, kLocalDomain, OnResolve, sdCtx);
442     VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err), CHIP_ERROR_INTERNAL);
443
444     return MdnsContexts::GetInstance().Add(sdCtx, sdRef);
445 }
446
447 CHIP_ERROR ChipMdnsInit(MdnsAsyncReturnCallback successCallback, MdnsAsyncReturnCallback errorCallback, void * context)
448 {
449     VerifyOrReturnError(successCallback != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
450     VerifyOrReturnError(errorCallback != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
451
452     successCallback(context, CHIP_NO_ERROR);
453     return CHIP_NO_ERROR;
454 }
455
456 CHIP_ERROR ChipMdnsSetHostname(const char * hostname)
457 {
458     MdnsContexts::GetInstance().SetHostname(hostname);
459     return CHIP_NO_ERROR;
460 }
461
462 CHIP_ERROR ChipMdnsPublishService(const MdnsService * service)
463 {
464     VerifyOrReturnError(service != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
465     VerifyOrReturnError(IsSupportedProtocol(service->mProtocol), CHIP_ERROR_INVALID_ARGUMENT);
466
467     std::string regtype  = GetFullType(service->mType, service->mProtocol);
468     uint32_t interfaceId = GetInterfaceId(service->mInterface);
469
470     TXTRecordRef record;
471     char buffer[kMdnsTextMaxSize];
472     ReturnErrorOnFailure(PopulateTextRecord(&record, buffer, sizeof(buffer), service->mTextEntries, service->mTextEntrySize));
473
474     return Register(interfaceId, regtype.c_str(), service->mName, service->mPort, &record);
475 }
476
477 CHIP_ERROR ChipMdnsStopPublish()
478 {
479     return MdnsContexts::GetInstance().Removes(ContextType::Register);
480 }
481
482 CHIP_ERROR ChipMdnsBrowse(const char * type, MdnsServiceProtocol protocol, chip::Inet::IPAddressType addressType,
483                           chip::Inet::InterfaceId interface, MdnsBrowseCallback callback, void * context)
484 {
485     VerifyOrReturnError(type != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
486     VerifyOrReturnError(callback != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
487     VerifyOrReturnError(IsSupportedProtocol(protocol), CHIP_ERROR_INVALID_ARGUMENT);
488
489     std::string regtype  = GetFullType(type, protocol);
490     uint32_t interfaceId = GetInterfaceId(interface);
491
492     return Browse(context, callback, interfaceId, regtype.c_str(), protocol);
493 }
494
495 CHIP_ERROR ChipMdnsResolve(MdnsService * service, chip::Inet::InterfaceId interface, MdnsResolveCallback callback, void * context)
496 {
497     VerifyOrReturnError(service != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
498     VerifyOrReturnError(IsSupportedProtocol(service->mProtocol), CHIP_ERROR_INVALID_ARGUMENT);
499
500     std::string regtype  = GetFullType(service->mType, service->mProtocol);
501     uint32_t interfaceId = GetInterfaceId(service->mInterface);
502
503     return Resolve(context, callback, interfaceId, regtype.c_str(), service->mName);
504 }
505
506 void UpdateMdnsDataset(fd_set & readFdSet, fd_set & writeFdSet, fd_set & errorFdSet, int & maxFd, timeval & timeout)
507 {
508     MdnsContexts::GetInstance().PrepareSelect(readFdSet, writeFdSet, errorFdSet, maxFd, timeout);
509 }
510
511 void ProcessMdns(fd_set & readFdSet, fd_set & writeFdSet, fd_set & errorFdSet)
512 {
513     MdnsContexts::GetInstance().HandleSelectResult(readFdSet, writeFdSet, errorFdSet);
514 }
515
516 } // namespace Mdns
517 } // namespace chip