Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 35 additions & 35 deletions src/zeroconf/_dns.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,21 +79,17 @@ def __eq__(self, other: Any) -> bool:
"""Equal when key, type and class match."""
return isinstance(other, DNSEntry) and self._dns_entry_matches(other)

@property
def type_label(self) -> str:
"""Human readable label for the record type."""
return _type_label(self.type)

@property
def class_label(self) -> str:
"""Human readable label for the record class."""
return _class_label(self.class_)

def _display_fields(self) -> list[tuple[str, str]]:
fields = [("name", self.name), ("type", self.type_label), ("class", self.class_label)]
if self.unique:
fields.append(("", "unique"))
return fields
def entry_to_string(self, hdr: str, other: bytes | str | None) -> str:
"""Compatibility alias rendering through the display formatter."""
fields = self._display_fields()
if other is not None:
fields.append(("data", str(other)))
return _format_display(hdr, fields)

@staticmethod
def get_class_(class_: int) -> str:
Expand All @@ -105,12 +101,16 @@ def get_type(t: int) -> str:
"""Compatibility alias for the type_label property."""
return _type_label(t)

def entry_to_string(self, hdr: str, other: bytes | str | None) -> str:
"""Compatibility alias rendering through the display formatter."""
fields = self._display_fields()
if other is not None:
fields.append(("data", str(other)))
return _format_display(hdr, fields)
@property
def type_label(self) -> str:
"""Human readable label for the record type."""
return _type_label(self.type)

def _display_fields(self) -> list[tuple[str, str]]:
fields = [("name", self.name), ("type", self.type_label), ("class", self.class_label)]
if self.unique:
fields.append(("", "unique"))
return fields

def _dns_entry_matches(self, other: DNSEntry) -> bool:
return self.key == other.key and self.type == other.type and self.class_ == other.class_
Expand Down Expand Up @@ -222,35 +222,35 @@ def suppressed_by(self, msg: DNSIncoming) -> bool:
return True
return False

def to_string(self, other: bytes | str) -> str:
"""Compatibility alias rendering through the display formatter."""
return self._repr_with(("data", str(other)))

def write(self, out: DNSOutgoing) -> None:
raise AbstractMethodException(f"{type(self).__name__} is missing write")

def _display_fields(self) -> list[tuple[str, str]]:
remaining = int(self.get_remaining_ttl(current_time_millis()))
return [*DNSEntry._display_fields(self), ("ttl", f"{self.ttl} ({remaining} remaining)")]

def _fast_init_record(self, name: str, type_: _int, class_: _int, ttl: _int, created: _float) -> None:
"""Fast init for reuse."""
self._fast_init_entry(name, type_, class_)
self.ttl = ttl
self.created = created

def _repr_with(self, *details: tuple[str, str]) -> str:
return _format_display(type(self).__name__, [*self._display_fields(), *details])

def _set_created_ttl(self, created: _float, ttl: _int) -> None:
"""Set the created and ttl of a record."""
# It would be better if we made a copy instead of mutating the record
# in place, but records currently don't have a copy method.
self.created = created
self.ttl = ttl

def _display_fields(self) -> list[tuple[str, str]]:
remaining = int(self.get_remaining_ttl(current_time_millis()))
return [*DNSEntry._display_fields(self), ("ttl", f"{self.ttl} ({remaining} remaining)")]

def _repr_with(self, *details: tuple[str, str]) -> str:
return _format_display(type(self).__name__, [*self._display_fields(), *details])

def to_string(self, other: bytes | str) -> str:
"""Compatibility alias rendering through the display formatter."""
return self._repr_with(("data", str(other)))

def _suppressed_by_answer(self, answer: DNSRecord) -> bool:
"""True when the answer matches this record with at least half its TTL left."""
"""RFC 6762 section 7.1 known answer test: an equal record whose TTL is at least half of ours."""
return self == answer and self.ttl / 2 < answer.ttl


Expand Down Expand Up @@ -618,17 +618,17 @@ def lookup_set(self) -> set[DNSRecord]:
"""Return the lookup table as aset."""
return set(self._get_lookup())

