use anyhow::{anyhow, Context as _, Result};
use std::collections::HashMap;
use {
fidl_fuchsia_component as fcomponent, fidl_fuchsia_component_decl as fdecl,
fidl_fuchsia_net_interfaces as fnet_interfaces,
fidl_fuchsia_net_interfaces_ext as fnet_interfaces_ext,
};
pub const HERMETIC_NETWORK_COLLECTION_NAME: &'static str = "enclosed-network";
pub const HERMETIC_NETWORK_REALM_NAME: &'static str = "hermetic-network";
pub const STUB_COLLECTION_NAME: &'static str = "stubs";
pub const STUB_COMPONENT_NAME: &'static str = "test-stub";
pub async fn has_hermetic_network_realm(realm_proxy: &fcomponent::RealmProxy) -> Result<bool> {
let child_ref = create_hermetic_network_realm_child_ref();
has_running_child(
fdecl::CollectionRef { name: HERMETIC_NETWORK_COLLECTION_NAME.to_string() },
&child_ref,
realm_proxy,
)
.await
}
pub async fn has_stub(realm_proxy: &fcomponent::RealmProxy) -> Result<bool> {
let child_ref = create_stub_child_ref();
has_running_child(
fdecl::CollectionRef { name: STUB_COLLECTION_NAME.to_string() },
&child_ref,
realm_proxy,
)
.await
}
async fn has_running_child(
collection_ref: fdecl::CollectionRef,
expected_child_ref: &fdecl::ChildRef,
realm_proxy: &fcomponent::RealmProxy,
) -> Result<bool> {
let (iterator_proxy, server_end) = fidl::endpoints::create_proxy().unwrap();
let list_children_result = realm_proxy
.list_children(&collection_ref, server_end)
.await
.context("failed to list_children")?;
match list_children_result {
Ok(()) => {
let children =
iterator_proxy.next().await.context("failed to iterate over children")?;
Ok(children.iter().any(|child| child == expected_child_ref))
}
Err(error) => match error {
fcomponent::Error::CollectionNotFound => Ok(false),
fcomponent::Error::AccessDenied
| fcomponent::Error::InstanceDied
| fcomponent::Error::InvalidArguments
| fcomponent::Error::InstanceAlreadyExists
| fcomponent::Error::InstanceAlreadyStarted
| fcomponent::Error::InstanceCannotResolve
| fcomponent::Error::InstanceCannotUnresolve
| fcomponent::Error::InstanceCannotStart
| fcomponent::Error::InstanceNotFound
| fcomponent::Error::Internal
| fcomponent::Error::ResourceNotFound
| fcomponent::Error::ResourceUnavailable
| fcomponent::Error::Unsupported
| fcomponent::ErrorUnknown!()
=> {
Err(anyhow!("failed to list children: {:?}", error))
}
},
}
}
pub fn create_hermetic_network_realm_child_ref() -> fdecl::ChildRef {
fdecl::ChildRef {
name: HERMETIC_NETWORK_REALM_NAME.to_string(),
collection: Some(HERMETIC_NETWORK_COLLECTION_NAME.to_string()),
}
}
pub fn create_stub_child_ref() -> fdecl::ChildRef {
fdecl::ChildRef {
name: STUB_COMPONENT_NAME.to_string(),
collection: Some(STUB_COLLECTION_NAME.to_string()),
}
}
pub async fn get_interface_id<'a>(
interface_name: &'a str,
state_proxy: &'a fnet_interfaces::StateProxy,
) -> Result<Option<u64>> {
let stream = fnet_interfaces_ext::event_stream_from_state(
&state_proxy,
fnet_interfaces_ext::IncludedAddresses::OnlyAssigned,
)
.context("failed to get interface stream")?;
let interfaces = fnet_interfaces_ext::existing(
stream,
HashMap::<u64, fidl_fuchsia_net_interfaces_ext::PropertiesAndState<()>>::new(),
)
.await
.context("failed to get existing interfaces")?;
Ok(interfaces.values().find_map(
|fidl_fuchsia_net_interfaces_ext::PropertiesAndState {
properties: fidl_fuchsia_net_interfaces_ext::Properties { id, name, .. },
state: _,
}| {
if name == interface_name {
Some(id.get())
} else {
None
}
},
))
}