1use std::io;
2use std::mem::size_of;
3use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
4
5pub(crate) fn new_ip_socket(addr: SocketAddr, socket_type: libc::c_int) -> io::Result<libc::c_int> {
6 let domain = match addr {
7 SocketAddr::V4(..) => libc::AF_INET,
8 SocketAddr::V6(..) => libc::AF_INET6,
9 };
10
11 new_socket(domain, socket_type)
12}
13
14pub(crate) fn new_socket(domain: libc::c_int, socket_type: libc::c_int) -> io::Result<libc::c_int> {
16 #[cfg(any(
17 target_os = "android",
18 target_os = "dragonfly",
19 target_os = "freebsd",
20 target_os = "hurd",
21 target_os = "illumos",
22 target_os = "linux",
23 target_os = "netbsd",
24 target_os = "openbsd",
25 target_os = "solaris",
26 target_os = "hermit",
27 target_os = "cygwin",
28 ))]
29 let socket_type = socket_type | libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC;
30 #[cfg(target_os = "wasi")]
33 let socket_type = socket_type | libc::SOCK_NONBLOCK;
34 #[cfg(target_os = "nto")]
35 let socket_type = socket_type | libc::SOCK_CLOEXEC;
36
37 let socket = syscall!(socket(domain, socket_type, 0))?;
38
39 #[cfg(any(
41 target_os = "ios",
42 target_os = "macos",
43 target_os = "tvos",
44 target_os = "visionos",
45 target_os = "watchos",
46 ))]
47 if let Err(err) = syscall!(setsockopt(
48 socket,
49 libc::SOL_SOCKET,
50 libc::SO_NOSIGPIPE,
51 &1 as *const libc::c_int as *const libc::c_void,
52 size_of::<libc::c_int>() as libc::socklen_t
53 )) {
54 let _ = syscall!(close(socket));
55 return Err(err);
56 }
57
58 #[cfg(any(
60 target_os = "aix",
61 target_os = "ios",
62 target_os = "macos",
63 target_os = "tvos",
64 target_os = "visionos",
65 target_os = "watchos",
66 target_os = "espidf",
67 target_os = "haiku",
68 target_os = "vita",
69 target_os = "nto",
70 ))]
71 {
72 if let Err(err) = syscall!(fcntl(socket, libc::F_SETFL, libc::O_NONBLOCK)) {
73 let _ = syscall!(close(socket));
74 return Err(err);
75 }
76 #[cfg(not(any(target_os = "espidf", target_os = "vita", target_os = "nto")))]
77 if let Err(err) = syscall!(fcntl(socket, libc::F_SETFD, libc::FD_CLOEXEC)) {
78 let _ = syscall!(close(socket));
79 return Err(err);
80 }
81 }
82
83 Ok(socket)
84}
85
86#[repr(C)]
91pub(crate) union SocketAddrCRepr {
92 v4: libc::sockaddr_in,
93 v6: libc::sockaddr_in6,
94}
95
96impl SocketAddrCRepr {
97 pub(crate) fn as_ptr(&self) -> *const libc::sockaddr {
98 self as *const _ as *const libc::sockaddr
99 }
100}
101
102pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, libc::socklen_t) {
104 match addr {
105 SocketAddr::V4(ref addr) => {
106 let sin_addr = libc::in_addr {
109 s_addr: u32::from_ne_bytes(addr.ip().octets()),
110 };
111
112 let sockaddr_in = libc::sockaddr_in {
113 sin_family: libc::AF_INET as libc::sa_family_t,
114 sin_port: addr.port().to_be(),
115 sin_addr,
116 #[cfg(not(any(target_os = "haiku", target_os = "vita", target_os = "wasi")))]
117 sin_zero: [0; 8],
118 #[cfg(target_os = "haiku")]
119 sin_zero: [0; 24],
120 #[cfg(target_os = "vita")]
121 sin_zero: [0; 6],
122 #[cfg(any(
123 target_os = "aix",
124 target_os = "dragonfly",
125 target_os = "freebsd",
126 target_os = "haiku",
127 target_os = "hurd",
128 target_os = "ios",
129 target_os = "macos",
130 target_os = "netbsd",
131 target_os = "openbsd",
132 target_os = "tvos",
133 target_os = "visionos",
134 target_os = "watchos",
135 target_os = "espidf",
136 target_os = "vita",
137 target_os = "hermit",
138 target_os = "nto",
139 ))]
140 sin_len: 0,
141 #[cfg(target_os = "vita")]
142 sin_vport: addr.port().to_be(),
143 };
144
145 let sockaddr = SocketAddrCRepr { v4: sockaddr_in };
146 let socklen = size_of::<libc::sockaddr_in>() as libc::socklen_t;
147 (sockaddr, socklen)
148 }
149 SocketAddr::V6(ref addr) => {
150 let sockaddr_in6 = libc::sockaddr_in6 {
151 sin6_family: libc::AF_INET6 as libc::sa_family_t,
152 sin6_port: addr.port().to_be(),
153 sin6_addr: libc::in6_addr {
154 s6_addr: addr.ip().octets(),
155 },
156 sin6_flowinfo: addr.flowinfo(),
157 sin6_scope_id: addr.scope_id(),
158 #[cfg(any(
159 target_os = "aix",
160 target_os = "dragonfly",
161 target_os = "freebsd",
162 target_os = "haiku",
163 target_os = "hurd",
164 target_os = "ios",
165 target_os = "macos",
166 target_os = "netbsd",
167 target_os = "openbsd",
168 target_os = "tvos",
169 target_os = "visionos",
170 target_os = "watchos",
171 target_os = "espidf",
172 target_os = "vita",
173 target_os = "nto",
174 target_os = "hermit",
175 ))]
176 sin6_len: 0,
177 #[cfg(target_os = "vita")]
178 sin6_vport: addr.port().to_be(),
179 #[cfg(any(target_os = "illumos", target_os = "solaris"))]
180 __sin6_src_id: 0,
181 };
182
183 let sockaddr = SocketAddrCRepr { v6: sockaddr_in6 };
184 let socklen = size_of::<libc::sockaddr_in6>() as libc::socklen_t;
185 (sockaddr, socklen)
186 }
187 }
188}
189
190pub(crate) unsafe fn to_socket_addr(
197 storage: *const libc::sockaddr_storage,
198) -> io::Result<SocketAddr> {
199 match (*storage).ss_family as libc::c_int {
200 libc::AF_INET => {
201 let addr: &libc::sockaddr_in = &*(storage as *const libc::sockaddr_in);
203 let ip = Ipv4Addr::from(addr.sin_addr.s_addr.to_ne_bytes());
204 let port = u16::from_be(addr.sin_port);
205 Ok(SocketAddr::V4(SocketAddrV4::new(ip, port)))
206 }
207 libc::AF_INET6 => {
208 let addr: &libc::sockaddr_in6 = &*(storage as *const libc::sockaddr_in6);
210 let ip = Ipv6Addr::from(addr.sin6_addr.s6_addr);
211 let port = u16::from_be(addr.sin6_port);
212 Ok(SocketAddr::V6(SocketAddrV6::new(
213 ip,
214 port,
215 addr.sin6_flowinfo,
216 addr.sin6_scope_id,
217 )))
218 }
219 _ => Err(io::ErrorKind::InvalidInput.into()),
220 }
221}