| // 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. |
| |
| #ifndef DISCOVERY_MDNS_MDNS_RECORDS_H_ |
| #define DISCOVERY_MDNS_MDNS_RECORDS_H_ |
| |
| #include <algorithm> |
| #include <chrono> |
| #include <functional> |
| #include <initializer_list> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "absl/strings/ascii.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/types/variant.h" |
| #include "discovery/mdns/public/mdns_constants.h" |
| #include "platform/base/error.h" |
| #include "platform/base/interface_info.h" |
| #include "platform/base/ip_address.h" |
| #include "util/osp_logging.h" |
| |
| namespace openscreen { |
| namespace discovery { |
| |
| bool IsValidDomainLabel(absl::string_view label); |
| |
| // Represents domain name as a collection of labels, ensures label length and |
| // domain name length requirements are met. |
| class DomainName { |
| public: |
| DomainName(); |
| |
| template <typename IteratorType> |
| static ErrorOr<DomainName> TryCreate(IteratorType first, IteratorType last) { |
| std::vector<std::string> labels; |
| size_t max_wire_size = 1; |
| labels.reserve(std::distance(first, last)); |
| for (IteratorType entry = first; entry != last; ++entry) { |
| if (!IsValidDomainLabel(*entry)) { |
| return Error::Code::kParameterInvalid; |
| } |
| labels.emplace_back(*entry); |
| // Include the length byte in the size calculation. |
| max_wire_size += entry->size() + 1; |
| } |
| |
| if (max_wire_size > kMaxDomainNameLength) { |
| return Error::Code::kIndexOutOfBounds; |
| } else { |
| return DomainName(std::move(labels), max_wire_size); |
| } |
| } |
| |
| template <typename IteratorType> |
| DomainName(IteratorType first, IteratorType last) { |
| ErrorOr<DomainName> domain = TryCreate(first, last); |
| *this = std::move(domain.value()); |
| } |
| explicit DomainName(std::vector<std::string> labels); |
| explicit DomainName(const std::vector<absl::string_view>& labels); |
| explicit DomainName(std::initializer_list<absl::string_view> labels); |
| DomainName(const DomainName& other); |
| DomainName(DomainName&& other) noexcept; |
| |
| DomainName& operator=(const DomainName& rhs); |
| DomainName& operator=(DomainName&& rhs); |
| bool operator<(const DomainName& rhs) const; |
| bool operator<=(const DomainName& rhs) const; |
| bool operator>(const DomainName& rhs) const; |
| bool operator>=(const DomainName& rhs) const; |
| bool operator==(const DomainName& rhs) const; |
| bool operator!=(const DomainName& rhs) const; |
| |
| std::string ToString() const; |
| |
| // Returns the maximum space that the domain name could take up in its |
| // on-the-wire format. This is an upper bound based on the length of the |
| // labels that make up the domain name. It's possible that with domain name |
| // compression the actual space taken in on-the-wire format is smaller. |
| size_t MaxWireSize() const; |
| bool empty() const { return labels_.empty(); } |
| bool IsRoot() const { return labels_.empty(); } |
| const std::vector<std::string>& labels() const { return labels_; } |
| |
| template <typename H> |
| friend H AbslHashValue(H h, const DomainName& domain_name) { |
| std::vector<std::string> labels_clone = domain_name.labels_; |
| for (auto& label : labels_clone) { |
| absl::AsciiStrToLower(&label); |
| } |
| return H::combine(std::move(h), std::move(labels_clone)); |
| } |
| |
| private: |
| DomainName(std::vector<std::string> labels, size_t max_wire_size); |
| |
| // max_wire_size_ starts at 1 for the terminating character length. |
| size_t max_wire_size_ = 1; |
| std::vector<std::string> labels_; |
| }; |
| |
| // Parsed representation of the extra data in a record. Does not include |
| // standard DNS record data such as TTL, Name, Type, and Class. We use it to |
| // distinguish a raw record type that we do not know the identity of. |
| class RawRecordRdata { |
| public: |
| static ErrorOr<RawRecordRdata> TryCreate(std::vector<uint8_t> rdata); |
| |
| RawRecordRdata(); |
| explicit RawRecordRdata(std::vector<uint8_t> rdata); |
| RawRecordRdata(const uint8_t* begin, size_t size); |
| RawRecordRdata(const RawRecordRdata& other); |
| RawRecordRdata(RawRecordRdata&& other) noexcept; |
| |
| RawRecordRdata& operator=(const RawRecordRdata& rhs); |
| RawRecordRdata& operator=(RawRecordRdata&& rhs); |
| bool operator==(const RawRecordRdata& rhs) const; |
| bool operator!=(const RawRecordRdata& rhs) const; |
| |
| size_t MaxWireSize() const; |
| uint16_t size() const { return rdata_.size(); } |
| const uint8_t* data() const { return rdata_.data(); } |
| |
| template <typename H> |
| friend H AbslHashValue(H h, const RawRecordRdata& rdata) { |
| return H::combine(std::move(h), rdata.rdata_); |
| } |
| |
| private: |
| std::vector<uint8_t> rdata_; |
| }; |
| |
| // SRV record format (http://www.ietf.org/rfc/rfc2782.txt): |
| // 2 bytes network-order unsigned priority |
| // 2 bytes network-order unsigned weight |
| // 2 bytes network-order unsigned port |
| // target: domain name (on-the-wire representation) |
| class SrvRecordRdata { |
| public: |
| SrvRecordRdata(); |
| SrvRecordRdata(uint16_t priority, |
| uint16_t weight, |
| uint16_t port, |
| DomainName target); |
| SrvRecordRdata(const SrvRecordRdata& other); |
| SrvRecordRdata(SrvRecordRdata&& other) noexcept; |
| |
| SrvRecordRdata& operator=(const SrvRecordRdata& rhs); |
| SrvRecordRdata& operator=(SrvRecordRdata&& rhs); |
| bool operator==(const SrvRecordRdata& rhs) const; |
| bool operator!=(const SrvRecordRdata& rhs) const; |
| |
| size_t MaxWireSize() const; |
| uint16_t priority() const { return priority_; } |
| uint16_t weight() const { return weight_; } |
| uint16_t port() const { return port_; } |
| const DomainName& target() const { return target_; } |
| |
| template <typename H> |
| friend H AbslHashValue(H h, const SrvRecordRdata& rdata) { |
| return H::combine(std::move(h), rdata.priority_, rdata.weight_, rdata.port_, |
| rdata.target_); |
| } |
| |
| private: |
| uint16_t priority_ = 0; |
| uint16_t weight_ = 0; |
| uint16_t port_ = 0; |
| DomainName target_; |
| }; |
| |
| // A Record format (http://www.ietf.org/rfc/rfc1035.txt): |
| // 4 bytes for IP address. |
| class ARecordRdata { |
| public: |
| ARecordRdata(); |
| explicit ARecordRdata(IPAddress ipv4_address, |
| NetworkInterfaceIndex interface_index = 0); |
| ARecordRdata(const ARecordRdata& other); |
| ARecordRdata(ARecordRdata&& other) noexcept; |
| |
| ARecordRdata& operator=(const ARecordRdata& rhs); |
| ARecordRdata& operator=(ARecordRdata&& rhs); |
| bool operator==(const ARecordRdata& rhs) const; |
| bool operator!=(const ARecordRdata& rhs) const; |
| |
| size_t MaxWireSize() const; |
| const IPAddress& ipv4_address() const { return ipv4_address_; } |
| NetworkInterfaceIndex interface_index() const { return interface_index_; } |
| |
| template <typename H> |
| friend H AbslHashValue(H h, const ARecordRdata& rdata) { |
| const auto& bytes = rdata.ipv4_address_.bytes(); |
| return H::combine_contiguous(std::move(h), bytes, 4); |
| } |
| |
| private: |
| IPAddress ipv4_address_{0, 0, 0, 0}; |
| NetworkInterfaceIndex interface_index_; |
| }; |
| |
| // AAAA Record format (http://www.ietf.org/rfc/rfc1035.txt): |
| // 16 bytes for IP address. |
| class AAAARecordRdata { |
| public: |
| AAAARecordRdata(); |
| explicit AAAARecordRdata(IPAddress ipv6_address, |
| NetworkInterfaceIndex interface_index = 0); |
| AAAARecordRdata(const AAAARecordRdata& other); |
| AAAARecordRdata(AAAARecordRdata&& other) noexcept; |
| |
| AAAARecordRdata& operator=(const AAAARecordRdata& rhs); |
| AAAARecordRdata& operator=(AAAARecordRdata&& rhs); |
| bool operator==(const AAAARecordRdata& rhs) const; |
| bool operator!=(const AAAARecordRdata& rhs) const; |
| |
| size_t MaxWireSize() const; |
| const IPAddress& ipv6_address() const { return ipv6_address_; } |
| NetworkInterfaceIndex interface_index() const { return interface_index_; } |
| |
| template <typename H> |
| friend H AbslHashValue(H h, const AAAARecordRdata& rdata) { |
| const auto& bytes = rdata.ipv6_address_.bytes(); |
| return H::combine_contiguous(std::move(h), bytes, 16); |
| } |
| |
| private: |
| IPAddress ipv6_address_{0x0000, 0x0000, 0x0000, 0x0000, |
| 0x0000, 0x0000, 0x0000, 0x0000}; |
| NetworkInterfaceIndex interface_index_; |
| }; |
| |
| // PTR record format (http://www.ietf.org/rfc/rfc1035.txt): |
| // domain: On the wire representation of domain name. |
| class PtrRecordRdata { |
| public: |
| PtrRecordRdata(); |
| explicit PtrRecordRdata(DomainName ptr_domain); |
| PtrRecordRdata(const PtrRecordRdata& other); |
| PtrRecordRdata(PtrRecordRdata&& other) noexcept; |
| |
| PtrRecordRdata& operator=(const PtrRecordRdata& rhs); |
| PtrRecordRdata& operator=(PtrRecordRdata&& rhs); |
| bool operator==(const PtrRecordRdata& rhs) const; |
| bool operator!=(const PtrRecordRdata& rhs) const; |
| |
| size_t MaxWireSize() const; |
| const DomainName& ptr_domain() const { return ptr_domain_; } |
| |
| template <typename H> |
| friend H AbslHashValue(H h, const PtrRecordRdata& rdata) { |
| return H::combine(std::move(h), rdata.ptr_domain_); |
| } |
| |
| private: |
| DomainName ptr_domain_; |
| }; |
| |
| // TXT record format (http://www.ietf.org/rfc/rfc1035.txt). |
| // texts: One or more <entries>. |
| // An <entry> is a length octet followed by as many data octets. |
| // |
| // DNS-SD interprets <entries> as a list of boolean keys and key=value |
| // attributes. See https://tools.ietf.org/html/rfc6763#section-6 for details. |
| class TxtRecordRdata { |
| public: |
| using Entry = std::vector<uint8_t>; |
| |
| static ErrorOr<TxtRecordRdata> TryCreate(std::vector<Entry> texts); |
| |
| TxtRecordRdata(); |
| explicit TxtRecordRdata(std::vector<Entry> texts); |
| TxtRecordRdata(const TxtRecordRdata& other); |
| TxtRecordRdata(TxtRecordRdata&& other) noexcept; |
| |
| TxtRecordRdata& operator=(const TxtRecordRdata& rhs); |
| TxtRecordRdata& operator=(TxtRecordRdata&& rhs); |
| bool operator==(const TxtRecordRdata& rhs) const; |
| bool operator!=(const TxtRecordRdata& rhs) const; |
| |
| size_t MaxWireSize() const; |
| // NOTE: TXT entries are not guaranteed to be character data. |
| const std::vector<std::string>& texts() const { return texts_; } |
| |
| template <typename H> |
| friend H AbslHashValue(H h, const TxtRecordRdata& rdata) { |
| return H::combine(std::move(h), rdata.texts_); |
| } |
| |
| private: |
| TxtRecordRdata(std::vector<std::string> texts, size_t max_wire_size); |
| |
| // max_wire_size_ is at least 3, uint16_t record length and at the |
| // minimum a NULL byte character string is present. |
| size_t max_wire_size_ = 3; |
| // NOTE: For compatibility with DNS-SD usage, std::string is used for internal |
| // storage. |
| std::vector<std::string> texts_; |
| }; |
| |
| // NSEC record format (https://tools.ietf.org/html/rfc4034#section-4). |
| // In mDNS, this record type is used for representing negative responses to |
| // queries. |
| // |
| // next_domain_name: The next domain to process. In mDNS, this value is expected |
| // to match the record-level domain name in a negative response. |
| // |
| // An example of how the |types_| vector is serialized is as follows: |
| // When encoding the following DNS types: |
| // - A (value 1) |
| // - MX (value 15) |
| // - RRSIG (value 46) |
| // - NSEC (value 47) |
| // - TYPE1234 (value 1234) |
| // The result would be: |
| // 0x00 0x06 0x40 0x01 0x00 0x00 0x00 0x03 |
| // 0x04 0x1b 0x00 0x00 0x00 0x00 0x00 0x00 |
| // 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 |
| // 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 |
| // 0x00 0x00 0x00 0x00 0x20 |
| class NsecRecordRdata { |
| public: |
| NsecRecordRdata(); |
| |
| // Constructor that takes an arbitrary number of DnsType parameters. |
| // NOTE: If `types...` provide a valid set of parameters for an |
| // std::vector<DnsType> ctor call, this will compile. Do not use this ctor |
| // except to provide multiple DnsType parameters. |
| template <typename... Types> |
| NsecRecordRdata(DomainName next_domain_name, Types... types) |
| : NsecRecordRdata(std::move(next_domain_name), |
| std::vector<DnsType>{types...}) {} |
| NsecRecordRdata(DomainName next_domain_name, std::vector<DnsType> types); |
| NsecRecordRdata(const NsecRecordRdata& other); |
| NsecRecordRdata(NsecRecordRdata&& other) noexcept; |
| |
| NsecRecordRdata& operator=(const NsecRecordRdata& rhs); |
| NsecRecordRdata& operator=(NsecRecordRdata&& rhs); |
| bool operator==(const NsecRecordRdata& rhs) const; |
| bool operator!=(const NsecRecordRdata& rhs) const; |
| |
| size_t MaxWireSize() const; |
| |
| const DomainName& next_domain_name() const { return next_domain_name_; } |
| const std::vector<DnsType>& types() const { return types_; } |
| const std::vector<uint8_t>& encoded_types() const { return encoded_types_; } |
| |
| template <typename H> |
| friend H AbslHashValue(H h, const NsecRecordRdata& rdata) { |
| return H::combine(std::move(h), rdata.types_, rdata.next_domain_name_); |
| } |
| |
| private: |
| std::vector<uint8_t> encoded_types_; |
| std::vector<DnsType> types_; |
| DomainName next_domain_name_; |
| }; |
| |
| // The OPT pseudo-record / meta-record as defined by RFC6891. |
| class OptRecordRdata { |
| public: |
| // A single option as defined in RFC6891 section 6.1.2. |
| struct Option { |
| size_t MaxWireSize() const; |
| |
| bool operator>(const Option& rhs) const; |
| bool operator<(const Option& rhs) const; |
| bool operator>=(const Option& rhs) const; |
| bool operator<=(const Option& rhs) const; |
| bool operator==(const Option& rhs) const; |
| bool operator!=(const Option& rhs) const; |
| |
| template <typename H> |
| friend H AbslHashValue(H h, const Option& option) { |
| return H::combine(std::move(h), option.code, option.length, option.data); |
| } |
| |
| // Code assigned by the Expert Review process as defined by the DNSEXT |
| // working group and the IESG, as specified in RFC6891 section 9.1. For |
| // specific assignments, see: |
| // https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml |
| uint16_t code; |
| |
| // Size (in octets) of |data|. |
| uint16_t length; |
| |
| // Bit Field with meaning varying based on |code|. |
| std::vector<uint8_t> data; |
| }; |
| |
| OptRecordRdata(); |
| |
| // Constructor that takes zero or more Option parameters. |
| template <typename... Types> |
| explicit OptRecordRdata(Types... types) |
| : OptRecordRdata(std::vector<Option>{std::move(types)...}) {} |
| explicit OptRecordRdata(std::vector<Option> options); |
| OptRecordRdata(const OptRecordRdata& other); |
| OptRecordRdata(OptRecordRdata&& other) noexcept; |
| |
| OptRecordRdata& operator=(const OptRecordRdata& rhs); |
| OptRecordRdata& operator=(OptRecordRdata&& rhs); |
| |
| // NOTE: Only the options field is technically considered part of the rdata, |
| // so only this field is considered for equality comparison. The other fields |
| // are included here solely because their meaning differs for OPT pseudo- |
| // records and normal record types. |
| bool operator==(const OptRecordRdata& rhs) const; |
| bool operator!=(const OptRecordRdata& rhs) const; |
| |
| size_t MaxWireSize() const { return max_wire_size_; } |
| |
| // Set of options stored in this OPT record. |
| const std::vector<Option>& options() { return options_; } |
| |
| template <typename H> |
| friend H AbslHashValue(H h, const OptRecordRdata& rdata) { |
| return H::combine(std::move(h), rdata.options_); |
| } |
| |
| private: |
| // NOTE: The elements of |options_| are stored is sorted order to simplify the |
| // comparison operators of OptRecordRdata. |
| std::vector<Option> options_; |
| |
| size_t max_wire_size_ = 0; |
| }; |
| |
| using Rdata = absl::variant<RawRecordRdata, |
| SrvRecordRdata, |
| ARecordRdata, |
| AAAARecordRdata, |
| PtrRecordRdata, |
| TxtRecordRdata, |
| NsecRecordRdata, |
| OptRecordRdata>; |
| |
| // Resource record top level format (http://www.ietf.org/rfc/rfc1035.txt): |
| // name: the name of the node to which this resource record pertains. |
| // type: 2 bytes network-order RR TYPE code. |
| // class: 2 bytes network-order RR CLASS code. |
| // ttl: 4 bytes network-order cache time interval. |
| // rdata: RDATA describing the resource. The format of this information varies |
| // according to the TYPE and CLASS of the resource record. |
| class MdnsRecord { |
| public: |
| using ConstRef = std::reference_wrapper<const MdnsRecord>; |
| |
| static ErrorOr<MdnsRecord> TryCreate(DomainName name, |
| DnsType dns_type, |
| DnsClass dns_class, |
| RecordType record_type, |
| std::chrono::seconds ttl, |
| Rdata rdata); |
| |
| MdnsRecord(); |
| MdnsRecord(DomainName name, |
| DnsType dns_type, |
| DnsClass dns_class, |
| RecordType record_type, |
| std::chrono::seconds ttl, |
| Rdata rdata); |
| MdnsRecord(const MdnsRecord& other); |
| MdnsRecord(MdnsRecord&& other) noexcept; |
| |
| MdnsRecord& operator=(const MdnsRecord& rhs); |
| MdnsRecord& operator=(MdnsRecord&& rhs); |
| bool operator==(const MdnsRecord& other) const; |
| bool operator!=(const MdnsRecord& other) const; |
| bool operator<(const MdnsRecord& other) const; |
| bool operator>(const MdnsRecord& other) const; |
| bool operator<=(const MdnsRecord& other) const; |
| bool operator>=(const MdnsRecord& other) const; |
| |
| size_t MaxWireSize() const; |
| const DomainName& name() const { return name_; } |
| DnsType dns_type() const { return dns_type_; } |
| DnsClass dns_class() const { return dns_class_; } |
| RecordType record_type() const { return record_type_; } |
| std::chrono::seconds ttl() const { return ttl_; } |
| const Rdata& rdata() const { return rdata_; } |
| |
| template <typename H> |
| friend H AbslHashValue(H h, const MdnsRecord& record) { |
| return H::combine(std::move(h), record.name_, record.dns_type_, |
| record.dns_class_, record.record_type_, |
| record.ttl_.count(), record.rdata_); |
| } |
| |
| std::string ToString() const; |
| |
| private: |
| static bool IsValidConfig(const DomainName& name, |
| DnsType dns_type, |
| std::chrono::seconds ttl, |
| const Rdata& rdata); |
| |
| DomainName name_; |
| DnsType dns_type_ = static_cast<DnsType>(0); |
| DnsClass dns_class_ = static_cast<DnsClass>(0); |
| RecordType record_type_ = RecordType::kShared; |
| std::chrono::seconds ttl_{kDefaultRecordTTLSeconds}; |
| // Default-constructed Rdata contains default-constructed RawRecordRdata |
| // as it is the first alternative type and it is default-constructible. |
| Rdata rdata_; |
| }; |
| |
| // Creates an A or AAAA record as appropriate for the provided parameters. |
| MdnsRecord CreateAddressRecord(DomainName name, const IPAddress& address); |
| |
| // Question top level format (http://www.ietf.org/rfc/rfc1035.txt): |
| // name: a domain name which identifies the target resource set. |
| // type: 2 bytes network-order RR TYPE code. |
| // class: 2 bytes network-order RR CLASS code. |
| class MdnsQuestion { |
| public: |
| static ErrorOr<MdnsQuestion> TryCreate(DomainName name, |
| DnsType dns_type, |
| DnsClass dns_class, |
| ResponseType response_type); |
| |
| MdnsQuestion() = default; |
| MdnsQuestion(DomainName name, |
| DnsType dns_type, |
| DnsClass dns_class, |
| ResponseType response_type); |
| |
| bool operator==(const MdnsQuestion& other) const; |
| bool operator!=(const MdnsQuestion& other) const; |
| |
| size_t MaxWireSize() const; |
| const DomainName& name() const { return name_; } |
| DnsType dns_type() const { return dns_type_; } |
| DnsClass dns_class() const { return dns_class_; } |
| ResponseType response_type() const { return response_type_; } |
| |
| template <typename H> |
| friend H AbslHashValue(H h, const MdnsQuestion& record) { |
| return H::combine(std::move(h), record.name_, record.dns_type_, |
| record.dns_class_, record.response_type_); |
| } |
| |
| private: |
| void CopyFrom(const MdnsQuestion& other); |
| |
| DomainName name_; |
| DnsType dns_type_ = static_cast<DnsType>(0); |
| DnsClass dns_class_ = static_cast<DnsClass>(0); |
| ResponseType response_type_ = ResponseType::kMulticast; |
| }; |
| |
| // Message top level format (http://www.ietf.org/rfc/rfc1035.txt): |
| // id: 2 bytes network-order identifier assigned by the program that generates |
| // any kind of query. This identifier is copied to the corresponding reply and |
| // can be used by the requester to match up replies to outstanding queries. |
| // flags: 2 bytes network-order flags bitfield. |
| // questions: questions in the message. |
| // answers: resource records that answer the questions. |
| // authority_records: resource records that point toward authoritative name. |
| // servers additional_records: additional resource records that relate to the |
| // query. |
| class MdnsMessage { |
| public: |
| static ErrorOr<MdnsMessage> TryCreate( |
| uint16_t id, |
| MessageType type, |
| std::vector<MdnsQuestion> questions, |
| std::vector<MdnsRecord> answers, |
| std::vector<MdnsRecord> authority_records, |
| std::vector<MdnsRecord> additional_records); |
| |
| MdnsMessage() = default; |
| // Constructs a message with ID, flags and empty question, answer, authority |
| // and additional record collections. |
| MdnsMessage(uint16_t id, MessageType type); |
| MdnsMessage(uint16_t id, |
| MessageType type, |
| std::vector<MdnsQuestion> questions, |
| std::vector<MdnsRecord> answers, |
| std::vector<MdnsRecord> authority_records, |
| std::vector<MdnsRecord> additional_records); |
| |
| bool operator==(const MdnsMessage& other) const; |
| bool operator!=(const MdnsMessage& other) const; |
| |
| void AddQuestion(MdnsQuestion question); |
| void AddAnswer(MdnsRecord record); |
| void AddAuthorityRecord(MdnsRecord record); |
| void AddAdditionalRecord(MdnsRecord record); |
| |
| // Returns false if adding a new record would push the size of this message |
| // beyond kMaxMulticastMessageSize, and true otherwise. |
| bool CanAddRecord(const MdnsRecord& record); |
| |
| // Sets the truncated bit (TC), as specified in RFC 1035 Section 4.1.1. |
| void set_truncated() { is_truncated_ = true; } |
| |
| // Returns true if the provided message is an mDNS probe query as described in |
| // RFC 6762 section 8.1. Specifically, it examines whether any question in |
| // the 'questions' section is a query for which answers are present in the |
| // 'authority records' section of the same message. |
| bool IsProbeQuery() const; |
| |
| size_t MaxWireSize() const; |
| uint16_t id() const { return id_; } |
| MessageType type() const { return type_; } |
| bool is_truncated() const { return is_truncated_; } |
| const std::vector<MdnsQuestion>& questions() const { return questions_; } |
| const std::vector<MdnsRecord>& answers() const { return answers_; } |
| const std::vector<MdnsRecord>& authority_records() const { |
| return authority_records_; |
| } |
| const std::vector<MdnsRecord>& additional_records() const { |
| return additional_records_; |
| } |
| |
| template <typename H> |
| friend H AbslHashValue(H h, const MdnsMessage& message) { |
| return H::combine(std::move(h), message.id_, message.type_, |
| message.questions_, message.answers_, |
| message.authority_records_, message.additional_records_); |
| } |
| |
| private: |
| // The mDNS header is 12 bytes long |
| size_t max_wire_size_ = sizeof(Header); |
| uint16_t id_ = 0; |
| bool is_truncated_ = false; |
| MessageType type_ = MessageType::Query; |
| std::vector<MdnsQuestion> questions_; |
| std::vector<MdnsRecord> answers_; |
| std::vector<MdnsRecord> authority_records_; |
| std::vector<MdnsRecord> additional_records_; |
| }; |
| |
| uint16_t CreateMessageId(); |
| |
| // Determines whether a record of the given type can be published. |
| bool CanBePublished(DnsType type); |
| |
| // Determines whether a record of the given type can be queried for. |
| bool CanBeQueried(DnsType type); |
| |
| // Determines whether a record of the given type received over the network |
| // should be processed. |
| bool CanBeProcessed(DnsType type); |
| |
| } // namespace discovery |
| } // namespace openscreen |
| |
| #endif // DISCOVERY_MDNS_MDNS_RECORDS_H_ |