Skip to content

Commit 605dc9c

Browse files
authored
feat: avoid decoding known answers if we have no answers to give (#1308)
1 parent ce98cb8 commit 605dc9c

7 files changed

Lines changed: 270 additions & 74 deletions

File tree

src/zeroconf/_core.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -577,15 +577,17 @@ def handle_assembled_query(
577577
) -> None:
578578
"""Respond to a (re)assembled query.
579579
580-
If the protocol recieved packets with the TC bit set, it will
580+
If the protocol received packets with the TC bit set, it will
581581
wait a bit for the rest of the packets and only call
582582
handle_assembled_query once it has a complete set of packets
583583
or the timer expires. If the TC bit is not set, a single
584584
packet will be in packets.
585585
"""
586-
now = packets[0].now
587586
ucast_source = port != _MDNS_PORT
588587
question_answers = self.query_handler.async_response(packets, ucast_source)
588+
if not question_answers:
589+
return
590+
now = packets[0].now
589591
if question_answers.ucast:
590592
questions = packets[0].questions
591593
id_ = packets[0].id

src/zeroconf/_handlers/answers.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@ def __init__(
5959
self.mcast_aggregate = mcast_aggregate
6060
self.mcast_aggregate_last_second = mcast_aggregate_last_second
6161

62+
def __repr__(self) -> str:
63+
"""Return a string representation of this QuestionAnswers."""
64+
return (
65+
f'QuestionAnswers(ucast={self.ucast}, mcast_now={self.mcast_now}, '
66+
f'mcast_aggregate={self.mcast_aggregate}, '
67+
f'mcast_aggregate_last_second={self.mcast_aggregate_last_second})'
68+
)
69+
6270

6371
class AnswerGroup:
6472
"""A group of answers scheduled to be sent at the same time."""

src/zeroconf/_handlers/multicast_outgoing_queue.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def async_add(self, now: _float, answers: _AnswerWithAdditionalsType) -> None:
7777
# If we calculate a random delay for the send after time
7878
# that is less than the last group scheduled to go out,
7979
# we instead add the answers to the last group as this
80-
# allows aggregating additonal responses
80+
# allows aggregating additional responses
8181
last_group = self.queue[-1]
8282
if send_after <= last_group.send_after:
8383
last_group.answers.update(answers)
@@ -116,7 +116,7 @@ def async_ready(self) -> None:
116116
# be sure we schedule them to go out later
117117
loop.call_at(loop.time() + millis_to_seconds(self.queue[0].send_after - now), self.async_ready)
118118

119-
if answers:
119+
if answers: # pragma: no branch
120120
# If we have the same answer scheduled to go out, remove them
121121
self._remove_answers_from_queue(answers)
122122
zc.async_send(construct_outgoing_multicast_answers(answers))

src/zeroconf/_handlers/query_handler.pxd

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,23 @@ cdef cython.set _ADDRESS_RECORD_TYPES
1818
cdef object IPVersion, _IPVersion_ALL
1919
cdef object _TYPE_PTR, _CLASS_IN, _DNS_OTHER_TTL
2020

21+
cdef unsigned int _ANSWER_STRATEGY_SERVICE_TYPE_ENUMERATION
22+
cdef unsigned int _ANSWER_STRATEGY_POINTER
23+
cdef unsigned int _ANSWER_STRATEGY_ADDRESS
24+
cdef unsigned int _ANSWER_STRATEGY_SERVICE
25+
cdef unsigned int _ANSWER_STRATEGY_TEXT
26+
27+
cdef list _EMPTY_SERVICES_LIST
28+
cdef list _EMPTY_TYPES_LIST
29+
30+
cdef class _AnswerStrategy:
31+
32+
cdef public DNSQuestion question
33+
cdef public unsigned int strategy_type
34+
cdef public list types
35+
cdef public list services
36+
37+
2138
cdef class _QueryResponse:
2239

2340
cdef bint _is_probe
@@ -53,24 +70,30 @@ cdef class QueryHandler:
5370
cdef QuestionHistory question_history
5471

5572
@cython.locals(service=ServiceInfo)
56-
cdef _add_service_type_enumeration_query_answers(self, cython.dict answer_set, DNSRRSet known_answers)
73+
cdef _add_service_type_enumeration_query_answers(self, list types, cython.dict answer_set, DNSRRSet known_answers)
5774

5875
@cython.locals(service=ServiceInfo)
59-
cdef _add_pointer_answers(self, str lower_name, cython.dict answer_set, DNSRRSet known_answers)
76+
cdef _add_pointer_answers(self, list services, cython.dict answer_set, DNSRRSet known_answers)
6077

6178
@cython.locals(service=ServiceInfo, dns_address=DNSAddress)
62-
cdef _add_address_answers(self, str lower_name, cython.dict answer_set, DNSRRSet known_answers, cython.uint type_)
79+
cdef _add_address_answers(self, list services, cython.dict answer_set, DNSRRSet known_answers, cython.uint type_)
6380

6481
@cython.locals(question_lower_name=str, type_=cython.uint, service=ServiceInfo)
65-
cdef cython.dict _answer_question(self, DNSQuestion question, DNSRRSet known_answers)
82+
cdef cython.dict _answer_question(self, DNSQuestion question, unsigned int strategy_type, list types, list services, DNSRRSet known_answers)
6683

6784
@cython.locals(
6885
msg=DNSIncoming,
86+
msgs=list,
87+
strategy=_AnswerStrategy,
6988
question=DNSQuestion,
7089
answer_set=cython.dict,
7190
known_answers=DNSRRSet,
7291
known_answers_set=cython.set,
92+
is_unicast=bint,
7393
is_probe=object,
74-
now=object
94+
now=float
7595
)
7696
cpdef async_response(self, cython.list msgs, cython.bint unicast_source)
97+
98+
@cython.locals(name=str, question_lower_name=str)
99+
cdef _get_answer_strategies(self, DNSQuestion question)

0 commit comments

Comments
 (0)