orb_network_manager/
device.rs

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    /// Connects a Network Manager device.
52    ///
53    /// Examples
54    ///
55    /// ```
56    /// use network_manager::{NetworkManager, DeviceType};
57    /// let manager = NetworkManager::new();
58    /// let devices = manager.get_devices().unwrap();
59    /// let i = devices.iter().position(|ref d| *d.device_type() == DeviceType::WiFi).unwrap();
60    /// devices[i].connect().unwrap();
61    /// ```
62    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    /// Disconnect a Network Manager device.
80    ///
81    /// # Examples
82    ///
83    /// ```
84    /// use network_manager::{NetworkManager, DeviceType};
85    /// let manager = NetworkManager::new();
86    /// let devices = manager.get_devices().unwrap();
87    /// let i = devices.iter().position(|ref d| *d.device_type() == DeviceType::WiFi).unwrap();
88    /// devices[i].disconnect().unwrap();
89    /// ```
90    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}