@@ -311,42 +311,33 @@ def async_updates_from_response(self, msg: DNSIncoming) -> None:
311311 other_adds : List [DNSRecord ] = []
312312 removes : List [DNSRecord ] = []
313313 now = msg .now
314- for record in msg .answers :
315-
316- updated = True
314+ unique_types : Set [Tuple [str , int , int ]] = set ()
317315
316+ for record in msg .answers :
318317 if record .unique : # https://tools.ietf.org/html/rfc6762#section-10.2
319- # rfc6762#section-10.2 para 2
320- # Since unique is set, all old records with that name, rrtype,
321- # and rrclass that were received more than one second ago are declared
322- # invalid, and marked to expire from the cache in one second.
323- for entry in self .cache .get_all_by_details (record .name , record .type , record .class_ ):
324- if entry == record :
325- updated = False
326- if record .created - entry .created > 1000 and entry not in msg .answers :
327- # Expire in 1s
328- entry .set_created_ttl (now , 1 )
329-
330- expired = record .is_expired (now )
318+ unique_types .add ((record .name , record .type , record .class_ ))
319+
331320 maybe_entry = self .cache .get (record )
332- if not expired :
321+ if not record . is_expired ( now ) :
333322 if maybe_entry is not None :
334323 maybe_entry .reset_ttl (record )
335324 else :
336325 if isinstance (record , DNSAddress ):
337326 address_adds .append (record )
338327 else :
339328 other_adds .append (record )
340- if updated :
341- updates .append (record )
329+ updates .append (record )
330+ # This is likely a goodbye since the record is
331+ # expired and exists in the cache
342332 elif maybe_entry is not None :
343333 updates .append (record )
344334 removes .append (record )
345335
346- if not updates and not address_adds and not other_adds and not removes :
347- return
336+ if unique_types :
337+ self . _async_mark_unique_cached_records_older_than_1s_to_expire ( unique_types , msg . answers , now )
348338
349- self .async_updates (now , updates )
339+ if updates :
340+ self .async_updates (now , updates )
350341 # The cache adds must be processed AFTER we trigger
351342 # the updates since we compare existing data
352343 # with the new data and updating the cache
@@ -362,12 +353,29 @@ def async_updates_from_response(self, msg: DNSIncoming) -> None:
362353 # zc.get_service_info will see the cached value
363354 # but ONLY after all the record updates have been
364355 # processsed.
365- self .cache .async_add_records (itertools .chain (address_adds , other_adds ))
356+ if other_adds or address_adds :
357+ self .cache .async_add_records (itertools .chain (address_adds , other_adds ))
366358 # Removes are processed last since
367359 # ServiceInfo could generate an un-needed query
368360 # because the data was not yet populated.
369- self .cache .async_remove_records (removes )
370- self .async_updates_complete ()
361+ if removes :
362+ self .cache .async_remove_records (removes )
363+ if updates :
364+ self .async_updates_complete ()
365+
366+ def _async_mark_unique_cached_records_older_than_1s_to_expire (
367+ self , unique_types : Set [Tuple [str , int , int ]], answers : List [DNSRecord ], now : float
368+ ) -> None :
369+ # rfc6762#section-10.2 para 2
370+ # Since unique is set, all old records with that name, rrtype,
371+ # and rrclass that were received more than one second ago are declared
372+ # invalid, and marked to expire from the cache in one second.
373+ answers_rrset = DNSRRSet (answers )
374+ for name , type_ , class_ in unique_types :
375+ for entry in self .cache .get_all_by_details (name , type_ , class_ ):
376+ if (now - entry .created > 1000 ) and entry not in answers_rrset :
377+ # Expire in 1s
378+ entry .set_created_ttl (now , 1 )
371379
372380 def add_listener (
373381 self , listener : RecordUpdateListener , question : Optional [Union [DNSQuestion , List [DNSQuestion ]]]
0 commit comments