extern crate libc;
use std::{
ffi::{c_void, CStr},
net::SocketAddr,
ptr::NonNull,
};
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
use libc::c_char;
pub struct NetworkRequestCallbackWrapper {
callback: Option<Box<dyn FnOnce(bool) + Send + Sync + 'static>>,
}
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
extern "C" fn network_activation_callback(ptr: *mut c_void, activated: bool) {
let data = ptr as *mut NetworkRequestCallbackWrapper;
unsafe {
if let Some(wrapper) = data.as_mut() {
if let Some(callback) = wrapper.callback.take() {
callback(activated);
}
}
}
}
#[repr(C)]
pub struct NetworkRequestCHandle {
_data: [u8; 0],
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}
pub struct NetworkRequestCHandleWrapper(NonNull<NetworkRequestCHandle>);
impl Drop for NetworkRequestCHandleWrapper {
fn drop(&mut self) {
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
let c_handle = self.0.as_ptr();
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
unsafe {
platform_drop_network_request(c_handle);
}
}
}
unsafe impl Send for NetworkRequestCHandleWrapper {}
#[repr(C)]
pub struct NetworkInfoCHandle {
_data: [u8; 0],
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}
pub struct NetworkInfoCHandleWrapper(NonNull<NetworkInfoCHandle>);
impl Drop for NetworkInfoCHandleWrapper {
fn drop(&mut self) {
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
let c_handle = self.0.as_ptr();
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
unsafe {
platform_drop_network_info(c_handle);
}
}
}
unsafe impl Send for NetworkInfoCHandleWrapper {}
#[repr(C)]
pub struct DnsInfoCHandle {
_data: [u8; 0],
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}
pub struct DnsInfoCHandleWrapper(NonNull<DnsInfoCHandle>);
impl Drop for DnsInfoCHandleWrapper {
fn drop(&mut self) {
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
let c_handle = self.0.as_ptr();
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
unsafe {
platform_drop_dns_info(c_handle);
}
}
}
unsafe impl Send for DnsInfoCHandleWrapper {}
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
extern "C" {
fn platform_activate_cellular_network(
ptr: *mut c_void,
callback: Option<extern "C" fn(*mut c_void, bool)>,
) -> *mut NetworkRequestCHandle;
fn platform_drop_network_request(c_handle: *mut NetworkRequestCHandle);
fn platform_get_active_network_info() -> *mut NetworkInfoCHandle;
fn platform_get_network_type(network_info: *mut NetworkInfoCHandle) -> i32;
fn platform_get_network_dns_info(network_info: *mut NetworkInfoCHandle) -> *mut DnsInfoCHandle;
fn platform_get_dns_server(dns_info: *mut DnsInfoCHandle) -> *const c_char;
fn platform_drop_dns_info(dns_info: *mut DnsInfoCHandle);
fn platform_drop_network_info(network_info: *mut NetworkInfoCHandle);
}
pub fn activate_cellular_network<T>(callback: T) -> Option<NetworkRequestCHandleWrapper>
where
T: 'static + FnOnce(bool) + Send + Sync,
{
let wrapper = NetworkRequestCallbackWrapper {
callback: Some(Box::new(callback)),
};
let data = Box::into_raw(Box::new(wrapper));
let ptr = data as *mut c_void;
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
unsafe {
if let Some(c_handle) =
platform_activate_cellular_network(ptr, Some(network_activation_callback)).as_mut()
{
return Some(NetworkRequestCHandleWrapper(
NonNull::new(c_handle).unwrap(),
));
}
}
None
}
pub fn get_active_network_info() -> Option<NetworkInfoCHandleWrapper> {
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
unsafe {
if let Some(network_info) = platform_get_active_network_info().as_mut() {
return Some(NetworkInfoCHandleWrapper(
NonNull::new(network_info).unwrap(),
));
}
}
None
}
pub fn get_network_type(network_info: &NetworkInfoCHandleWrapper) -> i32 {
let network_info_c_handle = network_info.0.as_ptr();
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
unsafe {
platform_get_network_type(network_info_c_handle)
}
#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
0
}
pub fn get_dns_info(network_info: &NetworkInfoCHandleWrapper) -> Option<DnsInfoCHandleWrapper> {
let network_info_c_handle = network_info.0.as_ptr();
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
unsafe {
if let Some(dns_info) = platform_get_network_dns_info(network_info_c_handle).as_mut() {
return Some(DnsInfoCHandleWrapper(NonNull::new(dns_info).unwrap()));
}
}
None
}
pub fn get_dns_servers(dns_info: &DnsInfoCHandleWrapper) -> Vec<SocketAddr> {
let dns_info_c_handle = dns_info.0.as_ptr();
let mut v = Vec::new();
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
unsafe {
while let Some(ptr) = platform_get_dns_server(dns_info_c_handle).as_ref() {
let str = CStr::from_ptr(ptr).to_string_lossy().into_owned();
if let Ok(dns_server) = str.parse::<SocketAddr>() {
v.push(dns_server);
}
}
}
v
}
pub fn get_active_dns_servers() -> Vec<SocketAddr> {
let mut v = Vec::new();
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
unsafe {
if let Some(network_info) = platform_get_active_network_info().as_mut() {
if let Some(dns_info) = platform_get_network_dns_info(network_info).as_mut() {
while let Some(ptr) = platform_get_dns_server(dns_info).as_ref() {
let str = CStr::from_ptr(ptr).to_string_lossy().into_owned();
if let Ok(dns_server) = str.parse::<SocketAddr>() {
v.push(dns_server);
}
}
platform_drop_dns_info(dns_info);
}
}
}
v
}