]>
Commit | Line | Data |
---|---|---|
1b1a35ee XL |
1 | #[cfg(test)] |
2 | mod tests; | |
3 | ||
532ac7d7 | 4 | use crate::cmp; |
60c5eb7d | 5 | use crate::convert::{TryFrom, TryInto}; |
532ac7d7 XL |
6 | use crate::ffi::CString; |
7 | use crate::fmt; | |
48663c56 | 8 | use crate::io::{self, Error, ErrorKind, IoSlice, IoSliceMut}; |
532ac7d7 | 9 | use crate::mem; |
60c5eb7d | 10 | use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; |
532ac7d7 | 11 | use crate::ptr; |
532ac7d7 | 12 | use crate::sys::net::netc as c; |
60c5eb7d | 13 | use crate::sys::net::{cvt, cvt_gai, cvt_r, init, wrlen_t, Socket}; |
532ac7d7 XL |
14 | use crate::sys_common::{AsInner, FromInner, IntoInner}; |
15 | use crate::time::Duration; | |
532ac7d7 | 16 | |
54a0048b | 17 | use libc::{c_int, c_void}; |
85aaf69f | 18 | |
dfeec247 XL |
19 | cfg_if::cfg_if! { |
20 | if #[cfg(any( | |
21 | target_os = "dragonfly", target_os = "freebsd", | |
22 | target_os = "ios", target_os = "macos", | |
ba9703b0 | 23 | target_os = "openbsd", target_os = "netbsd", target_os = "illumos", |
dfeec247 XL |
24 | target_os = "solaris", target_os = "haiku", target_os = "l4re"))] { |
25 | use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; | |
26 | use crate::sys::net::netc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP; | |
27 | } else { | |
28 | use crate::sys::net::netc::IPV6_ADD_MEMBERSHIP; | |
29 | use crate::sys::net::netc::IPV6_DROP_MEMBERSHIP; | |
30 | } | |
31 | } | |
32 | ||
33 | cfg_if::cfg_if! { | |
34 | if #[cfg(any( | |
35 | target_os = "linux", target_os = "android", | |
36 | target_os = "dragonfly", target_os = "freebsd", | |
37 | target_os = "openbsd", target_os = "netbsd", | |
38 | target_os = "haiku"))] { | |
39 | use libc::MSG_NOSIGNAL; | |
40 | } else { | |
41 | const MSG_NOSIGNAL: c_int = 0x0; | |
42 | } | |
43 | } | |
44 | ||
45 | cfg_if::cfg_if! { | |
46 | if #[cfg(any( | |
47 | target_os = "dragonfly", target_os = "freebsd", | |
48 | target_os = "openbsd", target_os = "netbsd", | |
ba9703b0 | 49 | target_os = "solaris", target_os = "illumos"))] { |
dfeec247 XL |
50 | use libc::c_uchar; |
51 | type IpV4MultiCastType = c_uchar; | |
52 | } else { | |
53 | type IpV4MultiCastType = c_int; | |
54 | } | |
55 | } | |
c30ab7b3 | 56 | |
85aaf69f SL |
57 | //////////////////////////////////////////////////////////////////////////////// |
58 | // sockaddr and misc bindings | |
59 | //////////////////////////////////////////////////////////////////////////////// | |
60 | ||
60c5eb7d | 61 | pub fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int, payload: T) -> io::Result<()> { |
85aaf69f SL |
62 | unsafe { |
63 | let payload = &payload as *const T as *const c_void; | |
60c5eb7d XL |
64 | cvt(c::setsockopt( |
65 | *sock.as_inner(), | |
66 | opt, | |
67 | val, | |
68 | payload, | |
69 | mem::size_of::<T>() as c::socklen_t, | |
70 | ))?; | |
85aaf69f SL |
71 | Ok(()) |
72 | } | |
73 | } | |
74 | ||
60c5eb7d | 75 | pub fn getsockopt<T: Copy>(sock: &Socket, opt: c_int, val: c_int) -> io::Result<T> { |
85aaf69f SL |
76 | unsafe { |
77 | let mut slot: T = mem::zeroed(); | |
92a42be0 | 78 | let mut len = mem::size_of::<T>() as c::socklen_t; |
60c5eb7d | 79 | cvt(c::getsockopt(*sock.as_inner(), opt, val, &mut slot as *mut _ as *mut _, &mut len))?; |
62682a34 | 80 | assert_eq!(len as usize, mem::size_of::<T>()); |
85aaf69f SL |
81 | Ok(slot) |
82 | } | |
83 | } | |
84 | ||
85 | fn sockname<F>(f: F) -> io::Result<SocketAddr> | |
60c5eb7d XL |
86 | where |
87 | F: FnOnce(*mut c::sockaddr, *mut c::socklen_t) -> c_int, | |
85aaf69f SL |
88 | { |
89 | unsafe { | |
92a42be0 SL |
90 | let mut storage: c::sockaddr_storage = mem::zeroed(); |
91 | let mut len = mem::size_of_val(&storage) as c::socklen_t; | |
54a0048b | 92 | cvt(f(&mut storage as *mut _ as *mut _, &mut len))?; |
85aaf69f SL |
93 | sockaddr_to_addr(&storage, len as usize) |
94 | } | |
95 | } | |
96 | ||
60c5eb7d | 97 | pub fn sockaddr_to_addr(storage: &c::sockaddr_storage, len: usize) -> io::Result<SocketAddr> { |
92a42be0 SL |
98 | match storage.ss_family as c_int { |
99 | c::AF_INET => { | |
100 | assert!(len as usize >= mem::size_of::<c::sockaddr_in>()); | |
c34b1796 | 101 | Ok(SocketAddr::V4(FromInner::from_inner(unsafe { |
92a42be0 | 102 | *(storage as *const _ as *const c::sockaddr_in) |
c34b1796 | 103 | }))) |
85aaf69f | 104 | } |
92a42be0 SL |
105 | c::AF_INET6 => { |
106 | assert!(len as usize >= mem::size_of::<c::sockaddr_in6>()); | |
c34b1796 | 107 | Ok(SocketAddr::V6(FromInner::from_inner(unsafe { |
92a42be0 | 108 | *(storage as *const _ as *const c::sockaddr_in6) |
c34b1796 | 109 | }))) |
85aaf69f | 110 | } |
cdc7bbd5 | 111 | _ => Err(Error::new_const(ErrorKind::InvalidInput, &"invalid argument")), |
85aaf69f SL |
112 | } |
113 | } | |
114 | ||
54a0048b SL |
115 | #[cfg(target_os = "android")] |
116 | fn to_ipv6mr_interface(value: u32) -> c_int { | |
117 | value as c_int | |
118 | } | |
119 | ||
120 | #[cfg(not(target_os = "android"))] | |
532ac7d7 XL |
121 | fn to_ipv6mr_interface(value: u32) -> libc::c_uint { |
122 | value as libc::c_uint | |
54a0048b SL |
123 | } |
124 | ||
85aaf69f SL |
125 | //////////////////////////////////////////////////////////////////////////////// |
126 | // get_host_addresses | |
127 | //////////////////////////////////////////////////////////////////////////////// | |
128 | ||
85aaf69f | 129 | pub struct LookupHost { |
92a42be0 SL |
130 | original: *mut c::addrinfo, |
131 | cur: *mut c::addrinfo, | |
60c5eb7d | 132 | port: u16, |
0731742a XL |
133 | } |
134 | ||
135 | impl LookupHost { | |
136 | pub fn port(&self) -> u16 { | |
137 | self.port | |
138 | } | |
85aaf69f SL |
139 | } |
140 | ||
141 | impl Iterator for LookupHost { | |
3157f602 XL |
142 | type Item = SocketAddr; |
143 | fn next(&mut self) -> Option<SocketAddr> { | |
144 | loop { | |
145 | unsafe { | |
ff7c6d11 | 146 | let cur = self.cur.as_ref()?; |
3157f602 | 147 | self.cur = cur.ai_next; |
60c5eb7d | 148 | match sockaddr_to_addr(mem::transmute(cur.ai_addr), cur.ai_addrlen as usize) { |
3157f602 XL |
149 | Ok(addr) => return Some(addr), |
150 | Err(_) => continue, | |
151 | } | |
152 | } | |
85aaf69f SL |
153 | } |
154 | } | |
155 | } | |
156 | ||
e9174d1e SL |
157 | unsafe impl Sync for LookupHost {} |
158 | unsafe impl Send for LookupHost {} | |
159 | ||
85aaf69f SL |
160 | impl Drop for LookupHost { |
161 | fn drop(&mut self) { | |
92a42be0 | 162 | unsafe { c::freeaddrinfo(self.original) } |
85aaf69f SL |
163 | } |
164 | } | |
165 | ||
532ac7d7 | 166 | impl TryFrom<&str> for LookupHost { |
0731742a | 167 | type Error = io::Error; |
85aaf69f | 168 | |
0731742a XL |
169 | fn try_from(s: &str) -> io::Result<LookupHost> { |
170 | macro_rules! try_opt { | |
60c5eb7d | 171 | ($e:expr, $msg:expr) => { |
0731742a XL |
172 | match $e { |
173 | Some(r) => r, | |
cdc7bbd5 | 174 | None => return Err(io::Error::new_const(io::ErrorKind::InvalidInput, &$msg)), |
0731742a | 175 | } |
60c5eb7d | 176 | }; |
0731742a XL |
177 | } |
178 | ||
179 | // split the string by ':' and convert the second part to u16 | |
fc512014 | 180 | let (host, port_str) = try_opt!(s.rsplit_once(':'), "invalid socket address"); |
0731742a | 181 | let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value"); |
0731742a XL |
182 | (host, port).try_into() |
183 | } | |
184 | } | |
185 | ||
186 | impl<'a> TryFrom<(&'a str, u16)> for LookupHost { | |
187 | type Error = io::Error; | |
188 | ||
189 | fn try_from((host, port): (&'a str, u16)) -> io::Result<LookupHost> { | |
190 | init(); | |
191 | ||
192 | let c_host = CString::new(host)?; | |
193 | let mut hints: c::addrinfo = unsafe { mem::zeroed() }; | |
194 | hints.ai_socktype = c::SOCK_STREAM; | |
195 | let mut res = ptr::null_mut(); | |
196 | unsafe { | |
60c5eb7d XL |
197 | cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res)) |
198 | .map(|_| LookupHost { original: res, cur: res, port }) | |
0731742a | 199 | } |
85aaf69f SL |
200 | } |
201 | } | |
202 | ||
203 | //////////////////////////////////////////////////////////////////////////////// | |
204 | // TCP streams | |
205 | //////////////////////////////////////////////////////////////////////////////// | |
206 | ||
207 | pub struct TcpStream { | |
208 | inner: Socket, | |
209 | } | |
210 | ||
211 | impl TcpStream { | |
0731742a XL |
212 | pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> { |
213 | let addr = addr?; | |
214 | ||
85aaf69f SL |
215 | init(); |
216 | ||
54a0048b | 217 | let sock = Socket::new(addr, c::SOCK_STREAM)?; |
85aaf69f SL |
218 | |
219 | let (addrp, len) = addr.into_inner(); | |
54a0048b | 220 | cvt_r(|| unsafe { c::connect(*sock.as_inner(), addrp, len) })?; |
85aaf69f SL |
221 | Ok(TcpStream { inner: sock }) |
222 | } | |
223 | ||
041b39d2 XL |
224 | pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> { |
225 | init(); | |
226 | ||
227 | let sock = Socket::new(addr, c::SOCK_STREAM)?; | |
228 | sock.connect_timeout(addr, timeout)?; | |
229 | Ok(TcpStream { inner: sock }) | |
230 | } | |
231 | ||
60c5eb7d XL |
232 | pub fn socket(&self) -> &Socket { |
233 | &self.inner | |
234 | } | |
85aaf69f | 235 | |
60c5eb7d XL |
236 | pub fn into_socket(self) -> Socket { |
237 | self.inner | |
238 | } | |
c1a9b12d | 239 | |
62682a34 | 240 | pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { |
92a42be0 | 241 | self.inner.set_timeout(dur, c::SO_RCVTIMEO) |
62682a34 SL |
242 | } |
243 | ||
244 | pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> { | |
92a42be0 | 245 | self.inner.set_timeout(dur, c::SO_SNDTIMEO) |
62682a34 SL |
246 | } |
247 | ||
248 | pub fn read_timeout(&self) -> io::Result<Option<Duration>> { | |
92a42be0 | 249 | self.inner.timeout(c::SO_RCVTIMEO) |
62682a34 SL |
250 | } |
251 | ||
252 | pub fn write_timeout(&self) -> io::Result<Option<Duration>> { | |
92a42be0 | 253 | self.inner.timeout(c::SO_SNDTIMEO) |
62682a34 SL |
254 | } |
255 | ||
8bb4bdeb XL |
256 | pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { |
257 | self.inner.peek(buf) | |
258 | } | |
259 | ||
85aaf69f SL |
260 | pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { |
261 | self.inner.read(buf) | |
262 | } | |
263 | ||
48663c56 | 264 | pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { |
9fa01778 XL |
265 | self.inner.read_vectored(bufs) |
266 | } | |
267 | ||
f9f354fc XL |
268 | #[inline] |
269 | pub fn is_read_vectored(&self) -> bool { | |
270 | self.inner.is_read_vectored() | |
271 | } | |
272 | ||
85aaf69f | 273 | pub fn write(&self, buf: &[u8]) -> io::Result<usize> { |
f035d41b | 274 | let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t; |
54a0048b | 275 | let ret = cvt(unsafe { |
60c5eb7d | 276 | c::send(*self.inner.as_inner(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL) |
54a0048b | 277 | })?; |
85aaf69f SL |
278 | Ok(ret as usize) |
279 | } | |
280 | ||
48663c56 | 281 | pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { |
9fa01778 XL |
282 | self.inner.write_vectored(bufs) |
283 | } | |
284 | ||
f9f354fc XL |
285 | #[inline] |
286 | pub fn is_write_vectored(&self) -> bool { | |
287 | self.inner.is_write_vectored() | |
288 | } | |
289 | ||
85aaf69f | 290 | pub fn peer_addr(&self) -> io::Result<SocketAddr> { |
60c5eb7d | 291 | sockname(|buf, len| unsafe { c::getpeername(*self.inner.as_inner(), buf, len) }) |
85aaf69f SL |
292 | } |
293 | ||
294 | pub fn socket_addr(&self) -> io::Result<SocketAddr> { | |
60c5eb7d | 295 | sockname(|buf, len| unsafe { c::getsockname(*self.inner.as_inner(), buf, len) }) |
85aaf69f SL |
296 | } |
297 | ||
298 | pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { | |
92a42be0 | 299 | self.inner.shutdown(how) |
85aaf69f SL |
300 | } |
301 | ||
302 | pub fn duplicate(&self) -> io::Result<TcpStream> { | |
303 | self.inner.duplicate().map(|s| TcpStream { inner: s }) | |
304 | } | |
54a0048b SL |
305 | |
306 | pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { | |
307 | self.inner.set_nodelay(nodelay) | |
308 | } | |
309 | ||
310 | pub fn nodelay(&self) -> io::Result<bool> { | |
311 | self.inner.nodelay() | |
312 | } | |
313 | ||
314 | pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { | |
315 | setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) | |
316 | } | |
317 | ||
318 | pub fn ttl(&self) -> io::Result<u32> { | |
319 | let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?; | |
320 | Ok(raw as u32) | |
321 | } | |
322 | ||
323 | pub fn take_error(&self) -> io::Result<Option<io::Error>> { | |
324 | self.inner.take_error() | |
325 | } | |
326 | ||
327 | pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { | |
328 | self.inner.set_nonblocking(nonblocking) | |
329 | } | |
85aaf69f SL |
330 | } |
331 | ||
c34b1796 AL |
332 | impl FromInner<Socket> for TcpStream { |
333 | fn from_inner(socket: Socket) -> TcpStream { | |
334 | TcpStream { inner: socket } | |
335 | } | |
336 | } | |
337 | ||
d9579d0f | 338 | impl fmt::Debug for TcpStream { |
532ac7d7 | 339 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
d9579d0f AL |
340 | let mut res = f.debug_struct("TcpStream"); |
341 | ||
342 | if let Ok(addr) = self.socket_addr() { | |
62682a34 | 343 | res.field("addr", &addr); |
d9579d0f AL |
344 | } |
345 | ||
346 | if let Ok(peer) = self.peer_addr() { | |
62682a34 | 347 | res.field("peer", &peer); |
d9579d0f AL |
348 | } |
349 | ||
60c5eb7d XL |
350 | let name = if cfg!(windows) { "socket" } else { "fd" }; |
351 | res.field(name, &self.inner.as_inner()).finish() | |
d9579d0f AL |
352 | } |
353 | } | |
354 | ||
85aaf69f SL |
355 | //////////////////////////////////////////////////////////////////////////////// |
356 | // TCP listeners | |
357 | //////////////////////////////////////////////////////////////////////////////// | |
358 | ||
359 | pub struct TcpListener { | |
360 | inner: Socket, | |
361 | } | |
362 | ||
363 | impl TcpListener { | |
0731742a XL |
364 | pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> { |
365 | let addr = addr?; | |
366 | ||
85aaf69f SL |
367 | init(); |
368 | ||
54a0048b | 369 | let sock = Socket::new(addr, c::SOCK_STREAM)?; |
85aaf69f | 370 | |
f9f354fc XL |
371 | // On platforms with Berkeley-derived sockets, this allows to quickly |
372 | // rebind a socket, without needing to wait for the OS to clean up the | |
373 | // previous one. | |
374 | // | |
375 | // On Windows, this allows rebinding sockets which are actively in use, | |
376 | // which allows “socket hijacking”, so we explicitly don't set it here. | |
377 | // https://docs.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse | |
378 | #[cfg(not(windows))] | |
379 | setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR, 1 as c_int)?; | |
85aaf69f SL |
380 | |
381 | // Bind our new socket | |
382 | let (addrp, len) = addr.into_inner(); | |
cc61c64b | 383 | cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?; |
85aaf69f SL |
384 | |
385 | // Start listening | |
54a0048b | 386 | cvt(unsafe { c::listen(*sock.as_inner(), 128) })?; |
85aaf69f SL |
387 | Ok(TcpListener { inner: sock }) |
388 | } | |
389 | ||
60c5eb7d XL |
390 | pub fn socket(&self) -> &Socket { |
391 | &self.inner | |
392 | } | |
85aaf69f | 393 | |
60c5eb7d XL |
394 | pub fn into_socket(self) -> Socket { |
395 | self.inner | |
396 | } | |
c1a9b12d | 397 | |
85aaf69f | 398 | pub fn socket_addr(&self) -> io::Result<SocketAddr> { |
60c5eb7d | 399 | sockname(|buf, len| unsafe { c::getsockname(*self.inner.as_inner(), buf, len) }) |
85aaf69f SL |
400 | } |
401 | ||
402 | pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { | |
92a42be0 SL |
403 | let mut storage: c::sockaddr_storage = unsafe { mem::zeroed() }; |
404 | let mut len = mem::size_of_val(&storage) as c::socklen_t; | |
60c5eb7d | 405 | let sock = self.inner.accept(&mut storage as *mut _ as *mut _, &mut len)?; |
54a0048b | 406 | let addr = sockaddr_to_addr(&storage, len as usize)?; |
60c5eb7d | 407 | Ok((TcpStream { inner: sock }, addr)) |
85aaf69f SL |
408 | } |
409 | ||
410 | pub fn duplicate(&self) -> io::Result<TcpListener> { | |
411 | self.inner.duplicate().map(|s| TcpListener { inner: s }) | |
412 | } | |
54a0048b SL |
413 | |
414 | pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { | |
415 | setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) | |
416 | } | |
417 | ||
418 | pub fn ttl(&self) -> io::Result<u32> { | |
419 | let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?; | |
420 | Ok(raw as u32) | |
421 | } | |
422 | ||
423 | pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { | |
424 | setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY, only_v6 as c_int) | |
425 | } | |
426 | ||
427 | pub fn only_v6(&self) -> io::Result<bool> { | |
428 | let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY)?; | |
429 | Ok(raw != 0) | |
430 | } | |
431 | ||
432 | pub fn take_error(&self) -> io::Result<Option<io::Error>> { | |
433 | self.inner.take_error() | |
434 | } | |
435 | ||
436 | pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { | |
437 | self.inner.set_nonblocking(nonblocking) | |
438 | } | |
85aaf69f SL |
439 | } |
440 | ||
c34b1796 AL |
441 | impl FromInner<Socket> for TcpListener { |
442 | fn from_inner(socket: Socket) -> TcpListener { | |
443 | TcpListener { inner: socket } | |
444 | } | |
445 | } | |
446 | ||
d9579d0f | 447 | impl fmt::Debug for TcpListener { |
532ac7d7 | 448 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
d9579d0f AL |
449 | let mut res = f.debug_struct("TcpListener"); |
450 | ||
451 | if let Ok(addr) = self.socket_addr() { | |
62682a34 | 452 | res.field("addr", &addr); |
d9579d0f AL |
453 | } |
454 | ||
60c5eb7d XL |
455 | let name = if cfg!(windows) { "socket" } else { "fd" }; |
456 | res.field(name, &self.inner.as_inner()).finish() | |
d9579d0f AL |
457 | } |
458 | } | |
459 | ||
85aaf69f SL |
460 | //////////////////////////////////////////////////////////////////////////////// |
461 | // UDP | |
462 | //////////////////////////////////////////////////////////////////////////////// | |
463 | ||
464 | pub struct UdpSocket { | |
465 | inner: Socket, | |
466 | } | |
467 | ||
468 | impl UdpSocket { | |
0731742a XL |
469 | pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<UdpSocket> { |
470 | let addr = addr?; | |
471 | ||
85aaf69f SL |
472 | init(); |
473 | ||
54a0048b | 474 | let sock = Socket::new(addr, c::SOCK_DGRAM)?; |
85aaf69f | 475 | let (addrp, len) = addr.into_inner(); |
cc61c64b | 476 | cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?; |
85aaf69f SL |
477 | Ok(UdpSocket { inner: sock }) |
478 | } | |
479 | ||
60c5eb7d XL |
480 | pub fn socket(&self) -> &Socket { |
481 | &self.inner | |
482 | } | |
85aaf69f | 483 | |
60c5eb7d XL |
484 | pub fn into_socket(self) -> Socket { |
485 | self.inner | |
486 | } | |
c1a9b12d | 487 | |
532ac7d7 | 488 | pub fn peer_addr(&self) -> io::Result<SocketAddr> { |
60c5eb7d | 489 | sockname(|buf, len| unsafe { c::getpeername(*self.inner.as_inner(), buf, len) }) |
532ac7d7 XL |
490 | } |
491 | ||
85aaf69f | 492 | pub fn socket_addr(&self) -> io::Result<SocketAddr> { |
60c5eb7d | 493 | sockname(|buf, len| unsafe { c::getsockname(*self.inner.as_inner(), buf, len) }) |
85aaf69f SL |
494 | } |
495 | ||
496 | pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { | |
8bb4bdeb XL |
497 | self.inner.recv_from(buf) |
498 | } | |
85aaf69f | 499 | |
8bb4bdeb XL |
500 | pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { |
501 | self.inner.peek_from(buf) | |
85aaf69f SL |
502 | } |
503 | ||
504 | pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result<usize> { | |
f035d41b | 505 | let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t; |
85aaf69f | 506 | let (dstp, dstlen) = dst.into_inner(); |
54a0048b | 507 | let ret = cvt(unsafe { |
60c5eb7d XL |
508 | c::sendto( |
509 | *self.inner.as_inner(), | |
510 | buf.as_ptr() as *const c_void, | |
511 | len, | |
512 | MSG_NOSIGNAL, | |
513 | dstp, | |
514 | dstlen, | |
515 | ) | |
54a0048b | 516 | })?; |
85aaf69f SL |
517 | Ok(ret as usize) |
518 | } | |
519 | ||
85aaf69f SL |
520 | pub fn duplicate(&self) -> io::Result<UdpSocket> { |
521 | self.inner.duplicate().map(|s| UdpSocket { inner: s }) | |
522 | } | |
62682a34 SL |
523 | |
524 | pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { | |
92a42be0 | 525 | self.inner.set_timeout(dur, c::SO_RCVTIMEO) |
62682a34 SL |
526 | } |
527 | ||
528 | pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> { | |
92a42be0 | 529 | self.inner.set_timeout(dur, c::SO_SNDTIMEO) |
62682a34 SL |
530 | } |
531 | ||
532 | pub fn read_timeout(&self) -> io::Result<Option<Duration>> { | |
92a42be0 | 533 | self.inner.timeout(c::SO_RCVTIMEO) |
62682a34 SL |
534 | } |
535 | ||
536 | pub fn write_timeout(&self) -> io::Result<Option<Duration>> { | |
92a42be0 | 537 | self.inner.timeout(c::SO_SNDTIMEO) |
62682a34 | 538 | } |
54a0048b SL |
539 | |
540 | pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { | |
541 | setsockopt(&self.inner, c::SOL_SOCKET, c::SO_BROADCAST, broadcast as c_int) | |
542 | } | |
543 | ||
544 | pub fn broadcast(&self) -> io::Result<bool> { | |
545 | let raw: c_int = getsockopt(&self.inner, c::SOL_SOCKET, c::SO_BROADCAST)?; | |
546 | Ok(raw != 0) | |
547 | } | |
548 | ||
549 | pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { | |
dfeec247 XL |
550 | setsockopt( |
551 | &self.inner, | |
552 | c::IPPROTO_IP, | |
553 | c::IP_MULTICAST_LOOP, | |
554 | multicast_loop_v4 as IpV4MultiCastType, | |
555 | ) | |
54a0048b SL |
556 | } |
557 | ||
558 | pub fn multicast_loop_v4(&self) -> io::Result<bool> { | |
dfeec247 | 559 | let raw: IpV4MultiCastType = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)?; |
54a0048b SL |
560 | Ok(raw != 0) |
561 | } | |
562 | ||
563 | pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { | |
dfeec247 XL |
564 | setsockopt( |
565 | &self.inner, | |
566 | c::IPPROTO_IP, | |
567 | c::IP_MULTICAST_TTL, | |
568 | multicast_ttl_v4 as IpV4MultiCastType, | |
569 | ) | |
54a0048b SL |
570 | } |
571 | ||
572 | pub fn multicast_ttl_v4(&self) -> io::Result<u32> { | |
dfeec247 | 573 | let raw: IpV4MultiCastType = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)?; |
54a0048b SL |
574 | Ok(raw as u32) |
575 | } | |
576 | ||
577 | pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { | |
578 | setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP, multicast_loop_v6 as c_int) | |
579 | } | |
580 | ||
581 | pub fn multicast_loop_v6(&self) -> io::Result<bool> { | |
582 | let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP)?; | |
583 | Ok(raw != 0) | |
584 | } | |
585 | ||
60c5eb7d | 586 | pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { |
54a0048b | 587 | let mreq = c::ip_mreq { |
3dfed10e XL |
588 | imr_multiaddr: multiaddr.into_inner(), |
589 | imr_interface: interface.into_inner(), | |
54a0048b SL |
590 | }; |
591 | setsockopt(&self.inner, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreq) | |
592 | } | |
593 | ||
60c5eb7d | 594 | pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { |
54a0048b SL |
595 | let mreq = c::ipv6_mreq { |
596 | ipv6mr_multiaddr: *multiaddr.as_inner(), | |
597 | ipv6mr_interface: to_ipv6mr_interface(interface), | |
598 | }; | |
599 | setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq) | |
600 | } | |
601 | ||
60c5eb7d | 602 | pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { |
54a0048b | 603 | let mreq = c::ip_mreq { |
3dfed10e XL |
604 | imr_multiaddr: multiaddr.into_inner(), |
605 | imr_interface: interface.into_inner(), | |
54a0048b SL |
606 | }; |
607 | setsockopt(&self.inner, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreq) | |
608 | } | |
609 | ||
60c5eb7d | 610 | pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { |
54a0048b SL |
611 | let mreq = c::ipv6_mreq { |
612 | ipv6mr_multiaddr: *multiaddr.as_inner(), | |
613 | ipv6mr_interface: to_ipv6mr_interface(interface), | |
614 | }; | |
615 | setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq) | |
616 | } | |
617 | ||
618 | pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { | |
619 | setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) | |
620 | } | |
621 | ||
622 | pub fn ttl(&self) -> io::Result<u32> { | |
623 | let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?; | |
624 | Ok(raw as u32) | |
625 | } | |
626 | ||
627 | pub fn take_error(&self) -> io::Result<Option<io::Error>> { | |
628 | self.inner.take_error() | |
629 | } | |
630 | ||
631 | pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { | |
632 | self.inner.set_nonblocking(nonblocking) | |
633 | } | |
634 | ||
635 | pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> { | |
636 | self.inner.read(buf) | |
637 | } | |
638 | ||
8bb4bdeb XL |
639 | pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { |
640 | self.inner.peek(buf) | |
641 | } | |
642 | ||
54a0048b | 643 | pub fn send(&self, buf: &[u8]) -> io::Result<usize> { |
f035d41b | 644 | let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t; |
54a0048b | 645 | let ret = cvt(unsafe { |
60c5eb7d | 646 | c::send(*self.inner.as_inner(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL) |
54a0048b SL |
647 | })?; |
648 | Ok(ret as usize) | |
649 | } | |
650 | ||
0731742a XL |
651 | pub fn connect(&self, addr: io::Result<&SocketAddr>) -> io::Result<()> { |
652 | let (addrp, len) = addr?.into_inner(); | |
dfeec247 | 653 | cvt_r(|| unsafe { c::connect(*self.inner.as_inner(), addrp, len) }).map(drop) |
54a0048b | 654 | } |
85aaf69f | 655 | } |
c34b1796 AL |
656 | |
657 | impl FromInner<Socket> for UdpSocket { | |
658 | fn from_inner(socket: Socket) -> UdpSocket { | |
659 | UdpSocket { inner: socket } | |
660 | } | |
661 | } | |
d9579d0f AL |
662 | |
663 | impl fmt::Debug for UdpSocket { | |
532ac7d7 | 664 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
d9579d0f AL |
665 | let mut res = f.debug_struct("UdpSocket"); |
666 | ||
667 | if let Ok(addr) = self.socket_addr() { | |
62682a34 | 668 | res.field("addr", &addr); |
d9579d0f AL |
669 | } |
670 | ||
60c5eb7d XL |
671 | let name = if cfg!(windows) { "socket" } else { "fd" }; |
672 | res.field(name, &self.inner.as_inner()).finish() | |
d9579d0f AL |
673 | } |
674 | } |