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