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