1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use std::ffi::OsStr;
15 use std::io::{Error, ErrorKind, Result};
16 use std::os::unix::ffi::OsStrExt;
17 use std::path::Path;
18 use std::{ascii, fmt};
19 
sun_path_offset(sockaddr: &libc::sockaddr_un) -> usize20 fn sun_path_offset(sockaddr: &libc::sockaddr_un) -> usize {
21     let path = &sockaddr.sun_path as *const _ as usize;
22     let base = sockaddr as *const _ as usize;
23     path - base
24 }
25 
socket_addr_trans_un(path: &Path) -> Result<(libc::sockaddr_un, libc::socklen_t)>26 pub(crate) fn socket_addr_trans_un(path: &Path) -> Result<(libc::sockaddr_un, libc::socklen_t)> {
27     let sockaddr: std::mem::MaybeUninit<libc::sockaddr_un> =
28         std::mem::MaybeUninit::<libc::sockaddr_un>::zeroed();
29 
30     let mut sockaddr = unsafe { sockaddr.assume_init() };
31 
32     sockaddr.sun_family = libc::AF_UNIX as libc::sa_family_t;
33 
34     let bytes = path.as_os_str().as_bytes();
35     if bytes.first() == Some(&0) {
36         return Err(Error::new(
37             ErrorKind::InvalidInput,
38             "paths must not start with interior null bytes",
39         ));
40     }
41     // Checks path len.
42     if bytes.len() >= sockaddr.sun_path.len() {
43         return Err(Error::new(
44             ErrorKind::InvalidInput,
45             "path must be shorter than libc::sockaddr_un.sun_path",
46         ));
47     }
48 
49     for (dest, source) in sockaddr.sun_path.iter_mut().zip(bytes.iter()) {
50         *dest = *source as libc::c_char;
51     }
52 
53     let mut socklen = sun_path_offset(&sockaddr) + bytes.len();
54 
55     match bytes.first() {
56         Some(&0) | None => {}
57         Some(_) => socklen += 1,
58     }
59 
60     Ok((sockaddr, socklen as libc::socklen_t))
61 }
62 
63 /// This structure is necessary because the `socketaddr` returned
64 /// when the `listener` calls `accept` cannot be derived from `std`.
65 pub struct SocketAddr {
66     sockaddr: libc::sockaddr_un,
67     socklen: libc::socklen_t,
68 }
69 
70 impl SocketAddr {
from_parts(sockaddr: libc::sockaddr_un, socklen: libc::socklen_t) -> SocketAddr71     pub(crate) fn from_parts(sockaddr: libc::sockaddr_un, socklen: libc::socklen_t) -> SocketAddr {
72         SocketAddr { sockaddr, socklen }
73     }
74 }
75 
76 impl fmt::Debug for SocketAddr {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result77     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
78         let offset = sun_path_offset(&self.sockaddr);
79         if (self.socklen as usize) < offset {
80             return write!(fmt, "(unnamed)");
81         }
82         let len = self.socklen as usize - offset;
83         let path = unsafe { &*(&self.sockaddr.sun_path as *const [libc::c_char] as *const [u8]) };
84 
85         if len == 0 || (cfg!(not(target_os = "linux")) && self.sockaddr.sun_path[0] == 0) {
86             write!(fmt, "(unnamed)")
87         } else if self.sockaddr.sun_path[0] == 0 {
88             write!(fmt, "\"")?;
89             let name = &path[1..len];
90             for byte in name.iter().cloned().flat_map(ascii::escape_default) {
91                 write!(fmt, "{}", byte as char)?;
92             }
93             write!(fmt, "\"(abstract)")
94         } else {
95             write!(
96                 fmt,
97                 "{:?} (pathname)",
98                 <std::ffi::OsStr as std::convert::AsRef<Path>>::as_ref(OsStr::from_bytes(
99                     &path[..len - 1]
100                 ))
101             )
102         }
103     }
104 }
105 
106 #[cfg(test)]
107 mod test {
108     use crate::SocketAddr;
109 
110     /// UT for uds sockaddr debug info
111     ///
112     /// # Brief
113     /// 1. Create an UDS socket address
114     /// 2. Check if the debug info is correct
115     #[test]
ut_uds_socket_addr_debug_info()116     fn ut_uds_socket_addr_debug_info() {
117         let sock_addr = libc::sockaddr_un {
118             sun_family: 1,
119             sun_path: [2; 108],
120         };
121 
122         let addr = SocketAddr::from_parts(sock_addr, 10);
123         let fmt = format!("{addr:?}");
124         assert!(fmt.contains("\"\\u{2}\\u{2}\\u{2}\\u{2}\\u{2}\\u{2}\\u{2}\" (pathname)"));
125     }
126 }
127