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