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