Skip to content

Commit 5df2d06

Browse files
committed
Merge branch 'add-service-order-code'
2 parents 1bc323a + 37aab08 commit 5df2d06

File tree

2 files changed

+137
-1
lines changed

2 files changed

+137
-1
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ Line wrap the file at 100 chars. Th
2222

2323

2424
## [Unreleased]
25+
### Added
26+
- Add bindings for `SCNetworkSet` and `SCNetworkService`
27+
2528
### Changed
2629
- Bump minimum supported Rust version to 1.56.0
2730

system-configuration/src/network_configuration.rs

Lines changed: 134 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
//! Bindings for [`SCNetworkConfiguration`].
22
//!
33
//! [`SCNetworkConfiguration`]: https://developer.apple.com/documentation/systemconfiguration/scnetworkconfiguration?language=objc
4-
use core_foundation::{array::CFArray, base::TCFType, string::CFString};
4+
use core_foundation::{
5+
array::CFArray,
6+
base::{TCFType, ToVoid},
7+
string::CFString,
8+
};
59
use system_configuration_sys::network_configuration::{
610
SCNetworkInterfaceCopyAll, SCNetworkInterfaceGetBSDName, SCNetworkInterfaceGetInterfaceType,
711
SCNetworkInterfaceGetLocalizedDisplayName, SCNetworkInterfaceGetTypeID, SCNetworkInterfaceRef,
12+
SCNetworkServiceCopyAll, SCNetworkServiceGetEnabled, SCNetworkServiceGetInterface,
13+
SCNetworkServiceGetServiceID, SCNetworkServiceGetTypeID, SCNetworkServiceRef,
14+
SCNetworkSetCopyCurrent, SCNetworkSetGetServiceOrder, SCNetworkSetGetTypeID, SCNetworkSetRef,
815
};
916

17+
use crate::preferences::SCPreferences;
18+
1019
core_foundation::declare_TCFType!(
1120
/// Represents a network interface.
1221
///
@@ -189,6 +198,108 @@ pub fn get_interfaces() -> CFArray<SCNetworkInterface> {
189198
unsafe { CFArray::<SCNetworkInterface>::wrap_under_create_rule(SCNetworkInterfaceCopyAll()) }
190199
}
191200

201+
core_foundation::declare_TCFType!(
202+
/// Represents a network service.
203+
///
204+
/// See [`SCNetworkInterfaceRef`] and its [methods] for details.
205+
///
206+
/// [`SCNetworkInterfaceRef`]: https://developer.apple.com/documentation/systemconfiguration/scnetworkserviceref?language=objc
207+
/// [methods]: https://developer.apple.com/documentation/systemconfiguration/scnetworkconfiguration?language=objc
208+
SCNetworkService,
209+
SCNetworkServiceRef
210+
);
211+
212+
core_foundation::impl_TCFType!(
213+
SCNetworkService,
214+
SCNetworkServiceRef,
215+
SCNetworkServiceGetTypeID
216+
);
217+
218+
impl SCNetworkService {
219+
/// Returns an array of all network services
220+
pub fn get_services(prefs: &SCPreferences) -> CFArray<Self> {
221+
unsafe {
222+
let array_ptr = SCNetworkServiceCopyAll(prefs.to_void());
223+
if array_ptr.is_null() {
224+
return create_empty_array();
225+
}
226+
CFArray::<Self>::wrap_under_create_rule(array_ptr)
227+
}
228+
}
229+
230+
/// Returns true if the network service is currently enabled
231+
pub fn enabled(&self) -> bool {
232+
unsafe { SCNetworkServiceGetEnabled(self.0) == 0 }
233+
}
234+
235+
/// Returns the network interface backing this network service, if it has one.
236+
pub fn network_interface(&self) -> Option<SCNetworkInterface> {
237+
unsafe {
238+
let ptr = SCNetworkServiceGetInterface(self.0);
239+
if ptr.is_null() {
240+
None
241+
} else {
242+
Some(SCNetworkInterface::wrap_under_get_rule(ptr))
243+
}
244+
}
245+
}
246+
247+
/// Returns the service identifier.
248+
pub fn id(&self) -> Option<CFString> {
249+
unsafe {
250+
let ptr = SCNetworkServiceGetServiceID(self.0);
251+
if ptr.is_null() {
252+
None
253+
} else {
254+
Some(CFString::wrap_under_get_rule(ptr))
255+
}
256+
}
257+
}
258+
}
259+
260+
core_foundation::declare_TCFType!(
261+
/// Represents a complete network configuration for a particular host.
262+
///
263+
/// See [`SCNetworkSet`] for details.
264+
///
265+
/// [`SCNetworkSet`]: https://developer.apple.com/documentation/systemconfiguration/scnetworksetref?language=objc
266+
SCNetworkSet,
267+
SCNetworkSetRef
268+
);
269+
270+
core_foundation::impl_TCFType!(SCNetworkSet, SCNetworkSetRef, SCNetworkSetGetTypeID);
271+
272+
impl SCNetworkSet {
273+
/// Constructs a new set of network services from the preferences.
274+
pub fn new(prefs: &SCPreferences) -> Self {
275+
let ptr = unsafe { SCNetworkSetCopyCurrent(prefs.to_void()) };
276+
unsafe { SCNetworkSet::wrap_under_create_rule(ptr) }
277+
}
278+
279+
/// Returns an list of network service identifiers, ordered by their priority.
280+
pub fn service_order(&self) -> CFArray<CFString> {
281+
unsafe {
282+
let array_ptr = SCNetworkSetGetServiceOrder(self.0);
283+
if array_ptr.is_null() {
284+
return create_empty_array();
285+
}
286+
CFArray::<CFString>::wrap_under_get_rule(array_ptr)
287+
}
288+
}
289+
}
290+
291+
fn create_empty_array<T>() -> CFArray<T> {
292+
use std::ptr::null;
293+
unsafe {
294+
CFArray::wrap_under_create_rule(core_foundation::array::CFArrayCreate(
295+
null() as *const _,
296+
null() as *const _,
297+
0,
298+
null() as *const _,
299+
))
300+
}
301+
}
302+
192303
#[cfg(test)]
193304
mod test {
194305
use super::*;
@@ -211,4 +322,26 @@ mod test {
211322
}
212323
}
213324
}
325+
326+
#[test]
327+
fn test_service_order() {
328+
let prefs = SCPreferences::default(&CFString::new("test"));
329+
let services = SCNetworkService::get_services(&prefs);
330+
let set = SCNetworkSet::new(&prefs);
331+
let service_order = set.service_order();
332+
333+
assert!(service_order.iter().all(|service_id| {
334+
services
335+
.iter()
336+
.find(|service| service.id().as_ref() == Some(&*service_id))
337+
.is_some()
338+
}))
339+
}
340+
341+
#[test]
342+
fn test_empty_array() {
343+
let empty = create_empty_array::<CFString>();
344+
let values = empty.get_all_values();
345+
assert!(values.is_empty())
346+
}
214347
}

0 commit comments

Comments
 (0)