1 // Copyright 2014 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.
18 use super::{last_error, last_net_error, retry, sock_t};
20 use sync::atomic::{AtomicBool, Ordering};
21 use sys::fs::FileDesc;
22 use sys::{set_nonblocking, wouldblock};
26 use sys_common::net::SocketStatus::Readable;
28 pub use sys_common::net::TcpStream;
30 ////////////////////////////////////////////////////////////////////////////////
32 ////////////////////////////////////////////////////////////////////////////////
34 pub struct TcpListener {
38 unsafe impl Sync for TcpListener {}
41 pub fn bind(addr: ip::SocketAddr) -> IoResult<TcpListener> {
42 let fd = try!(net::socket(addr, libc::SOCK_STREAM));
43 let ret = TcpListener { inner: FileDesc::new(fd, true) };
45 let mut storage = unsafe { mem::zeroed() };
46 let len = net::addr_to_sockaddr(addr, &mut storage);
47 let addrp = &storage as *const _ as *const libc::sockaddr;
49 // On platforms with Berkeley-derived sockets, this allows
50 // to quickly rebind a socket, without needing to wait for
51 // the OS to clean up the previous one.
52 try!(net::setsockopt(fd, libc::SOL_SOCKET,
57 match unsafe { libc::bind(fd, addrp, len) } {
58 -1 => Err(last_error()),
63 pub fn fd(&self) -> sock_t { self.inner.fd() }
65 pub fn listen(self, backlog: int) -> IoResult<TcpAcceptor> {
66 match unsafe { libc::listen(self.fd(), backlog as libc::c_int) } {
67 -1 => Err(last_net_error()),
69 let (reader, writer) = try!(unsafe { sys::os::pipe() });
70 try!(set_nonblocking(reader.fd(), true));
71 try!(set_nonblocking(writer.fd(), true));
72 try!(set_nonblocking(self.fd(), true));
74 inner: Arc::new(AcceptorInner {
78 closed: AtomicBool::new(false),
86 pub fn socket_name(&mut self) -> IoResult<ip::SocketAddr> {
87 net::sockname(self.fd(), libc::getsockname)
91 pub struct TcpAcceptor {
92 inner: Arc<AcceptorInner>,
96 struct AcceptorInner {
97 listener: TcpListener,
103 unsafe impl Sync for AcceptorInner {}
106 pub fn fd(&self) -> sock_t { self.inner.listener.fd() }
108 pub fn accept(&mut self) -> IoResult<TcpStream> {
109 // In implementing accept, the two main concerns are dealing with
110 // close_accept() and timeouts. The unix implementation is based on a
111 // nonblocking accept plus a call to select(). Windows ends up having
112 // an entirely separate implementation than unix, which is explained
115 // To implement timeouts, all blocking is done via select() instead of
116 // accept() by putting the socket in non-blocking mode. Because
117 // select() takes a timeout argument, we just pass through the timeout
120 // To implement close_accept(), we have a self-pipe to ourselves which
121 // is passed to select() along with the socket being accepted on. The
122 // self-pipe is never written to unless close_accept() is called.
123 let deadline = if self.deadline == 0 {None} else {Some(self.deadline)};
125 while !self.inner.closed.load(Ordering::SeqCst) {
126 match retry(|| unsafe {
127 libc::accept(self.fd(), ptr::null_mut(), ptr::null_mut())
129 -1 if wouldblock() => {}
130 -1 => return Err(last_net_error()),
131 fd => return Ok(TcpStream::new(fd as sock_t)),
133 try!(net::await(&[self.fd(), self.inner.reader.fd()],
134 deadline, Readable));
137 Err(sys_common::eof())
140 pub fn socket_name(&mut self) -> IoResult<ip::SocketAddr> {
141 net::sockname(self.fd(), libc::getsockname)
144 pub fn set_timeout(&mut self, timeout: Option<u64>) {
145 self.deadline = timeout.map(|a| sys::timer::now() + a).unwrap_or(0);
148 pub fn close_accept(&mut self) -> IoResult<()> {
149 self.inner.closed.store(true, Ordering::SeqCst);
150 let fd = FileDesc::new(self.inner.writer.fd(), false);
151 match fd.write(&[0]) {
153 Err(..) if wouldblock() => Ok(()),
159 impl Clone for TcpAcceptor {
160 fn clone(&self) -> TcpAcceptor {
162 inner: self.inner.clone(),