@@ -1795,21 +1795,20 @@ static int dns_packet_append_zone(DnsPacket *p, DnsTransaction *t, DnsResourceKe
17951795 return dns_packet_append_answer (p , answer , nscount );
17961796}
17971797
1798- static int dns_transaction_make_packet_mdns (DnsTransaction * t ) {
1798+ static int mdns_make_dummy_packet (DnsTransaction * t , DnsPacket * * ret_packet , Set * * ret_keys ) {
17991799 _cleanup_ (dns_packet_unrefp ) DnsPacket * p = NULL ;
18001800 _cleanup_set_free_ Set * keys = NULL ;
1801- unsigned qdcount , ancount = 0 /* avoid false maybe-uninitialized warning */ , nscount ;
18021801 bool add_known_answers = false;
1802+ unsigned qdcount ;
18031803 usec_t ts ;
18041804 int r ;
18051805
18061806 assert (t );
1807+ assert (t -> scope );
18071808 assert (t -> scope -> protocol == DNS_PROTOCOL_MDNS );
1809+ assert (ret_packet );
1810+ assert (ret_keys );
18081811
1809- /* Discard any previously prepared packet, so we can start over and coalesce again */
1810- t -> sent = dns_packet_unref (t -> sent );
1811-
1812- /* First, create a dummy packet to calculate packet size. */
18131812 r = dns_packet_new_query (& p , t -> scope -> protocol , 0 , false);
18141813 if (r < 0 )
18151814 return r ;
@@ -1832,120 +1831,139 @@ static int dns_transaction_make_packet_mdns(DnsTransaction *t) {
18321831 if (r < 0 )
18331832 return r ;
18341833
1835- /*
1836- * For mDNS, we want to coalesce as many open queries in pending transactions into one single
1837- * query packet on the wire as possible. To achieve that, we iterate through all pending transactions
1838- * in our current scope, and see whether their timing constraints allow them to be sent.
1839- */
1840-
18411834 assert_se (sd_event_now (t -> scope -> manager -> event , CLOCK_BOOTTIME , & ts ) >= 0 );
18421835
1843- for (bool restart = true; restart ;) {
1844- restart = false;
1845- LIST_FOREACH (transactions_by_scope , other , t -> scope -> transactions ) {
1846- size_t saved_packet_size ;
1847- bool append = false;
1836+ LIST_FOREACH (transactions_by_scope , other , t -> scope -> transactions ) {
18481837
1849- /* Skip ourselves */
1850- if (other == t )
1851- continue ;
1852-
1853- if (other -> state != DNS_TRANSACTION_PENDING )
1854- continue ;
1855-
1856- if (other -> next_attempt_after > ts )
1857- continue ;
1838+ /* Skip ourselves */
1839+ if (other == t )
1840+ continue ;
18581841
1859- if (!set_contains (keys , dns_transaction_key (other ))) {
1860- r = dns_packet_append_key (p , dns_transaction_key (other ), 0 , & saved_packet_size );
1861- /* If we can't stuff more questions into the packet, just give up.
1862- * One of the 'other' transactions will fire later and take care of the rest. */
1863- if (r == - EMSGSIZE )
1864- break ;
1865- if (r < 0 )
1866- return r ;
1842+ if (other -> state != DNS_TRANSACTION_PENDING )
1843+ continue ;
18671844
1868- r = dns_packet_append_zone (p , t , dns_transaction_key (other ), NULL );
1869- if (r == - EMSGSIZE )
1870- break ;
1871- if (r < 0 )
1872- return r ;
1845+ if (other -> next_attempt_after > ts )
1846+ continue ;
18731847
1874- append = true;
1875- }
1848+ if (! set_contains ( keys , dns_transaction_key ( other ))) {
1849+ size_t saved_packet_size ;
18761850
1877- r = dns_transaction_prepare (other , ts );
1851+ r = dns_packet_append_key (p , dns_transaction_key (other ), 0 , & saved_packet_size );
1852+ /* If we can't stuff more questions into the packet, just give up.
1853+ * One of the 'other' transactions will fire later and take care of the rest. */
1854+ if (r == - EMSGSIZE )
1855+ break ;
18781856 if (r < 0 )
18791857 return r ;
1880- if (r == 0 ) {
1881- if (append )
1882- dns_packet_truncate (p , saved_packet_size );
18831858
1884- /* In this case, not only this transaction, but multiple transactions may be
1885- * freed. Hence, we need to restart the loop. */
1886- restart = true ;
1859+ r = dns_packet_append_zone ( p , t , dns_transaction_key ( other ), NULL );
1860+ if ( r == - EMSGSIZE ) {
1861+ dns_packet_truncate ( p , saved_packet_size ) ;
18871862 break ;
18881863 }
1864+ if (r < 0 )
1865+ return r ;
18891866
1890- usec_t timeout = transaction_get_resend_timeout (other );
1891- r = dns_transaction_setup_timeout (other , timeout , usec_add (ts , timeout ));
1867+ r = set_ensure_put (& keys , & dns_resource_key_hash_ops , dns_transaction_key (other ));
18921868 if (r < 0 )
18931869 return r ;
1870+ }
18941871
1895- if (dns_key_is_shared (dns_transaction_key (other )))
1896- add_known_answers = true;
1872+ r = dns_transaction_prepare (other , ts );
1873+ if (r < 0 )
1874+ return r ;
1875+ if (r == 0 )
1876+ /* In this case, not only this transaction, but multiple transactions may be
1877+ * freed. Hence, we need to restart the loop. */
1878+ return - EAGAIN ;
18971879
1898- if (append ) {
1899- r = set_ensure_put (& keys , & dns_resource_key_hash_ops , dns_transaction_key (other ));
1900- if (r < 0 )
1901- return r ;
1902- }
1880+ usec_t timeout = transaction_get_resend_timeout (other );
1881+ r = dns_transaction_setup_timeout (other , timeout , usec_add (ts , timeout ));
1882+ if (r < 0 )
1883+ return r ;
19031884
1904- qdcount ++ ;
1905- if (qdcount >= UINT16_MAX )
1906- break ;
1907- }
1885+ if (dns_key_is_shared (dns_transaction_key (other )))
1886+ add_known_answers = true;
1887+
1888+ qdcount ++ ;
1889+ if (qdcount >= UINT16_MAX )
1890+ break ;
19081891 }
19091892
1910- /* Append known answer section if we're asking for any shared record */
1893+ DNS_PACKET_HEADER (p )-> qdcount = htobe16 (qdcount );
1894+
1895+ /* Append known answers section if we're asking for any shared record */
19111896 if (add_known_answers ) {
19121897 r = dns_cache_export_shared_to_packet (& t -> scope -> cache , p , ts , 0 );
19131898 if (r < 0 )
19141899 return r ;
1900+ }
1901+
1902+ * ret_packet = TAKE_PTR (p );
1903+ * ret_keys = TAKE_PTR (keys );
1904+ return add_known_answers ;
1905+ }
1906+
1907+ static int dns_transaction_make_packet_mdns (DnsTransaction * t ) {
1908+ _cleanup_ (dns_packet_unrefp ) DnsPacket * p = NULL , * dummy = NULL ;
1909+ _cleanup_set_free_ Set * keys = NULL ;
1910+ bool add_known_answers ;
1911+ DnsResourceKey * k ;
1912+ unsigned c ;
1913+ int r ;
1914+
1915+ assert (t );
1916+ assert (t -> scope -> protocol == DNS_PROTOCOL_MDNS );
1917+
1918+ /* Discard any previously prepared packet, so we can start over and coalesce again */
1919+ t -> sent = dns_packet_unref (t -> sent );
1920+
1921+ /* First, create a dummy packet to calculate the number of known answers to be appended in the first packet. */
1922+ for (;;) {
1923+ r = mdns_make_dummy_packet (t , & dummy , & keys );
1924+ if (r == - EAGAIN )
1925+ continue ;
1926+ if (r < 0 )
1927+ return r ;
19151928
1916- ancount = be16toh (DNS_PACKET_HEADER (p )-> ancount );
1929+ add_known_answers = r ;
1930+ break ;
19171931 }
19181932
19191933 /* Then, create actual packet. */
1920- p = dns_packet_unref (p );
19211934 r = dns_packet_new_query (& p , t -> scope -> protocol , 0 , false);
19221935 if (r < 0 )
19231936 return r ;
19241937
19251938 /* Questions */
1926- DnsResourceKey * k ;
1939+ c = 0 ;
19271940 SET_FOREACH (k , keys ) {
19281941 r = dns_packet_append_key (p , k , 0 , NULL );
19291942 if (r < 0 )
19301943 return r ;
1944+ c ++ ;
19311945 }
1932- DNS_PACKET_HEADER (p )-> qdcount = htobe16 (qdcount );
1946+ DNS_PACKET_HEADER (p )-> qdcount = htobe16 (c );
19331947
19341948 /* Known answers */
19351949 if (add_known_answers ) {
1936- r = dns_cache_export_shared_to_packet (& t -> scope -> cache , p , ts , ancount );
1950+ usec_t ts ;
1951+
1952+ assert_se (sd_event_now (t -> scope -> manager -> event , CLOCK_BOOTTIME , & ts ) >= 0 );
1953+
1954+ r = dns_cache_export_shared_to_packet (& t -> scope -> cache , p , ts , be16toh (DNS_PACKET_HEADER (dummy )-> ancount ));
19371955 if (r < 0 )
19381956 return r ;
19391957 }
19401958
19411959 /* Authorities */
1942- nscount = 0 ;
1960+ c = 0 ;
19431961 SET_FOREACH (k , keys ) {
1944- r = dns_packet_append_zone (p , t , k , & nscount );
1962+ r = dns_packet_append_zone (p , t , k , & c );
19451963 if (r < 0 )
19461964 return r ;
19471965 }
1948- DNS_PACKET_HEADER (p )-> nscount = htobe16 (nscount );
1966+ DNS_PACKET_HEADER (p )-> nscount = htobe16 (c );
19491967
19501968 t -> sent = TAKE_PTR (p );
19511969 return 0 ;
0 commit comments