Bug 1567201 - Join multicast group on all interfaces; r=mjf
authorDan Minor <dminor@mozilla.com>
Tue, 01 Oct 2019 12:59:02 +0000
changeset 495828 87443564bb2a1563f1f099055c4bee3fa38bb8a5
parent 495827 9f849d55a360814bda6baf9e1779d62e33597817
child 495829 ddc6931cddeccc448423cf4c5dc20d787a8e2daa
push id114140
push userdvarga@mozilla.com
push dateWed, 02 Oct 2019 18:04:51 +0000
treeherdermozilla-inbound@32eb0ea893f3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmjf
bugs1567201
milestone71.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1567201 - Join multicast group on all interfaces; r=mjf We need to join the multicast group on all network interfaces or we may end up missing packets. There is a limit on the number of groups joinable by a single socket (20 on my Linux system) but it doesn't seem worth worrying about hitting that limit at the moment as it seems unlikely that many users would have more than 20 network interfaces on a system on which they are running Firefox. Differential Revision: https://phabricator.services.mozilla.com/D46981
media/mtransport/ipc/StunAddrsRequestParent.cpp
media/mtransport/mdns_service/src/lib.rs
--- a/media/mtransport/ipc/StunAddrsRequestParent.cpp
+++ b/media/mtransport/ipc/StunAddrsRequestParent.cpp
@@ -165,27 +165,31 @@ void StunAddrsRequestParent::SendStunAdd
 
   // This means that the mDNS service will continue running until shutdown
   // once started. The StunAddrsRequestParent destructor does not run until
   // shutdown anyway (see Bug 1569311), so there is not much we can do about
   // this here. One option would be to add a check if there are no hostnames
   // registered after UnregisterHostname is called, and if so, stop the mDNS
   // service at that time (see Bug 1569955.)
   if (!mSharedMDNSService) {
+    std::ostringstream o;
+    char buffer[16];
     for (auto& addr : addrs) {
       nr_transport_addr* local_addr =
           const_cast<nr_transport_addr*>(&addr.localAddr().addr);
       if (addr.localAddr().addr.ip_version == NR_IPV4 &&
           !nr_transport_addr_is_loopback(local_addr)) {
-        char addrstring[16];
-        nr_transport_addr_get_addrstring(local_addr, addrstring, 16);
-        mSharedMDNSService = new MDNSServiceWrapper(addrstring);
-        break;
+        nr_transport_addr_get_addrstring(local_addr, buffer, 16);
+        o << buffer << ";";
       }
     }
+    std::string addrstring = o.str();
+    if (!addrstring.empty()) {
+      mSharedMDNSService = new MDNSServiceWrapper(addrstring);
+    }
   }
 
   // send the new addresses back to the child
   Unused << SendOnStunAddrsAvailable(addrs);
 }
 
 void StunAddrsRequestParent::OnQueryComplete_m(const nsCString& hostname,
                                                const nsCString& address) {
--- a/media/mtransport/mdns_service/src/lib.rs
+++ b/media/mtransport/mdns_service/src/lib.rs
@@ -231,36 +231,44 @@ impl MDNSService {
                 warn!(
                     "Could not send unregister hostname {} message: {}",
                     hostname, err
                 );
             }
         }
     }
 
