1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
// Take a look at the license at the top of the repository in the LICENSE file.
#[cfg(not(docsrs))]
use std::ffi::OsStr;
#[cfg(unix)]
#[cfg(not(docsrs))]
use std::os::unix::ffi::OsStrExt;
use std::{path, ptr, slice};
use glib::translate::*;
use crate::{prelude::*, SocketAddress, UnixSocketAddress, UnixSocketAddressType};
#[derive(Debug)]
pub enum UnixSocketAddressPath<'a> {
Path(&'a path::Path),
Anonymous,
Abstract(&'a [u8]),
AbstractPadded(&'a [u8]),
}
impl<'a> UnixSocketAddressPath<'a> {
fn to_type(&self) -> UnixSocketAddressType {
use self::UnixSocketAddressPath::*;
match *self {
Path(_) => UnixSocketAddressType::Path,
Anonymous => UnixSocketAddressType::Anonymous,
Abstract(_) => UnixSocketAddressType::Abstract,
AbstractPadded(_) => UnixSocketAddressType::AbstractPadded,
}
}
}
impl UnixSocketAddress {
/// Creates a new #GUnixSocketAddress for @path.
///
/// To create abstract socket addresses, on systems that support that,
/// use g_unix_socket_address_new_abstract().
/// ## `path`
/// the socket path
///
/// # Returns
///
/// a new #GUnixSocketAddress
#[doc(alias = "g_unix_socket_address_new")]
pub fn new(path: &path::Path) -> UnixSocketAddress {
unsafe {
SocketAddress::from_glib_full(ffi::g_unix_socket_address_new(path.to_glib_none().0))
.unsafe_cast()
}
}
/// Creates a new #GUnixSocketAddress of type @type_ with name @path.
///
/// If @type_ is [`UnixSocketAddressType::Path`][crate::UnixSocketAddressType::Path], this is equivalent to
/// calling g_unix_socket_address_new().
///
/// If @type_ is [`UnixSocketAddressType::Anonymous`][crate::UnixSocketAddressType::Anonymous], @path and @path_len will be
/// ignored.
///
/// If @path_type is [`UnixSocketAddressType::Abstract`][crate::UnixSocketAddressType::Abstract], then @path_len
/// bytes of @path will be copied to the socket's path, and only those
/// bytes will be considered part of the name. (If @path_len is -1,
/// then @path is assumed to be NUL-terminated.) For example, if @path
/// was "test", then calling g_socket_address_get_native_size() on the
/// returned socket would return 7 (2 bytes of overhead, 1 byte for the
/// abstract-socket indicator byte, and 4 bytes for the name "test").
///
/// If @path_type is [`UnixSocketAddressType::AbstractPadded`][crate::UnixSocketAddressType::AbstractPadded], then
/// @path_len bytes of @path will be copied to the socket's path, the
/// rest of the path will be padded with 0 bytes, and the entire
/// zero-padded buffer will be considered the name. (As above, if
/// @path_len is -1, then @path is assumed to be NUL-terminated.) In
/// this case, g_socket_address_get_native_size() will always return
/// the full size of a `struct sockaddr_un`, although
/// g_unix_socket_address_get_path_len() will still return just the
/// length of @path.
///
/// [`UnixSocketAddressType::Abstract`][crate::UnixSocketAddressType::Abstract] is preferred over
/// [`UnixSocketAddressType::AbstractPadded`][crate::UnixSocketAddressType::AbstractPadded] for new programs. Of course,
/// when connecting to a server created by another process, you must
/// use the appropriate type corresponding to how that process created
/// its listening socket.
/// ## `path`
/// the name
/// ## `type_`
/// a #GUnixSocketAddressType
///
/// # Returns
///
/// a new #GUnixSocketAddress
#[doc(alias = "g_unix_socket_address_new_with_type")]
pub fn with_type(address_type: UnixSocketAddressPath) -> Self {
use self::UnixSocketAddressPath::*;
let type_ = address_type.to_type();
let new = |ptr, len| unsafe {
SocketAddress::from_glib_full(ffi::g_unix_socket_address_new_with_type(
ptr,
len,
type_.into_glib(),
))
.unsafe_cast()
};
match address_type {
Path(path) => new(path.to_glib_none().0, -1),
Abstract(path) | AbstractPadded(path) => new(
path.to_glib_none().0 as *mut libc::c_char,
path.len() as i32,
),
Anonymous => new(ptr::null_mut(), 0),
}
}
}
mod sealed {
pub trait Sealed {}
impl<T: super::IsA<super::UnixSocketAddress>> Sealed for T {}
}
pub trait UnixSocketAddressExtManual: sealed::Sealed + IsA<UnixSocketAddress> + 'static {
/// Gets @self's path, or for abstract sockets the "name".
///
/// Guaranteed to be zero-terminated, but an abstract socket
/// may contain embedded zeros, and thus you should use
/// g_unix_socket_address_get_path_len() to get the true length
/// of this string.
///
/// # Returns
///
/// the path for @self
#[doc(alias = "g_unix_socket_address_get_path")]
#[doc(alias = "get_path")]
fn path(&self) -> Option<UnixSocketAddressPath> {
use self::UnixSocketAddressPath::*;
let path = unsafe {
let path = ffi::g_unix_socket_address_get_path(self.as_ref().to_glib_none().0);
if path.is_null() || self.path_len() == 0 {
&[]
} else {
slice::from_raw_parts(path as *const u8, self.path_len())
}
};
match self.address_type() {
UnixSocketAddressType::Anonymous => Some(Anonymous),
#[cfg(not(docsrs))]
UnixSocketAddressType::Path => Some(Path(path::Path::new(OsStr::from_bytes(path)))),
#[cfg(docsrs)]
UnixSocketAddressType::Path => unreachable!(),
UnixSocketAddressType::Abstract => Some(Abstract(path)),
UnixSocketAddressType::AbstractPadded => Some(AbstractPadded(path)),
UnixSocketAddressType::Invalid | UnixSocketAddressType::__Unknown(_) => None,
}
}
}
impl<O: IsA<UnixSocketAddress>> UnixSocketAddressExtManual for O {}
#[cfg(test)]
mod test {
use super::*;
// Check the actual path and len are correct and are not the underlying OsString
#[test]
fn check_path() {
let mut os_string = std::ffi::OsString::with_capacity(100);
os_string.push("/tmp/foo");
let path = os_string.as_ref();
let addr = UnixSocketAddress::new(path);
assert_eq!(addr.path_len(), 8);
assert_eq!(addr.path_as_array().unwrap().as_ref(), b"/tmp/foo");
let addr = UnixSocketAddress::with_type(UnixSocketAddressPath::Path(path));
assert_eq!(addr.path_len(), 8);
assert_eq!(addr.path_as_array().unwrap().as_ref(), b"/tmp/foo");
}
}