base/sys/linux/
net.rs

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
5use std::io;
6use std::net::SocketAddrV4;
7use std::net::SocketAddrV6;
8use std::os::fd::RawFd;
9use std::os::unix::ffi::OsStrExt;
10use std::os::unix::net::UnixDatagram;
11use std::os::unix::net::UnixListener;
12use std::os::unix::net::UnixStream;
13use std::path::Path;
14use std::ptr::null_mut;
15
16use libc::c_int;
17use libc::in6_addr;
18use libc::in_addr;
19use libc::msghdr;
20use libc::sa_family_t;
21use libc::sendmsg;
22use libc::sockaddr_in;
23use libc::sockaddr_in6;
24use libc::ssize_t;
25use libc::AF_INET;
26use libc::AF_INET6;
27use libc::MSG_NOSIGNAL;
28use libc::SOCK_CLOEXEC;
29use libc::SOCK_STREAM;
30
31use crate::descriptor::AsRawDescriptor;
32use crate::descriptor::FromRawDescriptor;
33use crate::unix::net::socket;
34use crate::unix::net::socketpair;
35use crate::unix::net::sun_path_offset;
36use crate::unix::net::InetVersion;
37use crate::unix::net::TcpSocket;
38use crate::SafeDescriptor;
39use crate::ScmSocket;
40use crate::UnixSeqpacket;
41use crate::UnixSeqpacketListener;
42
43pub(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
51pub(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
62pub(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`
75pub(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
116impl TcpSocket {
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
129impl UnixSeqpacket {
130    /// Creates a pair of connected `SOCK_SEQPACKET` sockets.
131    ///
132    /// Both returned file descriptors have the `CLOEXEC` flag set.
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
139impl 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.
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
167macro_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
179ScmSocketTryFrom!(UnixDatagram);
180ScmSocketTryFrom!(UnixListener);
181ScmSocketTryFrom!(UnixSeqpacket);
182ScmSocketTryFrom!(UnixStream);