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