blob: 29fec065088ba1e2aee4830beb8b8167dd71a84d [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{format_err, Error};
use fidl::endpoints::RequestStream;
use fidl_fuchsia_net_mdns::{
Media, Publication, PublicationResponder_Request, PublicationResponder_RequestStream,
PublisherMarker, PublisherProxy, ServiceSubscriberRequest, ServiceSubscriberRequestStream,
SubscriberMarker,
};
use fuchsia_async as fasync;
use fuchsia_zircon as zx;
use futures::prelude::*;
use overnet_core::NodeId;
const SERVICE_NAME: &str = "_overnet._udp.";
async fn connect_to_proxy(
node_id: NodeId,
publisher: PublisherProxy,
port: u16,
proxy: zx::Channel,
) -> Result<(), Error> {
log::info!("Publish overnet service on port {}", port);
publisher
.publish_service_instance(
SERVICE_NAME,
&format!("{:?}", node_id.0),
Media::WIRED | Media::WIRELESS,
true,
fidl::endpoints::ClientEnd::new(proxy),
)
.await?
.map_err(|e| format_err!("{:?}", e))?;
log::info!("Published overnet service on port {}", port);
Ok(())
}
/// Run main loop to publish a udp socket to mdns.
pub async fn publish(port: u16, node_id: NodeId) -> Result<(), Error> {
let (server, proxy) = zx::Channel::create()?;
let server = fasync::Channel::from_channel(server)?;
let publisher = fuchsia_component::client::connect_to_protocol::<PublisherMarker>()?;
futures::future::try_join(
connect_to_proxy(node_id, publisher, port, proxy),
PublicationResponder_RequestStream::from_channel(server).map_err(Into::into).try_for_each(
|PublicationResponder_Request::OnPublication { responder, .. }| async move {
responder
.send(Some(&mut Publication {
port,
text: vec![],
srv_priority: fidl_fuchsia_net_mdns::DEFAULT_SRV_PRIORITY,
srv_weight: fidl_fuchsia_net_mdns::DEFAULT_SRV_WEIGHT,
ptr_ttl: fidl_fuchsia_net_mdns::DEFAULT_PTR_TTL,
srv_ttl: fidl_fuchsia_net_mdns::DEFAULT_SRV_TTL,
txt_ttl: fidl_fuchsia_net_mdns::DEFAULT_TXT_TTL,
}))
.map_err(Into::into)
},
),
)
.await?;
Ok(())
}
fn convert_ipv6_buffer(in_arr: [u8; 16]) -> [u16; 8] {
let mut out_arr: [u16; 8] = [0; 8];
for i in 0..8 {
out_arr[i] = ((in_arr[2 * i] as u16) << 8) | (in_arr[2 * i + 1] as u16);
}
out_arr
}
fn fuchsia_to_rust_ipaddr4(addr: fidl_fuchsia_net::Ipv4Address) -> std::net::Ipv4Addr {
std::net::Ipv4Addr::new(addr.addr[0], addr.addr[1], addr.addr[2], addr.addr[3])
}
fn fuchsia_to_rust_ipaddr6(addr: fidl_fuchsia_net::Ipv6Address) -> std::net::Ipv6Addr {
let addr = convert_ipv6_buffer(addr.addr);
std::net::Ipv6Addr::new(addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7])
}
fn endpoint4_to_socket(ep: fidl_fuchsia_net::Ipv4SocketAddress) -> std::net::SocketAddrV6 {
std::net::SocketAddrV6::new(fuchsia_to_rust_ipaddr4(ep.address).to_ipv6_mapped(), ep.port, 0, 0)
}
fn endpoint6_to_socket(ep: fidl_fuchsia_net::Ipv6SocketAddress) -> std::net::SocketAddrV6 {
std::net::SocketAddrV6::new(fuchsia_to_rust_ipaddr6(ep.address), ep.port, 0, 0)
}
/// Run main loop to look for overnet mdns advertisements and add them to the mesh.
pub async fn subscribe(
found: futures::channel::mpsc::Sender<std::net::SocketAddrV6>,
) -> Result<(), Error> {
log::info!("Query for overnet services");
let (server, proxy) = zx::Channel::create()?;
fuchsia_component::client::connect_to_protocol::<SubscriberMarker>()?
.subscribe_to_service(SERVICE_NAME, fidl::endpoints::ClientEnd::new(proxy))?;
log::info!("Wait for overnet services");
let found = &found;
ServiceSubscriberRequestStream::from_channel(fasync::Channel::from_channel(server)?)
.map_err(Into::into)
.try_for_each(|request| async move {
match request {
ServiceSubscriberRequest::OnInstanceDiscovered { instance, responder } => {
log::info!("Discovered: {:?}", instance);
if let Some(ipv4_endpoint) = instance.ipv4_endpoint {
found.clone().send(endpoint4_to_socket(ipv4_endpoint)).await?;
}
if let Some(ipv6_endpoint) = instance.ipv6_endpoint {
found.clone().send(endpoint6_to_socket(ipv6_endpoint)).await?;
}
responder.send()?;
}
ServiceSubscriberRequest::OnInstanceChanged { instance, responder } => {
log::info!("Changed: {:?}", instance);
if let Some(ipv4_endpoint) = instance.ipv4_endpoint {
found.clone().send(endpoint4_to_socket(ipv4_endpoint)).await?;
}
if let Some(ipv6_endpoint) = instance.ipv6_endpoint {
found.clone().send(endpoint6_to_socket(ipv6_endpoint)).await?;
}
responder.send()?;
}
ServiceSubscriberRequest::OnInstanceLost { responder, .. } => {
log::info!("Removed a thing");
responder.send()?;
}
ServiceSubscriberRequest::OnQuery { responder, .. } => {
responder.send()?;
}
}
Ok::<_, Error>(())
})
.await?;
log::info!("Mdns subscriber finishes");
Ok(())
}
// [START test_mod]
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fuchsia_to_rust_ipaddr6() {
//test example IPv6 address [fe80::5054:ff:fe40:5763]
//fidl_fuchsia_net::Ipv6Address
let ipv6_addr = fidl_fuchsia_net::Ipv6Address {
addr: [
0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x54, 0x00, 0xff, 0xfe, 0x40,
0x57, 0x63,
],
};
//std::net::IpAddr
let net_addr = std::net::IpAddr::V6(std::net::Ipv6Addr::new(
0xff80, 0x0000, 0x0000, 0x0000, 0x5054, 0x00ff, 0xfe40, 0x5763,
));
//expected:[fuchsia_to_rust_ipaddr6(ipv6_addr)] == [net_addr]
assert_eq!(fuchsia_to_rust_ipaddr6(ipv6_addr), net_addr);
}
}
// [END test_mod]