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.
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.
15 use libc
::{self, c_int, size_t, sockaddr, socklen_t}
;
16 use net
::{SocketAddr, Shutdown}
;
18 use sys
::fd
::FileDesc
;
19 use sys_common
::{AsInner, FromInner, IntoInner}
;
20 use sys_common
::net
::{getsockopt, setsockopt}
;
23 pub use sys
::{cvt, cvt_r}
;
24 pub extern crate libc
as netc
;
26 pub type wrlen_t
= size_t
;
28 // See below for the usage of SOCK_CLOEXEC, but this constant is only defined on
29 // Linux currently (e.g. support doesn't exist on other platforms). In order to
30 // get name resolution to work and things to compile we just define a dummy
31 // SOCK_CLOEXEC here for other platforms. Note that the dummy constant isn't
32 // actually ever used (the blocks below are wrapped in `if cfg!` as well.
33 #[cfg(target_os = "linux")]
34 use libc
::SOCK_CLOEXEC
;
35 #[cfg(not(target_os = "linux"))]
36 const SOCK_CLOEXEC
: c_int
= 0;
38 pub struct Socket(FileDesc
);
42 pub fn cvt_gai(err
: c_int
) -> io
::Result
<()> {
43 if err
== 0 { return Ok(()) }
46 str::from_utf8(CStr
::from_ptr(libc
::gai_strerror(err
)).to_bytes()).unwrap()
49 Err(io
::Error
::new(io
::ErrorKind
::Other
,
50 &format
!("failed to lookup address information: {}",
55 pub fn new(addr
: &SocketAddr
, ty
: c_int
) -> io
::Result
<Socket
> {
56 let fam
= match *addr
{
57 SocketAddr
::V4(..) => libc
::AF_INET
,
58 SocketAddr
::V6(..) => libc
::AF_INET6
,
60 Socket
::new_raw(fam
, ty
)
63 pub fn new_raw(fam
: c_int
, ty
: c_int
) -> io
::Result
<Socket
> {
65 // On linux we first attempt to pass the SOCK_CLOEXEC flag to
66 // atomically create the socket and set it as CLOEXEC. Support for
67 // this option, however, was added in 2.6.27, and we still support
68 // 2.6.18 as a kernel, so if the returned error is EINVAL we
69 // fallthrough to the fallback.
71 match cvt(libc
::socket(fam
, ty
| SOCK_CLOEXEC
, 0)) {
72 Ok(fd
) => return Ok(Socket(FileDesc
::new(fd
))),
73 Err(ref e
) if e
.raw_os_error() == Some(libc
::EINVAL
) => {}
74 Err(e
) => return Err(e
),
78 let fd
= cvt(libc
::socket(fam
, ty
, 0))?
;
79 let fd
= FileDesc
::new(fd
);
85 pub fn new_pair(fam
: c_int
, ty
: c_int
) -> io
::Result
<(Socket
, Socket
)> {
89 // Like above, see if we can set cloexec atomically
91 match cvt(libc
::socketpair(fam
, ty
| SOCK_CLOEXEC
, 0, fds
.as_mut_ptr())) {
93 return Ok((Socket(FileDesc
::new(fds
[0])), Socket(FileDesc
::new(fds
[1]))));
95 Err(ref e
) if e
.raw_os_error() == Some(libc
::EINVAL
) => {}
,
96 Err(e
) => return Err(e
),
100 cvt(libc
::socketpair(fam
, ty
, 0, fds
.as_mut_ptr()))?
;
101 let a
= FileDesc
::new(fds
[0]);
103 let b
= FileDesc
::new(fds
[1]);
105 Ok((Socket(a
), Socket(b
)))
109 pub fn accept(&self, storage
: *mut sockaddr
, len
: *mut socklen_t
)
110 -> io
::Result
<Socket
> {
111 // Unfortunately the only known way right now to accept a socket and
112 // atomically set the CLOEXEC flag is to use the `accept4` syscall on
113 // Linux. This was added in 2.6.28, however, and because we support
114 // 2.6.18 we must detect this support dynamically.
115 if cfg
!(target_os
= "linux") {
117 fn accept4(c_int
, *mut sockaddr
, *mut socklen_t
, c_int
) -> c_int
119 if let Some(accept
) = accept4
.get() {
120 let res
= cvt_r(|| unsafe {
121 accept(self.0.raw(), storage
, len
, SOCK_CLOEXEC
)
124 Ok(fd
) => return Ok(Socket(FileDesc
::new(fd
))),
125 Err(ref e
) if e
.raw_os_error() == Some(libc
::ENOSYS
) => {}
126 Err(e
) => return Err(e
),
131 let fd
= cvt_r(|| unsafe {
132 libc
::accept(self.0.raw(), storage
, len
)
134 let fd
= FileDesc
::new(fd
);
139 pub fn duplicate(&self) -> io
::Result
<Socket
> {
140 self.0.duplicate().map(Socket
)
143 pub fn read(&self, buf
: &mut [u8]) -> io
::Result
<usize> {
147 pub fn read_to_end(&self, buf
: &mut Vec
<u8>) -> io
::Result
<usize> {
148 self.0.read_to_end(buf
)
151 pub fn write(&self, buf
: &[u8]) -> io
::Result
<usize> {
155 pub fn set_timeout(&self, dur
: Option
<Duration
>, kind
: libc
::c_int
) -> io
::Result
<()> {
156 let timeout
= match dur
{
158 if dur
.as_secs() == 0 && dur
.subsec_nanos() == 0 {
159 return Err(io
::Error
::new(io
::ErrorKind
::InvalidInput
,
160 "cannot set a 0 duration timeout"));
163 let secs
= if dur
.as_secs() > libc
::time_t
::max_value() as u64 {
164 libc
::time_t
::max_value()
166 dur
.as_secs() as libc
::time_t
168 let mut timeout
= libc
::timeval
{
170 tv_usec
: (dur
.subsec_nanos() / 1000) as libc
::suseconds_t
,
172 if timeout
.tv_sec
== 0 && timeout
.tv_usec
== 0 {
184 setsockopt(self, libc
::SOL_SOCKET
, kind
, timeout
)
187 pub fn timeout(&self, kind
: libc
::c_int
) -> io
::Result
<Option
<Duration
>> {
188 let raw
: libc
::timeval
= getsockopt(self, libc
::SOL_SOCKET
, kind
)?
;
189 if raw
.tv_sec
== 0 && raw
.tv_usec
== 0 {
192 let sec
= raw
.tv_sec
as u64;
193 let nsec
= (raw
.tv_usec
as u32) * 1000;
194 Ok(Some(Duration
::new(sec
, nsec
)))
198 pub fn shutdown(&self, how
: Shutdown
) -> io
::Result
<()> {
199 let how
= match how
{
200 Shutdown
::Write
=> libc
::SHUT_WR
,
201 Shutdown
::Read
=> libc
::SHUT_RD
,
202 Shutdown
::Both
=> libc
::SHUT_RDWR
,
204 cvt(unsafe { libc::shutdown(self.0.raw(), how) }
)?
;
208 pub fn set_nodelay(&self, nodelay
: bool
) -> io
::Result
<()> {
209 setsockopt(self, libc
::IPPROTO_TCP
, libc
::TCP_NODELAY
, nodelay
as c_int
)
212 pub fn nodelay(&self) -> io
::Result
<bool
> {
213 let raw
: c_int
= getsockopt(self, libc
::IPPROTO_TCP
, libc
::TCP_NODELAY
)?
;
217 pub fn set_nonblocking(&self, nonblocking
: bool
) -> io
::Result
<()> {
218 let mut nonblocking
= nonblocking
as libc
::c_ulong
;
219 cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO, &mut nonblocking) }
).map(|_
| ())
222 pub fn take_error(&self) -> io
::Result
<Option
<io
::Error
>> {
223 let raw
: c_int
= getsockopt(self, libc
::SOL_SOCKET
, libc
::SO_ERROR
)?
;
227 Ok(Some(io
::Error
::from_raw_os_error(raw
as i32)))
232 impl AsInner
<c_int
> for Socket
{
233 fn as_inner(&self) -> &c_int { self.0.as_inner() }
236 impl FromInner
<c_int
> for Socket
{
237 fn from_inner(fd
: c_int
) -> Socket { Socket(FileDesc::new(fd)) }
240 impl IntoInner
<c_int
> for Socket
{
241 fn into_inner(self) -> c_int { self.0.into_raw() }