-    fn start(&mut self, addr: std::net::Ipv4Addr) -> io::Result<()> {
+    fn start(&mut self, addrs: Vec<std::net::Ipv4Addr>) -> io::Result<()> {
         let (sender, receiver) = channel();
         self.sender = Some(sender);
 
+        let mdns_addr = std::net::Ipv4Addr::new(224, 0, 0, 251);
         let port = 5353;
 
         let socket = Socket::new(Domain::ipv4(), Type::dgram(), None).unwrap();
         socket.set_reuse_address(true)?;
 
         #[cfg(not(target_os = "windows"))]
         socket.set_reuse_port(true)?;
         socket.bind(&socket2::SockAddr::from(std::net::SocketAddr::from((
             [0, 0, 0, 0],
             port,
         ))))?;
 
         let socket = socket.into_udp_socket();
         socket.set_multicast_loop_v4(true)?;
         socket.set_read_timeout(Some(time::Duration::from_millis(10)))?;
-        socket.join_multicast_v4(&std::net::Ipv4Addr::new(224, 0, 0, 251), &addr)?;
+        for addr in addrs {
+            if let Err(err) = socket.join_multicast_v4(&mdns_addr, &addr) {
+                warn!(
+                    "Could not join multicast group on interface: {:?}: {}",
+                    addr, err
+                );
+            }
+        }
 
         let builder = thread::Builder::new().name("mdns_service".to_string());
         self.handle = Some(builder.spawn(move || {
             let mdns_addr = std::net::SocketAddr::from(([224, 0, 0, 251], port));
             let mut buffer: [u8; 1024] = [0; 1024];
             let mut hosts = HashMap::new();
             let mut unsent_queries = LinkedList::new();
             let mut pending_queries = HashMap::new();
@@ -495,27 +503,28 @@ pub extern "C" fn mdns_service_register_
     unsafe {
         let hostname = CStr::from_ptr(hostname).to_string_lossy();
         let address = CStr::from_ptr(address).to_string_lossy();
         (*serv).register_hostname(&hostname, &address);
     }
 }
 
 #[no_mangle]
-pub extern "C" fn mdns_service_start(ifaddr: *const c_char) -> *mut MDNSService {
-    assert!(!ifaddr.is_null());
+pub extern "C" fn mdns_service_start(ifaddrs: *const c_char) -> *mut MDNSService {
+    assert!(!ifaddrs.is_null());
     let mut r = Box::new(MDNSService::new());
     unsafe {
-        let ifaddr = CStr::from_ptr(ifaddr).to_string_lossy();
-        if let Ok(addr) = ifaddr.parse() {
-            if let Err(err) = r.start(addr) {
-                warn!("Could not start mDNS Service: {}", err);
-            }
-        } else {
-            warn!("Could not parse interface address: {}", ifaddr);
+        let ifaddrs = CStr::from_ptr(ifaddrs).to_string_lossy();
+        let addrs: Vec<std::net::Ipv4Addr> =
+            ifaddrs.split(';').filter_map(|x| x.parse().ok()).collect();
+
+        if addrs.len() == 0 {
+            warn!("Could not parse interface addresses from: {}", ifaddrs);
+        } else if let Err(err) = r.start(addrs) {
+            warn!("Could not start mDNS Service: {}", err);
         }
     }
     Box::into_raw(r)
 }
 
 #[no_mangle]
 pub extern "C" fn mdns_service_stop(serv: *mut MDNSService) {
     assert!(!serv.is_null());
@@ -680,27 +689,27 @@ mod tests {
         );
         assert_eq!(validate_hostname("hi there"), false);
     }
 
     #[test]
     fn start_stop() {
         let mut service = MDNSService::new();
         let addr = "127.0.0.1".parse().unwrap();
-        service.start(addr).unwrap();
+        service.start(vec![addr]).unwrap();
         service.stop();
     }
 
     #[test]
     fn simple_query() {
         let mut service = MDNSService::new();
         let addr = "127.0.0.1".parse().unwrap();
         let handle = listen_until(&addr, 1);
 
-        service.start(addr).unwrap();
+        service.start(vec![addr]).unwrap();
 
         let callback = Callback {
             data: 0 as *const c_void,
             resolved: mdns_service_resolved,
         };
         let hostname = Uuid::new_v4().to_hyphenated().to_string() + ".local";
         service.query_hostname(callback, &hostname);
         service.stop();
@@ -709,17 +718,17 @@ mod tests {
     }
 
     #[test]
     fn rate_limited_query() {
         let mut service = MDNSService::new();
         let addr = "127.0.0.1".parse().unwrap();
         let handle = listen_until(&addr, 1);
 
-        service.start(addr).unwrap();
+        service.start(vec![addr]).unwrap();
 
         let mut hostnames = HashSet::new();
         for _ in 0..100 {
             let callback = Callback {
                 data: 0 as *const c_void,
                 resolved: mdns_service_resolved,
             };
             let hostname = Uuid::new_v4().to_hyphenated().to_string() + ".local";
@@ -733,17 +742,17 @@ mod tests {
     }
 
     #[test]
     fn repeat_failed_query() {
         let mut service = MDNSService::new();
         let addr = "127.0.0.1".parse().unwrap();
         let handle = listen_until(&addr, 4);
 
-        service.start(addr).unwrap();
+        service.start(vec![addr]).unwrap();
 
         let hostname = Uuid::new_v4().to_hyphenated().to_string() + ".local";
         let callback = Callback {
             data: 0 as *const c_void,
             resolved: mdns_service_resolved,
         };
         service.query_hostname(callback, &hostname);
         thread::sleep(time::Duration::from_secs(4));