blob: 09982dd858cbaad0d6459910d78a06300aef5010 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "discovery/mdns/mdns_receiver.h"
#include <utility>
#include "discovery/mdns/mdns_reader.h"
#include "util/trace_logging.h"
namespace openscreen {
namespace discovery {
MdnsReceiver::ResponseClient::~ResponseClient() = default;
MdnsReceiver::MdnsReceiver(Config config) : config_(std::move(config)) {}
MdnsReceiver::~MdnsReceiver() {
if (state_ == State::kRunning) {
Stop();
}
OSP_DCHECK(response_clients_.empty());
}
void MdnsReceiver::SetQueryCallback(
std::function<void(const MdnsMessage&, const IPEndpoint&)> callback) {
// This check verifies that either new or stored callback has a target. It
// will fail in case multiple objects try to set or clear the callback.
OSP_DCHECK(static_cast<bool>(query_callback_) != static_cast<bool>(callback));
query_callback_ = callback;
}
void MdnsReceiver::AddResponseCallback(ResponseClient* callback) {
auto it =
std::find(response_clients_.begin(), response_clients_.end(), callback);
OSP_DCHECK(it == response_clients_.end());
response_clients_.push_back(callback);
}
void MdnsReceiver::RemoveResponseCallback(ResponseClient* callback) {
auto it =
std::find(response_clients_.begin(), response_clients_.end(), callback);
OSP_DCHECK(it != response_clients_.end());
response_clients_.erase(it);
}
void MdnsReceiver::Start() {
state_ = State::kRunning;
}
void MdnsReceiver::Stop() {
state_ = State::kStopped;
}
void MdnsReceiver::OnRead(UdpSocket* socket,
ErrorOr<UdpPacket> packet_or_error) {
if (state_ != State::kRunning || packet_or_error.is_error()) {
return;
}
UdpPacket packet = std::move(packet_or_error.value());
TRACE_SCOPED(TraceCategory::kMdns, "MdnsReceiver::OnRead");
MdnsReader reader(config_, packet.data(), packet.size());
const ErrorOr<MdnsMessage> message = reader.Read();
if (message.is_error()) {
if (message.error().code() == Error::Code::kMdnsNonConformingFailure) {
OSP_DVLOG << "mDNS message dropped due to invalid rcode or opcode...";
} else {
OSP_DVLOG << "mDNS message failed to parse...";
}
return;
}
if (message.value().type() == MessageType::Response) {
for (ResponseClient* client : response_clients_) {
client->OnMessageReceived(message.value());
}
if (response_clients_.empty()) {
OSP_DVLOG
<< "mDNS response message dropped. No response client registered...";
}
} else {
if (query_callback_) {
query_callback_(message.value(), packet.source());
} else {
OSP_DVLOG << "mDNS query message dropped. No query client registered...";
}
}
}
} // namespace discovery
} // namespace openscreen