2 * Copyright (c) 2020, The OpenThread Authors.
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.
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.
31 * The file implements the Advertising Proxy.
34 #include "agent/advertising_proxy.hpp"
36 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
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"
46 #include "common/code_utils.hpp"
47 #include "common/logging.hpp"
51 // TODO: better to have SRP server provide separated service name labels.
52 static otbrError SplitFullServiceName(const std::string &aFullName,
53 std::string & aInstanceName,
55 std::string & aDomain)
57 otbrError error = OTBR_ERROR_INVALID_ARGS;
60 dotPos[0] = aFullName.find_first_of('.');
61 VerifyOrExit(dotPos[0] != std::string::npos);
63 dotPos[1] = aFullName.find_first_of('.', dotPos[0] + 1);
64 VerifyOrExit(dotPos[1] != std::string::npos);
66 dotPos[2] = aFullName.find_first_of('.', dotPos[1] + 1);
67 VerifyOrExit(dotPos[2] != std::string::npos);
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);
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)
81 otbrError error = OTBR_ERROR_INVALID_ARGS;
84 dotPos = aFullName.find_first_of('.');
85 VerifyOrExit(dotPos != std::string::npos);
87 error = OTBR_ERROR_NONE;
88 aHostName = aFullName.substr(0, dotPos);
89 aDomain = aFullName.substr(dotPos + 1, aFullName.size() - dotPos - 1);
95 static otError OtbrErrorToOtError(otbrError aError)
101 case OTBR_ERROR_NONE:
102 error = OT_ERROR_NONE;
105 case OTBR_ERROR_NOT_FOUND:
106 error = OT_ERROR_NOT_FOUND;
109 case OTBR_ERROR_PARSE:
110 error = OT_ERROR_PARSE;
113 case OTBR_ERROR_NOT_IMPLEMENTED:
114 error = OT_ERROR_NOT_IMPLEMENTED;
117 case OTBR_ERROR_INVALID_ARGS:
118 error = OT_ERROR_INVALID_ARGS;
121 case OTBR_ERROR_DUPLICATED:
122 error = OT_ERROR_DUPLICATED;
126 error = OT_ERROR_FAILED;
133 AdvertisingProxy::AdvertisingProxy(Ncp::ControllerOpenThread &aNcp, Mdns::Publisher &aPublisher)
135 , mPublisher(aPublisher)
139 otbrError AdvertisingProxy::Start(void)
141 otSrpServerSetServiceUpdateHandler(GetInstance(), AdvertisingHandler, this);
143 mPublisher.SetPublishServiceHandler(PublishServiceHandler, this);
144 mPublisher.SetPublishHostHandler(PublishHostHandler, this);
146 otbrLog(OTBR_LOG_INFO, "[adproxy] Started");
148 return OTBR_ERROR_NONE;
151 void AdvertisingProxy::Stop()
153 mPublisher.SetPublishServiceHandler(nullptr, nullptr);
154 mPublisher.SetPublishHostHandler(nullptr, nullptr);
156 // Outstanding updates will fail on the SRP server because of timeout.
157 // TODO: handle this case gracefully.
159 // Stop receiving SRP server events.
160 if (GetInstance() != nullptr)
162 otSrpServerSetServiceUpdateHandler(GetInstance(), nullptr, nullptr);
165 otbrLog(OTBR_LOG_INFO, "[adproxy] Stopped");
168 void AdvertisingProxy::AdvertisingHandler(const otSrpServerHost *aHost, uint32_t aTimeout, void *aContext)
170 static_cast<AdvertisingProxy *>(aContext)->AdvertisingHandler(aHost, aTimeout);
173 void AdvertisingProxy::AdvertisingHandler(const otSrpServerHost *aHost, uint32_t aTimeout)
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);
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;
190 const otSrpServerService *service;
191 OutstandingUpdate * update;
193 mOutstandingUpdates.resize(mOutstandingUpdates.size() + 1);
194 update = &mOutstandingUpdates.back();
196 fullHostName = otSrpServerHostGetFullName(aHost);
198 otbrLog(OTBR_LOG_INFO, "[adproxy] advertise SRP service updates: host=%s", fullHostName);
200 SuccessOrExit(error = SplitFullHostName(fullHostName, hostName, hostDomain));
201 hostAddress = otSrpServerHostGetAddresses(aHost, &hostAddressNum);
202 hostDeleted = otSrpServerHostIsDeleted(aHost);
204 update->mHost = aHost;
205 update->mCount += !hostDeleted;
206 update->mHostName = hostName;
209 while ((service = otSrpServerHostGetNextService(aHost, service)) != nullptr)
211 update->mCount += !otSrpServerServiceIsDeleted(service);
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])));
223 otbrLog(OTBR_LOG_INFO, "[adproxy] unpublish SRP host: %s", fullHostName);
224 SuccessOrExit(error = mPublisher.UnpublishHost(hostName.c_str()));
228 while ((service = otSrpServerHostGetNextService(aHost, service)) != nullptr)
230 const char *fullServiceName = otSrpServerServiceGetFullName(service);
231 std::string serviceName;
232 std::string serviceType;
233 std::string serviceDomain;
235 SuccessOrExit(error = SplitFullServiceName(fullServiceName, serviceName, serviceType, serviceDomain));
237 update->mServiceNames.emplace_back(serviceName, serviceType);
239 if (!hostDeleted && !otSrpServerServiceIsDeleted(service))
241 Mdns::Publisher::TxtList txtList = MakeTxtList(service);
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));
249 otbrLog(OTBR_LOG_INFO, "[adproxy] unpublish SRP service: %s", fullServiceName);
250 SuccessOrExit(error = mPublisher.UnpublishService(serviceName.c_str(), serviceType.c_str()));
255 if (error != OTBR_ERROR_NONE || update->mCount == 0)
257 if (error != OTBR_ERROR_NONE)
259 otbrLog(OTBR_LOG_INFO, "[adproxy] failed to advertise SRP service updates %p", aHost);
262 mOutstandingUpdates.pop_back();
263 otSrpServerHandleServiceUpdateResult(GetInstance(), aHost, OtbrErrorToOtError(error));
267 void AdvertisingProxy::PublishServiceHandler(const char *aName, const char *aType, otbrError aError, void *aContext)
269 static_cast<AdvertisingProxy *>(aContext)->PublishServiceHandler(aName, aType, aError);
272 void AdvertisingProxy::PublishServiceHandler(const char *aName, const char *aType, otbrError aError)
274 otbrError error = OTBR_ERROR_NONE;
276 otbrLog(OTBR_LOG_INFO, "[adproxy] handle publish service '%s.%s' result: %d", aName, aType, aError);
278 // TODO: there may be same names between two SRP updates.
279 for (auto update = mOutstandingUpdates.begin(); update != mOutstandingUpdates.end(); ++update)
281 for (const auto &nameAndType : update->mServiceNames)
283 if (aName != nameAndType.first || !Mdns::Publisher::IsServiceTypeEqual(aType, nameAndType.second.c_str()))
288 if (aError != OTBR_ERROR_NONE || update->mCount == 1)
290 otSrpServerHandleServiceUpdateResult(GetInstance(), update->mHost, OtbrErrorToOtError(aError));
291 mOutstandingUpdates.erase(update);
302 if (error != OTBR_ERROR_NONE)
304 otbrLog(OTBR_LOG_WARNING, "[adproxy] failed to handle result of service %s", aName);
308 void AdvertisingProxy::PublishHostHandler(const char *aName, otbrError aError, void *aContext)
310 static_cast<AdvertisingProxy *>(aContext)->PublishHostHandler(aName, aError);
313 void AdvertisingProxy::PublishHostHandler(const char *aName, otbrError aError)
315 otbrError error = OTBR_ERROR_NONE;
317 otbrLog(OTBR_LOG_INFO, "[adproxy] handle publish host '%s' result: %d", aName, aError);
319 for (auto update = mOutstandingUpdates.begin(); update != mOutstandingUpdates.end(); ++update)
321 if (aName != update->mHostName)
326 if (aError != OTBR_ERROR_NONE || update->mCount == 1)
328 otSrpServerHandleServiceUpdateResult(GetInstance(), update->mHost, OtbrErrorToOtError(aError));
329 mOutstandingUpdates.erase(update);
339 if (error != OTBR_ERROR_NONE)
341 otbrLog(OTBR_LOG_WARNING, "[adproxy] failed to handle result of host %s", aName);
345 Mdns::Publisher::TxtList AdvertisingProxy::MakeTxtList(const otSrpServerService *aSrpService)
347 const uint8_t * txtData;
348 uint16_t txtDataLength = 0;
349 otDnsTxtEntryIterator iterator;
350 otDnsTxtEntry txtEntry;
351 Mdns::Publisher::TxtList txtList;
353 txtData = otSrpServerServiceGetTxtData(aSrpService, &txtDataLength);
355 otDnsInitTxtEntryIterator(&iterator, txtData, txtDataLength);
357 while (otDnsGetNextTxtEntry(&iterator, &txtEntry) == OT_ERROR_NONE)
359 txtList.emplace_back(txtEntry.mKey, txtEntry.mValue, txtEntry.mValueLength);
367 #endif // OTBR_ENABLE_SRP_ADVERTISING_PROXY