1 // Copyright 2019 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 "discovery/mdns/mdns_receiver.h"
6
7 #include <utility>
8
9 #include "discovery/mdns/mdns_reader.h"
10 #include "util/trace_logging.h"
11
12 namespace openscreen {
13 namespace discovery {
14
15 MdnsReceiver::ResponseClient::~ResponseClient() = default;
16
MdnsReceiver(Config config)17 MdnsReceiver::MdnsReceiver(Config config) : config_(std::move(config)) {}
18
~MdnsReceiver()19 MdnsReceiver::~MdnsReceiver() {
20 if (state_ == State::kRunning) {
21 Stop();
22 }
23
24 OSP_DCHECK(response_clients_.empty());
25 }
26
SetQueryCallback(std::function<void (const MdnsMessage &,const IPEndpoint &)> callback)27 void MdnsReceiver::SetQueryCallback(
28 std::function<void(const MdnsMessage&, const IPEndpoint&)> callback) {
29 // This check verifies that either new or stored callback has a target. It
30 // will fail in case multiple objects try to set or clear the callback.
31 OSP_DCHECK(static_cast<bool>(query_callback_) != static_cast<bool>(callback));
32 query_callback_ = callback;
33 }
34
AddResponseCallback(ResponseClient * callback)35 void MdnsReceiver::AddResponseCallback(ResponseClient* callback) {
36 auto it =
37 std::find(response_clients_.begin(), response_clients_.end(), callback);
38 OSP_DCHECK(it == response_clients_.end());
39
40 response_clients_.push_back(callback);
41 }
42
RemoveResponseCallback(ResponseClient * callback)43 void MdnsReceiver::RemoveResponseCallback(ResponseClient* callback) {
44 auto it =
45 std::find(response_clients_.begin(), response_clients_.end(), callback);
46 OSP_DCHECK(it != response_clients_.end());
47
48 response_clients_.erase(it);
49 }
50
Start()51 void MdnsReceiver::Start() {
52 state_ = State::kRunning;
53 }
54
Stop()55 void MdnsReceiver::Stop() {
56 state_ = State::kStopped;
57 }
58
OnRead(UdpSocket * socket,ErrorOr<UdpPacket> packet_or_error)59 void MdnsReceiver::OnRead(UdpSocket* socket,
60 ErrorOr<UdpPacket> packet_or_error) {
61 if (state_ != State::kRunning || packet_or_error.is_error()) {
62 return;
63 }
64
65 UdpPacket packet = std::move(packet_or_error.value());
66
67 TRACE_SCOPED(TraceCategory::kMdns, "MdnsReceiver::OnRead");
68 MdnsReader reader(config_, packet.data(), packet.size());
69 const ErrorOr<MdnsMessage> message = reader.Read();
70 if (message.is_error()) {
71 if (message.error().code() == Error::Code::kMdnsNonConformingFailure) {
72 OSP_DVLOG << "mDNS message dropped due to invalid rcode or opcode...";
73 } else {
74 OSP_DVLOG << "mDNS message failed to parse...";
75 }
76 return;
77 }
78
79 if (message.value().type() == MessageType::Response) {
80 for (ResponseClient* client : response_clients_) {
81 client->OnMessageReceived(message.value());
82 }
83 if (response_clients_.empty()) {
84 OSP_DVLOG
85 << "mDNS response message dropped. No response client registered...";
86 }
87 } else {
88 if (query_callback_) {
89 query_callback_(message.value(), packet.source());
90 } else {
91 OSP_DVLOG << "mDNS query message dropped. No query client registered...";
92 }
93 }
94 }
95
96 } // namespace discovery
97 } // namespace openscreen
98