Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion system-configuration/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ edition = "2021"
rust-version = "1.64.0"

[dependencies]
core-foundation = "0.9"
core-foundation = "0.10"
system-configuration-sys = { path = "../system-configuration-sys", version = "0.6" }
bitflags = "2"
9 changes: 5 additions & 4 deletions system-configuration/src/dynamic_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ impl<T> SCDynamicStoreBuilder<T> {

/// Create the dynamic store session.
pub fn build(mut self) -> Option<SCDynamicStore> {
let store_options = self.create_store_options();
let store_options = self.create_store_options()?;
if let Some(callback_context) = self.callback_context.take() {
SCDynamicStore::create(
&self.name,
Expand All @@ -116,11 +116,12 @@ impl<T> SCDynamicStoreBuilder<T> {
}
}

fn create_store_options(&self) -> CFDictionary {
let key = unsafe { CFString::wrap_under_create_rule(kSCDynamicStoreUseSessionKeys) };
fn create_store_options(&self) -> Option<CFDictionary> {
let key =
unsafe { CFString::try_wrap_under_create_rule(kSCDynamicStoreUseSessionKeys) }?;
let value = CFBoolean::from(self.session_keys);
let typed_dict = CFDictionary::from_CFType_pairs(&[(key, value)]);
unsafe { CFDictionary::wrap_under_get_rule(typed_dict.as_concrete_TypeRef()) }
unsafe { CFDictionary::try_wrap_under_get_rule(typed_dict.as_concrete_TypeRef()) }
}

fn create_context(
Expand Down
22 changes: 12 additions & 10 deletions system-configuration/src/network_configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,10 @@ impl SCNetworkInterfaceType {
use system_configuration_sys::network_configuration::*;

let id_is_equal_to = |const_str| -> bool {
let const_str = unsafe { CFString::wrap_under_get_rule(const_str) };
&const_str == type_id
match unsafe { CFString::try_wrap_under_get_rule(const_str) } {
Some(const_str) => &const_str == type_id,
None => false,
}
};
unsafe {
if id_is_equal_to(kSCNetworkInterfaceType6to4) {
Expand Down Expand Up @@ -200,8 +202,8 @@ impl SCNetworkInterfaceType {
/// See [`SCNetworkInterfaceCopyAll`] for more details.
///
/// [`SCNetworkInterfaceCopyAll`]: https://developer.apple.com/documentation/systemconfiguration/1517090-scnetworkinterfacecopyall?language=objc
pub fn get_interfaces() -> CFArray<SCNetworkInterface> {
unsafe { CFArray::<SCNetworkInterface>::wrap_under_create_rule(SCNetworkInterfaceCopyAll()) }
pub fn get_interfaces() -> Option<CFArray<SCNetworkInterface>> {
unsafe { CFArray::<SCNetworkInterface>::try_wrap_under_create_rule(SCNetworkInterfaceCopyAll()) }
}

core_foundation::declare_TCFType!(
Expand Down Expand Up @@ -277,9 +279,9 @@ core_foundation::impl_TCFType!(SCNetworkSet, SCNetworkSetRef, SCNetworkSetGetTyp

impl SCNetworkSet {
/// Constructs a new set of network services from the preferences.
pub fn new(prefs: &SCPreferences) -> Self {
pub fn new(prefs: &SCPreferences) -> Option<Self> {
let ptr = unsafe { SCNetworkSetCopyCurrent(prefs.to_void()) };
unsafe { SCNetworkSet::wrap_under_create_rule(ptr) }
unsafe { SCNetworkSet::try_wrap_under_create_rule(ptr) }
}

/// Returns an list of network service identifiers, ordered by their priority.
Expand Down Expand Up @@ -312,12 +314,12 @@ mod test {

#[test]
fn test_get_all_interfaces() {
let _ = get_interfaces();
let _ = get_interfaces().unwrap();
}

#[test]
fn test_get_type() {
for iface in get_interfaces().into_iter() {
for iface in get_interfaces().unwrap().into_iter() {
if iface.interface_type().is_none() {
panic!(
"Interface {:?} ({:?}) has unrecognized type {:?}",
Expand All @@ -331,9 +333,9 @@ mod test {

#[test]
fn test_service_order() {
let prefs = SCPreferences::default(&CFString::new("test"));
let prefs = SCPreferences::default(&CFString::new("test")).unwrap();
let services = SCNetworkService::get_services(&prefs);
let set = SCNetworkSet::new(&prefs);
let set = SCNetworkSet::new(&prefs).unwrap();
let service_order = set.service_order();

assert!(service_order.iter().all(|service_id| {
Expand Down
42 changes: 32 additions & 10 deletions system-configuration/src/network_reachability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,10 @@ impl SCNetworkReachability {
/// See [`SCNetworkReachabilityCreateWithAddressPair`] for details.
///
/// [`SCNetworkReachabilityCreateWithAddressPair`]: https://developer.apple.com/documentation/systemconfiguration/1514908-scnetworkreachabilitycreatewitha?language=objc
pub fn from_addr_pair(local: SocketAddr, remote: SocketAddr) -> SCNetworkReachability {
pub fn from_addr_pair(
local: SocketAddr,
remote: SocketAddr,
) -> Option<SCNetworkReachability> {
let ptr = unsafe {
SCNetworkReachabilityCreateWithAddressPair(
std::ptr::null(),
Expand All @@ -163,7 +166,7 @@ impl SCNetworkReachability {
)
};

unsafe { Self::wrap_under_create_rule(ptr) }
unsafe { Self::try_wrap_under_create_rule(ptr) }
}

/// Construct a Reachability from either a hostname or a network node
Expand Down Expand Up @@ -300,12 +303,30 @@ impl SCNetworkReachability {
}
}

impl From<SocketAddr> for SCNetworkReachability {
fn from(addr: SocketAddr) -> Self {
/// Failure to create a `SCNetworkReachability` from a network address.
#[derive(Debug)]
pub struct NetworkReachabilityCreateError(());

impl Display for NetworkReachabilityCreateError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Failed to create SCNetworkReachability from network address"
)
}
}

impl Error for NetworkReachabilityCreateError {}

impl TryFrom<SocketAddr> for SCNetworkReachability {
type Error = NetworkReachabilityCreateError;

fn try_from(addr: SocketAddr) -> Result<Self, Self::Error> {
unsafe {
let ptr =
SCNetworkReachabilityCreateWithAddress(std::ptr::null(), &*to_c_sockaddr(addr));
SCNetworkReachability::wrap_under_create_rule(ptr)
SCNetworkReachability::try_wrap_under_create_rule(ptr)
.ok_or(NetworkReachabilityCreateError(()))
}
}
}
Expand Down Expand Up @@ -410,7 +431,7 @@ mod test {
];

for addr in sockaddrs {
let mut reachability = SCNetworkReachability::from(addr);
let mut reachability = SCNetworkReachability::try_from(addr).unwrap();
assert!(
!reachability.0.is_null(),
"Failed to construct a SCNetworkReachability struct with {}",
Expand Down Expand Up @@ -441,7 +462,7 @@ mod test {
.map(|(a, b)| (a.parse().unwrap(), b.parse().unwrap()));

for (local, remote) in pairs {
let mut reachability = SCNetworkReachability::from_addr_pair(local, remote);
let mut reachability = SCNetworkReachability::from_addr_pair(local, remote).unwrap();
assert!(
!reachability.0.is_null(),
"Failed to construct a SCNetworkReachability struct with address pair {} - {}",
Expand Down Expand Up @@ -476,15 +497,15 @@ mod test {
SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), 0)
};
let reachability =
SCNetworkReachability::from_addr_pair(local_addr, remote_addr);
SCNetworkReachability::from_addr_pair(local_addr, remote_addr).unwrap();
let reachability_flags = reachability.reachability().unwrap();
// Verify that not established tcp connection path is reported as not reachable.
assert!(!reachability_flags.contains(ReachabilityFlags::REACHABLE));
}
Ok(tcp) => {
let local = tcp.local_addr().unwrap();
let remote = tcp.peer_addr().unwrap();
let reachability = SCNetworkReachability::from_addr_pair(local, remote);
let reachability = SCNetworkReachability::from_addr_pair(local, remote).unwrap();
let reachability_flags = reachability.reachability().unwrap();
// Verify established tcp connection path is reported as reachable.
assert!(reachability_flags.contains(ReachabilityFlags::REACHABLE));
Expand Down Expand Up @@ -539,7 +560,8 @@ mod test {
let (tx, rx) = std::sync::mpsc::channel();
std::thread::spawn(move || {
let mut reachability =
SCNetworkReachability::from("0.0.0.0:0".parse::<SocketAddr>().unwrap());
SCNetworkReachability::try_from("0.0.0.0:0".parse::<SocketAddr>().unwrap())
.unwrap();
reachability.set_callback(|_| {}).unwrap();
// SAFETY: We use the Apple provided run_loop_mode kCFRunLoopCommonModes
unsafe {
Expand Down
10 changes: 5 additions & 5 deletions system-configuration/src/preferences.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl_TCFType!(SCPreferences, SCPreferencesRef, SCPreferencesGetTypeID);

impl SCPreferences {
/// Initiates access to the default system preferences using the default allocator.
pub fn default(calling_process_name: &CFString) -> Self {
pub fn default(calling_process_name: &CFString) -> Option<Self> {
Self::new(None, calling_process_name, None)
}

Expand All @@ -35,7 +35,7 @@ impl SCPreferences {
/// constructor.
///
/// [`default`]: #method.default
pub fn group(calling_process_name: &CFString, prefs_id: &CFString) -> Self {
pub fn group(calling_process_name: &CFString, prefs_id: &CFString) -> Option<Self> {
Self::new(None, calling_process_name, Some(prefs_id))
}

Expand All @@ -51,7 +51,7 @@ impl SCPreferences {
allocator: Option<&CFAllocator>,
calling_process_name: &CFString,
prefs_id: Option<&CFString>,
) -> Self {
) -> Option<Self> {
let allocator_ref = match allocator {
Some(allocator) => allocator.as_concrete_TypeRef(),
None => ptr::null(),
Expand All @@ -62,7 +62,7 @@ impl SCPreferences {
};

unsafe {
SCPreferences::wrap_under_create_rule(SCPreferencesCreate(
SCPreferences::try_wrap_under_create_rule(SCPreferencesCreate(
allocator_ref,
calling_process_name.as_concrete_TypeRef(),
prefs_id_ref,
Expand All @@ -77,7 +77,7 @@ mod tests {

#[test]
fn retain_count() {
let preferences = SCPreferences::default(&CFString::new("test"));
let preferences = SCPreferences::default(&CFString::new("test")).unwrap();
assert_eq!(preferences.retain_count(), 1);
}
}
Loading