1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "osp/impl/testing/fake_mdns_responder_adapter.h"
6
7 #include <algorithm>
8 #include <map>
9 #include <string>
10 #include <utility>
11
12 #include "platform/base/error.h"
13 #include "util/osp_logging.h"
14
15 namespace openscreen {
16 namespace osp {
17
18 constexpr char kLocalDomain[] = "local";
19
MakePtrEvent(const std::string & service_instance,const std::string & service_type,const std::string & service_protocol,UdpSocket * socket)20 PtrEvent MakePtrEvent(const std::string& service_instance,
21 const std::string& service_type,
22 const std::string& service_protocol,
23 UdpSocket* socket) {
24 const auto labels = std::vector<std::string>{service_instance, service_type,
25 service_protocol, kLocalDomain};
26 ErrorOr<DomainName> full_instance_name =
27 DomainName::FromLabels(labels.begin(), labels.end());
28 OSP_CHECK(full_instance_name);
29 PtrEvent result{QueryEventHeader{QueryEventHeader::Type::kAdded, socket},
30 full_instance_name.value()};
31 return result;
32 }
33
MakeSrvEvent(const std::string & service_instance,const std::string & service_type,const std::string & service_protocol,const std::string & hostname,uint16_t port,UdpSocket * socket)34 SrvEvent MakeSrvEvent(const std::string& service_instance,
35 const std::string& service_type,
36 const std::string& service_protocol,
37 const std::string& hostname,
38 uint16_t port,
39 UdpSocket* socket) {
40 const auto instance_labels = std::vector<std::string>{
41 service_instance, service_type, service_protocol, kLocalDomain};
42 ErrorOr<DomainName> full_instance_name =
43 DomainName::FromLabels(instance_labels.begin(), instance_labels.end());
44 OSP_CHECK(full_instance_name);
45
46 const auto host_labels = std::vector<std::string>{hostname, kLocalDomain};
47 ErrorOr<DomainName> domain_name =
48 DomainName::FromLabels(host_labels.begin(), host_labels.end());
49 OSP_CHECK(domain_name);
50
51 SrvEvent result{QueryEventHeader{QueryEventHeader::Type::kAdded, socket},
52 full_instance_name.value(), domain_name.value(), port};
53 return result;
54 }
55
MakeTxtEvent(const std::string & service_instance,const std::string & service_type,const std::string & service_protocol,const std::vector<std::string> & txt_lines,UdpSocket * socket)56 TxtEvent MakeTxtEvent(const std::string& service_instance,
57 const std::string& service_type,
58 const std::string& service_protocol,
59 const std::vector<std::string>& txt_lines,
60 UdpSocket* socket) {
61 const auto labels = std::vector<std::string>{service_instance, service_type,
62 service_protocol, kLocalDomain};
63 ErrorOr<DomainName> domain_name =
64 DomainName::FromLabels(labels.begin(), labels.end());
65 OSP_CHECK(domain_name);
66 TxtEvent result{QueryEventHeader{QueryEventHeader::Type::kAdded, socket},
67 domain_name.value(), txt_lines};
68 return result;
69 }
70
MakeAEvent(const std::string & hostname,IPAddress address,UdpSocket * socket)71 AEvent MakeAEvent(const std::string& hostname,
72 IPAddress address,
73 UdpSocket* socket) {
74 const auto labels = std::vector<std::string>{hostname, kLocalDomain};
75 ErrorOr<DomainName> domain_name =
76 DomainName::FromLabels(labels.begin(), labels.end());
77 OSP_CHECK(domain_name);
78 AEvent result{QueryEventHeader{QueryEventHeader::Type::kAdded, socket},
79 domain_name.value(), address};
80 return result;
81 }
82
MakeAaaaEvent(const std::string & hostname,IPAddress address,UdpSocket * socket)83 AaaaEvent MakeAaaaEvent(const std::string& hostname,
84 IPAddress address,
85 UdpSocket* socket) {
86 const auto labels = std::vector<std::string>{hostname, kLocalDomain};
87 ErrorOr<DomainName> domain_name =
88 DomainName::FromLabels(labels.begin(), labels.end());
89 OSP_CHECK(domain_name);
90 AaaaEvent result{QueryEventHeader{QueryEventHeader::Type::kAdded, socket},
91 domain_name.value(), address};
92 return result;
93 }
94
AddEventsForNewService(FakeMdnsResponderAdapter * mdns_responder,const std::string & service_instance,const std::string & service_name,const std::string & service_protocol,const std::string & hostname,uint16_t port,const std::vector<std::string> & txt_lines,const IPAddress & address,UdpSocket * socket)95 void AddEventsForNewService(FakeMdnsResponderAdapter* mdns_responder,
96 const std::string& service_instance,
97 const std::string& service_name,
98 const std::string& service_protocol,
99 const std::string& hostname,
100 uint16_t port,
101 const std::vector<std::string>& txt_lines,
102 const IPAddress& address,
103 UdpSocket* socket) {
104 mdns_responder->AddPtrEvent(
105 MakePtrEvent(service_instance, service_name, service_protocol, socket));
106 mdns_responder->AddSrvEvent(MakeSrvEvent(service_instance, service_name,
107 service_protocol, hostname, port,
108 socket));
109 mdns_responder->AddTxtEvent(MakeTxtEvent(
110 service_instance, service_name, service_protocol, txt_lines, socket));
111 mdns_responder->AddAEvent(MakeAEvent(hostname, address, socket));
112 }
113
~FakeMdnsResponderAdapter()114 FakeMdnsResponderAdapter::~FakeMdnsResponderAdapter() {
115 if (observer_) {
116 observer_->OnDestroyed();
117 }
118 }
119
AddPtrEvent(PtrEvent && ptr_event)120 void FakeMdnsResponderAdapter::AddPtrEvent(PtrEvent&& ptr_event) {
121 if (running_)
122 ptr_events_.push_back(std::move(ptr_event));
123 }
124
AddSrvEvent(SrvEvent && srv_event)125 void FakeMdnsResponderAdapter::AddSrvEvent(SrvEvent&& srv_event) {
126 if (running_)
127 srv_events_.push_back(std::move(srv_event));
128 }
129
AddTxtEvent(TxtEvent && txt_event)130 void FakeMdnsResponderAdapter::AddTxtEvent(TxtEvent&& txt_event) {
131 if (running_)
132 txt_events_.push_back(std::move(txt_event));
133 }
134
AddAEvent(AEvent && a_event)135 void FakeMdnsResponderAdapter::AddAEvent(AEvent&& a_event) {
136 if (running_)
137 a_events_.push_back(std::move(a_event));
138 }
139
AddAaaaEvent(AaaaEvent && aaaa_event)140 void FakeMdnsResponderAdapter::AddAaaaEvent(AaaaEvent&& aaaa_event) {
141 if (running_)
142 aaaa_events_.push_back(std::move(aaaa_event));
143 }
144
ptr_queries_empty() const145 bool FakeMdnsResponderAdapter::ptr_queries_empty() const {
146 for (const auto& queries : queries_) {
147 if (!queries.second.ptr_queries.empty())
148 return false;
149 }
150 return true;
151 }
152
srv_queries_empty() const153 bool FakeMdnsResponderAdapter::srv_queries_empty() const {
154 for (const auto& queries : queries_) {
155 if (!queries.second.srv_queries.empty())
156 return false;
157 }
158 return true;
159 }
160
txt_queries_empty() const161 bool FakeMdnsResponderAdapter::txt_queries_empty() const {
162 for (const auto& queries : queries_) {
163 if (!queries.second.txt_queries.empty())
164 return false;
165 }
166 return true;
167 }
168
a_queries_empty() const169 bool FakeMdnsResponderAdapter::a_queries_empty() const {
170 for (const auto& queries : queries_) {
171 if (!queries.second.a_queries.empty())
172 return false;
173 }
174 return true;
175 }
176
aaaa_queries_empty() const177 bool FakeMdnsResponderAdapter::aaaa_queries_empty() const {
178 for (const auto& queries : queries_) {
179 if (!queries.second.aaaa_queries.empty())
180 return false;
181 }
182 return true;
183 }
184
Init()185 Error FakeMdnsResponderAdapter::Init() {
186 OSP_CHECK(!running_);
187 running_ = true;
188 return Error::None();
189 }
190
Close()191 void FakeMdnsResponderAdapter::Close() {
192 queries_.clear();
193 ptr_events_.clear();
194 srv_events_.clear();
195 txt_events_.clear();
196 a_events_.clear();
197 aaaa_events_.clear();
198 registered_interfaces_.clear();
199 registered_services_.clear();
200 running_ = false;
201 }
202
SetHostLabel(const std::string & host_label)203 Error FakeMdnsResponderAdapter::SetHostLabel(const std::string& host_label) {
204 return Error::Code::kNotImplemented;
205 }
206
RegisterInterface(const InterfaceInfo & interface_info,const IPSubnet & interface_address,UdpSocket * socket)207 Error FakeMdnsResponderAdapter::RegisterInterface(
208 const InterfaceInfo& interface_info,
209 const IPSubnet& interface_address,
210 UdpSocket* socket) {
211 if (!running_)
212 return Error::Code::kOperationInvalid;
213
214 if (std::find_if(registered_interfaces_.begin(), registered_interfaces_.end(),
215 [&socket](const RegisteredInterface& interface) {
216 return interface.socket == socket;
217 }) != registered_interfaces_.end()) {
218 return Error::Code::kItemNotFound;
219 }
220 registered_interfaces_.push_back({interface_info, interface_address, socket});
221 return Error::None();
222 }
223
DeregisterInterface(UdpSocket * socket)224 Error FakeMdnsResponderAdapter::DeregisterInterface(UdpSocket* socket) {
225 auto it =
226 std::find_if(registered_interfaces_.begin(), registered_interfaces_.end(),
227 [&socket](const RegisteredInterface& interface) {
228 return interface.socket == socket;
229 });
230 if (it == registered_interfaces_.end())
231 return Error::Code::kItemNotFound;
232
233 registered_interfaces_.erase(it);
234 return Error::None();
235 }
236
OnRead(UdpSocket * socket,ErrorOr<UdpPacket> packet)237 void FakeMdnsResponderAdapter::OnRead(UdpSocket* socket,
238 ErrorOr<UdpPacket> packet) {
239 OSP_NOTREACHED();
240 }
241
OnSendError(UdpSocket * socket,Error error)242 void FakeMdnsResponderAdapter::OnSendError(UdpSocket* socket, Error error) {
243 OSP_NOTREACHED();
244 }
245
OnError(UdpSocket * socket,Error error)246 void FakeMdnsResponderAdapter::OnError(UdpSocket* socket, Error error) {
247 OSP_NOTREACHED();
248 }
249
OnBound(UdpSocket * socket)250 void FakeMdnsResponderAdapter::OnBound(UdpSocket* socket) {
251 OSP_NOTREACHED();
252 }
253
RunTasks()254 Clock::duration FakeMdnsResponderAdapter::RunTasks() {
255 return std::chrono::seconds(1);
256 }
257
TakePtrResponses()258 std::vector<PtrEvent> FakeMdnsResponderAdapter::TakePtrResponses() {
259 std::vector<PtrEvent> result;
260 for (auto& queries : queries_) {
261 const auto query_it = std::stable_partition(
262 ptr_events_.begin(), ptr_events_.end(),
263 [&queries](const PtrEvent& ptr_event) {
264 const auto instance_labels = ptr_event.service_instance.GetLabels();
265 for (const auto& query : queries.second.ptr_queries) {
266 const auto query_labels = query.GetLabels();
267 // TODO(btolsch): Just use qname if it's added to PtrEvent.
268 if (ptr_event.header.socket == queries.first &&
269 std::equal(instance_labels.begin() + 1, instance_labels.end(),
270 query_labels.begin())) {
271 return false;
272 }
273 }
274 return true;
275 });
276 for (auto it = query_it; it != ptr_events_.end(); ++it) {
277 result.push_back(std::move(*it));
278 }
279 ptr_events_.erase(query_it, ptr_events_.end());
280 }
281 OSP_LOG_INFO << "taking " << result.size() << " ptr response(s)";
282 return result;
283 }
284
TakeSrvResponses()285 std::vector<SrvEvent> FakeMdnsResponderAdapter::TakeSrvResponses() {
286 std::vector<SrvEvent> result;
287 for (auto& queries : queries_) {
288 const auto query_it = std::stable_partition(
289 srv_events_.begin(), srv_events_.end(),
290 [&queries](const SrvEvent& srv_event) {
291 for (const auto& query : queries.second.srv_queries) {
292 if (srv_event.header.socket == queries.first &&
293 srv_event.service_instance == query)
294 return false;
295 }
296 return true;
297 });
298 for (auto it = query_it; it != srv_events_.end(); ++it) {
299 result.push_back(std::move(*it));
300 }
301 srv_events_.erase(query_it, srv_events_.end());
302 }
303 OSP_LOG_INFO << "taking " << result.size() << " srv response(s)";
304 return result;
305 }
306
TakeTxtResponses()307 std::vector<TxtEvent> FakeMdnsResponderAdapter::TakeTxtResponses() {
308 std::vector<TxtEvent> result;
309 for (auto& queries : queries_) {
310 const auto query_it = std::stable_partition(
311 txt_events_.begin(), txt_events_.end(),
312 [&queries](const TxtEvent& txt_event) {
313 for (const auto& query : queries.second.txt_queries) {
314 if (txt_event.header.socket == queries.first &&
315 txt_event.service_instance == query) {
316 return false;
317 }
318 }
319 return true;
320 });
321 for (auto it = query_it; it != txt_events_.end(); ++it) {
322 result.push_back(std::move(*it));
323 }
324 txt_events_.erase(query_it, txt_events_.end());
325 }
326 OSP_LOG_INFO << "taking " << result.size() << " txt response(s)";
327 return result;
328 }
329
TakeAResponses()330 std::vector<AEvent> FakeMdnsResponderAdapter::TakeAResponses() {
331 std::vector<AEvent> result;
332 for (auto& queries : queries_) {
333 const auto query_it = std::stable_partition(
334 a_events_.begin(), a_events_.end(), [&queries](const AEvent& a_event) {
335 for (const auto& query : queries.second.a_queries) {
336 if (a_event.header.socket == queries.first &&
337 a_event.domain_name == query) {
338 return false;
339 }
340 }
341 return true;
342 });
343 for (auto it = query_it; it != a_events_.end(); ++it) {
344 result.push_back(std::move(*it));
345 }
346 a_events_.erase(query_it, a_events_.end());
347 }
348 OSP_LOG_INFO << "taking " << result.size() << " a response(s)";
349 return result;
350 }
351
TakeAaaaResponses()352 std::vector<AaaaEvent> FakeMdnsResponderAdapter::TakeAaaaResponses() {
353 std::vector<AaaaEvent> result;
354 for (auto& queries : queries_) {
355 const auto query_it = std::stable_partition(
356 aaaa_events_.begin(), aaaa_events_.end(),
357 [&queries](const AaaaEvent& aaaa_event) {
358 for (const auto& query : queries.second.aaaa_queries) {
359 if (aaaa_event.header.socket == queries.first &&
360 aaaa_event.domain_name == query) {
361 return false;
362 }
363 }
364 return true;
365 });
366 for (auto it = query_it; it != aaaa_events_.end(); ++it) {
367 result.push_back(std::move(*it));
368 }
369 aaaa_events_.erase(query_it, aaaa_events_.end());
370 }
371 OSP_LOG_INFO << "taking " << result.size() << " a response(s)";
372 return result;
373 }
374
StartPtrQuery(UdpSocket * socket,const DomainName & service_type)375 MdnsResponderErrorCode FakeMdnsResponderAdapter::StartPtrQuery(
376 UdpSocket* socket,
377 const DomainName& service_type) {
378 if (!running_)
379 return MdnsResponderErrorCode::kUnknownError;
380
381 auto canonical_service_type = service_type;
382 if (!canonical_service_type.EndsWithLocalDomain())
383 OSP_CHECK(canonical_service_type.Append(DomainName::GetLocalDomain()).ok());
384
385 auto maybe_inserted =
386 queries_[socket].ptr_queries.insert(canonical_service_type);
387 if (maybe_inserted.second) {
388 return MdnsResponderErrorCode::kNoError;
389 } else {
390 return MdnsResponderErrorCode::kUnknownError;
391 }
392 }
393
StartSrvQuery(UdpSocket * socket,const DomainName & service_instance)394 MdnsResponderErrorCode FakeMdnsResponderAdapter::StartSrvQuery(
395 UdpSocket* socket,
396 const DomainName& service_instance) {
397 if (!running_)
398 return MdnsResponderErrorCode::kUnknownError;
399
400 auto maybe_inserted = queries_[socket].srv_queries.insert(service_instance);
401 if (maybe_inserted.second) {
402 return MdnsResponderErrorCode::kNoError;
403 } else {
404 return MdnsResponderErrorCode::kUnknownError;
405 }
406 }
407
StartTxtQuery(UdpSocket * socket,const DomainName & service_instance)408 MdnsResponderErrorCode FakeMdnsResponderAdapter::StartTxtQuery(
409 UdpSocket* socket,
410 const DomainName& service_instance) {
411 if (!running_)
412 return MdnsResponderErrorCode::kUnknownError;
413
414 auto maybe_inserted = queries_[socket].txt_queries.insert(service_instance);
415 if (maybe_inserted.second) {
416 return MdnsResponderErrorCode::kNoError;
417 } else {
418 return MdnsResponderErrorCode::kUnknownError;
419 }
420 }
421
StartAQuery(UdpSocket * socket,const DomainName & domain_name)422 MdnsResponderErrorCode FakeMdnsResponderAdapter::StartAQuery(
423 UdpSocket* socket,
424 const DomainName& domain_name) {
425 if (!running_)
426 return MdnsResponderErrorCode::kUnknownError;
427
428 auto maybe_inserted = queries_[socket].a_queries.insert(domain_name);
429 if (maybe_inserted.second) {
430 return MdnsResponderErrorCode::kNoError;
431 } else {
432 return MdnsResponderErrorCode::kUnknownError;
433 }
434 }
435
StartAaaaQuery(UdpSocket * socket,const DomainName & domain_name)436 MdnsResponderErrorCode FakeMdnsResponderAdapter::StartAaaaQuery(
437 UdpSocket* socket,
438 const DomainName& domain_name) {
439 if (!running_)
440 return MdnsResponderErrorCode::kUnknownError;
441
442 auto maybe_inserted = queries_[socket].aaaa_queries.insert(domain_name);
443 if (maybe_inserted.second) {
444 return MdnsResponderErrorCode::kNoError;
445 } else {
446 return MdnsResponderErrorCode::kUnknownError;
447 }
448 }
449
StopPtrQuery(UdpSocket * socket,const DomainName & service_type)450 MdnsResponderErrorCode FakeMdnsResponderAdapter::StopPtrQuery(
451 UdpSocket* socket,
452 const DomainName& service_type) {
453 auto interface_entry = queries_.find(socket);
454 if (interface_entry == queries_.end())
455 return MdnsResponderErrorCode::kUnknownError;
456 auto& ptr_queries = interface_entry->second.ptr_queries;
457 auto canonical_service_type = service_type;
458 if (!canonical_service_type.EndsWithLocalDomain())
459 OSP_CHECK(canonical_service_type.Append(DomainName::GetLocalDomain()).ok());
460
461 auto it = ptr_queries.find(canonical_service_type);
462 if (it == ptr_queries.end())
463 return MdnsResponderErrorCode::kUnknownError;
464
465 ptr_queries.erase(it);
466 return MdnsResponderErrorCode::kNoError;
467 }
468
StopSrvQuery(UdpSocket * socket,const DomainName & service_instance)469 MdnsResponderErrorCode FakeMdnsResponderAdapter::StopSrvQuery(
470 UdpSocket* socket,
471 const DomainName& service_instance) {
472 auto interface_entry = queries_.find(socket);
473 if (interface_entry == queries_.end())
474 return MdnsResponderErrorCode::kUnknownError;
475 auto& srv_queries = interface_entry->second.srv_queries;
476 auto it = srv_queries.find(service_instance);
477 if (it == srv_queries.end())
478 return MdnsResponderErrorCode::kUnknownError;
479
480 srv_queries.erase(it);
481 return MdnsResponderErrorCode::kNoError;
482 }
483
StopTxtQuery(UdpSocket * socket,const DomainName & service_instance)484 MdnsResponderErrorCode FakeMdnsResponderAdapter::StopTxtQuery(
485 UdpSocket* socket,
486 const DomainName& service_instance) {
487 auto interface_entry = queries_.find(socket);
488 if (interface_entry == queries_.end())
489 return MdnsResponderErrorCode::kUnknownError;
490 auto& txt_queries = interface_entry->second.txt_queries;
491 auto it = txt_queries.find(service_instance);
492 if (it == txt_queries.end())
493 return MdnsResponderErrorCode::kUnknownError;
494
495 txt_queries.erase(it);
496 return MdnsResponderErrorCode::kNoError;
497 }
498
StopAQuery(UdpSocket * socket,const DomainName & domain_name)499 MdnsResponderErrorCode FakeMdnsResponderAdapter::StopAQuery(
500 UdpSocket* socket,
501 const DomainName& domain_name) {
502 auto interface_entry = queries_.find(socket);
503 if (interface_entry == queries_.end())
504 return MdnsResponderErrorCode::kUnknownError;
505 auto& a_queries = interface_entry->second.a_queries;
506 auto it = a_queries.find(domain_name);
507 if (it == a_queries.end())
508 return MdnsResponderErrorCode::kUnknownError;
509
510 a_queries.erase(it);
511 return MdnsResponderErrorCode::kNoError;
512 }
513
StopAaaaQuery(UdpSocket * socket,const DomainName & domain_name)514 MdnsResponderErrorCode FakeMdnsResponderAdapter::StopAaaaQuery(
515 UdpSocket* socket,
516 const DomainName& domain_name) {
517 auto interface_entry = queries_.find(socket);
518 if (interface_entry == queries_.end())
519 return MdnsResponderErrorCode::kUnknownError;
520 auto& aaaa_queries = interface_entry->second.aaaa_queries;
521 auto it = aaaa_queries.find(domain_name);
522 if (it == aaaa_queries.end())
523 return MdnsResponderErrorCode::kUnknownError;
524
525 aaaa_queries.erase(it);
526 return MdnsResponderErrorCode::kNoError;
527 }
528
RegisterService(const std::string & service_instance,const std::string & service_name,const std::string & service_protocol,const DomainName & target_host,uint16_t target_port,const std::map<std::string,std::string> & txt_data)529 MdnsResponderErrorCode FakeMdnsResponderAdapter::RegisterService(
530 const std::string& service_instance,
531 const std::string& service_name,
532 const std::string& service_protocol,
533 const DomainName& target_host,
534 uint16_t target_port,
535 const std::map<std::string, std::string>& txt_data) {
536 if (!running_)
537 return MdnsResponderErrorCode::kUnknownError;
538
539 if (std::find_if(registered_services_.begin(), registered_services_.end(),
540 [&service_instance, &service_name,
541 &service_protocol](const RegisteredService& service) {
542 return service.service_instance == service_instance &&
543 service.service_name == service_name &&
544 service.service_protocol == service_protocol;
545 }) != registered_services_.end()) {
546 return MdnsResponderErrorCode::kUnknownError;
547 }
548 registered_services_.push_back({service_instance, service_name,
549 service_protocol, target_host, target_port,
550 txt_data});
551 return MdnsResponderErrorCode::kNoError;
552 }
553
DeregisterService(const std::string & service_instance,const std::string & service_name,const std::string & service_protocol)554 MdnsResponderErrorCode FakeMdnsResponderAdapter::DeregisterService(
555 const std::string& service_instance,
556 const std::string& service_name,
557 const std::string& service_protocol) {
558 if (!running_)
559 return MdnsResponderErrorCode::kUnknownError;
560
561 auto it =
562 std::find_if(registered_services_.begin(), registered_services_.end(),
563 [&service_instance, &service_name,
564 &service_protocol](const RegisteredService& service) {
565 return service.service_instance == service_instance &&
566 service.service_name == service_name &&
567 service.service_protocol == service_protocol;
568 });
569 if (it == registered_services_.end())
570 return MdnsResponderErrorCode::kUnknownError;
571
572 registered_services_.erase(it);
573 return MdnsResponderErrorCode::kNoError;
574 }
575
UpdateTxtData(const std::string & service_instance,const std::string & service_name,const std::string & service_protocol,const std::map<std::string,std::string> & txt_data)576 MdnsResponderErrorCode FakeMdnsResponderAdapter::UpdateTxtData(
577 const std::string& service_instance,
578 const std::string& service_name,
579 const std::string& service_protocol,
580 const std::map<std::string, std::string>& txt_data) {
581 if (!running_)
582 return MdnsResponderErrorCode::kUnknownError;
583
584 auto it =
585 std::find_if(registered_services_.begin(), registered_services_.end(),
586 [&service_instance, &service_name,
587 &service_protocol](const RegisteredService& service) {
588 return service.service_instance == service_instance &&
589 service.service_name == service_name &&
590 service.service_protocol == service_protocol;
591 });
592 if (it == registered_services_.end())
593 return MdnsResponderErrorCode::kUnknownError;
594
595 it->txt_data = txt_data;
596 return MdnsResponderErrorCode::kNoError;
597 }
598
599 } // namespace osp
600 } // namespace openscreen
601