diff --git a/zeroconf/__init__.py b/zeroconf/__init__.py index f0fce54a8..347bbdd3c 100644 --- a/zeroconf/__init__.py +++ b/zeroconf/__init__.py @@ -75,7 +75,6 @@ IPVersion, get_all_addresses, ) -from ._utils.struct import int2byte # noqa # import needed for backwards compat from ._utils.time import current_time_millis, millis_to_seconds # noqa # import needed for backwards compat __author__ = 'Paul Scott-Murphy, William McBrine' diff --git a/zeroconf/_protocol.py b/zeroconf/_protocol.py index b87e67d87..15c7533f0 100644 --- a/zeroconf/_protocol.py +++ b/zeroconf/_protocol.py @@ -28,7 +28,6 @@ from ._dns import DNSAddress, DNSHinfo, DNSNsec, DNSPointer, DNSQuestion, DNSRecord, DNSService, DNSText from ._exceptions import IncomingDecodeError, NamePartTooLongException from ._logger import QuietLogger, log -from ._utils.struct import int2byte from ._utils.time import current_time_millis from .const import ( _CLASS_UNIQUE, @@ -64,6 +63,8 @@ class DNSMessage: """A base class for DNS messages.""" + __slots__ = ('flags',) + def __init__(self, flags: int) -> None: """Construct a DNS message.""" self.flags = flags @@ -128,11 +129,9 @@ def __repr__(self) -> str: ] ) - def unpack(self, format_: bytes) -> tuple: - length = struct.calcsize(format_) - info = struct.unpack(format_, self.data[self.offset : self.offset + length]) + def unpack(self, format_: bytes, length: int) -> tuple: self.offset += length - return info + return struct.unpack(format_, self.data[self.offset - length : self.offset]) def read_header(self) -> None: """Reads header portion of packet""" @@ -143,16 +142,14 @@ def read_header(self) -> None: self.num_answers, self.num_authorities, self.num_additionals, - ) = self.unpack(b'!6H') + ) = self.unpack(b'!6H', 12) def read_questions(self) -> None: """Reads questions section of packet""" for _ in range(self.num_questions): name = self.read_name() - type_, class_ = self.unpack(b'!HH') - - question = DNSQuestion(name, type_, class_) - self.questions.append(question) + type_, class_ = self.unpack(b'!HH', 4) + self.questions.append(DNSQuestion(name, type_, class_)) def read_character_string(self) -> bytes: """Reads a character string from the packet""" @@ -168,7 +165,7 @@ def read_string(self, length: int) -> bytes: def read_unsigned_short(self) -> int: """Reads an unsigned short from the packet""" - return cast(int, self.unpack(b'!H')[0]) + return cast(int, self.unpack(b'!H', 2)[0]) def read_others(self) -> None: """Reads the answers, authorities and additionals section of the @@ -176,7 +173,7 @@ def read_others(self) -> None: n = self.num_answers + self.num_authorities + self.num_additionals for _ in range(n): domain = self.read_name() - type_, class_, ttl, length = self.unpack(b'!HHiH') + type_, class_, ttl, length = self.unpack(b'!HHiH', 10) end = self.offset + length rec = None try: @@ -266,8 +263,7 @@ def read_name(self) -> str: labels: List[str] = [] self.seen_pointers.clear() self.offset = self._decode_labels_at_offset(self.offset, labels) - labels.append("") - name = ".".join(labels) + name = ".".join(labels) + "." if len(name) > MAX_NAME_LENGTH: raise IncomingDecodeError(f"DNS name {name} exceeds maximum length of {MAX_NAME_LENGTH}") return name @@ -440,7 +436,7 @@ def _pack(self, format_: Union[bytes, str], value: Any) -> None: def _write_byte(self, value: int) -> None: """Writes a single byte to the packet""" - self._pack(b'!c', int2byte(value)) + self._pack(b'!c', bytes((value,))) def _insert_short_at_start(self, value: int) -> None: """Inserts an unsigned short at the start of the packet""" diff --git a/zeroconf/_services/browser.py b/zeroconf/_services/browser.py index aadbd7ac6..d47e42e92 100644 --- a/zeroconf/_services/browser.py +++ b/zeroconf/_services/browser.py @@ -352,21 +352,19 @@ def _async_process_record_update( self, now: float, record: DNSRecord, old_record: Optional[DNSRecord] ) -> None: """Process a single record update from a batch of updates.""" - expired = record.is_expired(now) - if isinstance(record, DNSPointer): if record.name not in self.types: return if old_record is None: self._enqueue_callback(ServiceStateChange.Added, record.name, record.alias) - elif expired: + elif record.is_expired(now): self._enqueue_callback(ServiceStateChange.Removed, record.name, record.alias) else: self.reschedule_type(record.name, record.get_expiration_time(_EXPIRE_REFRESH_TIME_PERCENT)) return # If its expired or already exists in the cache it cannot be updated. - if expired or old_record: + if old_record or record.is_expired(now): return if isinstance(record, DNSAddress): diff --git a/zeroconf/_services/info.py b/zeroconf/_services/info.py index 33c0488ac..7aaea1b6a 100644 --- a/zeroconf/_services/info.py +++ b/zeroconf/_services/info.py @@ -36,7 +36,6 @@ _encode_address, _is_v6_address, ) -from .._utils.struct import int2byte from .._utils.time import current_time_millis from ..const import ( _CLASS_IN, @@ -239,7 +238,7 @@ def _set_properties(self, properties: Dict) -> None: record += b'=' + value list_.append(record) for item in list_: - result = b''.join((result, int2byte(len(item)), item)) + result = b''.join((result, bytes((len(item),)), item)) self.text = result def _set_text(self, text: bytes) -> None: diff --git a/zeroconf/_utils/struct.py b/zeroconf/_utils/struct.py deleted file mode 100644 index 6ec999882..000000000 --- a/zeroconf/_utils/struct.py +++ /dev/null @@ -1,25 +0,0 @@ -""" Multicast DNS Service Discovery for Python, v0.14-wmcbrine - Copyright 2003 Paul Scott-Murphy, 2014 William McBrine - - This module provides a framework for the use of DNS Service Discovery - using IP multicast. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 - USA -""" - -import struct - -int2byte = struct.Struct(">B").pack