]> git.proxmox.com Git - rustc.git/blame - vendor/net2/src/tcp.rs
New upstream version 1.48.0+dfsg1
[rustc.git] / vendor / net2 / src / tcp.rs
CommitLineData
1b1a35ee
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::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}