[go: up one dir, main page]

net2/
tcp.rs

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::cell::RefCell;
12use std::io;
13use std::net::{SocketAddr, ToSocketAddrs, TcpListener, TcpStream};
14use std::fmt;
15
16use IntoInner;
17use socket::Socket;
18use sys::c;
19
20/// An "in progress" TCP socket which has not yet been connected or listened.
21///
22/// Allows configuration of a socket before one of these operations is executed.
23pub struct TcpBuilder {
24    socket: RefCell<Option<Socket>>,
25}
26
27impl TcpBuilder {
28    /// Constructs a new TcpBuilder with the `AF_INET` domain, the `SOCK_STREAM`
29    /// type, and with a protocol argument of 0.
30    ///
31    /// Note that passing other kinds of flags or arguments can be done through
32    /// the `FromRaw{Fd,Socket}` implementation.
33    pub fn new_v4() -> io::Result<TcpBuilder> {
34        Socket::new(c::AF_INET, c::SOCK_STREAM).map(::FromInner::from_inner)
35    }
36
37    /// Constructs a new TcpBuilder with the `AF_INET6` domain, the `SOCK_STREAM`
38    /// type, and with a protocol argument of 0.
39    ///
40    /// Note that passing other kinds of flags or arguments can be done through
41    /// the `FromRaw{Fd,Socket}` implementation.
42    pub fn new_v6() -> io::Result<TcpBuilder> {
43        Socket::new(c::AF_INET6, c::SOCK_STREAM).map(::FromInner::from_inner)
44    }
45
46    /// Binds this socket to the specified address.
47    ///
48    /// This function directly corresponds to the bind(2) function on Windows
49    /// and Unix.
50    pub fn bind<T>(&self, addr: T) -> io::Result<&TcpBuilder>
51        where T: ToSocketAddrs
52    {
53        self.with_socket(|sock| {
54            let addr = try!(::one_addr(addr));
55            sock.bind(&addr)
56        }).map(|()| self)
57    }
58
59    /// Mark a socket as ready to accept incoming connection requests using
60    /// accept()
61    ///
62    /// This function directly corresponds to the listen(2) function on Windows
63    /// and Unix.
64    ///
65    /// An error will be returned if `listen` or `connect` has already been
66    /// called on this builder.
67    pub fn listen(&self, backlog: i32) -> io::Result<TcpListener> {
68        self.with_socket(|sock| {
69            sock.listen(backlog)
70        }).and_then(|()| {
71            self.to_tcp_listener()
72        })
73    }
74
75    /// Initiate a connection on this socket to the specified address.
76    ///
77    /// This function directly corresponds to the connect(2) function on Windows
78    /// and Unix.
79    ///
80    /// An error will be returned if `listen` or `connect` has already been
81    /// called on this builder.
82    pub fn connect<T>(&self, addr: T) -> io::Result<TcpStream>
83        where T: ToSocketAddrs
84    {
85        self.with_socket(|sock| {
86            let err = io::Error::new(io::ErrorKind::Other,
87                                     "no socket addresses resolved");
88            try!(addr.to_socket_addrs()).fold(Err(err), |prev, addr| {
89                prev.or_else(|_| sock.connect(&addr))
90            })
91        }).and_then(|()| {
92            self.to_tcp_stream()
93        })
94    }
95
96    /// Converts this builder into a `TcpStream`
97    ///
98    /// This function will consume the internal socket and return it re-wrapped
99    /// as a `TcpStream`. An error will be returned if the internal socket has
100    /// already been consumed from a successful call to `connect`, `listen`,
101    /// etc.
102    pub fn to_tcp_stream(&self) -> io::Result<TcpStream> {
103        self.socket.borrow_mut().take().map(|s| s.into_inner().into_tcp_stream())
104            .ok_or(io::Error::new(io::ErrorKind::Other,
105                                  "socket has already been consumed"))
106    }
107
108    /// Converts this builder into a `TcpListener`
109    ///
110    /// This function will consume the internal socket and return it re-wrapped
111    /// as a `TcpListener`. An error will be returned if the internal socket has
112    /// already been consumed from a successful call to `connect`, `listen`,
113    /// etc.
114    pub fn to_tcp_listener(&self) -> io::Result<TcpListener> {
115        self.socket.borrow_mut().take()
116            .map(|s| s.into_inner().into_tcp_listener())
117            .ok_or(io::Error::new(io::ErrorKind::Other,
118                                  "socket has already been consumed"))
119    }
120
121    /// Returns the address of the local half of this TCP socket.
122    ///
123    /// An error will be returned if `listen` or `connect` has already been
124    /// called on this builder.
125    pub fn local_addr(&self) -> io::Result<SocketAddr> {
126        match *self.socket.borrow() {
127            Some(ref s) => s.getsockname(),
128            None => Err(io::Error::new(io::ErrorKind::Other,
129                                       "builder has already finished its socket")),
130        }
131    }
132
133    fn with_socket<F>(&self, f: F) -> io::Result<()>
134        where F: FnOnce(&Socket) -> io::Result<()>
135    {
136        match *self.socket.borrow() {
137            Some(ref s) => f(s),
138            None => Err(io::Error::new(io::ErrorKind::Other,
139                                       "builder has already finished its socket")),
140        }
141    }
142}
143
144impl fmt::Debug for TcpBuilder {
145    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
146        write!(f, "TcpBuilder {{ socket: {:?} }}",
147               self.socket.borrow().as_ref().unwrap())
148    }
149}
150
151impl ::AsInner for TcpBuilder {
152    type Inner = RefCell<Option<Socket>>;
153    fn as_inner(&self) -> &RefCell<Option<Socket>> { &self.socket }
154}
155
156impl ::FromInner for TcpBuilder {
157    type Inner = Socket;
158    fn from_inner(sock: Socket) -> TcpBuilder {
159        TcpBuilder { socket: RefCell::new(Some(sock)) }
160    }
161}