]> git.proxmox.com Git - rustc.git/blame - vendor/socket2/src/sys/unix.rs
New upstream version 1.51.0+dfsg1
[rustc.git] / vendor / socket2 / src / sys / unix.rs
CommitLineData
0531ce1d
XL
1// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11use std::cmp;
5869c6ff
XL
12#[cfg(target_os = "linux")]
13use std::ffi::{CStr, CString};
0531ce1d 14use std::fmt;
0531ce1d 15use std::io;
dfeec247 16use std::io::{ErrorKind, Read, Write};
0531ce1d 17use std::mem;
5869c6ff
XL
18#[cfg(target_os = "linux")]
19use std::mem::MaybeUninit;
0531ce1d
XL
20use std::net::Shutdown;
21use std::net::{self, Ipv4Addr, Ipv6Addr};
22use std::ops::Neg;
0531ce1d
XL
23#[cfg(feature = "unix")]
24use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream};
dfeec247 25use std::os::unix::prelude::*;
5869c6ff
XL
26#[cfg(target_os = "linux")]
27use std::ptr;
28#[cfg(target_os = "linux")]
29use std::slice;
dfeec247
XL
30use std::sync::atomic::{AtomicBool, Ordering};
31use std::time::{Duration, Instant};
0531ce1d 32
ba9703b0
XL
33use libc::{self, c_void, socklen_t, ssize_t};
34
35use crate::{Domain, Type};
36
37pub use libc::c_int;
38
39// Used in `Domain`.
40pub(crate) use libc::{AF_INET, AF_INET6};
41// Used in `Type`.
5869c6ff
XL
42#[cfg(not(target_os = "redox"))]
43pub(crate) use libc::SOCK_RAW;
44pub(crate) use libc::{SOCK_DGRAM, SOCK_SEQPACKET, SOCK_STREAM};
ba9703b0
XL
45// Used in `Protocol`.
46pub(crate) use libc::{IPPROTO_ICMP, IPPROTO_ICMPV6, IPPROTO_TCP, IPPROTO_UDP};
0531ce1d 47
dfeec247 48cfg_if::cfg_if! {
0531ce1d
XL
49 if #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
50 target_os = "ios", target_os = "macos",
51 target_os = "openbsd", target_os = "netbsd",
ba9703b0
XL
52 target_os = "solaris", target_os = "illumos",
53 target_os = "haiku"))] {
0531ce1d
XL
54 use libc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
55 use libc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP;
56 } else {
57 use libc::IPV6_ADD_MEMBERSHIP;
58 use libc::IPV6_DROP_MEMBERSHIP;
59 }
60}
61
dfeec247 62cfg_if::cfg_if! {
0531ce1d
XL
63 if #[cfg(any(target_os = "macos", target_os = "ios"))] {
64 use libc::TCP_KEEPALIVE as KEEPALIVE_OPTION;
65 } else if #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "haiku"))] {
66 use libc::SO_KEEPALIVE as KEEPALIVE_OPTION;
67 } else {
68 use libc::TCP_KEEPIDLE as KEEPALIVE_OPTION;
69 }
70}
71
dfeec247
XL
72use crate::utils::One;
73use crate::SockAddr;
0531ce1d 74
ba9703b0
XL
75/// Unix only API.
76impl Domain {
77 /// Domain for Unix socket communication, corresponding to `AF_UNIX`.
78 pub fn unix() -> Domain {
79 Domain(libc::AF_UNIX)
80 }
81
82 /// Domain for low-level packet interface, corresponding to `AF_PACKET`.
83 ///
84 /// # Notes
85 ///
86 /// This function is only available on Linux.
87 #[cfg(target_os = "linux")]
88 pub fn packet() -> Domain {
89 Domain(libc::AF_PACKET)
90 }
91}
92
93impl_debug!(
94 Domain,
95 libc::AF_INET,
96 libc::AF_INET6,
97 libc::AF_UNIX,
98 libc::AF_UNSPEC, // = 0.
99);
100
101/// Unix only API.
102impl Type {
103 /// Set `SOCK_NONBLOCK` on the `Type`.
104 ///
105 /// # Notes
106 ///
107 /// This function is only available on Android, DragonFlyBSD, FreeBSD,
108 /// Linux, NetBSD and OpenBSD.
109 #[cfg(any(
110 target_os = "android",
111 target_os = "dragonfly",
112 target_os = "freebsd",
113 target_os = "linux",
114 target_os = "netbsd",
115 target_os = "openbsd"
116 ))]
117 pub fn non_blocking(self) -> Type {
118 Type(self.0 | libc::SOCK_NONBLOCK)
119 }
120
121 /// Set `SOCK_CLOEXEC` on the `Type`.
122 ///
123 /// # Notes
124 ///
125 /// This function is only available on Android, DragonFlyBSD, FreeBSD,
126 /// Linux, NetBSD and OpenBSD.
127 #[cfg(any(
128 target_os = "android",
129 target_os = "dragonfly",
130 target_os = "freebsd",
131 target_os = "linux",
132 target_os = "netbsd",
133 target_os = "openbsd"
134 ))]
135 pub fn cloexec(self) -> Type {
136 Type(self.0 | libc::SOCK_CLOEXEC)
137 }
138}
139
140impl_debug!(
141 crate::Type,
142 libc::SOCK_STREAM,
143 libc::SOCK_DGRAM,
5869c6ff 144 #[cfg(not(target_os = "redox"))]
ba9703b0 145 libc::SOCK_RAW,
5869c6ff 146 #[cfg(not(any(target_os = "haiku", target_os = "redox")))]
ba9703b0
XL
147 libc::SOCK_RDM,
148 libc::SOCK_SEQPACKET,
149 /* TODO: add these optional bit OR-ed flags:
150 #[cfg(any(
151 target_os = "android",
152 target_os = "dragonfly",
153 target_os = "freebsd",
154 target_os = "linux",
155 target_os = "netbsd",
156 target_os = "openbsd"
157 ))]
158 libc::SOCK_NONBLOCK,
159 #[cfg(any(
160 target_os = "android",
161 target_os = "dragonfly",
162 target_os = "freebsd",
163 target_os = "linux",
164 target_os = "netbsd",
165 target_os = "openbsd"
166 ))]
167 libc::SOCK_CLOEXEC,
168 */
169);
170
171impl_debug!(
172 crate::Protocol,
173 libc::IPPROTO_ICMP,
174 libc::IPPROTO_ICMPV6,
175 libc::IPPROTO_TCP,
176 libc::IPPROTO_UDP,
177);
0531ce1d 178
0531ce1d
XL
179pub struct Socket {
180 fd: c_int,
181}
182
183impl Socket {
184 pub fn new(family: c_int, ty: c_int, protocol: c_int) -> io::Result<Socket> {
185 unsafe {
186 // On linux we first attempt to pass the SOCK_CLOEXEC flag to
187 // atomically create the socket and set it as CLOEXEC. Support for
188 // this option, however, was added in 2.6.27, and we still support
189 // 2.6.18 as a kernel, so if the returned error is EINVAL we
190 // fallthrough to the fallback.
191 #[cfg(target_os = "linux")]
192 {
193 match cvt(libc::socket(family, ty | libc::SOCK_CLOEXEC, protocol)) {
194 Ok(fd) => return Ok(Socket::from_raw_fd(fd)),
195 Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}
196 Err(e) => return Err(e),
197 }
198 }
199
200 let fd = cvt(libc::socket(family, ty, protocol))?;
201 let fd = Socket::from_raw_fd(fd);
202 set_cloexec(fd.as_raw_fd())?;
fc512014 203 #[cfg(any(target_os = "macos", target_os = "ios"))]
0531ce1d
XL
204 {
205 fd.setsockopt(libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1i32)?;
206 }
207 Ok(fd)
208 }
209 }
210
211 pub fn pair(family: c_int, ty: c_int, protocol: c_int) -> io::Result<(Socket, Socket)> {
212 unsafe {
213 let mut fds = [0, 0];
214 cvt(libc::socketpair(family, ty, protocol, fds.as_mut_ptr()))?;
215 let fds = (Socket::from_raw_fd(fds[0]), Socket::from_raw_fd(fds[1]));
216 set_cloexec(fds.0.as_raw_fd())?;
217 set_cloexec(fds.1.as_raw_fd())?;
fc512014 218 #[cfg(any(target_os = "macos", target_os = "ios"))]
0531ce1d
XL
219 {
220 fds.0
221 .setsockopt(libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1i32)?;
222 fds.1
223 .setsockopt(libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1i32)?;
224 }
225 Ok(fds)
226 }
227 }
228
229 pub fn bind(&self, addr: &SockAddr) -> io::Result<()> {
230 unsafe { cvt(libc::bind(self.fd, addr.as_ptr(), addr.len() as _)).map(|_| ()) }
231 }
232
233 pub fn listen(&self, backlog: i32) -> io::Result<()> {
234 unsafe { cvt(libc::listen(self.fd, backlog)).map(|_| ()) }
235 }
236
237 pub fn connect(&self, addr: &SockAddr) -> io::Result<()> {
238 unsafe { cvt(libc::connect(self.fd, addr.as_ptr(), addr.len())).map(|_| ()) }
239 }
240
241 pub fn connect_timeout(&self, addr: &SockAddr, timeout: Duration) -> io::Result<()> {
242 self.set_nonblocking(true)?;
243 let r = self.connect(addr);
244 self.set_nonblocking(false)?;
245
246 match r {
247 Ok(()) => return Ok(()),
248 // there's no io::ErrorKind conversion registered for EINPROGRESS :(
249 Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {}
250 Err(e) => return Err(e),
251 }
252
253 let mut pollfd = libc::pollfd {
254 fd: self.fd,
255 events: libc::POLLOUT,
256 revents: 0,
257 };
258
259 if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
260 return Err(io::Error::new(
261 io::ErrorKind::InvalidInput,
262 "cannot set a 0 duration timeout",
263 ));
264 }
265
266 let start = Instant::now();
267
268 loop {
269 let elapsed = start.elapsed();
270 if elapsed >= timeout {
271 return Err(io::Error::new(
272 io::ErrorKind::TimedOut,
273 "connection timed out",
274 ));
275 }
276
277 let timeout = timeout - elapsed;
278 let mut timeout = timeout
279 .as_secs()
280 .saturating_mul(1_000)
281 .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000);
282 if timeout == 0 {
283 timeout = 1;
284 }
285
286 let timeout = cmp::min(timeout, c_int::max_value() as u64) as c_int;
287
288 match unsafe { libc::poll(&mut pollfd, 1, timeout) } {
289 -1 => {
290 let err = io::Error::last_os_error();
291 if err.kind() != io::ErrorKind::Interrupted {
292 return Err(err);
293 }
294 }
295 0 => {
296 return Err(io::Error::new(
297 io::ErrorKind::TimedOut,
298 "connection timed out",
299 ))
300 }
301 _ => {
302 // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look
303 // for POLLHUP rather than read readiness
304 if pollfd.revents & libc::POLLHUP != 0 {
305 let e = self.take_error()?.unwrap_or_else(|| {
306 io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP")
307 });
308 return Err(e);
309 }
310 return Ok(());
311 }
312 }
313 }
314 }
315
316 pub fn local_addr(&self) -> io::Result<SockAddr> {
317 unsafe {
318 let mut storage: libc::sockaddr_storage = mem::zeroed();
319 let mut len = mem::size_of_val(&storage) as libc::socklen_t;
320 cvt(libc::getsockname(
321 self.fd,
322 &mut storage as *mut _ as *mut _,
323 &mut len,
324 ))?;
325 Ok(SockAddr::from_raw_parts(
326 &storage as *const _ as *const _,
327 len,
328 ))
329 }
330 }
331
332 pub fn peer_addr(&self) -> io::Result<SockAddr> {
333 unsafe {
334 let mut storage: libc::sockaddr_storage = mem::zeroed();
335 let mut len = mem::size_of_val(&storage) as libc::socklen_t;
336 cvt(libc::getpeername(
337 self.fd,
338 &mut storage as *mut _ as *mut _,
339 &mut len,
340 ))?;
341 Ok(SockAddr::from_raw_parts(
342 &storage as *const _ as *const _,
343 len,
344 ))
345 }
346 }
347
348 pub fn try_clone(&self) -> io::Result<Socket> {
349 // implementation lifted from libstd
350 #[cfg(any(target_os = "android", target_os = "haiku"))]
351 use libc::F_DUPFD as F_DUPFD_CLOEXEC;
352 #[cfg(not(any(target_os = "android", target_os = "haiku")))]
353 use libc::F_DUPFD_CLOEXEC;
354
dfeec247 355 static CLOEXEC_FAILED: AtomicBool = AtomicBool::new(false);
0531ce1d
XL
356 unsafe {
357 if !CLOEXEC_FAILED.load(Ordering::Relaxed) {
358 match cvt(libc::fcntl(self.fd, F_DUPFD_CLOEXEC, 0)) {
359 Ok(fd) => {
360 let fd = Socket::from_raw_fd(fd);
361 if cfg!(target_os = "linux") {
362 set_cloexec(fd.as_raw_fd())?;
363 }
364 return Ok(fd);
365 }
366 Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {
367 CLOEXEC_FAILED.store(true, Ordering::Relaxed);
368 }
369 Err(e) => return Err(e),
370 }
371 }
372 let fd = cvt(libc::fcntl(self.fd, libc::F_DUPFD, 0))?;
373 let fd = Socket::from_raw_fd(fd);
374 set_cloexec(fd.as_raw_fd())?;
375 Ok(fd)
376 }
377 }
378
379 #[allow(unused_mut)]
380 pub fn accept(&self) -> io::Result<(Socket, SockAddr)> {
381 let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
382 let mut len = mem::size_of_val(&storage) as socklen_t;
383
384 let mut socket = None;
385 #[cfg(target_os = "linux")]
386 {
dfeec247
XL
387 let res = cvt_r(|| unsafe {
388 libc::syscall(
389 libc::SYS_accept4,
390 self.fd as libc::c_long,
391 &mut storage as *mut _ as libc::c_long,
392 &mut len,
393 libc::SOCK_CLOEXEC as libc::c_long,
394 ) as libc::c_int
395 });
396 match res {
397 Ok(fd) => socket = Some(Socket { fd: fd }),
398 Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {}
399 Err(e) => return Err(e),
0531ce1d
XL
400 }
401 }
402
403 let socket = match socket {
404 Some(socket) => socket,
405 None => unsafe {
406 let fd =
407 cvt_r(|| libc::accept(self.fd, &mut storage as *mut _ as *mut _, &mut len))?;
408 let fd = Socket::from_raw_fd(fd);
409 set_cloexec(fd.as_raw_fd())?;
410 fd
411 },
412 };
413 let addr = unsafe { SockAddr::from_raw_parts(&storage as *const _ as *const _, len) };
414 Ok((socket, addr))
415 }
416
417 pub fn take_error(&self) -> io::Result<Option<io::Error>> {
418 unsafe {
419 let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_ERROR)?;
420 if raw == 0 {
421 Ok(None)
422 } else {
423 Ok(Some(io::Error::from_raw_os_error(raw as i32)))
424 }
425 }
426 }
427
428 pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
429 unsafe {
430 let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?;
431 let new = if nonblocking {
432 previous | libc::O_NONBLOCK
433 } else {
434 previous & !libc::O_NONBLOCK
435 };
436 if new != previous {
437 cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?;
438 }
439 Ok(())
440 }
441 }
442
443 pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
444 let how = match how {
445 Shutdown::Write => libc::SHUT_WR,
446 Shutdown::Read => libc::SHUT_RD,
447 Shutdown::Both => libc::SHUT_RDWR,
448 };
449 cvt(unsafe { libc::shutdown(self.fd, how) })?;
450 Ok(())
451 }
452
ba9703b0 453 pub fn recv(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
0531ce1d
XL
454 unsafe {
455 let n = cvt({
456 libc::recv(
457 self.fd,
458 buf.as_mut_ptr() as *mut c_void,
459 cmp::min(buf.len(), max_len()),
ba9703b0 460 flags,
0531ce1d
XL
461 )
462 })?;
463 Ok(n as usize)
464 }
465 }
466
467 pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
468 unsafe {
469 let n = cvt({
470 libc::recv(
471 self.fd,
472 buf.as_mut_ptr() as *mut c_void,
473 cmp::min(buf.len(), max_len()),
474 libc::MSG_PEEK,
475 )
476 })?;
477 Ok(n as usize)
478 }
479 }
480
0531ce1d 481 pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> {
ba9703b0 482 self.recv_from(buf, libc::MSG_PEEK)
0531ce1d
XL
483 }
484
ba9703b0 485 pub fn recv_from(&self, buf: &mut [u8], flags: c_int) -> io::Result<(usize, SockAddr)> {
0531ce1d
XL
486 unsafe {
487 let mut storage: libc::sockaddr_storage = mem::zeroed();
488 let mut addrlen = mem::size_of_val(&storage) as socklen_t;
489
490 let n = cvt({
491 libc::recvfrom(
492 self.fd,
493 buf.as_mut_ptr() as *mut c_void,
494 cmp::min(buf.len(), max_len()),
495 flags,
496 &mut storage as *mut _ as *mut _,
497 &mut addrlen,
498 )
499 })?;
500 let addr = SockAddr::from_raw_parts(&storage as *const _ as *const _, addrlen);
501 Ok((n as usize, addr))
502 }
503 }
504
ba9703b0 505 pub fn send(&self, buf: &[u8], flags: c_int) -> io::Result<usize> {
0531ce1d
XL
506 unsafe {
507 let n = cvt({
508 libc::send(
509 self.fd,
510 buf.as_ptr() as *const c_void,
511 cmp::min(buf.len(), max_len()),
ba9703b0 512 flags,
0531ce1d
XL
513 )
514 })?;
515 Ok(n as usize)
516 }
517 }
518
ba9703b0 519 pub fn send_to(&self, buf: &[u8], flags: c_int, addr: &SockAddr) -> io::Result<usize> {
0531ce1d
XL
520 unsafe {
521 let n = cvt({
522 libc::sendto(
523 self.fd,
524 buf.as_ptr() as *const c_void,
525 cmp::min(buf.len(), max_len()),
ba9703b0 526 flags,
0531ce1d
XL
527 addr.as_ptr(),
528 addr.len(),
529 )
530 })?;
531 Ok(n as usize)
532 }
533 }
534
535 // ================================================
536
537 pub fn ttl(&self) -> io::Result<u32> {
538 unsafe {
539 let raw: c_int = self.getsockopt(libc::IPPROTO_IP, libc::IP_TTL)?;
540 Ok(raw as u32)
541 }
542 }
543
544 pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
545 unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_TTL, ttl as c_int) }
546 }
547
5869c6ff
XL
548 #[cfg(not(target_os = "redox"))]
549 pub fn mss(&self) -> io::Result<u32> {
550 unsafe {
551 let raw: c_int = self.getsockopt(libc::IPPROTO_TCP, libc::TCP_MAXSEG)?;
552 Ok(raw as u32)
553 }
554 }
555
556 #[cfg(not(target_os = "redox"))]
557 pub fn set_mss(&self, mss: u32) -> io::Result<()> {
558 unsafe { self.setsockopt(libc::IPPROTO_TCP, libc::TCP_MAXSEG, mss as c_int) }
559 }
560
561 #[cfg(target_os = "linux")]
562 pub fn mark(&self) -> io::Result<u32> {
563 unsafe {
564 let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_MARK)?;
565 Ok(raw as u32)
566 }
567 }
568
569 #[cfg(target_os = "linux")]
570 pub fn set_mark(&self, mark: u32) -> io::Result<()> {
571 unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_MARK, mark as c_int) }
572 }
573
574 #[cfg(target_os = "linux")]
575 pub fn device(&self) -> io::Result<Option<CString>> {
576 // TODO: replace with `MaybeUninit::uninit_array` once stable.
577 let mut buf: [MaybeUninit<u8>; libc::IFNAMSIZ] =
578 unsafe { MaybeUninit::<[MaybeUninit<u8>; libc::IFNAMSIZ]>::uninit().assume_init() };
579 let mut len = buf.len() as libc::socklen_t;
580 let len = unsafe {
581 cvt(libc::getsockopt(
582 self.fd,
583 libc::SOL_SOCKET,
584 libc::SO_BINDTODEVICE,
585 buf.as_mut_ptr().cast(),
586 &mut len,
587 ))?
588 };
589 if len == 0 {
590 Ok(None)
591 } else {
592 // Allocate a buffer for `CString` with the length including the
593 // null terminator.
594 let len = len as usize;
595 let mut name = Vec::with_capacity(len);
596
597 // TODO: use `MaybeUninit::slice_assume_init_ref` once stable.
598 // Safety: `len` bytes are writen by the OS, this includes a null
599 // terminator. However we don't copy the null terminator because
600 // `CString::from_vec_unchecked` adds its own null terminator.
601 let buf = unsafe { slice::from_raw_parts(buf.as_ptr().cast(), len - 1) };
602 name.extend_from_slice(buf);
603
604 // Safety: the OS initialised the string for us, which shouldn't
605 // include any null bytes.
606 Ok(Some(unsafe { CString::from_vec_unchecked(name) }))
607 }
608 }
609
610 #[cfg(target_os = "linux")]
611 pub fn bind_device(&self, interface: Option<&CStr>) -> io::Result<()> {
612 let (value, len) = if let Some(interface) = interface {
613 (interface.as_ptr(), interface.to_bytes_with_nul().len())
614 } else {
615 (ptr::null(), 0)
616 };
617
618 unsafe {
619 cvt(libc::setsockopt(
620 self.fd,
621 libc::SOL_SOCKET,
622 libc::SO_BINDTODEVICE,
623 value.cast(),
624 len as libc::socklen_t,
625 ))
626 .map(|_| ())
627 }
628 }
629
0531ce1d
XL
630 pub fn unicast_hops_v6(&self) -> io::Result<u32> {
631 unsafe {
632 let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_UNICAST_HOPS)?;
633 Ok(raw as u32)
634 }
635 }
636
637 pub fn set_unicast_hops_v6(&self, hops: u32) -> io::Result<()> {
638 unsafe {
639 self.setsockopt(
640 libc::IPPROTO_IPV6 as c_int,
641 libc::IPV6_UNICAST_HOPS,
642 hops as c_int,
643 )
644 }
645 }
646
647 pub fn only_v6(&self) -> io::Result<bool> {
648 unsafe {
649 let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_V6ONLY)?;
650 Ok(raw != 0)
651 }
652 }
653
654 pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
655 unsafe { self.setsockopt(libc::IPPROTO_IPV6, libc::IPV6_V6ONLY, only_v6 as c_int) }
656 }
657
658 pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
659 unsafe {
dfeec247
XL
660 Ok(timeval2dur(
661 self.getsockopt(libc::SOL_SOCKET, libc::SO_RCVTIMEO)?,
662 ))
0531ce1d
XL
663 }
664 }
665
666 pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
667 unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_RCVTIMEO, dur2timeval(dur)?) }
668 }
669
670 pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
671 unsafe {
dfeec247
XL
672 Ok(timeval2dur(
673 self.getsockopt(libc::SOL_SOCKET, libc::SO_SNDTIMEO)?,
674 ))
0531ce1d
XL
675 }
676 }
677
678 pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
679 unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_SNDTIMEO, dur2timeval(dur)?) }
680 }
681
682 pub fn nodelay(&self) -> io::Result<bool> {
683 unsafe {
684 let raw: c_int = self.getsockopt(libc::IPPROTO_TCP, libc::TCP_NODELAY)?;
685 Ok(raw != 0)
686 }
687 }
688
689 pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
690 unsafe { self.setsockopt(libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) }
691 }
692
693 pub fn broadcast(&self) -> io::Result<bool> {
694 unsafe {
695 let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_BROADCAST)?;
696 Ok(raw != 0)
697 }
698 }
699
700 pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
701 unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_BROADCAST, broadcast as c_int) }
702 }
703
704 pub fn multicast_loop_v4(&self) -> io::Result<bool> {
705 unsafe {
706 let raw: c_int = self.getsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP)?;
707 Ok(raw != 0)
708 }
709 }
710
711 pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> {
712 unsafe {
713 self.setsockopt(
714 libc::IPPROTO_IP,
715 libc::IP_MULTICAST_LOOP,
716 multicast_loop_v4 as c_int,
717 )
718 }
719 }
720
721 pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
722 unsafe {
723 let raw: c_int = self.getsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_TTL)?;
724 Ok(raw as u32)
725 }
726 }
727
728 pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> {
729 unsafe {
730 self.setsockopt(
731 libc::IPPROTO_IP,
732 libc::IP_MULTICAST_TTL,
733 multicast_ttl_v4 as c_int,
734 )
735 }
736 }
737
738 pub fn multicast_hops_v6(&self) -> io::Result<u32> {
739 unsafe {
740 let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_MULTICAST_HOPS)?;
741 Ok(raw as u32)
742 }
743 }
744
745 pub fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()> {
746 unsafe { self.setsockopt(libc::IPPROTO_IPV6, libc::IPV6_MULTICAST_HOPS, hops as c_int) }
747 }
748
749 pub fn multicast_if_v4(&self) -> io::Result<Ipv4Addr> {
750 unsafe {
751 let imr_interface: libc::in_addr =
752 self.getsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_IF)?;
753 Ok(from_s_addr(imr_interface.s_addr))
754 }
755 }
756
757 pub fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()> {
758 let interface = to_s_addr(interface);
759 let imr_interface = libc::in_addr { s_addr: interface };
760
761 unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_IF, imr_interface) }
762 }
763
764 pub fn multicast_if_v6(&self) -> io::Result<u32> {
765 unsafe {
766 let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_MULTICAST_IF)?;
767 Ok(raw as u32)
768 }
769 }
770
771 pub fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()> {
772 unsafe {
773 self.setsockopt(
774 libc::IPPROTO_IPV6,
775 libc::IPV6_MULTICAST_IF,
776 interface as c_int,
777 )
778 }
779 }
780
781 pub fn multicast_loop_v6(&self) -> io::Result<bool> {
782 unsafe {
783 let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_MULTICAST_LOOP)?;
784 Ok(raw != 0)
785 }
786 }
787
788 pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> {
789 unsafe {
790 self.setsockopt(
791 libc::IPPROTO_IPV6,
792 libc::IPV6_MULTICAST_LOOP,
793 multicast_loop_v6 as c_int,
794 )
795 }
796 }
797
798 pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
799 let multiaddr = to_s_addr(multiaddr);
800 let interface = to_s_addr(interface);
801 let mreq = libc::ip_mreq {
802 imr_multiaddr: libc::in_addr { s_addr: multiaddr },
803 imr_interface: libc::in_addr { s_addr: interface },
804 };
805 unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_ADD_MEMBERSHIP, mreq) }
806 }
807
808 pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
809 let multiaddr = to_in6_addr(multiaddr);
810 let mreq = libc::ipv6_mreq {
811 ipv6mr_multiaddr: multiaddr,
812 ipv6mr_interface: to_ipv6mr_interface(interface),
813 };
814 unsafe { self.setsockopt(libc::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq) }
815 }
816
817 pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
818 let multiaddr = to_s_addr(multiaddr);
819 let interface = to_s_addr(interface);
820 let mreq = libc::ip_mreq {
821 imr_multiaddr: libc::in_addr { s_addr: multiaddr },
822 imr_interface: libc::in_addr { s_addr: interface },
823 };
824 unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_DROP_MEMBERSHIP, mreq) }
825 }
826
827 pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
828 let multiaddr = to_in6_addr(multiaddr);
829 let mreq = libc::ipv6_mreq {
830 ipv6mr_multiaddr: multiaddr,
831 ipv6mr_interface: to_ipv6mr_interface(interface),
832 };
833 unsafe { self.setsockopt(libc::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq) }
834 }
835
836 pub fn linger(&self) -> io::Result<Option<Duration>> {
837 unsafe {
dfeec247
XL
838 Ok(linger2dur(
839 self.getsockopt(libc::SOL_SOCKET, libc::SO_LINGER)?,
840 ))
0531ce1d
XL
841 }
842 }
843
844 pub fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> {
845 unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_LINGER, dur2linger(dur)) }
846 }
847
848 pub fn set_reuse_address(&self, reuse: bool) -> io::Result<()> {
849 unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_REUSEADDR, reuse as c_int) }
850 }
851
852 pub fn reuse_address(&self) -> io::Result<bool> {
853 unsafe {
854 let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_REUSEADDR)?;
855 Ok(raw != 0)
856 }
857 }
858
859 pub fn recv_buffer_size(&self) -> io::Result<usize> {
860 unsafe {
861 let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_RCVBUF)?;
862 Ok(raw as usize)
863 }
864 }
865
866 pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> {
867 unsafe {
868 // TODO: casting usize to a c_int should be a checked cast
869 self.setsockopt(libc::SOL_SOCKET, libc::SO_RCVBUF, size as c_int)
870 }
871 }
872
873 pub fn send_buffer_size(&self) -> io::Result<usize> {
874 unsafe {
875 let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_SNDBUF)?;
876 Ok(raw as usize)
877 }
878 }
879
880 pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> {
881 unsafe {
882 // TODO: casting usize to a c_int should be a checked cast
883 self.setsockopt(libc::SOL_SOCKET, libc::SO_SNDBUF, size as c_int)
884 }
885 }
886
887 pub fn keepalive(&self) -> io::Result<Option<Duration>> {
888 unsafe {
889 let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_KEEPALIVE)?;
890 if raw == 0 {
891 return Ok(None);
892 }
893 let secs: c_int = self.getsockopt(libc::IPPROTO_TCP, KEEPALIVE_OPTION)?;
894 Ok(Some(Duration::new(secs as u64, 0)))
895 }
896 }
897
898 pub fn set_keepalive(&self, keepalive: Option<Duration>) -> io::Result<()> {
899 unsafe {
900 self.setsockopt(
901 libc::SOL_SOCKET,
902 libc::SO_KEEPALIVE,
903 keepalive.is_some() as c_int,
904 )?;
905 if let Some(dur) = keepalive {
906 // TODO: checked cast here
dfeec247 907 self.setsockopt(libc::IPPROTO_TCP, KEEPALIVE_OPTION, dur.as_secs() as c_int)?;
0531ce1d
XL
908 }
909 Ok(())
910 }
911 }
912
ba9703b0
XL
913 #[cfg(all(
914 unix,
915 not(any(target_os = "solaris", target_os = "illumos")),
916 feature = "reuseport"
917 ))]
0531ce1d
XL
918 pub fn reuse_port(&self) -> io::Result<bool> {
919 unsafe {
920 let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_REUSEPORT)?;
921 Ok(raw != 0)
922 }
923 }
924
ba9703b0
XL
925 #[cfg(all(
926 unix,
927 not(any(target_os = "solaris", target_os = "illumos")),
928 feature = "reuseport"
929 ))]
0531ce1d
XL
930 pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> {
931 unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_REUSEPORT, reuse as c_int) }
932 }
933
ba9703b0
XL
934 pub fn out_of_band_inline(&self) -> io::Result<bool> {
935 unsafe {
936 let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_OOBINLINE)?;
937 Ok(raw != 0)
938 }
939 }
940
941 pub fn set_out_of_band_inline(&self, oob_inline: bool) -> io::Result<()> {
942 unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_OOBINLINE, oob_inline as c_int) }
943 }
944
0531ce1d
XL
945 unsafe fn setsockopt<T>(&self, opt: c_int, val: c_int, payload: T) -> io::Result<()>
946 where
947 T: Copy,
948 {
949 let payload = &payload as *const T as *const c_void;
950 cvt(libc::setsockopt(
951 self.fd,
952 opt,
953 val,
954 payload,
955 mem::size_of::<T>() as libc::socklen_t,
956 ))?;
957 Ok(())
958 }
959
960 unsafe fn getsockopt<T: Copy>(&self, opt: c_int, val: c_int) -> io::Result<T> {
961 let mut slot: T = mem::zeroed();
962 let mut len = mem::size_of::<T>() as libc::socklen_t;
963 cvt(libc::getsockopt(
964 self.fd,
965 opt,
966 val,
967 &mut slot as *mut _ as *mut _,
968 &mut len,
969 ))?;
970 assert_eq!(len as usize, mem::size_of::<T>());
971 Ok(slot)
972 }
973}
974
975impl Read for Socket {
976 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
977 <&Socket>::read(&mut &*self, buf)
978 }
979}
980
981impl<'a> Read for &'a Socket {
982 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
983 unsafe {
984 let n = cvt({
985 libc::read(
986 self.fd,
987 buf.as_mut_ptr() as *mut c_void,
988 cmp::min(buf.len(), max_len()),
989 )
990 })?;
991 Ok(n as usize)
992 }
993 }
994}
995
996impl Write for Socket {
997 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
998 <&Socket>::write(&mut &*self, buf)
999 }
1000
1001 fn flush(&mut self) -> io::Result<()> {
1002 <&Socket>::flush(&mut &*self)
1003 }
1004}
1005
1006impl<'a> Write for &'a Socket {
1007 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
ba9703b0 1008 self.send(buf, 0)
0531ce1d
XL
1009 }
1010
1011 fn flush(&mut self) -> io::Result<()> {
1012 Ok(())
1013 }
1014}
1015
1016impl fmt::Debug for Socket {
1017 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1018 let mut f = f.debug_struct("Socket");
1019 f.field("fd", &self.fd);
1020 if let Ok(addr) = self.local_addr() {
1021 f.field("local_addr", &addr);
1022 }
1023 if let Ok(addr) = self.peer_addr() {
1024 f.field("peer_addr", &addr);
1025 }
1026 f.finish()
1027 }
1028}
1029
1030impl AsRawFd for Socket {
1031 fn as_raw_fd(&self) -> c_int {
1032 self.fd
1033 }
1034}
1035
1036impl IntoRawFd for Socket {
1037 fn into_raw_fd(self) -> c_int {
1038 let fd = self.fd;
1039 mem::forget(self);
1040 return fd;
1041 }
1042}
1043
1044impl FromRawFd for Socket {
1045 unsafe fn from_raw_fd(fd: c_int) -> Socket {
1046 Socket { fd: fd }
1047 }
1048}
1049
dfeec247 1050impl AsRawFd for crate::Socket {
0531ce1d
XL
1051 fn as_raw_fd(&self) -> c_int {
1052 self.inner.as_raw_fd()
1053 }
1054}
1055
dfeec247 1056impl IntoRawFd for crate::Socket {
0531ce1d
XL
1057 fn into_raw_fd(self) -> c_int {
1058 self.inner.into_raw_fd()
1059 }
1060}
1061
dfeec247
XL
1062impl FromRawFd for crate::Socket {
1063 unsafe fn from_raw_fd(fd: c_int) -> crate::Socket {
1064 crate::Socket {
0531ce1d
XL
1065 inner: Socket::from_raw_fd(fd),
1066 }
1067 }
1068}
1069
1070impl Drop for Socket {
1071 fn drop(&mut self) {
1072 unsafe {
1073 let _ = libc::close(self.fd);
1074 }
1075 }
1076}
1077
1078impl From<Socket> for net::TcpStream {
1079 fn from(socket: Socket) -> net::TcpStream {
1080 unsafe { net::TcpStream::from_raw_fd(socket.into_raw_fd()) }
1081 }
1082}
1083
1084impl From<Socket> for net::TcpListener {
1085 fn from(socket: Socket) -> net::TcpListener {
1086 unsafe { net::TcpListener::from_raw_fd(socket.into_raw_fd()) }
1087 }
1088}
1089
1090impl From<Socket> for net::UdpSocket {
1091 fn from(socket: Socket) -> net::UdpSocket {
1092 unsafe { net::UdpSocket::from_raw_fd(socket.into_raw_fd()) }
1093 }
1094}
1095
1096#[cfg(all(unix, feature = "unix"))]
1097impl From<Socket> for UnixStream {
1098 fn from(socket: Socket) -> UnixStream {
1099 unsafe { UnixStream::from_raw_fd(socket.into_raw_fd()) }
1100 }
1101}
1102
1103#[cfg(all(unix, feature = "unix"))]
1104impl From<Socket> for UnixListener {
1105 fn from(socket: Socket) -> UnixListener {
1106 unsafe { UnixListener::from_raw_fd(socket.into_raw_fd()) }
1107 }
1108}
1109
1110#[cfg(all(unix, feature = "unix"))]
1111impl From<Socket> for UnixDatagram {
1112 fn from(socket: Socket) -> UnixDatagram {
1113 unsafe { UnixDatagram::from_raw_fd(socket.into_raw_fd()) }
1114 }
1115}
1116
1117impl From<net::TcpStream> for Socket {
1118 fn from(socket: net::TcpStream) -> Socket {
1119 unsafe { Socket::from_raw_fd(socket.into_raw_fd()) }
1120 }
1121}
1122
1123impl From<net::TcpListener> for Socket {
1124 fn from(socket: net::TcpListener) -> Socket {
1125 unsafe { Socket::from_raw_fd(socket.into_raw_fd()) }
1126 }
1127}
1128
1129impl From<net::UdpSocket> for Socket {
1130 fn from(socket: net::UdpSocket) -> Socket {
1131 unsafe { Socket::from_raw_fd(socket.into_raw_fd()) }
1132 }
1133}
1134
1135#[cfg(all(unix, feature = "unix"))]
1136impl From<UnixStream> for Socket {
1137 fn from(socket: UnixStream) -> Socket {
1138 unsafe { Socket::from_raw_fd(socket.into_raw_fd()) }
1139 }
1140}
1141
1142#[cfg(all(unix, feature = "unix"))]
1143impl From<UnixListener> for Socket {
1144 fn from(socket: UnixListener) -> Socket {
1145 unsafe { Socket::from_raw_fd(socket.into_raw_fd()) }
1146 }
1147}
1148
1149#[cfg(all(unix, feature = "unix"))]
1150impl From<UnixDatagram> for Socket {
1151 fn from(socket: UnixDatagram) -> Socket {
1152 unsafe { Socket::from_raw_fd(socket.into_raw_fd()) }
1153 }
1154}
1155
1156fn max_len() -> usize {
1157 // The maximum read limit on most posix-like systems is `SSIZE_MAX`,
1158 // with the man page quoting that if the count of bytes to read is
1159 // greater than `SSIZE_MAX` the result is "unspecified".
1160 //
1161 // On macOS, however, apparently the 64-bit libc is either buggy or
1162 // intentionally showing odd behavior by rejecting any read with a size
1163 // larger than or equal to INT_MAX. To handle both of these the read
1164 // size is capped on both platforms.
1165 if cfg!(target_os = "macos") {
1166 <c_int>::max_value() as usize - 1
1167 } else {
1168 <ssize_t>::max_value() as usize
1169 }
1170}
1171
1172fn cvt<T: One + PartialEq + Neg<Output = T>>(t: T) -> io::Result<T> {
1173 let one: T = T::one();
1174 if t == -one {
1175 Err(io::Error::last_os_error())
1176 } else {
1177 Ok(t)
1178 }
1179}
1180
1181fn cvt_r<F, T>(mut f: F) -> io::Result<T>
1182where
1183 F: FnMut() -> T,
1184 T: One + PartialEq + Neg<Output = T>,
1185{
1186 loop {
1187 match cvt(f()) {
1188 Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
1189 other => return other,
1190 }
1191 }
1192}
1193
1194fn set_cloexec(fd: c_int) -> io::Result<()> {
1195 unsafe {
1196 let previous = cvt(libc::fcntl(fd, libc::F_GETFD))?;
1197 let new = previous | libc::FD_CLOEXEC;
1198 if new != previous {
1199 cvt(libc::fcntl(fd, libc::F_SETFD, new))?;
1200 }
1201 Ok(())
1202 }
1203}
1204
1205fn dur2timeval(dur: Option<Duration>) -> io::Result<libc::timeval> {
1206 match dur {
1207 Some(dur) => {
1208 if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
1209 return Err(io::Error::new(
1210 io::ErrorKind::InvalidInput,
1211 "cannot set a 0 duration timeout",
1212 ));
1213 }
1214
1215 let secs = if dur.as_secs() > libc::time_t::max_value() as u64 {
1216 libc::time_t::max_value()
1217 } else {
1218 dur.as_secs() as libc::time_t
1219 };
1220 let mut timeout = libc::timeval {
1221 tv_sec: secs,
1222 tv_usec: (dur.subsec_nanos() / 1000) as libc::suseconds_t,
1223 };
1224 if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
1225 timeout.tv_usec = 1;
1226 }
1227 Ok(timeout)
1228 }
1229 None => Ok(libc::timeval {
1230 tv_sec: 0,
1231 tv_usec: 0,
1232 }),
1233 }
1234}
1235
1236fn timeval2dur(raw: libc::timeval) -> Option<Duration> {
1237 if raw.tv_sec == 0 && raw.tv_usec == 0 {
1238 None
1239 } else {
1240 let sec = raw.tv_sec as u64;
1241 let nsec = (raw.tv_usec as u32) * 1000;
1242 Some(Duration::new(sec, nsec))
1243 }
1244}
1245
1246fn to_s_addr(addr: &Ipv4Addr) -> libc::in_addr_t {
1247 let octets = addr.octets();
dfeec247
XL
1248 crate::hton(
1249 ((octets[0] as libc::in_addr_t) << 24)
1250 | ((octets[1] as libc::in_addr_t) << 16)
1251 | ((octets[2] as libc::in_addr_t) << 8)
1252 | ((octets[3] as libc::in_addr_t) << 0),
0531ce1d
XL
1253 )
1254}
1255
1256fn from_s_addr(in_addr: libc::in_addr_t) -> Ipv4Addr {
dfeec247 1257 let h_addr = crate::ntoh(in_addr);
0531ce1d
XL
1258
1259 let a: u8 = (h_addr >> 24) as u8;
1260 let b: u8 = (h_addr >> 16) as u8;
1261 let c: u8 = (h_addr >> 8) as u8;
1262 let d: u8 = (h_addr >> 0) as u8;
1263
1264 Ipv4Addr::new(a, b, c, d)
1265}
1266
1267fn to_in6_addr(addr: &Ipv6Addr) -> libc::in6_addr {
1268 let mut ret: libc::in6_addr = unsafe { mem::zeroed() };
1269 ret.s6_addr = addr.octets();
1270 return ret;
1271}
1272
1273#[cfg(target_os = "android")]
1274fn to_ipv6mr_interface(value: u32) -> c_int {
1275 value as c_int
1276}
1277
1278#[cfg(not(target_os = "android"))]
1279fn to_ipv6mr_interface(value: u32) -> libc::c_uint {
1280 value as libc::c_uint
1281}
1282
1283fn linger2dur(linger_opt: libc::linger) -> Option<Duration> {
1284 if linger_opt.l_onoff == 0 {
1285 None
1286 } else {
1287 Some(Duration::from_secs(linger_opt.l_linger as u64))
1288 }
1289}
1290
1291fn dur2linger(dur: Option<Duration>) -> libc::linger {
1292 match dur {
1293 Some(d) => libc::linger {
1294 l_onoff: 1,
1295 l_linger: d.as_secs() as c_int,
1296 },
1297 None => libc::linger {
1298 l_onoff: 0,
1299 l_linger: 0,
1300 },
1301 }
1302}
1303
1304#[test]
1305fn test_ip() {
1306 let ip = Ipv4Addr::new(127, 0, 0, 1);
1307 assert_eq!(ip, from_s_addr(to_s_addr(&ip)));
1308}
ba9703b0
XL
1309
1310#[test]
1311fn test_out_of_band_inline() {
1312 let tcp = Socket::new(libc::AF_INET, libc::SOCK_STREAM, 0).unwrap();
1313 assert_eq!(tcp.out_of_band_inline().unwrap(), false);
1314
1315 tcp.set_out_of_band_inline(true).unwrap();
1316 assert_eq!(tcp.out_of_band_inline().unwrap(), true);
1317}