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 = "vita",
68 target_os = "nto",
69 ))]
70 {
71 if let Err(err) = syscall!(fcntl(socket, libc::F_SETFL, libc::O_NONBLOCK)) {
72 let _ = syscall!(close(socket));
73 return Err(err);
74 }
75 #[cfg(not(any(target_os = "espidf", target_os = "vita", target_os = "nto")))]
76 if let Err(err) = syscall!(fcntl(socket, libc::F_SETFD, libc::FD_CLOEXEC)) {
77 let _ = syscall!(close(socket));
78 return Err(err);
79 }
80 }
81
82 Ok(socket)
83}
84
85#[repr(C)]
90pub(crate) union SocketAddrCRepr {
91 v4: libc::sockaddr_in,
92 v6: libc::sockaddr_in6,
93}
94
95impl SocketAddrCRepr {
96 pub(crate) fn as_ptr(&self) -> *const libc::sockaddr {
97 self as *const _ as *const libc::sockaddr
98 }
99}
100
101pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, libc::socklen_t) {
103 match addr {
104 SocketAddr::V4(ref addr) => {
105 let sin_addr = libc::in_addr {
108 s_addr: u32::from_ne_bytes(addr.ip().octets()),
109 };
110
111 let sockaddr_in = libc::sockaddr_in {
112 sin_family: libc::AF_INET as libc::sa_family_t,
113 sin_port: addr.port().to_be(),
114 sin_addr,
115 #[cfg(not(any(target_os = "haiku", target_os = "vita", target_os = "wasi")))]
116 sin_zero: [0; 8],
117 #[cfg(target_os = "haiku")]
118 sin_zero: [0; 24],
119 #[cfg(target_os = "vita")]
120 sin_zero: [0; 6],
121 #[cfg(any(
122 target_os = "aix",
123 target_os = "dragonfly",
124 target_os = "freebsd",
125 target_os = "haiku",
126 target_os = "hurd",
127 target_os = "ios",
128 target_os = "macos",
129 target_os = "netbsd",
130 target_os = "openbsd",
131 target_os = "tvos",
132 target_os = "visionos",
133 target_os = "watchos",
134 target_os = "espidf",
135 target_os = "vita",
136 target_os = "hermit",
137 target_os = "nto",
138 ))]
139 sin_len: 0,
140 #[cfg(target_os = "vita")]
141 sin_vport: addr.port().to_be(),
142 };
143
144 let sockaddr = SocketAddrCRepr { v4: sockaddr_in };
145 let socklen = size_of::<libc::sockaddr_in>() as libc::socklen_t;
146 (sockaddr, socklen)
147 }
148 SocketAddr::V6(ref addr) => {
149 let sockaddr_in6 = libc::sockaddr_in6 {
150 sin6_family: libc::AF_INET6 as libc::sa_family_t,
151 sin6_port: addr.port().to_be(),
152 sin6_addr: libc::in6_addr {
153 s6_addr: addr.ip().octets(),
154 },
155 sin6_flowinfo: addr.flowinfo(),
156 sin6_scope_id: addr.scope_id(),
157 #[cfg(any(
158 target_os = "aix",
159 target_os = "dragonfly",
160 target_os = "freebsd",
161 target_os = "haiku",
162 target_os = "hurd",
163 target_os = "ios",
164 target_os = "macos",
165 target_os = "netbsd",
166 target_os = "openbsd",
167 target_os = "tvos",
168 target_os = "visionos",
169 target_os = "watchos",
170 target_os = "espidf",
171 target_os = "vita",
172 target_os = "nto",
173 target_os = "hermit",
174 ))]
175 sin6_len: 0,
176 #[cfg(target_os = "vita")]
177 sin6_vport: addr.port().to_be(),
178 #[cfg(any(target_os = "illumos", target_os = "solaris"))]
179 __sin6_src_id: 0,
180 };
181
182 let sockaddr = SocketAddrCRepr { v6: sockaddr_in6 };
183 let socklen = size_of::<libc::sockaddr_in6>() as libc::socklen_t;
184 (sockaddr, socklen)
185 }
186 }
187}
188
189pub(crate) unsafe fn to_socket_addr(
196 storage: *const libc::sockaddr_storage,
197) -> io::Result<SocketAddr> {
198 match (*storage).ss_family as libc::c_int {
199 libc::AF_INET => {
200 let addr: &libc::sockaddr_in = &*(storage as *const libc::sockaddr_in);
202 let ip = Ipv4Addr::from(addr.sin_addr.s_addr.to_ne_bytes());
203 let port = u16::from_be(addr.sin_port);
204 Ok(SocketAddr::V4(SocketAddrV4::new(ip, port)))
205 }
206 libc::AF_INET6 => {
207 let addr: &libc::sockaddr_in6 = &*(storage as *const libc::sockaddr_in6);
209 let ip = Ipv6Addr::from(addr.sin6_addr.s6_addr);
210 let port = u16::from_be(addr.sin6_port);
211 Ok(SocketAddr::V6(SocketAddrV6::new(
212 ip,
213 port,
214 addr.sin6_flowinfo,
215 addr.sin6_scope_id,
216 )))
217 }
218 _ => Err(io::ErrorKind::InvalidInput.into()),
219 }
220}