Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / ot-br-posix / repo / src / agent / advertising_proxy.cpp
1 /*
2  *    Copyright (c) 2020, The OpenThread Authors.
3  *    All rights reserved.
4  *
5  *    Redistribution and use in source and binary forms, with or without
6  *    modification, are permitted provided that the following conditions are met:
7  *    1. Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *    2. Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *    3. Neither the name of the copyright holder nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *    POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 /**
30  * @file
31  *   The file implements the Advertising Proxy.
32  */
33
34 #include "agent/advertising_proxy.hpp"
35
36 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
37
38 #if !OTBR_ENABLE_MDNS_AVAHI && !OTBR_ENABLE_MDNS_MDNSSD && !OTBR_ENABLE_MDNS_MOJO
39 #error "The Advertising Proxy requires OTBR_ENABLE_MDNS_AVAHI, OTBR_ENABLE_MDNS_MDNSSD or OTBR_ENABLE_MDNS_MOJO"
40 #endif
41
42 #include <string>
43
44 #include <assert.h>
45
46 #include "common/code_utils.hpp"
47 #include "common/logging.hpp"
48
49 namespace otbr {
50
51 // TODO: better to have SRP server provide separated service name labels.
52 static otbrError SplitFullServiceName(const std::string &aFullName,
53                                       std::string &      aInstanceName,
54                                       std::string &      aType,
55                                       std::string &      aDomain)
56 {
57     otbrError error = OTBR_ERROR_INVALID_ARGS;
58     size_t    dotPos[3];
59
60     dotPos[0] = aFullName.find_first_of('.');
61     VerifyOrExit(dotPos[0] != std::string::npos);
62
63     dotPos[1] = aFullName.find_first_of('.', dotPos[0] + 1);
64     VerifyOrExit(dotPos[1] != std::string::npos);
65
66     dotPos[2] = aFullName.find_first_of('.', dotPos[1] + 1);
67     VerifyOrExit(dotPos[2] != std::string::npos);
68
69     error         = OTBR_ERROR_NONE;
70     aInstanceName = aFullName.substr(0, dotPos[0]);
71     aType         = aFullName.substr(dotPos[0] + 1, dotPos[2] - dotPos[0] - 1);
72     aDomain       = aFullName.substr(dotPos[2] + 1, aFullName.size() - dotPos[2] - 1);
73
74 exit:
75     return error;
76 }
77
78 // TODO: better to have the SRP server to provide separated host name.
79 static otbrError SplitFullHostName(const std::string &aFullName, std::string &aHostName, std::string &aDomain)
80 {
81     otbrError error = OTBR_ERROR_INVALID_ARGS;
82     size_t    dotPos;
83
84     dotPos = aFullName.find_first_of('.');
85     VerifyOrExit(dotPos != std::string::npos);
86
87     error     = OTBR_ERROR_NONE;
88     aHostName = aFullName.substr(0, dotPos);
89     aDomain   = aFullName.substr(dotPos + 1, aFullName.size() - dotPos - 1);
90
91 exit:
92     return error;
93 }
94
95 static otError OtbrErrorToOtError(otbrError aError)
96 {
97     otError error;
98
99     switch (aError)
100     {
101     case OTBR_ERROR_NONE:
102         error = OT_ERROR_NONE;
103         break;
104
105     case OTBR_ERROR_NOT_FOUND:
106         error = OT_ERROR_NOT_FOUND;
107         break;
108
109     case OTBR_ERROR_PARSE:
110         error = OT_ERROR_PARSE;
111         break;
112
113     case OTBR_ERROR_NOT_IMPLEMENTED:
114         error = OT_ERROR_NOT_IMPLEMENTED;
115         break;
116
117     case OTBR_ERROR_INVALID_ARGS:
118         error = OT_ERROR_INVALID_ARGS;
119         break;
120
121     case OTBR_ERROR_DUPLICATED:
122         error = OT_ERROR_DUPLICATED;
123         break;
124
125     default:
126         error = OT_ERROR_FAILED;
127         break;
128     }
129
130     return error;
131 }
132
133 AdvertisingProxy::AdvertisingProxy(Ncp::ControllerOpenThread &aNcp, Mdns::Publisher &aPublisher)
134     : mNcp(aNcp)
135     , mPublisher(aPublisher)
136 {
137 }
138
139 otbrError AdvertisingProxy::Start(void)
140 {
141     otSrpServerSetServiceUpdateHandler(GetInstance(), AdvertisingHandler, this);
142
143     mPublisher.SetPublishServiceHandler(PublishServiceHandler, this);
144     mPublisher.SetPublishHostHandler(PublishHostHandler, this);
145
146     otbrLog(OTBR_LOG_INFO, "[adproxy] Started");
147
148     return OTBR_ERROR_NONE;
149 }
150
151 void AdvertisingProxy::Stop()
152 {
153     mPublisher.SetPublishServiceHandler(nullptr, nullptr);
154     mPublisher.SetPublishHostHandler(nullptr, nullptr);
155
156     // Outstanding updates will fail on the SRP server because of timeout.
157     // TODO: handle this case gracefully.
158
159     // Stop receiving SRP server events.
160     if (GetInstance() != nullptr)
161     {
162         otSrpServerSetServiceUpdateHandler(GetInstance(), nullptr, nullptr);
163     }
164
165     otbrLog(OTBR_LOG_INFO, "[adproxy] Stopped");
166 }
167
168 void AdvertisingProxy::AdvertisingHandler(const otSrpServerHost *aHost, uint32_t aTimeout, void *aContext)
169 {
170     static_cast<AdvertisingProxy *>(aContext)->AdvertisingHandler(aHost, aTimeout);
171 }
172
173 void AdvertisingProxy::AdvertisingHandler(const otSrpServerHost *aHost, uint32_t aTimeout)
174 {
175     // TODO: There are corner cases that the `aHost` is freed by SRP server because
176     // of timeout, but this `aHost` is passed back to SRP server and matches a newly
177     // allocated otSrpServerHost object which has the same pointer value as this
178     // `aHost`. This results in mismatching of the outstanding SRP updates. Solutions
179     // are cleaning up the outstanding update entries before timing out or using
180     // incremental ID to match oustanding SRP updates.
181     OTBR_UNUSED_VARIABLE(aTimeout);
182
183     otbrError                 error = OTBR_ERROR_NONE;
184     const char *              fullHostName;
185     std::string               hostName;
186     std::string               hostDomain;
187     const otIp6Address *      hostAddress;
188     uint8_t                   hostAddressNum;
189     bool                      hostDeleted;
190     const otSrpServerService *service;
191     OutstandingUpdate *       update;
192
193     mOutstandingUpdates.resize(mOutstandingUpdates.size() + 1);
194     update = &mOutstandingUpdates.back();
195
196     fullHostName = otSrpServerHostGetFullName(aHost);
197
198     otbrLog(OTBR_LOG_INFO, "[adproxy] advertise SRP service updates: host=%s", fullHostName);
199
200     SuccessOrExit(error = SplitFullHostName(fullHostName, hostName, hostDomain));
201     hostAddress = otSrpServerHostGetAddresses(aHost, &hostAddressNum);
202     hostDeleted = otSrpServerHostIsDeleted(aHost);
203
204     update->mHost = aHost;
205     update->mCount += !hostDeleted;
206     update->mHostName = hostName;
207
208     service = nullptr;
209     while ((service = otSrpServerHostGetNextService(aHost, service)) != nullptr)
210     {
211         update->mCount += !otSrpServerServiceIsDeleted(service);
212     }
213
214     if (!hostDeleted)
215     {
216         // TODO: select a preferred address or advertise all addresses from SRP client.
217         otbrLog(OTBR_LOG_INFO, "[adproxy] publish SRP host: %s", fullHostName);
218         SuccessOrExit(error =
219                           mPublisher.PublishHost(hostName.c_str(), hostAddress[0].mFields.m8, sizeof(hostAddress[0])));
220     }
221     else
222     {
223         otbrLog(OTBR_LOG_INFO, "[adproxy] unpublish SRP host: %s", fullHostName);
224         SuccessOrExit(error = mPublisher.UnpublishHost(hostName.c_str()));
225     }
226
227     service = nullptr;
228     while ((service = otSrpServerHostGetNextService(aHost, service)) != nullptr)
229     {
230         const char *fullServiceName = otSrpServerServiceGetFullName(service);
231         std::string serviceName;
232         std::string serviceType;
233         std::string serviceDomain;
234
235         SuccessOrExit(error = SplitFullServiceName(fullServiceName, serviceName, serviceType, serviceDomain));
236
237         update->mServiceNames.emplace_back(serviceName, serviceType);
238
239         if (!hostDeleted && !otSrpServerServiceIsDeleted(service))
240         {
241             Mdns::Publisher::TxtList txtList = MakeTxtList(service);
242
243             otbrLog(OTBR_LOG_INFO, "[adproxy] publish SRP service: %s", fullServiceName);
244             SuccessOrExit(error = mPublisher.PublishService(hostName.c_str(), otSrpServerServiceGetPort(service),
245                                                             serviceName.c_str(), serviceType.c_str(), txtList));
246         }
247         else
248         {
249             otbrLog(OTBR_LOG_INFO, "[adproxy] unpublish SRP service: %s", fullServiceName);
250             SuccessOrExit(error = mPublisher.UnpublishService(serviceName.c_str(), serviceType.c_str()));
251         }
252     }
253
254 exit:
255     if (error != OTBR_ERROR_NONE || update->mCount == 0)
256     {
257         if (error != OTBR_ERROR_NONE)
258         {
259             otbrLog(OTBR_LOG_INFO, "[adproxy] failed to advertise SRP service updates %p", aHost);
260         }
261
262         mOutstandingUpdates.pop_back();
263         otSrpServerHandleServiceUpdateResult(GetInstance(), aHost, OtbrErrorToOtError(error));
264     }
265 }
266
267 void AdvertisingProxy::PublishServiceHandler(const char *aName, const char *aType, otbrError aError, void *aContext)
268 {
269     static_cast<AdvertisingProxy *>(aContext)->PublishServiceHandler(aName, aType, aError);
270 }
271
272 void AdvertisingProxy::PublishServiceHandler(const char *aName, const char *aType, otbrError aError)
273 {
274     otbrError error = OTBR_ERROR_NONE;
275
276     otbrLog(OTBR_LOG_INFO, "[adproxy] handle publish service '%s.%s' result: %d", aName, aType, aError);
277
278     // TODO: there may be same names between two SRP updates.
279     for (auto update = mOutstandingUpdates.begin(); update != mOutstandingUpdates.end(); ++update)
280     {
281         for (const auto &nameAndType : update->mServiceNames)
282         {
283             if (aName != nameAndType.first || !Mdns::Publisher::IsServiceTypeEqual(aType, nameAndType.second.c_str()))
284             {
285                 continue;
286             }
287
288             if (aError != OTBR_ERROR_NONE || update->mCount == 1)
289             {
290                 otSrpServerHandleServiceUpdateResult(GetInstance(), update->mHost, OtbrErrorToOtError(aError));
291                 mOutstandingUpdates.erase(update);
292             }
293             else
294             {
295                 --update->mCount;
296             }
297             ExitNow();
298         }
299     }
300
301 exit:
302     if (error != OTBR_ERROR_NONE)
303     {
304         otbrLog(OTBR_LOG_WARNING, "[adproxy] failed to handle result of service %s", aName);
305     }
306 }
307
308 void AdvertisingProxy::PublishHostHandler(const char *aName, otbrError aError, void *aContext)
309 {
310     static_cast<AdvertisingProxy *>(aContext)->PublishHostHandler(aName, aError);
311 }
312
313 void AdvertisingProxy::PublishHostHandler(const char *aName, otbrError aError)
314 {
315     otbrError error = OTBR_ERROR_NONE;
316
317     otbrLog(OTBR_LOG_INFO, "[adproxy] handle publish host '%s' result: %d", aName, aError);
318
319     for (auto update = mOutstandingUpdates.begin(); update != mOutstandingUpdates.end(); ++update)
320     {
321         if (aName != update->mHostName)
322         {
323             continue;
324         }
325
326         if (aError != OTBR_ERROR_NONE || update->mCount == 1)
327         {
328             otSrpServerHandleServiceUpdateResult(GetInstance(), update->mHost, OtbrErrorToOtError(aError));
329             mOutstandingUpdates.erase(update);
330         }
331         else
332         {
333             --update->mCount;
334         }
335         ExitNow();
336     }
337
338 exit:
339     if (error != OTBR_ERROR_NONE)
340     {
341         otbrLog(OTBR_LOG_WARNING, "[adproxy] failed to handle result of host %s", aName);
342     }
343 }
344
345 Mdns::Publisher::TxtList AdvertisingProxy::MakeTxtList(const otSrpServerService *aSrpService)
346 {
347     const uint8_t *          txtData;
348     uint16_t                 txtDataLength = 0;
349     otDnsTxtEntryIterator    iterator;
350     otDnsTxtEntry            txtEntry;
351     Mdns::Publisher::TxtList txtList;
352
353     txtData = otSrpServerServiceGetTxtData(aSrpService, &txtDataLength);
354
355     otDnsInitTxtEntryIterator(&iterator, txtData, txtDataLength);
356
357     while (otDnsGetNextTxtEntry(&iterator, &txtEntry) == OT_ERROR_NONE)
358     {
359         txtList.emplace_back(txtEntry.mKey, txtEntry.mValue, txtEntry.mValueLength);
360     }
361
362     return txtList;
363 }
364
365 } // namespace otbr
366
367 #endif // OTBR_ENABLE_SRP_ADVERTISING_PROXY