Skip to content

Commit f1d6fc3

Browse files
authored
Reduce name compression overhead and complexity (#978)
1 parent 769b397 commit f1d6fc3

1 file changed

Lines changed: 28 additions & 37 deletions

File tree

zeroconf/_protocol.py

Lines changed: 28 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -430,13 +430,13 @@ def add_question_or_all_cache(
430430
for cached_entry in cached_entries:
431431
self.add_answer_at_time(cached_entry, now)
432432

433-
def _pack(self, format_: Union[bytes, str], value: Any) -> None:
433+
def _pack(self, format_: Union[bytes, str], size: int, value: Any) -> None:
434434
self.data.append(struct.pack(format_, value))
435-
self.size += struct.calcsize(format_)
435+
self.size += size
436436

437437
def _write_byte(self, value: int) -> None:
438438
"""Writes a single byte to the packet"""
439-
self._pack(b'!c', bytes((value,)))
439+
self._pack(b'!c', 1, bytes((value,)))
440440

441441
def _insert_short_at_start(self, value: int) -> None:
442442
"""Inserts an unsigned short at the start of the packet"""
@@ -448,11 +448,11 @@ def _replace_short(self, index: int, value: int) -> None:
448448

449449
def write_short(self, value: int) -> None:
450450
"""Writes an unsigned short to the packet"""
451-
self._pack(b'!H', value)
451+
self._pack(b'!H', 2, value)
452452

453453
def _write_int(self, value: Union[float, int]) -> None:
454454
"""Writes an unsigned integer to the packet"""
455-
self._pack(b'!I', int(value))
455+
self._pack(b'!I', 4, int(value))
456456

457457
def write_string(self, value: bytes) -> None:
458458
"""Writes a string to the packet"""
@@ -491,38 +491,29 @@ def write_name(self, name: str) -> None:
491491
"""
492492

493493
# split name into each label
494-
parts = name.split('.')
495-
if not parts[-1]:
496-
parts.pop()
497-
498-
# construct each suffix
499-
name_suffices = ['.'.join(parts[i:]) for i in range(len(parts))]
500-
501-
# look for an existing name or suffix
502-
for count, sub_name in enumerate(name_suffices):
503-
if sub_name in self.names:
504-
break
505-
else:
506-
count = len(name_suffices)
507-
508-
# note the new names we are saving into the packet
509-
name_length = len(name.encode('utf-8'))
510-
for suffix in name_suffices[:count]:
511-
self.names[suffix] = self.size + name_length - len(suffix.encode('utf-8')) - 1
512-
513-
# write the new names out.
514-
for part in parts[:count]:
515-
self._write_utf(part)
516-
517-
# if we wrote part of the name, create a pointer to the rest
518-
if count != len(name_suffices):
519-
# Found substring in packet, create pointer
520-
index = self.names[name_suffices[count]]
521-
self._write_byte((index >> 8) | 0xC0)
522-
self._write_byte(index & 0xFF)
523-
else:
524-
# this is the end of a name
525-
self._write_byte(0)
494+
name_length = None
495+
if name.endswith('.'):
496+
name = name[: len(name) - 1]
497+
labels = name.split('.')
498+
# Write each new label or a pointer to the existing
499+
# on in the packet
500+
start_size = self.size
501+
for count in range(len(labels)):
502+
label = name if count == 0 else '.'.join(labels[count:])
503+
index = self.names.get(label)
504+
if index:
505+
# If part of the name already exists in the packet,
506+
# create a pointer to it
507+
self._write_byte((index >> 8) | 0xC0)
508+
self._write_byte(index & 0xFF)
509+
return
510+
if name_length is None:
511+
name_length = len(name.encode('utf-8'))
512+
self.names[label] = start_size + name_length - len(label.encode('utf-8'))
513+
self._write_utf(labels[count])
514+
515+
# this is the end of a name
516+
self._write_byte(0)
526517

527518
def _write_question(self, question: DNSQuestion) -> bool:
528519
"""Writes a question to the packet"""

0 commit comments

Comments
 (0)