librqbit_dualstack_sockets/
bind_device.rs1#[cfg(test)]
2mod tests;
3
4use crate::Error;
5use std::{ffi::CString, num::NonZeroU32, str::FromStr};
6
7#[derive(Debug)]
8pub struct BindDevice {
9 #[allow(unused)]
10 index: NonZeroU32,
11 #[allow(unused)]
12 name: CString,
13}
14
15impl BindDevice {
16 #[cfg(not(windows))]
17 pub fn new_from_name(name: &str) -> crate::Result<Self> {
18 let name = CString::new(name).map_err(|_| Error::BindDeviceInvalid)?;
19
20 let index = unsafe { libc::if_nametoindex(name.as_ptr()) };
21 let index = NonZeroU32::new(index)
22 .ok_or_else(|| Error::BindDeviceInvalidError(std::io::Error::last_os_error()))?;
23 Ok(Self { index, name })
24 }
25
26 #[cfg(windows)]
27 pub fn new_from_name(name: &str) -> crate::Result<Self> {
28 Err(Error::BindDeviceNotSupported)
29 }
30
31 #[cfg(target_os = "macos")]
32 pub fn bind_sref(&self, sref: &socket2::Socket, is_v6: bool) -> crate::Result<()> {
33 if is_v6 {
34 sref.bind_device_by_index_v6(Some(self.index))
35 .map_err(Error::BindDeviceSetDeviceError)
36 } else {
37 sref.bind_device_by_index_v4(Some(self.index))
38 .map_err(Error::BindDeviceSetDeviceError)
39 }
40 }
41
42 #[cfg(not(any(target_os = "macos", windows)))]
43 pub fn bind_sref(&self, sref: &socket2::Socket, _is_v6: bool) -> crate::Result<()> {
44 let name = self.name.as_bytes();
45 sref.bind_device(Some(name))
46 .map_err(Error::BindDeviceSetDeviceError)
47 }
48
49 #[cfg(windows)]
50 pub fn bind_sref(&self, _sref: &socket2::Socket, _is_v6: bool) -> crate::Result<()> {
51 Err(Error::BindDeviceNotSupported)
52 }
53}
54
55impl FromStr for BindDevice {
56 type Err = crate::Error;
57
58 fn from_str(s: &str) -> Result<Self, Self::Err> {
59 Self::new_from_name(s)
60 }
61}