Skip to content

Commit 290fc79

Browse files
committed
Merge branch 'improve-documentation'
2 parents 122586c + 46f526a commit 290fc79

File tree

9 files changed

+168
-126
lines changed

9 files changed

+168
-126
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
## SystemConfiguration bindings
2+
3+
This crate is a high level binding to the Apple [SystemConfiguration] framework. For low level
4+
FFI bindings, check out the [`system-configuration-sys`] crate.
5+
6+
This crate only implements a small part of the [SystemConfiguration] framework so far. If you
7+
need a yet unimplemented part, feel free to submit a pull request!
8+
9+
[SystemConfiguration]: https://developer.apple.com/documentation/systemconfiguration?language=objc
10+
[`system-configuration-sys`]: https://crates.io/crates/system-configuration-sys
11+
12+
License: MIT/Apache-2.0

system-configuration-sys/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
// option. This file may not be copied, modified, or distributed
77
// except according to those terms.
88

9+
//! Low level bindings to the Apple [SystemConfiguration] framework. Generated with bindgen.
10+
//! For a safe, higher level, API, check out the [`system-configuration`] crate.
11+
//!
12+
//! [SystemConfiguration]: https://developer.apple.com/documentation/systemconfiguration?language=objc
13+
//! [`system-configuration`]: https://crates.io/crates/system-configuration
14+
915
#![allow(non_camel_case_types)]
1016
#![allow(non_upper_case_globals)]
1117
#![allow(non_snake_case)]

system-configuration/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ keywords = ["macos", "system", "configuration", "bindings"]
77
categories = ["api-bindings", "os::macos-apis"]
88
repository = "https://github.com/mullvad/system-configuration-rs"
99
license = "MIT/Apache-2.0"
10+
readme = "../README.md"
1011

