1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 07:47:37 +00:00

LibDNS: Implement Traits for DNSAnswer class

This enables DNSAnswer instances being used e.g. in a HashTable for
caching purposes.
This commit is contained in:
Tom 2022-04-12 23:38:39 -06:00 committed by Linus Groh
parent be4a4144f2
commit f3af82585d
4 changed files with 45 additions and 4 deletions

View file

@ -26,6 +26,34 @@ bool DNSAnswer::has_expired() const
return time(nullptr) >= m_received_time + m_ttl;
}
unsigned DNSAnswer::hash() const
{
auto hash = pair_int_hash(CaseInsensitiveStringTraits::hash(name().as_string()), (u32)type());
hash = pair_int_hash(hash, pair_int_hash((u32)class_code(), ttl()));
hash = pair_int_hash(hash, record_data().hash());
hash = pair_int_hash(hash, (u32)mdns_cache_flush());
return hash;
}
bool DNSAnswer::operator==(DNSAnswer const& other) const
{
if (&other == this)
return true;
if (!DNSName::Traits::equals(name(), other.name()))
return false;
if (type() != other.type())
return false;
if (class_code() != other.class_code())
return false;
if (ttl() != other.ttl())
return false;
if (record_data() != other.record_data())
return false;
if (mdns_cache_flush() != other.mdns_cache_flush())
return false;
return true;
}
}
ErrorOr<void> AK::Formatter<DNS::DNSRecordType>::format(AK::FormatBuilder& builder, DNS::DNSRecordType value)

View file

@ -9,6 +9,7 @@
#include "DNSName.h"
#include <AK/Format.h>
#include <AK/String.h>
#include <AK/Traits.h>
#include <AK/Types.h>
namespace DNS {
@ -33,6 +34,7 @@ enum class DNSRecordClass : u16 {
class DNSAnswer {
public:
DNSAnswer() = default;
DNSAnswer(DNSName const& name, DNSRecordType type, DNSRecordClass class_code, u32 ttl, String const& record_data, bool mdns_cache_flush);
DNSName const& name() const { return m_name; }
@ -46,6 +48,9 @@ public:
bool has_expired() const;
unsigned hash() const;
bool operator==(DNSAnswer const&) const;
private:
DNSName m_name;
DNSRecordType m_type { 0 };
@ -57,6 +62,13 @@ private:
};
}
template<>
struct AK::Traits<DNS::DNSAnswer> : public GenericTraits<DNS::DNSAnswer> {
static constexpr bool is_trivial() { return false; }
static unsigned hash(DNS::DNSAnswer a) { return a.hash(); }
};
template<>
struct AK::Formatter<DNS::DNSRecordType> : StandardFormatter {
Formatter() = default;

View file

@ -23,12 +23,12 @@ DNSName::DNSName(String const& name)
DNSName DNSName::parse(u8 const* data, size_t& offset, size_t max_offset, size_t recursion_level)
{
if (recursion_level > 4)
return DNSName({});
return {};
StringBuilder builder;
while (true) {
if (offset >= max_offset)
return DNSName({});
return {};
u8 b = data[offset++];
if (b == '\0') {
// This terminates the name.
@ -36,7 +36,7 @@ DNSName DNSName::parse(u8 const* data, size_t& offset, size_t max_offset, size_t
} else if ((b & 0xc0) == 0xc0) {
// The two bytes tell us the offset when to continue from.
if (offset >= max_offset)
return DNSName({});
return {};
size_t dummy = (b & 0x3f) << 8 | data[offset++];
auto rest_of_name = parse(data, dummy, max_offset, recursion_level + 1);
builder.append(rest_of_name.as_string());
@ -44,7 +44,7 @@ DNSName DNSName::parse(u8 const* data, size_t& offset, size_t max_offset, size_t
} else {
// This is the length of a part.
if (offset + b >= max_offset)
return DNSName({});
return {};
builder.append((char const*)&data[offset], (size_t)b);
builder.append('.');
offset += b;

View file

@ -14,6 +14,7 @@ namespace DNS {
class DNSName {
public:
DNSName() = default;
DNSName(String const&);
static DNSName parse(u8 const* data, size_t& offset, size_t max_offset, size_t recursion_level = 0);