From d6bac2eaba6c54485d9474b41c6d912c682948d1 Mon Sep 17 00:00:00 2001 From: Dan Minor Date: Wed, 26 Feb 2020 17:22:08 +0000 Subject: [PATCH] Bug 1616667 - Add handle_mdns_socket function; r=mjf Depends on D64380 Differential Revision: https://phabricator.services.mozilla.com/D64381 --HG-- extra : moz-landing-system : lando --- media/mtransport/mdns_service/src/lib.rs | 205 +++++++++++------------ 1 file changed, 99 insertions(+), 106 deletions(-) diff --git a/media/mtransport/mdns_service/src/lib.rs b/media/mtransport/mdns_service/src/lib.rs index 0310a127cea8..3d4a13516287 100644 --- a/media/mtransport/mdns_service/src/lib.rs +++ b/media/mtransport/mdns_service/src/lib.rs @@ -186,6 +186,97 @@ fn handle_queries( } } +fn handle_mdns_socket( + socket: &std::net::UdpSocket, + mdns_addr: &std::net::SocketAddr, + mut buffer: &mut [u8], + hosts: &mut HashMap>, + pending_queries: &mut HashMap, +) -> bool { + match socket.recv_from(&mut buffer) { + Ok((amt, _)) => { + if amt > 0 { + let buffer = &buffer[0..amt]; + match dns_parser::Packet::parse(&buffer) { + Ok(parsed) => { + let mut answers: Vec<(String, &[u8])> = Vec::new(); + + // If a packet contains both both questions and + // answers, the questions should be ignored. + if parsed.answers.len() == 0 { + parsed + .questions + .iter() + .filter(|question| question.qtype == dns_parser::QueryType::A) + .for_each(|question| { + let qname = question.qname.to_string(); + trace!("mDNS question: {} {:?}", qname, question.qtype); + if let Some(octets) = hosts.get(&qname) { + trace!("Sending mDNS answer for {}: {:?}", qname, octets); + answers.push((qname, &octets)); + } + }); + } + for answer in parsed.answers { + let hostname = answer.name.to_string(); + match pending_queries.get(&hostname) { + Some(query) => { + match answer.data { + dns_parser::RData::A(dns_parser::rdata::a::Record( + addr, + )) => { + let addr = addr.to_string(); + trace!("mDNS response: {} {}", hostname, addr); + hostname_resolved(&query.callback, &hostname, &addr); + } + dns_parser::RData::AAAA( + dns_parser::rdata::aaaa::Record(addr), + ) => { + let addr = addr.to_string(); + trace!("mDNS response: {} {}", hostname, addr); + hostname_resolved(&query.callback, &hostname, &addr); + } + _ => {} + } + pending_queries.remove(&hostname); + } + None => { + continue; + } + } + } + // TODO: If we did not answer every query in this + // question, we should wait for a random amount of time + // so as to not collide with someone else responding to + // this query. + if answers.len() > 0 { + if let Ok(buf) = create_answer(parsed.header.id, &answers) { + if let Err(err) = socket.send_to(&buf, &mdns_addr) { + warn!("Sending mDNS answer failed: {}", err); + } + } + } + } + Err(err) => { + warn!("Could not parse mDNS packet: {}", err); + } + } + } + } + Err(err) => { + if err.kind() != io::ErrorKind::Interrupted + && err.kind() != io::ErrorKind::TimedOut + && err.kind() != io::ErrorKind::WouldBlock + { + error!("Socket error: {}", err); + return false; + } + } + } + + true +} + fn validate_hostname(hostname: &str) -> bool { match hostname.find(".local") { Some(index) => match hostname.get(0..index) { @@ -393,112 +484,14 @@ impl MDNSService { &mut unsent_queries, ); - match socket.recv_from(&mut buffer) { - Ok((amt, _)) => { - if amt > 0 { - let buffer = &buffer[0..amt]; - match dns_parser::Packet::parse(&buffer) { - Ok(parsed) => { - let mut answers: Vec<(String, &[u8])> = Vec::new(); - - // If a packet contains both both questions and - // answers, the questions should be ignored. - if parsed.answers.len() == 0 { - parsed - .questions - .iter() - .filter(|question| { - question.qtype == dns_parser::QueryType::A - }) - .for_each(|question| { - let qname = question.qname.to_string(); - trace!( - "mDNS question: {} {:?}", - qname, - question.qtype - ); - if let Some(octets) = hosts.get(&qname) { - trace!( - "Sending mDNS answer for {}: {:?}", - qname, - octets - ); - answers.push((qname, &octets)); - } - }); - } - for answer in parsed.answers { - let hostname = answer.name.to_string(); - match pending_queries.get(&hostname) { - Some(query) => { - match answer.data { - dns_parser::RData::A( - dns_parser::rdata::a::Record(addr), - ) => { - let addr = addr.to_string(); - trace!( - "mDNS response: {} {}", - hostname, - addr - ); - hostname_resolved( - &query.callback, - &hostname, - &addr, - ); - } - dns_parser::RData::AAAA( - dns_parser::rdata::aaaa::Record(addr), - ) => { - let addr = addr.to_string(); - trace!( - "mDNS response: {} {}", - hostname, - addr - ); - hostname_resolved( - &query.callback, - &hostname, - &addr, - ); - } - _ => {} - } - pending_queries.remove(&hostname); - } - None => { - continue; - } - } - } - // TODO: If we did not answer every query - // in this question, we should wait for a - // random amount of time so as to not - // collide with someone else responding to - // this query. - if answers.len() > 0 { - if let Ok(buf) = create_answer(parsed.header.id, &answers) { - if let Err(err) = socket.send_to(&buf, &mdns_addr) { - warn!("Sending mDNS answer failed: {}", err); - } - } - } - } - Err(err) => { - warn!("Could not parse mDNS packet: {}", err); - } - } - } - } - Err(err) => { - if err.kind() != io::ErrorKind::Interrupted - && err.kind() != io::ErrorKind::TimedOut - && err.kind() != io::ErrorKind::WouldBlock - { - error!("Socket error: {}", err); - break; - } - } + if !handle_mdns_socket( + &socket, + &mdns_addr, + &mut buffer, + &mut hosts, + &mut pending_queries, + ) { + break; } } })?);