def _get_lookup(self) -> dict[DNSRecord, DNSRecord]:
"""Return the lookup table, building it if needed."""
if self._lookup is None:
# Build the hash table so we can lookup the record ttl
self._lookup = {record: record for record in self._records}
return self._lookup

def suppresses(self, record: _DNSRecord) -> bool:
"""True when the set holds a match with over half the record's TTL left."""
lookup = self._get_lookup()
other = lookup.get(record)
if other is None:
return False
return other.ttl > (record.ttl / 2)

def _get_lookup(self) -> dict[DNSRecord, DNSRecord]:
"""Return the lookup table, building it if needed."""
if self._lookup is None:
# Build the hash table so we can lookup the record ttl
self._lookup = {record: record for record in self._records}
return self._lookup
2 changes: 1 addition & 1 deletion src/zeroconf/_protocol/incoming.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ def _read_name(self) -> str:
return name

def _read_others(self) -> None:
"""Read the answer, authority and additional sections."""
"""Parse everything after the question section in one pass."""
self._did_read_others = True
buf = self._buf
answers = self._answers
Expand Down
8 changes: 4 additions & 4 deletions src/zeroconf/_protocol/outgoing.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ def write_name(self, name: str_) -> None:
self._write_byte(0)

def write_short(self, value: int_) -> None:
"""Append an unsigned short."""
"""Append a 16 bit value in network order."""
self.data.append(self._get_short(value))
self.size += 2

Expand Down Expand Up @@ -361,7 +361,7 @@ def _check_data_limit_or_rollback(self, start_data_length: int_, start_size: int
return False

def _get_short(self, value: int_) -> bytes:
"""Convert an unsigned short to 2 bytes."""
"""Encode a 16 bit value as two network order bytes."""
return SHORT_LOOKUP[value] if value < SHORT_CACHE_MAX else PACK_SHORT(value)

def _has_more_to_add(
Expand All @@ -380,11 +380,11 @@ def _has_more_to_add(
)

def _insert_short_at_start(self, value: int_) -> None:
"""Prepend an unsigned short as the first chunk."""
"""Prepend a 16 bit value as the first chunk."""
self.data.insert(0, self._get_short(value))

def _replace_short(self, index: int_, value: int_) -> None:
"""Overwrite the chunk at index with an unsigned short."""
"""Overwrite the chunk at index with a 16 bit value."""
self.data[index] = self._get_short(value)

def _reset_for_next_packet(self) -> None:
Expand Down
16 changes: 8 additions & 8 deletions src/zeroconf/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
import re
import socket

_UNREGISTER_TIME = 125 # ms
_BROWSER_TIME = 10000 # ms
_CHECK_TIME = 500 # ms
_REGISTER_TIME = 225 # ms
_LISTENER_TIME = 200 # ms
_BROWSER_TIME = 10000 # ms
_REGISTER_TIME = 225 # ms
_UNREGISTER_TIME = 125 # ms
_DUPLICATE_PACKET_SUPPRESSION_INTERVAL = 1000 # ms
# Per-listener bounded recency window. 16 is large enough to defeat
# the alternating-payload bypass (RFC 6762 §6.2, issue #1724 — even a
Expand Down Expand Up @@ -94,16 +94,16 @@
_MAX_MSG_TYPICAL = 1460

# DNS header flag bits, RFC 1035 section 4.1.1 and RFC 6762 section 18
_FLAGS_AA = 0x0400
_FLAGS_AD = 0x0020
_FLAGS_CD = 0x0010
_FLAGS_QR_MASK = 0x8000
_FLAGS_QR_QUERY = 0x0000
_FLAGS_QR_RESPONSE = 0x8000
_FLAGS_AA = 0x0400
_FLAGS_TC = 0x0200
_FLAGS_RD = 0x0100
_FLAGS_RA = 0x8000
_FLAGS_RD = 0x0100
_FLAGS_TC = 0x0200
_FLAGS_Z = 0x0040
_FLAGS_AD = 0x0020
_FLAGS_CD = 0x0010


_CLASS_IN = 1
Expand Down
Loading