1use std::{
2 ffi::c_void,
3 sync::{Arc, Mutex},
4};
5
6use crate::{bridge, error::Result, ffi, PropertyList, ReachabilityFlags};
7
8pub type NetworkConnectionFlags = ReachabilityFlags;
9
10#[derive(Clone, Copy, Debug, Eq, PartialEq)]
11pub enum NetworkConnectionStatus {
12 Invalid,
13 Disconnected,
14 Connecting,
15 Connected,
16 Disconnecting,
17 Unknown(i32),
18}
19
20impl NetworkConnectionStatus {
21 pub const fn from_raw(raw: i32) -> Self {
22 match raw {
23 -1 => Self::Invalid,
24 0 => Self::Disconnected,
25 1 => Self::Connecting,
26 2 => Self::Connected,
27 3 => Self::Disconnecting,
28 other => Self::Unknown(other),
29 }
30 }
31
32 pub const fn raw_value(self) -> i32 {
33 match self {
34 Self::Invalid => -1,
35 Self::Disconnected => 0,
36 Self::Connecting => 1,
37 Self::Connected => 2,
38 Self::Disconnecting => 3,
39 Self::Unknown(raw) => raw,
40 }
41 }
42}
43
44#[derive(Clone, Copy, Debug, Eq, PartialEq)]
45pub enum NetworkConnectionPppStatus {
46 Disconnected,
47 Initializing,
48 ConnectingLink,
49 DialOnTraffic,
50 NegotiatingLink,
51 Authenticating,
52 WaitingForCallback,
53 NegotiatingNetwork,
54 Connected,
55 Terminating,
56 DisconnectingLink,
57 HoldingLinkOff,
58 Suspended,
59 WaitingForRedial,
60 Unknown(i32),
61}
62
63impl NetworkConnectionPppStatus {
64 pub const fn from_raw(raw: i32) -> Self {
65 match raw {
66 0 => Self::Disconnected,
67 1 => Self::Initializing,
68 2 => Self::ConnectingLink,
69 3 => Self::DialOnTraffic,
70 4 => Self::NegotiatingLink,
71 5 => Self::Authenticating,
72 6 => Self::WaitingForCallback,
73 7 => Self::NegotiatingNetwork,
74 8 => Self::Connected,
75 9 => Self::Terminating,
76 10 => Self::DisconnectingLink,
77 11 => Self::HoldingLinkOff,
78 12 => Self::Suspended,
79 13 => Self::WaitingForRedial,
80 other => Self::Unknown(other),
81 }
82 }
83
84 pub const fn raw_value(self) -> i32 {
85 match self {
86 Self::Disconnected => 0,
87 Self::Initializing => 1,
88 Self::ConnectingLink => 2,
89 Self::DialOnTraffic => 3,
90 Self::NegotiatingLink => 4,
91 Self::Authenticating => 5,
92 Self::WaitingForCallback => 6,
93 Self::NegotiatingNetwork => 7,
94 Self::Connected => 8,
95 Self::Terminating => 9,
96 Self::DisconnectingLink => 10,
97 Self::HoldingLinkOff => 11,
98 Self::Suspended => 12,
99 Self::WaitingForRedial => 13,
100 Self::Unknown(raw) => raw,
101 }
102 }
103}
104
105#[derive(Clone, Debug)]
106pub struct NetworkConnectionUserPreferences {
107 pub service_id: String,
108 pub user_options: Option<PropertyList>,
109}
110
111struct CallbackState {
112 callback: Box<dyn FnMut(NetworkConnectionStatus) + Send>,
113}
114
115unsafe extern "C" fn network_connection_callback(status: i32, info: *mut c_void) {
116 if info.is_null() {
117 return;
118 }
119
120 let mutex = &*info.cast::<Mutex<CallbackState>>();
121 if let Ok(mut state) = mutex.lock() {
122 (state.callback)(NetworkConnectionStatus::from_raw(status));
123 }
124}
125
126#[derive(Clone)]
127pub struct NetworkConnection {
128 raw: bridge::OwnedHandle,
129 _callback: Option<Arc<Mutex<CallbackState>>>,
130}
131
132impl std::fmt::Debug for NetworkConnection {
133 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
134 f.debug_struct("NetworkConnection").finish_non_exhaustive()
135 }
136}
137
138impl NetworkConnection {
139 pub fn type_id() -> u64 {
140 unsafe { ffi::network_connection::sc_network_connection_get_type_id() }
141 }
142
143 pub fn with_service_id(service_id: &str) -> Result<Self> {
144 Self::create(service_id, None)
145 }
146
147 pub fn with_service_id_and_callback<F>(service_id: &str, callback: F) -> Result<Self>
148 where
149 F: FnMut(NetworkConnectionStatus) + Send + 'static,
150 {
151 let state = Arc::new(Mutex::new(CallbackState {
152 callback: Box::new(callback),
153 }));
154 Self::create(service_id, Some(state))
155 }
156
157 fn create(service_id: &str, callback: Option<Arc<Mutex<CallbackState>>>) -> Result<Self> {
158 let service_id =
159 bridge::cstring(service_id, "sc_network_connection_create_with_service_id")?;
160 let raw = unsafe {
161 ffi::network_connection::sc_network_connection_create_with_service_id(
162 service_id.as_ptr(),
163 callback
164 .as_ref()
165 .map(|_| network_connection_callback as unsafe extern "C" fn(i32, *mut c_void)),
166 callback.as_ref().map_or(std::ptr::null_mut(), |state| {
167 Arc::as_ptr(state).cast_mut().cast::<c_void>()
168 }),
169 )
170 };
171 let raw =
172 bridge::owned_handle_or_last("sc_network_connection_create_with_service_id", raw)?;
173 Ok(Self {
174 raw,
175 _callback: callback,
176 })
177 }
178
179 pub fn copy_user_preferences() -> Result<NetworkConnectionUserPreferences> {
180 let service_id = bridge::take_optional_string(unsafe {
181 ffi::network_connection::sc_network_connection_copy_user_preferences_service_id()
182 })
183 .ok_or_else(|| {
184 crate::SystemConfigurationError::last(
185 "sc_network_connection_copy_user_preferences_service_id",
186 )
187 })?;
188 let user_options = unsafe {
189 bridge::OwnedHandle::from_raw(
190 ffi::network_connection::sc_network_connection_copy_user_preferences_user_options(),
191 )
192 }
193 .map(PropertyList::from_owned_handle);
194 Ok(NetworkConnectionUserPreferences {
195 service_id,
196 user_options,
197 })
198 }
199
200 pub fn service_id(&self) -> Result<Option<String>> {
201 Ok(bridge::take_optional_string(unsafe {
202 ffi::network_connection::sc_network_connection_copy_service_id(self.raw.as_ptr())
203 }))
204 }
205
206 pub fn status(&self) -> NetworkConnectionStatus {
207 NetworkConnectionStatus::from_raw(unsafe {
208 ffi::network_connection::sc_network_connection_get_status(self.raw.as_ptr())
209 })
210 }
211
212 pub fn extended_status(&self) -> Option<PropertyList> {
213 unsafe {
214 bridge::OwnedHandle::from_raw(
215 ffi::network_connection::sc_network_connection_copy_extended_status(
216 self.raw.as_ptr(),
217 ),
218 )
219 }
220 .map(PropertyList::from_owned_handle)
221 }
222
223 pub fn statistics(&self) -> Option<PropertyList> {
224 unsafe {
225 bridge::OwnedHandle::from_raw(
226 ffi::network_connection::sc_network_connection_copy_statistics(self.raw.as_ptr()),
227 )
228 }
229 .map(PropertyList::from_owned_handle)
230 }
231
232 pub fn user_options(&self) -> Option<PropertyList> {
233 unsafe {
234 bridge::OwnedHandle::from_raw(
235 ffi::network_connection::sc_network_connection_copy_user_options(self.raw.as_ptr()),
236 )
237 }
238 .map(PropertyList::from_owned_handle)
239 }
240
241 pub fn start(&self, user_options: Option<&PropertyList>, linger: bool) -> Result<()> {
242 let ok = unsafe {
243 ffi::network_connection::sc_network_connection_start(
244 self.raw.as_ptr(),
245 user_options.map_or(std::ptr::null_mut(), PropertyList::as_ptr),
246 u8::from(linger),
247 )
248 };
249 bridge::bool_result("sc_network_connection_start", ok)
250 }
251
252 pub fn stop(&self, force_disconnect: bool) -> Result<()> {
253 let ok = unsafe {
254 ffi::network_connection::sc_network_connection_stop(
255 self.raw.as_ptr(),
256 u8::from(force_disconnect),
257 )
258 };
259 bridge::bool_result("sc_network_connection_stop", ok)
260 }
261
262 pub fn schedule_with_run_loop_current(&self) -> Result<()> {
263 let ok = unsafe {
264 ffi::network_connection::sc_network_connection_schedule_with_run_loop_current(
265 self.raw.as_ptr(),
266 )
267 };
268 bridge::bool_result("sc_network_connection_schedule_with_run_loop_current", ok)
269 }
270
271 pub fn unschedule_from_run_loop_current(&self) -> Result<()> {
272 let ok = unsafe {
273 ffi::network_connection::sc_network_connection_unschedule_from_run_loop_current(
274 self.raw.as_ptr(),
275 )
276 };
277 bridge::bool_result("sc_network_connection_unschedule_from_run_loop_current", ok)
278 }
279
280 pub fn set_dispatch_queue_global(&self) -> Result<()> {
281 let ok = unsafe {
282 ffi::network_connection::sc_network_connection_set_dispatch_queue_global(
283 self.raw.as_ptr(),
284 )
285 };
286 bridge::bool_result("sc_network_connection_set_dispatch_queue_global", ok)
287 }
288
289 pub fn clear_dispatch_queue(&self) -> Result<()> {
290 let ok = unsafe {
291 ffi::network_connection::sc_network_connection_clear_dispatch_queue(self.raw.as_ptr())
292 };
293 bridge::bool_result("sc_network_connection_clear_dispatch_queue", ok)
294 }
295}