1use std::rc::Rc;
2use std::fmt;
3
4use errors::*;
5use dbus_nm::DBusNetworkManager;
6
7use wifi::{new_wifi_device, WiFiDevice};
8
9#[derive(Clone)]
10pub struct Device {
11 dbus_manager: Rc<DBusNetworkManager>,
12 path: String,
13 interface: String,
14 device_type: DeviceType,
15}
16
17impl Device {
18 fn init(dbus_manager: &Rc<DBusNetworkManager>, path: &str) -> Result<Self> {
19 let interface = dbus_manager.get_device_interface(path)?;
20
21 let device_type = dbus_manager.get_device_type(path)?;
22
23 Ok(Device {
24 dbus_manager: Rc::clone(dbus_manager),
25 path: path.to_string(),
26 interface: interface,
27 device_type: device_type,
28 })
29 }
30
31 pub fn device_type(&self) -> &DeviceType {
32 &self.device_type
33 }
34
35 pub fn interface(&self) -> &str {
36 &self.interface
37 }
38
39 pub fn get_state(&self) -> Result<DeviceState> {
40 self.dbus_manager.get_device_state(&self.path)
41 }
42
43 pub fn as_wifi_device(&self) -> Option<WiFiDevice> {
44 if self.device_type == DeviceType::WiFi {
45 Some(new_wifi_device(&self.dbus_manager, self))
46 } else {
47 None
48 }
49 }
50
51 pub fn connect(&self) -> Result<DeviceState> {
63 let state = self.get_state()?;
64
65 match state {
66 DeviceState::Activated => Ok(DeviceState::Activated),
67 _ => {
68 self.dbus_manager.connect_device(&self.path)?;
69
70 wait(
71 self,
72 &DeviceState::Activated,
73 self.dbus_manager.method_timeout(),
74 )
75 },
76 }
77 }
78
79 pub fn disconnect(&self) -> Result<DeviceState> {
91 let state = self.get_state()?;
92
93 match state {
94 DeviceState::Disconnected => Ok(DeviceState::Disconnected),
95 _ => {
96 self.dbus_manager.disconnect_device(&self.path)?;
97
98 wait(
99 self,
100 &DeviceState::Disconnected,
101 self.dbus_manager.method_timeout(),
102 )
103 },
104 }
105 }
106}
107
108impl fmt::Debug for Device {
109 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
110 write!(
111 f,
112 "Device {{ path: {:?}, interface: {:?}, device_type: {:?} }}",
113 self.path, self.interface, self.device_type
114 )
115 }
116}
117
118pub trait PathGetter {
119 fn path(&self) -> &str;
120}
121
122impl PathGetter for Device {
123 fn path(&self) -> &str {
124 &self.path
125 }
126}
127
128#[derive(Clone, Debug, PartialEq)]
129pub enum DeviceType {
130 Unknown,
131 Ethernet,
132 WiFi,
133 Unused1,
134 Unused2,
135 Bt,
136 OlpcMesh,
137 Wimax,
138 Modem,
139 Infiniband,
140 Bond,
141 Vlan,
142 Adsl,
143 Bridge,
144 Generic,
145 Team,
146 Tun,
147 IpTunnel,
148 Macvlan,
149 Vxlan,
150 Veth,
151 Macsec,
152 Dummy,
153}
154
155impl From<i64> for DeviceType {
156 fn from(device_type: i64) -> Self {
157 match device_type {
158 0 => DeviceType::Unknown,
159 1 => DeviceType::Ethernet,
160 2 => DeviceType::WiFi,
161 3 => DeviceType::Unused1,
162 4 => DeviceType::Unused2,
163 5 => DeviceType::Bt,
164 6 => DeviceType::OlpcMesh,
165 7 => DeviceType::Wimax,
166 8 => DeviceType::Modem,
167 9 => DeviceType::Infiniband,
168 10 => DeviceType::Bond,
169 11 => DeviceType::Vlan,
170 12 => DeviceType::Adsl,
171 13 => DeviceType::Bridge,
172 14 => DeviceType::Generic,
173 15 => DeviceType::Team,
174 16 => DeviceType::Tun,
175 17 => DeviceType::IpTunnel,
176 18 => DeviceType::Macvlan,
177 19 => DeviceType::Vxlan,
178 20 => DeviceType::Veth,
179 21 => DeviceType::Macsec,
180 22 => DeviceType::Dummy,
181 _ => {
182 warn!("Undefined device type: {}", device_type);
183 DeviceType::Unknown
184 },
185 }
186 }
187}
188
189#[derive(Clone, Debug, PartialEq)]
190pub enum DeviceState {
191 Unknown,
192 Unmanaged,
193 Unavailable,
194 Disconnected,
195 Prepare,
196 Config,
197 NeedAuth,
198 IpConfig,
199 IpCheck,
200 Secondaries,
201 Activated,
202 Deactivating,
203 Failed,
204}
205
206impl From<i64> for DeviceState {
207 fn from(state: i64) -> Self {
208 match state {
209 0 => DeviceState::Unknown,
210 10 => DeviceState::Unmanaged,
211 20 => DeviceState::Unavailable,
212 30 => DeviceState::Disconnected,
213 40 => DeviceState::Prepare,
214 50 => DeviceState::Config,
215 60 => DeviceState::NeedAuth,
216 70 => DeviceState::IpConfig,
217 80 => DeviceState::IpCheck,
218 90 => DeviceState::Secondaries,
219 100 => DeviceState::Activated,
220 110 => DeviceState::Deactivating,
221 120 => DeviceState::Failed,
222 _ => {
223 warn!("Undefined device state: {}", state);
224 DeviceState::Unknown
225 },
226 }
227 }
228}
229
230pub fn get_devices(dbus_manager: &Rc<DBusNetworkManager>) -> Result<Vec<Device>> {
231 let device_paths = dbus_manager.get_devices()?;
232
233 let mut result = Vec::with_capacity(device_paths.len());
234
235 for path in device_paths {
236 let device = Device::init(dbus_manager, &path)?;
237
238 result.push(device);
239 }
240
241 Ok(result)
242}
243
244pub fn get_device_by_interface(
245 dbus_manager: &Rc<DBusNetworkManager>,
246 interface: &str,
247) -> Result<Device> {
248 let path = dbus_manager.get_device_by_interface(interface)?;
249
250 Device::init(dbus_manager, &path)
251}
252
253pub fn get_active_connection_devices(
254 dbus_manager: &Rc<DBusNetworkManager>,
255 active_path: &str,
256) -> Result<Vec<Device>> {
257 let device_paths = dbus_manager.get_active_connection_devices(active_path)?;
258
259 let mut result = Vec::with_capacity(device_paths.len());
260
261 for path in device_paths {
262 let device = Device::init(dbus_manager, &path)?;
263
264 result.push(device);
265 }
266
267 Ok(result)
268}
269
270fn wait(device: &Device, target_state: &DeviceState, timeout: u64) -> Result<DeviceState> {
271 if timeout == 0 {
272 return device.get_state();
273 }
274
275 debug!("Waiting for device state: {:?}", target_state);
276
277 let mut total_time = 0;
278
279 loop {
280 ::std::thread::sleep(::std::time::Duration::from_secs(1));
281
282 let state = device.get_state()?;
283
284 total_time += 1;
285
286 if state == *target_state {
287 debug!(
288 "Device target state reached: {:?} / {}s elapsed",
289 state, total_time
290 );
291
292 return Ok(state);
293 } else if total_time >= timeout {
294 debug!(
295 "Timeout reached in waiting for device state ({:?}): {:?} / {}s elapsed",
296 target_state, state, total_time
297 );
298
299 return Ok(state);
300 }
301
302 debug!(
303 "Still waiting for device state ({:?}): {:?} / {}s elapsed",
304 target_state, state, total_time
305 );
306 }
307}
308
309#[cfg(test)]
310mod tests {
311 use super::super::NetworkManager;
312
313 use super::*;
314
315 #[test]
316 fn test_device_connect_disconnect() {
317 let manager = NetworkManager::new();
318
319 let devices = manager.get_devices().unwrap();
320
321 let i = devices
322 .iter()
323 .position(|ref d| d.device_type == DeviceType::WiFi)
324 .unwrap();
325 let device = &devices[i];
326
327 let state = device.get_state().unwrap();
328
329 if state == DeviceState::Activated {
330 let state = device.disconnect().unwrap();
331 assert_eq!(DeviceState::Disconnected, state);
332
333 ::std::thread::sleep(::std::time::Duration::from_secs(5));
334
335 let state = device.connect().unwrap();
336 assert_eq!(DeviceState::Activated, state);
337
338 ::std::thread::sleep(::std::time::Duration::from_secs(5));
339 } else {
340 let state = device.connect().unwrap();
341 assert_eq!(DeviceState::Activated, state);
342
343 ::std::thread::sleep(::std::time::Duration::from_secs(5));
344
345 let state = device.disconnect().unwrap();
346 assert_eq!(DeviceState::Disconnected, state);
347
348 ::std::thread::sleep(::std::time::Duration::from_secs(5));
349 }
350 }
351}