|
3 | 3 | //! [Further reading](http://man7.org/linux/man-pages/man7/socket.7.html)
|
4 | 4 | use {Error, Errno, Result};
|
5 | 5 | use features;
|
6 |
| -use fcntl::{fcntl, FD_CLOEXEC, O_NONBLOCK}; |
7 |
| -use fcntl::FcntlArg::{F_SETFD, F_SETFL}; |
8 | 6 | use libc::{self, c_void, c_int, socklen_t, size_t, pid_t, uid_t, gid_t};
|
9 | 7 | use std::{mem, ptr, slice};
|
10 | 8 | use std::os::unix::io::RawFd;
|
@@ -92,13 +90,34 @@ pub enum SockProtocol {
|
92 | 90 | KextControl = libc::SYSPROTO_CONTROL,
|
93 | 91 | }
|
94 | 92 |
|
95 |
| -bitflags!( |
96 |
| - /// Extra flags - Supported by Linux 2.6.27, normalized on other platforms |
97 |
| - pub struct SockFlag: c_int { |
98 |
| - const SOCK_NONBLOCK = 0o0004000; |
99 |
| - const SOCK_CLOEXEC = 0o2000000; |
| 93 | +libc_bitflags!{ |
| 94 | + /// Additional socket options |
| 95 | + pub flags SockFlag: c_int { |
| 96 | + /// Set non-blocking mode on the new socket |
| 97 | + #[cfg(any(target_os = "android", |
| 98 | + target_os = "dragonfly", |
| 99 | + target_os = "freebsd", |
| 100 | + target_os = "linux", |
| 101 | + target_os = "netbsd", |
| 102 | + target_os = "openbsd"))] |
| 103 | + SOCK_NONBLOCK, |
| 104 | + /// Set close-on-exec on the new descriptor |
| 105 | + #[cfg(any(target_os = "android", |
| 106 | + target_os = "dragonfly", |
| 107 | + target_os = "freebsd", |
| 108 | + target_os = "linux", |
| 109 | + target_os = "netbsd", |
| 110 | + target_os = "openbsd"))] |
| 111 | + SOCK_CLOEXEC, |
| 112 | + /// Return `EPIPE` instead of raising `SIGPIPE` |
| 113 | + #[cfg(target_os = "netbsd")] |
| 114 | + SOCK_NOSIGPIPE, |
| 115 | + /// For domains `AF_INET(6)`, only allow `connect(2)`, `sendto(2)`, or `sendmsg(2)` |
| 116 | + /// to the DNS port (typically 53) |
| 117 | + #[cfg(target_os = "openbsd")] |
| 118 | + SOCK_DNS, |
100 | 119 | }
|
101 |
| -); |
| 120 | +} |
102 | 121 |
|
103 | 122 | libc_bitflags!{
|
104 | 123 | /// Flags for send/recv and their relatives
|
@@ -449,13 +468,24 @@ pub fn socket<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType
|
449 | 468 | // TODO: Check the kernel version
|
450 | 469 | let res = try!(Errno::result(unsafe { ffi::socket(domain as c_int, ty, protocol) }));
|
451 | 470 |
|
452 |
| - if !feat_atomic { |
453 |
| - if flags.contains(SOCK_CLOEXEC) { |
454 |
| - try!(fcntl(res, F_SETFD(FD_CLOEXEC))); |
455 |
| - } |
| 471 | + #[cfg(any(target_os = "android", |
| 472 | + target_os = "dragonfly", |
| 473 | + target_os = "freebsd", |
| 474 | + target_os = "linux", |
| 475 | + target_os = "netbsd", |
| 476 | + target_os = "openbsd"))] |
| 477 | + { |
| 478 | + use fcntl::{fcntl, FD_CLOEXEC, O_NONBLOCK}; |
| 479 | + use fcntl::FcntlArg::{F_SETFD, F_SETFL}; |
456 | 480 |
|
457 |
| - if flags.contains(SOCK_NONBLOCK) { |
458 |
| - try!(fcntl(res, F_SETFL(O_NONBLOCK))); |
| 481 | + if !feat_atomic { |
| 482 | + if flags.contains(SOCK_CLOEXEC) { |
| 483 | + try!(fcntl(res, F_SETFD(FD_CLOEXEC))); |
| 484 | + } |
| 485 | + |
| 486 | + if flags.contains(SOCK_NONBLOCK) { |
| 487 | + try!(fcntl(res, F_SETFL(O_NONBLOCK))); |
| 488 | + } |
459 | 489 | }
|
460 | 490 | }
|
461 | 491 |
|
@@ -483,15 +513,26 @@ pub fn socketpair<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: Sock
|
483 | 513 | };
|
484 | 514 | try!(Errno::result(res));
|
485 | 515 |
|
486 |
| - if !feat_atomic { |
487 |
| - if flags.contains(SOCK_CLOEXEC) { |
488 |
| - try!(fcntl(fds[0], F_SETFD(FD_CLOEXEC))); |
489 |
| - try!(fcntl(fds[1], F_SETFD(FD_CLOEXEC))); |
490 |
| - } |
| 516 | + #[cfg(any(target_os = "android", |
| 517 | + target_os = "dragonfly", |
| 518 | + target_os = "freebsd", |
| 519 | + target_os = "linux", |
| 520 | + target_os = "netbsd", |
| 521 | + target_os = "openbsd"))] |
| 522 | + { |
| 523 | + use fcntl::{fcntl, FD_CLOEXEC, O_NONBLOCK}; |
| 524 | + use fcntl::FcntlArg::{F_SETFD, F_SETFL}; |
491 | 525 |
|
492 |
| - if flags.contains(SOCK_NONBLOCK) { |
493 |
| - try!(fcntl(fds[0], F_SETFL(O_NONBLOCK))); |
494 |
| - try!(fcntl(fds[1], F_SETFL(O_NONBLOCK))); |
| 526 | + if !feat_atomic { |
| 527 | + if flags.contains(SOCK_CLOEXEC) { |
| 528 | + try!(fcntl(fds[0], F_SETFD(FD_CLOEXEC))); |
| 529 | + try!(fcntl(fds[1], F_SETFD(FD_CLOEXEC))); |
| 530 | + } |
| 531 | + |
| 532 | + if flags.contains(SOCK_NONBLOCK) { |
| 533 | + try!(fcntl(fds[0], F_SETFL(O_NONBLOCK))); |
| 534 | + try!(fcntl(fds[1], F_SETFL(O_NONBLOCK))); |
| 535 | + } |
495 | 536 | }
|
496 | 537 | }
|
497 | 538 | Ok((fds[0], fds[1]))
|
@@ -554,14 +595,37 @@ pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> {
|
554 | 595 | fn accept4_polyfill(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> {
|
555 | 596 | let res = try!(Errno::result(unsafe { ffi::accept(sockfd, ptr::null_mut(), ptr::null_mut()) }));
|
556 | 597 |
|
557 |
| - if flags.contains(SOCK_CLOEXEC) { |
558 |
| - try!(fcntl(res, F_SETFD(FD_CLOEXEC))); |
| 598 | + #[cfg(any(target_os = "android", |
| 599 | + target_os = "dragonfly", |
| 600 | + target_os = "freebsd", |
| 601 | + target_os = "linux", |
| 602 | + target_os = "netbsd", |
| 603 | + target_os = "openbsd"))] |
| 604 | + { |
| 605 | + use fcntl::{fcntl, FD_CLOEXEC, O_NONBLOCK}; |
| 606 | + use fcntl::FcntlArg::{F_SETFD, F_SETFL}; |
| 607 | + |
| 608 | + if flags.contains(SOCK_CLOEXEC) { |
| 609 | + try!(fcntl(res, F_SETFD(FD_CLOEXEC))); |
| 610 | + } |
| 611 | + |
| 612 | + if flags.contains(SOCK_NONBLOCK) { |
| 613 | + try!(fcntl(res, F_SETFL(O_NONBLOCK))); |
| 614 | + } |
559 | 615 | }
|
560 | 616 |
|
561 |
| - if flags.contains(SOCK_NONBLOCK) { |
562 |
| - try!(fcntl(res, F_SETFL(O_NONBLOCK))); |
| 617 | + // Disable unused variable warning on some platforms |
| 618 | + #[cfg(not(any(target_os = "android", |
| 619 | + target_os = "dragonfly", |
| 620 | + target_os = "freebsd", |
| 621 | + target_os = "linux", |
| 622 | + target_os = "netbsd", |
| 623 | + target_os = "openbsd")))] |
| 624 | + { |
| 625 | + let _ = flags; |
563 | 626 | }
|
564 | 627 |
|
| 628 | + |
565 | 629 | Ok(res)
|
566 | 630 | }
|
567 | 631 |
|
|
0 commit comments