Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/base/src/sys/macos/net.rs
5394 views
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::mem::size_of;
7
use std::net::SocketAddrV4;
8
use std::net::SocketAddrV6;
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::c_void;
18
use libc::close;
19
use libc::fcntl;
20
use libc::in6_addr;
21
use libc::in_addr;
22
use libc::sa_family_t;
23
use libc::setsockopt;
24
use libc::sockaddr_in;
25
use libc::sockaddr_in6;
26
use libc::socklen_t;
27
use libc::AF_INET;
28
use libc::AF_INET6;
29
use libc::FD_CLOEXEC;
30
use libc::F_SETFD;
31
use libc::SOCK_STREAM;
32
use libc::SOL_SOCKET;
33
use libc::SO_NOSIGPIPE;
34
35
use crate::unix::net::socket;
36
use crate::unix::net::socketpair;
37
use crate::unix::net::sun_path_offset;
38
use crate::unix::net::InetVersion;
39
use crate::unix::net::TcpSocket;
40
use crate::AsRawDescriptor;
41
use crate::FromRawDescriptor;
42
use crate::SafeDescriptor;
43
use crate::ScmSocket;
44
use crate::UnixSeqpacket;
45
use crate::UnixSeqpacketListener;
46
47
macro_rules! ScmSocketTryFrom {
48
($name:ident) => {
49
impl TryFrom<$name> for ScmSocket<$name> {
50
type Error = io::Error;
51
52
fn try_from(socket: $name) -> io::Result<Self> {
53
let set = 1;
54
let set_ptr = &set as *const c_int as *const c_void;
55
let size = size_of::<c_int>() as socklen_t;
56
// SAFETY: because we are taking ownership of the file descriptor, and `set_ptr`
57
// has at least `size` data available.
58
let res = unsafe {
59
setsockopt(
60
socket.as_raw_descriptor(),
61
SOL_SOCKET,
62
SO_NOSIGPIPE,
63
set_ptr,
64
size,
65
)
66
};
67
if res < 0 {
68
Err(io::Error::last_os_error())
69
} else {
70
Ok(ScmSocket { socket })
71
}
72
}
73
}
74
};
75
}
76
77
ScmSocketTryFrom!(UnixDatagram);
78
ScmSocketTryFrom!(UnixListener);
79
ScmSocketTryFrom!(UnixSeqpacket);
80
ScmSocketTryFrom!(UnixStream);
81
82
pub(crate) fn sockaddrv4_to_lib_c(s: &SocketAddrV4) -> sockaddr_in {
83
sockaddr_in {
84
sin_family: AF_INET as sa_family_t,
85
sin_port: s.port().to_be(),
86
sin_addr: in_addr {
87
s_addr: u32::from_ne_bytes(s.ip().octets()),
88
},
89
sin_zero: [0; 8],
90
sin_len: size_of::<sockaddr_in>() as u8,
91
}
92
}
93
94
pub(crate) fn sockaddrv6_to_lib_c(s: &SocketAddrV6) -> sockaddr_in6 {
95
sockaddr_in6 {
96
sin6_family: AF_INET6 as sa_family_t,
97
sin6_port: s.port().to_be(),
98
sin6_flowinfo: 0,
99
sin6_addr: in6_addr {
100
s6_addr: s.ip().octets(),
101
},
102
sin6_scope_id: 0,
103
sin6_len: size_of::<sockaddr_in6>() as u8,
104
}
105
}
106
107
fn cloexec_or_close<Raw: AsRawDescriptor>(raw: Raw) -> io::Result<Raw> {
108
// SAFETY: `raw` owns a file descriptor, there are no actions with memory. This potentially
109
// races with `fork()` calls in other threads, but on MacOS it's the best we have.
110
let res = unsafe { fcntl(raw.as_raw_descriptor(), F_SETFD, FD_CLOEXEC) };
111
if res >= 0 {
112
Ok(raw)
113
} else {
114
let err = io::Error::last_os_error();
115
// SAFETY: `raw` owns this file descriptor.
116
unsafe { close(raw.as_raw_descriptor()) };
117
Err(err)
118
}
119
}
120
121
// Return `sockaddr_un` for a given `path`
122
pub(in crate::sys) fn sockaddr_un<P: AsRef<Path>>(
123
path: P,
124
) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
125
let mut addr = libc::sockaddr_un {
126
sun_family: libc::AF_UNIX as libc::sa_family_t,
127
sun_path: std::array::from_fn(|_| 0),
128
sun_len: 0,
129
};
130
131
// Check if the input path is valid. Since
132
// * The pathname in sun_path should be null-terminated.
133
// * The length of the pathname, including the terminating null byte, should not exceed the size
134
// of sun_path.
135
//
136
// and our input is a `Path`, we only need to check
137
// * If the string size of `Path` should less than sizeof(sun_path)
138
// and make sure `sun_path` ends with '\0' by initialized the sun_path with zeros.
139
//
140
// Empty path name is valid since abstract socket address has sun_paht[0] = '\0'
141
let bytes = path.as_ref().as_os_str().as_bytes();
142
if bytes.len() >= addr.sun_path.len() {
143
return Err(io::Error::new(
144
io::ErrorKind::InvalidInput,
145
"Input path size should be less than the length of sun_path.",
146
));
147
};
148
149
// Copy data from `path` to `addr.sun_path`
150
for (dst, src) in addr.sun_path.iter_mut().zip(bytes) {
151
*dst = *src as libc::c_char;
152
}
153
154
// The addrlen argument that describes the enclosing sockaddr_un structure
155
// should have a value of at least:
156
//
157
// offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path) + 1
158
//
159
// or, more simply, addrlen can be specified as sizeof(struct sockaddr_un).
160
addr.sun_len = sun_path_offset() as u8 + bytes.len() as u8 + 1;
161
Ok((addr, addr.sun_len as libc::socklen_t))
162
}
163
164
impl TcpSocket {
165
pub fn new(inet_version: InetVersion) -> io::Result<Self> {
166
Ok(TcpSocket {
167
inet_version,
168
descriptor: cloexec_or_close(socket(
169
Into::<sa_family_t>::into(inet_version) as libc::c_int,
170
SOCK_STREAM,
171
0,
172
)?)?,
173
})
174
}
175
}
176
177
impl UnixSeqpacket {
178
/// Creates a pair of connected `SOCK_SEQPACKET` sockets.
179
///
180
/// Both returned file descriptors have the `CLOEXEC` flag set.
181
pub fn pair() -> io::Result<(UnixSeqpacket, UnixSeqpacket)> {
182
let (fd0, fd1) = socketpair(libc::AF_UNIX, libc::SOCK_SEQPACKET, 0)?;
183
let (s0, s1) = (UnixSeqpacket::from(fd0), UnixSeqpacket::from(fd1));
184
Ok((cloexec_or_close(s0)?, cloexec_or_close(s1)?))
185
}
186
}
187
188
impl UnixSeqpacketListener {
189
/// Blocks for and accepts a new incoming connection and returns the socket associated with that
190
/// connection.
191
///
192
/// The returned socket has the close-on-exec flag set.
193
pub fn accept(&self) -> io::Result<UnixSeqpacket> {
194
// SAFETY: we own this fd and the kernel will not write to null pointers.
195
let fd = unsafe { libc::accept(self.as_raw_descriptor(), null_mut(), null_mut()) };
196
match fd {
197
-1 => Err(io::Error::last_os_error()),
198
fd => {
199
// SAFETY: we checked the return value of accept. Therefore, the return value
200
// must be a valid socket.
201
let safe_desc = unsafe { SafeDescriptor::from_raw_descriptor(fd) };
202
Ok(UnixSeqpacket::from(cloexec_or_close(safe_desc)?))
203
}
204
}
205
}
206
}
207
208