From 4604ce35f9e07ebca43a38529754632acb02aecb Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 15 Sep 2021 16:29:43 -1000 Subject: [PATCH 1/9] Reduce name compression overhead --- zeroconf/_protocol.py | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/zeroconf/_protocol.py b/zeroconf/_protocol.py index 15c7533f0..0132f36ce 100644 --- a/zeroconf/_protocol.py +++ b/zeroconf/_protocol.py @@ -491,33 +491,26 @@ def write_name(self, name: str) -> None: """ # split name into each label - parts = name.split('.') - if not parts[-1]: - parts.pop() + name_length = None + labels = name.split('.') + if not labels[-1]: + labels.pop() # construct each suffix - name_suffices = ['.'.join(parts[i:]) for i in range(len(parts))] - - # look for an existing name or suffix - for count, sub_name in enumerate(name_suffices): - if sub_name in self.names: + start_size = self.size + index = None + for count in range(len(labels)): + label = '.'.join(labels[count:]) + if label in self.names: + index = self.names[label] break - else: - count = len(name_suffices) - - # note the new names we are saving into the packet - name_length = len(name.encode('utf-8')) - for suffix in name_suffices[:count]: - self.names[suffix] = self.size + name_length - len(suffix.encode('utf-8')) - 1 - - # write the new names out. - for part in parts[:count]: - self._write_utf(part) + if name_length is None: + name_length = len(name.encode('utf-8')) + self.names[label] = start_size + name_length - len(label.encode('utf-8')) - 1 + self._write_utf(labels[count]) - # if we wrote part of the name, create a pointer to the rest - if count != len(name_suffices): - # Found substring in packet, create pointer - index = self.names[name_suffices[count]] + if index: + # If we wrote part of the name, create a pointer to the rest self._write_byte((index >> 8) | 0xC0) self._write_byte(index & 0xFF) else: From 0d932ae2718d9f4befb8637d1274826aca1cc03c Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 15 Sep 2021 16:31:02 -1000 Subject: [PATCH 2/9] Reduce name compression overhead --- zeroconf/_protocol.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/zeroconf/_protocol.py b/zeroconf/_protocol.py index 0132f36ce..fec99a5d4 100644 --- a/zeroconf/_protocol.py +++ b/zeroconf/_protocol.py @@ -502,20 +502,18 @@ def write_name(self, name: str) -> None: for count in range(len(labels)): label = '.'.join(labels[count:]) if label in self.names: + # If we wrote part of the name, create a pointer to the rest index = self.names[label] - break + self._write_byte((index >> 8) | 0xC0) + self._write_byte(index & 0xFF) + return if name_length is None: name_length = len(name.encode('utf-8')) self.names[label] = start_size + name_length - len(label.encode('utf-8')) - 1 self._write_utf(labels[count]) - if index: - # If we wrote part of the name, create a pointer to the rest - self._write_byte((index >> 8) | 0xC0) - self._write_byte(index & 0xFF) - else: - # this is the end of a name - self._write_byte(0) + # this is the end of a name + self._write_byte(0) def _write_question(self, question: DNSQuestion) -> bool: """Writes a question to the packet""" From d4b2c25f850ade2b85adb69d4ce840c90abe782e Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 15 Sep 2021 16:31:58 -1000 Subject: [PATCH 3/9] Reduce name compression overhead --- zeroconf/_protocol.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zeroconf/_protocol.py b/zeroconf/_protocol.py index fec99a5d4..d99ff0857 100644 --- a/zeroconf/_protocol.py +++ b/zeroconf/_protocol.py @@ -502,7 +502,8 @@ def write_name(self, name: str) -> None: for count in range(len(labels)): label = '.'.join(labels[count:]) if label in self.names: - # If we wrote part of the name, create a pointer to the rest + # If part of the name already exists in the packet, + # create a pointer to it index = self.names[label] self._write_byte((index >> 8) | 0xC0) self._write_byte(index & 0xFF) From 8ee238d7c2fd40a83b3b0d9fd842c32145a8acb9 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 15 Sep 2021 16:32:31 -1000 Subject: [PATCH 4/9] Reduce name compression overhead --- zeroconf/_protocol.py | 1 - 1 file changed, 1 deletion(-) diff --git a/zeroconf/_protocol.py b/zeroconf/_protocol.py index d99ff0857..ad09bd9bd 100644 --- a/zeroconf/_protocol.py +++ b/zeroconf/_protocol.py @@ -498,7 +498,6 @@ def write_name(self, name: str) -> None: # construct each suffix start_size = self.size - index = None for count in range(len(labels)): label = '.'.join(labels[count:]) if label in self.names: From 3e51f63c5b9e04c1bbf49fee4418d889b6f63424 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 15 Sep 2021 16:34:40 -1000 Subject: [PATCH 5/9] Reduce name compression overhead --- zeroconf/_protocol.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zeroconf/_protocol.py b/zeroconf/_protocol.py index ad09bd9bd..0766a42a9 100644 --- a/zeroconf/_protocol.py +++ b/zeroconf/_protocol.py @@ -496,7 +496,8 @@ def write_name(self, name: str) -> None: if not labels[-1]: labels.pop() - # construct each suffix + # Write each new label or a pointer to the existing + # on in the packet start_size = self.size for count in range(len(labels)): label = '.'.join(labels[count:]) From 0a0c55b2aee3b36893d50f01b14f5ed97cfeb994 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 15 Sep 2021 16:35:38 -1000 Subject: [PATCH 6/9] Reduce name compression overhead --- zeroconf/_protocol.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zeroconf/_protocol.py b/zeroconf/_protocol.py index 0766a42a9..8cafd9f2c 100644 --- a/zeroconf/_protocol.py +++ b/zeroconf/_protocol.py @@ -501,10 +501,10 @@ def write_name(self, name: str) -> None: start_size = self.size for count in range(len(labels)): label = '.'.join(labels[count:]) - if label in self.names: + index = self.names.get(label) + if index: # If part of the name already exists in the packet, # create a pointer to it - index = self.names[label] self._write_byte((index >> 8) | 0xC0) self._write_byte(index & 0xFF) return From fcb733883aafd523f1a6982123924adb28d521b5 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 15 Sep 2021 16:43:10 -1000 Subject: [PATCH 7/9] Reduce name compression overhead --- zeroconf/_protocol.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/zeroconf/_protocol.py b/zeroconf/_protocol.py index 8cafd9f2c..703f36cbc 100644 --- a/zeroconf/_protocol.py +++ b/zeroconf/_protocol.py @@ -430,13 +430,13 @@ def add_question_or_all_cache( for cached_entry in cached_entries: self.add_answer_at_time(cached_entry, now) - def _pack(self, format_: Union[bytes, str], value: Any) -> None: + def _pack(self, format_: Union[bytes, str], size: int, value: Any) -> None: self.data.append(struct.pack(format_, value)) - self.size += struct.calcsize(format_) + self.size += size def _write_byte(self, value: int) -> None: """Writes a single byte to the packet""" - self._pack(b'!c', bytes((value,))) + self._pack(b'!c', 1, bytes((value,))) def _insert_short_at_start(self, value: int) -> None: """Inserts an unsigned short at the start of the packet""" @@ -448,11 +448,11 @@ def _replace_short(self, index: int, value: int) -> None: def write_short(self, value: int) -> None: """Writes an unsigned short to the packet""" - self._pack(b'!H', value) + self._pack(b'!H', 2, value) def _write_int(self, value: Union[float, int]) -> None: """Writes an unsigned integer to the packet""" - self._pack(b'!I', int(value)) + self._pack(b'!I', 4, int(value)) def write_string(self, value: bytes) -> None: """Writes a string to the packet""" From db8610a6822bf7946f953381b8b85ebb8a8aab40 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 15 Sep 2021 16:49:55 -1000 Subject: [PATCH 8/9] Handle names that do not have a trailing . --- zeroconf/_protocol.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/zeroconf/_protocol.py b/zeroconf/_protocol.py index 703f36cbc..343910dd5 100644 --- a/zeroconf/_protocol.py +++ b/zeroconf/_protocol.py @@ -492,10 +492,9 @@ def write_name(self, name: str) -> None: # split name into each label name_length = None + if name.endswith('.'): + name = name[: len(name) - 1] labels = name.split('.') - if not labels[-1]: - labels.pop() - # Write each new label or a pointer to the existing # on in the packet start_size = self.size @@ -510,7 +509,7 @@ def write_name(self, name: str) -> None: return if name_length is None: name_length = len(name.encode('utf-8')) - self.names[label] = start_size + name_length - len(label.encode('utf-8')) - 1 + self.names[label] = start_size + name_length - len(label.encode('utf-8')) self._write_utf(labels[count]) # this is the end of a name From 0b6928ad8c9376e447ec17c78b89e25a50f0de6e Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 15 Sep 2021 16:50:22 -1000 Subject: [PATCH 9/9] tweak --- zeroconf/_protocol.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zeroconf/_protocol.py b/zeroconf/_protocol.py index 343910dd5..713d5d918 100644 --- a/zeroconf/_protocol.py +++ b/zeroconf/_protocol.py @@ -499,7 +499,7 @@ def write_name(self, name: str) -> None: # on in the packet start_size = self.size for count in range(len(labels)): - label = '.'.join(labels[count:]) + label = name if count == 0 else '.'.join(labels[count:]) index = self.names.get(label) if index: # If part of the name already exists in the packet,