• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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