1112
[dependencies]
1213
core-foundation = "0.5"
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
extern crate system_configuration;
2+
3+
extern crate core_foundation;
4+
5+
use core_foundation::array::CFArray;
6+
use core_foundation::base::TCFType;
7+
use core_foundation::dictionary::CFDictionary;
8+
use core_foundation::propertylist::CFPropertyList;
9+
use core_foundation::string::{CFString, CFStringRef};
10+
11+
use system_configuration::dynamic_store::{SCDynamicStore, SCDynamicStoreBuilder};
12+
13+
// This example will change the DNS settings on the primary
14+
// network interface to 8.8.8.8 and 8.8.4.4
15+
16+
fn main() {
17+
let store = SCDynamicStoreBuilder::new("my-test-dyn-store").build();
18+
let primary_service_uuid = get_primary_service_uuid(&store).expect("No PrimaryService active");
19+
println!("PrimaryService UUID: {}", primary_service_uuid);
20+
21+
let primary_service_path = CFString::new(&format!(
22+
"State:/Network/Service/{}/DNS",
23+
primary_service_uuid
24+
));
25+
println!("PrimaryService path: {}", primary_service_path);
26+
27+
let dns_dictionary = create_dns_dictionary(&[
28+
CFString::from_static_string("8.8.8.8"),
29+
CFString::from_static_string("8.8.4.4"),
30+
]);
31+
32+
let success = store.set(primary_service_path, dns_dictionary);
33+
println!("success? {}", success);
34+
}
35+
36+
fn get_primary_service_uuid(store: &SCDynamicStore) -> Option<CFString> {
37+
let dictionary = store
38+
.get("State:/Network/Global/IPv4")
39+
.and_then(CFPropertyList::downcast_into::<CFDictionary>);
40+
if let Some(dictionary) = dictionary {
41+
dictionary
42+
.find2(&CFString::from_static_string("PrimaryService"))
43+
.map(|ptr| unsafe { CFString::wrap_under_get_rule(ptr as CFStringRef) })
44+
} else {
45+
None
46+
}
47+
}
48+
49+
fn create_dns_dictionary(addresses: &[CFString]) -> CFDictionary {
50+
let key = CFString::from_static_string("ServerAddresses");
51+
let value = CFArray::from_CFTypes(addresses);
52+
CFDictionary::from_CFType_pairs(&[(key, value)])
53+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
extern crate system_configuration;
2+
3+
extern crate core_foundation;
4+
5+
use core_foundation::array::CFArray;
6+
use core_foundation::base::{CFType, TCFType};
7+
use core_foundation::dictionary::CFDictionary;
8+
use core_foundation::propertylist::CFPropertyList;
9+
use core_foundation::runloop::{CFRunLoop, kCFRunLoopCommonModes};
10+
use core_foundation::string::CFString;
11+
12+
use system_configuration::dynamic_store::{SCDynamicStore, SCDynamicStoreBuilder,
13+
SCDynamicStoreCallBackContext};
14+
15+
// This example will watch the dynamic store for changes to any DNS setting. As soon as a change
16+
// is detected, it will be printed to stdout.
17+
18+
fn main() {
19+
let callback_context = SCDynamicStoreCallBackContext {
20+
callout: my_callback,
21+
info: Context { call_count: 0 },
22+
};
23+
24+
let store = SCDynamicStoreBuilder::new("my-watch-dns-store")
25+
.callback_context(callback_context)
26+
.build();
27+
28+
let watch_keys: CFArray<CFString> = CFArray::from_CFTypes(&[]);
29+
let watch_patterns =
30+
CFArray::from_CFTypes(&[CFString::from("(State|Setup):/Network/Service/.*/DNS")]);
31+
32+
if store.set_notification_keys(&watch_keys, &watch_patterns) {
33+
println!("Registered for notifications");
34+
} else {
35+
panic!("Unable to register notifications");
36+
}
37+
38+
let run_loop_source = store.create_run_loop_source();
39+
let run_loop = CFRunLoop::get_current();
40+
run_loop.add_source(&run_loop_source, unsafe { kCFRunLoopCommonModes });
41+
42+
println!("Entering run loop");
43+
CFRunLoop::run_current();
44+
}
45+
46+
/// This struct acts as a user provided context/payload to each notification callback.
47+
/// Here one can store any type of data or state needed in the callback function.
48+
#[derive(Debug)]
49+
struct Context {
50+
call_count: u64,
51+
}
52+
53+
fn my_callback(store: SCDynamicStore, changed_keys: CFArray<CFString>, context: &mut Context) {
54+
context.call_count += 1;
55+
println!("Callback call count: {}", context.call_count);
56+
57+
for key in changed_keys.iter() {
58+
if let Some(addresses) = get_dns(&store, key.clone()) {
59+
let addresses = addresses.iter().map(|s| s.to_string()).collect::<Vec<_>>();
60+
println!("{} changed DNS to {:?}", *key, addresses);
61+
} else {
62+
println!("{} removed DNS", *key);
63+
}
64+
}
65+
}
66+
67+
fn get_dns(store: &SCDynamicStore, path: CFString) -> Option<CFArray<CFString>> {
68+
let dictionary = store
69+
.get(path)
70+
.and_then(CFPropertyList::downcast_into::<CFDictionary>);
71+
if let Some(dictionary) = dictionary {
72+
dictionary
73+
.find2(&CFString::from_static_string("ServerAddresses"))
74+
.map(|ptr| unsafe { CFType::wrap_under_get_rule(ptr) })
75+
.and_then(CFType::downcast_into::<CFArray<CFString>>)
76+
} else {
77+
None
78+
}
79+
}

system-configuration/src/bin/set_dns.rs

Lines changed: 0 additions & 44 deletions
This file was deleted.

system-configuration/src/bin/watch_dns.rs

Lines changed: 0 additions & 82 deletions
This file was deleted.

system-configuration/src/dynamic_store.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
// option. This file may not be copied, modified, or distributed
77
// except according to those terms.
88

9+
//! Bindings to [`SCDynamicStore`].
10+
//!
11+
//! See the examples directory for examples how to use this module.
12+
//!
13+
//! [`SCDynamicStore`]: https://developer.apple.com/documentation/systemconfiguration/scdynamicstore?language=objc
14+
915
use core_foundation::array::{CFArray, CFArrayRef};
1016
use core_foundation::base::{TCFType, kCFAllocatorDefault};
1117
use core_foundation::boolean::CFBoolean;

system-configuration/src/lib.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@
66
// option. This file may not be copied, modified, or distributed
77
// except according to those terms.
88

9+
//! # SystemConfiguration bindings
10+
//!
11+
//! This crate is a high level binding to the Apple [SystemConfiguration] framework. For low level
12+
//! FFI bindings, check out the [`system-configuration-sys`] crate.
13+
//!
14+
//! This crate only implements a small part of the [SystemConfiguration] framework so far. If you
15+
//! need a yet unimplemented part, feel free to submit a pull request!
16+
//!
17+
//! [SystemConfiguration]: https://developer.apple.com/documentation/systemconfiguration?language=objc
18+
//! [`system-configuration-sys`]: https://crates.io/crates/system-configuration-sys
19+
920
#[macro_use]
1021
extern crate core_foundation;
1122
extern crate system_configuration_sys;

0 commit comments

Comments
 (0)