• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::io;
6 use std::net::SocketAddrV4;
7 use std::net::SocketAddrV6;
8 use std::os::fd::RawFd;
9 use std::os::unix::ffi::OsStrExt;
10 use std::os::unix::net::UnixDatagram;
11 use std::os::unix::net::UnixListener;
12 use std::os::unix::net::UnixStream;
13 use std::path::Path;
14 use std::ptr::null_mut;
15 
16 use libc::c_int;
17 use libc::in6_addr;
18 use libc::in_addr;
19 use libc::msghdr;
20 use libc::sa_family_t;
21 use libc::sendmsg;
22 use libc::sockaddr_in;
23 use libc::sockaddr_in6;
24 use libc::ssize_t;
25 use libc::AF_INET;
26 use libc::AF_INET6;
27 use libc::MSG_NOSIGNAL;
28 use libc::SOCK_CLOEXEC;
29 use libc::SOCK_STREAM;
30 
31 use crate::descriptor::AsRawDescriptor;
32 use crate::descriptor::FromRawDescriptor;
33 use crate::unix::net::socket;
34 use crate::unix::net::socketpair;
35 use crate::unix::net::sun_path_offset;
36 use crate::unix::net::InetVersion;
37 use crate::unix::net::TcpSocket;
38 use crate::SafeDescriptor;
39 use crate::ScmSocket;
40 use crate::UnixSeqpacket;
41 use crate::UnixSeqpacketListener;
42 
sendmsg_nosignal( fd: RawFd, msg: *const msghdr, flags: c_int, ) -> ssize_t43 pub(in crate::sys) unsafe fn sendmsg_nosignal(
44     fd: RawFd,
45     msg: *const msghdr,
46     flags: c_int,
47 ) -> ssize_t {
48     sendmsg(fd, msg, flags | MSG_NOSIGNAL)
49 }
50 
sockaddrv4_to_lib_c(s: &SocketAddrV4) -> sockaddr_in51 pub(in crate::sys) fn sockaddrv4_to_lib_c(s: &SocketAddrV4) -> sockaddr_in {
52     sockaddr_in {
53         sin_family: AF_INET as sa_family_t,
54         sin_port: s.port().to_be(),
55         sin_addr: in_addr {
56             s_addr: u32::from_ne_bytes(s.ip().octets()),
57         },
58         sin_zero: [0; 8],
59     }
60 }
61 
sockaddrv6_to_lib_c(s: &SocketAddrV6) -> sockaddr_in662 pub(in crate::sys) fn sockaddrv6_to_lib_c(s: &SocketAddrV6) -> sockaddr_in6 {
63     sockaddr_in6 {
64         sin6_family: AF_INET6 as sa_family_t,
65         sin6_port: s.port().to_be(),
66         sin6_flowinfo: 0,
67         sin6_addr: in6_addr {
68             s6_addr: s.ip().octets(),
69         },
70         sin6_scope_id: 0,
71     }
72 }
73 
74 // Return `sockaddr_un` for a given `path`
sockaddr_un<P: AsRef<Path>>( path: P, ) -> io::Result<(libc::sockaddr_un, libc::socklen_t)>75 pub(in crate::sys) fn sockaddr_un<P: AsRef<Path>>(
76     path: P,
77 ) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
78     let mut addr = libc::sockaddr_un {
79         sun_family: libc::AF_UNIX as libc::sa_family_t,
80         sun_path: std::array::from_fn(|_| 0),
81     };
82 
83     // Check if the input path is valid. Since
84     // * The pathname in sun_path should be null-terminated.
85     // * The length of the pathname, including the terminating null byte, should not exceed the size
86     //   of sun_path.
87     //
88     // and our input is a `Path`, we only need to check
89     // * If the string size of `Path` should less than sizeof(sun_path)
90     // and make sure `sun_path` ends with '\0' by initialized the sun_path with zeros.
91     //
92     // Empty path name is valid since abstract socket address has sun_paht[0] = '\0'
93     let bytes = path.as_ref().as_os_str().as_bytes();
94     if bytes.len() >= addr.sun_path.len() {
95         return Err(io::Error::new(
96             io::ErrorKind::InvalidInput,
97             "Input path size should be less than the length of sun_path.",
98         ));
99     };
100 
101     // Copy data from `path` to `addr.sun_path`
102     for (dst, src) in addr.sun_path.iter_mut().zip(bytes) {
103         *dst = *src as libc::c_char;
104     }
105 
106     // The addrlen argument that describes the enclosing sockaddr_un structure
107     // should have a value of at least:
108     //
109     //     offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path) + 1
110     //
111     // or, more simply, addrlen can be specified as sizeof(struct sockaddr_un).
112     let len = sun_path_offset() + bytes.len() + 1;
113     Ok((addr, len as libc::socklen_t))
114 }
115 
116 impl TcpSocket {
new(inet_version: InetVersion) -> io::Result<Self>117     pub fn new(inet_version: InetVersion) -> io::Result<Self> {
118         Ok(TcpSocket {
119             inet_version,
120             descriptor: socket(
121                 Into::<sa_family_t>::into(inet_version) as libc::c_int,
122                 SOCK_STREAM | SOCK_CLOEXEC,
123                 0,
124             )?,
125         })
126     }
127 }
128 
129 impl UnixSeqpacket {
130     /// Creates a pair of connected `SOCK_SEQPACKET` sockets.
131     ///
132     /// Both returned file descriptors have the `CLOEXEC` flag set.
pair() -> io::Result<(UnixSeqpacket, UnixSeqpacket)>133     pub fn pair() -> io::Result<(UnixSeqpacket, UnixSeqpacket)> {
134         socketpair(libc::AF_UNIX, libc::SOCK_SEQPACKET | libc::SOCK_CLOEXEC, 0)
135             .map(|(s0, s1)| (UnixSeqpacket::from(s0), UnixSeqpacket::from(s1)))
136     }
137 }
138 
139 impl UnixSeqpacketListener {
140     /// Blocks for and accepts a new incoming connection and returns the socket associated with that
141     /// connection.
142     ///
143     /// The returned socket has the close-on-exec flag set.
accept(&self) -> io::Result<UnixSeqpacket>144     pub fn accept(&self) -> io::Result<UnixSeqpacket> {
145         // SAFETY:
146         // Safe because we own this fd and the kernel will not write to null pointers.
147         match unsafe {
148             libc::accept4(
149                 self.as_raw_descriptor(),
150                 null_mut(),
151                 null_mut(),
152                 SOCK_CLOEXEC,
153             )
154         } {
155             -1 => Err(io::Error::last_os_error()),
156             fd => {
157                 Ok(UnixSeqpacket::from(
158                     // SAFETY: Safe because we checked the return value of accept. Therefore, the
159                     // return value must be a valid socket.
160                     unsafe { SafeDescriptor::from_raw_descriptor(fd) },
161                 ))
162             }
163         }
164     }
165 }
166 
167 macro_rules! ScmSocketTryFrom {
168     ($name:ident) => {
169         impl TryFrom<$name> for ScmSocket<$name> {
170             type Error = io::Error;
171 
172             fn try_from(socket: $name) -> io::Result<Self> {
173                 Ok(ScmSocket { socket })
174             }
175         }
176     };
177 }
178 
179 ScmSocketTryFrom!(UnixDatagram);
180 ScmSocketTryFrom!(UnixListener);
181 ScmSocketTryFrom!(UnixSeqpacket);
182 ScmSocketTryFrom!(UnixStream);
183