]>
Commit | Line | Data |
---|---|---|
532ac7d7 | 1 | use crate::io::prelude::*; |
85aaf69f | 2 | |
532ac7d7 | 3 | use crate::fmt; |
48663c56 | 4 | use crate::io::{self, Initializer, IoSlice, IoSliceMut}; |
60c5eb7d | 5 | use crate::net::{Shutdown, SocketAddr, ToSocketAddrs}; |
532ac7d7 XL |
6 | use crate::sys_common::net as net_imp; |
7 | use crate::sys_common::{AsInner, FromInner, IntoInner}; | |
8 | use crate::time::Duration; | |
85aaf69f | 9 | |
cc61c64b | 10 | /// A TCP stream between a local and a remote socket. |
85aaf69f | 11 | /// |
cc61c64b XL |
12 | /// After creating a `TcpStream` by either [`connect`]ing to a remote host or |
13 | /// [`accept`]ing a connection on a [`TcpListener`], data can be transmitted | |
14 | /// by [reading] and [writing] to it. | |
15 | /// | |
16 | /// The connection will be closed when the value is dropped. The reading and writing | |
17 | /// portions of the connection can also be shut down individually with the [`shutdown`] | |
18 | /// method. | |
19 | /// | |
20 | /// The Transmission Control Protocol is specified in [IETF RFC 793]. | |
21 | /// | |
22 | /// [`accept`]: ../../std/net/struct.TcpListener.html#method.accept | |
23 | /// [`connect`]: #method.connect | |
24 | /// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 | |
25 | /// [reading]: ../../std/io/trait.Read.html | |
26 | /// [`shutdown`]: #method.shutdown | |
27 | /// [`TcpListener`]: ../../std/net/struct.TcpListener.html | |
28 | /// [writing]: ../../std/io/trait.Write.html | |
85aaf69f | 29 | /// |
c34b1796 | 30 | /// # Examples |
85aaf69f SL |
31 | /// |
32 | /// ```no_run | |
33 | /// use std::io::prelude::*; | |
34 | /// use std::net::TcpStream; | |
35 | /// | |
0bf4aa26 XL |
36 | /// fn main() -> std::io::Result<()> { |
37 | /// let mut stream = TcpStream::connect("127.0.0.1:34254")?; | |
85aaf69f | 38 | /// |
0bf4aa26 XL |
39 | /// stream.write(&[1])?; |
40 | /// stream.read(&mut [0; 128])?; | |
41 | /// Ok(()) | |
85aaf69f SL |
42 | /// } // the stream is closed here |
43 | /// ``` | |
c34b1796 | 44 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
45 | pub struct TcpStream(net_imp::TcpStream); |
46 | ||
cc61c64b XL |
47 | /// A TCP socket server, listening for connections. |
48 | /// | |
49 | /// After creating a `TcpListener` by [`bind`]ing it to a socket address, it listens | |
50 | /// for incoming TCP connections. These can be accepted by calling [`accept`] or by | |
51 | /// iterating over the [`Incoming`] iterator returned by [`incoming`][`TcpListener::incoming`]. | |
52 | /// | |
53 | /// The socket will be closed when the value is dropped. | |
54 | /// | |
55 | /// The Transmission Control Protocol is specified in [IETF RFC 793]. | |
56 | /// | |
57 | /// [`accept`]: #method.accept | |
58 | /// [`bind`]: #method.bind | |
59 | /// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 | |
60 | /// [`Incoming`]: ../../std/net/struct.Incoming.html | |
61 | /// [`TcpListener::incoming`]: #method.incoming | |
85aaf69f SL |
62 | /// |
63 | /// # Examples | |
64 | /// | |
0531ce1d | 65 | /// ```no_run |
85aaf69f | 66 | /// use std::net::{TcpListener, TcpStream}; |
85aaf69f | 67 | /// |
85aaf69f SL |
68 | /// fn handle_client(stream: TcpStream) { |
69 | /// // ... | |
70 | /// } | |
71 | /// | |
dfeec247 | 72 | /// fn main() -> std::io::Result<()> { |
8faf50e0 | 73 | /// let listener = TcpListener::bind("127.0.0.1:80")?; |
7cac9316 | 74 | /// |
0531ce1d XL |
75 | /// // accept connections and process them serially |
76 | /// for stream in listener.incoming() { | |
77 | /// handle_client(stream?); | |
78 | /// } | |
79 | /// Ok(()) | |
85aaf69f | 80 | /// } |
85aaf69f | 81 | /// ``` |
c34b1796 | 82 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
83 | pub struct TcpListener(net_imp::TcpListener); |
84 | ||
cc61c64b | 85 | /// An iterator that infinitely [`accept`]s connections on a [`TcpListener`]. |
5bcae85e SL |
86 | /// |
87 | /// This `struct` is created by the [`incoming`] method on [`TcpListener`]. | |
cc61c64b | 88 | /// See its documentation for more. |
5bcae85e | 89 | /// |
cc61c64b XL |
90 | /// [`accept`]: ../../std/net/struct.TcpListener.html#method.accept |
91 | /// [`incoming`]: ../../std/net/struct.TcpListener.html#method.incoming | |
92 | /// [`TcpListener`]: ../../std/net/struct.TcpListener.html | |
c34b1796 | 93 | #[stable(feature = "rust1", since = "1.0.0")] |
32a655c1 | 94 | #[derive(Debug)] |
60c5eb7d XL |
95 | pub struct Incoming<'a> { |
96 | listener: &'a TcpListener, | |
97 | } | |
85aaf69f SL |
98 | |
99 | impl TcpStream { | |
9346a6ac | 100 | /// Opens a TCP connection to a remote host. |
85aaf69f SL |
101 | /// |
102 | /// `addr` is an address of the remote host. Anything which implements | |
cc61c64b | 103 | /// [`ToSocketAddrs`] trait can be supplied for the address; see this trait |
85aaf69f | 104 | /// documentation for concrete examples. |
ea8adc8c XL |
105 | /// |
106 | /// If `addr` yields multiple addresses, `connect` will be attempted with | |
107 | /// each of the addresses until a connection is successful. If none of | |
108 | /// the addresses result in a successful connection, the error returned from | |
109 | /// the last connection attempt (the last address) is returned. | |
476ff2be | 110 | /// |
cc61c64b | 111 | /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html |
cc61c64b | 112 | /// |
476ff2be SL |
113 | /// # Examples |
114 | /// | |
ea8adc8c XL |
115 | /// Open a TCP connection to `127.0.0.1:8080`: |
116 | /// | |
476ff2be SL |
117 | /// ```no_run |
118 | /// use std::net::TcpStream; | |
119 | /// | |
120 | /// if let Ok(stream) = TcpStream::connect("127.0.0.1:8080") { | |
121 | /// println!("Connected to the server!"); | |
122 | /// } else { | |
123 | /// println!("Couldn't connect to server..."); | |
124 | /// } | |
125 | /// ``` | |
ea8adc8c XL |
126 | /// |
127 | /// Open a TCP connection to `127.0.0.1:8080`. If the connection fails, open | |
128 | /// a TCP connection to `127.0.0.1:8081`: | |
129 | /// | |
130 | /// ```no_run | |
131 | /// use std::net::{SocketAddr, TcpStream}; | |
132 | /// | |
133 | /// let addrs = [ | |
134 | /// SocketAddr::from(([127, 0, 0, 1], 8080)), | |
135 | /// SocketAddr::from(([127, 0, 0, 1], 8081)), | |
136 | /// ]; | |
137 | /// if let Ok(stream) = TcpStream::connect(&addrs[..]) { | |
138 | /// println!("Connected to the server!"); | |
139 | /// } else { | |
140 | /// println!("Couldn't connect to server..."); | |
141 | /// } | |
142 | /// ``` | |
c34b1796 AL |
143 | #[stable(feature = "rust1", since = "1.0.0")] |
144 | pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> { | |
85aaf69f SL |
145 | super::each_addr(addr, net_imp::TcpStream::connect).map(TcpStream) |
146 | } | |
147 | ||
041b39d2 XL |
148 | /// Opens a TCP connection to a remote host with a timeout. |
149 | /// | |
150 | /// Unlike `connect`, `connect_timeout` takes a single [`SocketAddr`] since | |
151 | /// timeout must be applied to individual addresses. | |
152 | /// | |
153 | /// It is an error to pass a zero `Duration` to this function. | |
154 | /// | |
155 | /// Unlike other methods on `TcpStream`, this does not correspond to a | |
156 | /// single system call. It instead calls `connect` in nonblocking mode and | |
157 | /// then uses an OS-specific mechanism to await the completion of the | |
158 | /// connection request. | |
159 | /// | |
160 | /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html | |
3b2f2976 | 161 | #[stable(feature = "tcpstream_connect_timeout", since = "1.21.0")] |
041b39d2 XL |
162 | pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> { |
163 | net_imp::TcpStream::connect_timeout(addr, timeout).map(TcpStream) | |
164 | } | |
165 | ||
85aaf69f | 166 | /// Returns the socket address of the remote peer of this TCP connection. |
476ff2be SL |
167 | /// |
168 | /// # Examples | |
169 | /// | |
170 | /// ```no_run | |
171 | /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpStream}; | |
172 | /// | |
173 | /// let stream = TcpStream::connect("127.0.0.1:8080") | |
174 | /// .expect("Couldn't connect to the server..."); | |
175 | /// assert_eq!(stream.peer_addr().unwrap(), | |
176 | /// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080))); | |
177 | /// ``` | |
c34b1796 | 178 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
179 | pub fn peer_addr(&self) -> io::Result<SocketAddr> { |
180 | self.0.peer_addr() | |
181 | } | |
182 | ||
183 | /// Returns the socket address of the local half of this TCP connection. | |
476ff2be SL |
184 | /// |
185 | /// # Examples | |
186 | /// | |
187 | /// ```no_run | |
ea8adc8c | 188 | /// use std::net::{IpAddr, Ipv4Addr, TcpStream}; |
476ff2be SL |
189 | /// |
190 | /// let stream = TcpStream::connect("127.0.0.1:8080") | |
191 | /// .expect("Couldn't connect to the server..."); | |
ea8adc8c XL |
192 | /// assert_eq!(stream.local_addr().unwrap().ip(), |
193 | /// IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))); | |
476ff2be | 194 | /// ``` |
c34b1796 AL |
195 | #[stable(feature = "rust1", since = "1.0.0")] |
196 | pub fn local_addr(&self) -> io::Result<SocketAddr> { | |
85aaf69f SL |
197 | self.0.socket_addr() |
198 | } | |
199 | ||
9346a6ac | 200 | /// Shuts down the read, write, or both halves of this connection. |
85aaf69f SL |
201 | /// |
202 | /// This function will cause all pending and future I/O on the specified | |
203 | /// portions to return immediately with an appropriate value (see the | |
476ff2be SL |
204 | /// documentation of [`Shutdown`]). |
205 | /// | |
206 | /// [`Shutdown`]: ../../std/net/enum.Shutdown.html | |
207 | /// | |
7cac9316 XL |
208 | /// # Platform-specific behavior |
209 | /// | |
210 | /// Calling this function multiple times may result in different behavior, | |
211 | /// depending on the operating system. On Linux, the second call will | |
212 | /// return `Ok(())`, but on macOS, it will return `ErrorKind::NotConnected`. | |
213 | /// This may change in the future. | |
214 | /// | |
476ff2be SL |
215 | /// # Examples |
216 | /// | |
217 | /// ```no_run | |
218 | /// use std::net::{Shutdown, TcpStream}; | |
219 | /// | |
220 | /// let stream = TcpStream::connect("127.0.0.1:8080") | |
221 | /// .expect("Couldn't connect to the server..."); | |
222 | /// stream.shutdown(Shutdown::Both).expect("shutdown call failed"); | |
223 | /// ``` | |
c34b1796 | 224 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
225 | pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { |
226 | self.0.shutdown(how) | |
227 | } | |
228 | ||
9346a6ac | 229 | /// Creates a new independently owned handle to the underlying socket. |
85aaf69f SL |
230 | /// |
231 | /// The returned `TcpStream` is a reference to the same stream that this | |
232 | /// object references. Both handles will read and write the same stream of | |
233 | /// data, and options set on one stream will be propagated to the other | |
234 | /// stream. | |
476ff2be SL |
235 | /// |
236 | /// # Examples | |
237 | /// | |
238 | /// ```no_run | |
239 | /// use std::net::TcpStream; | |
240 | /// | |
241 | /// let stream = TcpStream::connect("127.0.0.1:8080") | |
242 | /// .expect("Couldn't connect to the server..."); | |
243 | /// let stream_clone = stream.try_clone().expect("clone failed..."); | |
244 | /// ``` | |
c34b1796 | 245 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
246 | pub fn try_clone(&self) -> io::Result<TcpStream> { |
247 | self.0.duplicate().map(TcpStream) | |
248 | } | |
249 | ||
62682a34 SL |
250 | /// Sets the read timeout to the timeout specified. |
251 | /// | |
cc61c64b | 252 | /// If the value specified is [`None`], then [`read`] calls will block |
0531ce1d XL |
253 | /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is |
254 | /// passed to this method. | |
e9174d1e | 255 | /// |
0531ce1d | 256 | /// # Platform-specific behavior |
e9174d1e SL |
257 | /// |
258 | /// Platforms may return a different error code whenever a read times out as | |
259 | /// a result of setting this option. For example Unix typically returns an | |
476ff2be SL |
260 | /// error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. |
261 | /// | |
262 | /// [`None`]: ../../std/option/enum.Option.html#variant.None | |
0531ce1d | 263 | /// [`Err`]: ../../std/result/enum.Result.html#variant.Err |
cc61c64b | 264 | /// [`read`]: ../../std/io/trait.Read.html#tymethod.read |
476ff2be SL |
265 | /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock |
266 | /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut | |
0531ce1d | 267 | /// [`Duration`]: ../../std/time/struct.Duration.html |
476ff2be SL |
268 | /// |
269 | /// # Examples | |
270 | /// | |
271 | /// ```no_run | |
272 | /// use std::net::TcpStream; | |
273 | /// | |
274 | /// let stream = TcpStream::connect("127.0.0.1:8080") | |
275 | /// .expect("Couldn't connect to the server..."); | |
276 | /// stream.set_read_timeout(None).expect("set_read_timeout call failed"); | |
277 | /// ``` | |
0531ce1d XL |
278 | /// |
279 | /// An [`Err`] is returned if the zero [`Duration`] is passed to this | |
280 | /// method: | |
281 | /// | |
282 | /// ```no_run | |
283 | /// use std::io; | |
284 | /// use std::net::TcpStream; | |
285 | /// use std::time::Duration; | |
286 | /// | |
287 | /// let stream = TcpStream::connect("127.0.0.1:8080").unwrap(); | |
288 | /// let result = stream.set_read_timeout(Some(Duration::new(0, 0))); | |
289 | /// let err = result.unwrap_err(); | |
290 | /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) | |
291 | /// ``` | |
e9174d1e | 292 | #[stable(feature = "socket_timeout", since = "1.4.0")] |
62682a34 SL |
293 | pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { |
294 | self.0.set_read_timeout(dur) | |
295 | } | |
296 | ||
297 | /// Sets the write timeout to the timeout specified. | |
298 | /// | |
cc61c64b | 299 | /// If the value specified is [`None`], then [`write`] calls will block |
0531ce1d XL |
300 | /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is |
301 | /// passed to this method. | |
e9174d1e | 302 | /// |
0531ce1d | 303 | /// # Platform-specific behavior |
e9174d1e SL |
304 | /// |
305 | /// Platforms may return a different error code whenever a write times out | |
306 | /// as a result of setting this option. For example Unix typically returns | |
476ff2be SL |
307 | /// an error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. |
308 | /// | |
309 | /// [`None`]: ../../std/option/enum.Option.html#variant.None | |
0531ce1d | 310 | /// [`Err`]: ../../std/result/enum.Result.html#variant.Err |
cc61c64b | 311 | /// [`write`]: ../../std/io/trait.Write.html#tymethod.write |
476ff2be SL |
312 | /// [`Duration`]: ../../std/time/struct.Duration.html |
313 | /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock | |
314 | /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut | |
315 | /// | |
316 | /// # Examples | |
317 | /// | |
318 | /// ```no_run | |
319 | /// use std::net::TcpStream; | |
320 | /// | |
321 | /// let stream = TcpStream::connect("127.0.0.1:8080") | |
322 | /// .expect("Couldn't connect to the server..."); | |
323 | /// stream.set_write_timeout(None).expect("set_write_timeout call failed"); | |
324 | /// ``` | |
0531ce1d XL |
325 | /// |
326 | /// An [`Err`] is returned if the zero [`Duration`] is passed to this | |
327 | /// method: | |
328 | /// | |
329 | /// ```no_run | |
330 | /// use std::io; | |
331 | /// use std::net::TcpStream; | |
332 | /// use std::time::Duration; | |
333 | /// | |
334 | /// let stream = TcpStream::connect("127.0.0.1:8080").unwrap(); | |
335 | /// let result = stream.set_write_timeout(Some(Duration::new(0, 0))); | |
336 | /// let err = result.unwrap_err(); | |
337 | /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) | |
338 | /// ``` | |
e9174d1e | 339 | #[stable(feature = "socket_timeout", since = "1.4.0")] |
62682a34 SL |
340 | pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> { |
341 | self.0.set_write_timeout(dur) | |
342 | } | |
343 | ||
344 | /// Returns the read timeout of this socket. | |
345 | /// | |
cc61c64b | 346 | /// If the timeout is [`None`], then [`read`] calls will block indefinitely. |
62682a34 | 347 | /// |
0531ce1d | 348 | /// # Platform-specific behavior |
62682a34 SL |
349 | /// |
350 | /// Some platforms do not provide access to the current timeout. | |
476ff2be SL |
351 | /// |
352 | /// [`None`]: ../../std/option/enum.Option.html#variant.None | |
cc61c64b | 353 | /// [`read`]: ../../std/io/trait.Read.html#tymethod.read |
476ff2be SL |
354 | /// |
355 | /// # Examples | |
356 | /// | |
357 | /// ```no_run | |
358 | /// use std::net::TcpStream; | |
359 | /// | |
360 | /// let stream = TcpStream::connect("127.0.0.1:8080") | |
361 | /// .expect("Couldn't connect to the server..."); | |
362 | /// stream.set_read_timeout(None).expect("set_read_timeout call failed"); | |
363 | /// assert_eq!(stream.read_timeout().unwrap(), None); | |
364 | /// ``` | |
e9174d1e | 365 | #[stable(feature = "socket_timeout", since = "1.4.0")] |
62682a34 SL |
366 | pub fn read_timeout(&self) -> io::Result<Option<Duration>> { |
367 | self.0.read_timeout() | |
368 | } | |
369 | ||
370 | /// Returns the write timeout of this socket. | |
371 | /// | |
cc61c64b | 372 | /// If the timeout is [`None`], then [`write`] calls will block indefinitely. |
62682a34 | 373 | /// |
0531ce1d | 374 | /// # Platform-specific behavior |
62682a34 SL |
375 | /// |
376 | /// Some platforms do not provide access to the current timeout. | |
476ff2be SL |
377 | /// |
378 | /// [`None`]: ../../std/option/enum.Option.html#variant.None | |
cc61c64b | 379 | /// [`write`]: ../../std/io/trait.Write.html#tymethod.write |
476ff2be SL |
380 | /// |
381 | /// # Examples | |
382 | /// | |
383 | /// ```no_run | |
384 | /// use std::net::TcpStream; | |
385 | /// | |
386 | /// let stream = TcpStream::connect("127.0.0.1:8080") | |
387 | /// .expect("Couldn't connect to the server..."); | |
388 | /// stream.set_write_timeout(None).expect("set_write_timeout call failed"); | |
389 | /// assert_eq!(stream.write_timeout().unwrap(), None); | |
390 | /// ``` | |
e9174d1e | 391 | #[stable(feature = "socket_timeout", since = "1.4.0")] |
62682a34 SL |
392 | pub fn write_timeout(&self) -> io::Result<Option<Duration>> { |
393 | self.0.write_timeout() | |
394 | } | |
54a0048b | 395 | |
3b2f2976 | 396 | /// Receives data on the socket from the remote address to which it is |
8bb4bdeb XL |
397 | /// connected, without removing that data from the queue. On success, |
398 | /// returns the number of bytes peeked. | |
399 | /// | |
400 | /// Successive calls return the same data. This is accomplished by passing | |
401 | /// `MSG_PEEK` as a flag to the underlying `recv` system call. | |
402 | /// | |
403 | /// # Examples | |
404 | /// | |
405 | /// ```no_run | |
8bb4bdeb XL |
406 | /// use std::net::TcpStream; |
407 | /// | |
408 | /// let stream = TcpStream::connect("127.0.0.1:8000") | |
409 | /// .expect("couldn't bind to address"); | |
410 | /// let mut buf = [0; 10]; | |
411 | /// let len = stream.peek(&mut buf).expect("peek failed"); | |
412 | /// ``` | |
cc61c64b | 413 | #[stable(feature = "peek", since = "1.18.0")] |
8bb4bdeb XL |
414 | pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { |
415 | self.0.peek(buf) | |
416 | } | |
417 | ||
54a0048b SL |
418 | /// Sets the value of the `TCP_NODELAY` option on this socket. |
419 | /// | |
420 | /// If set, this option disables the Nagle algorithm. This means that | |
421 | /// segments are always sent as soon as possible, even if there is only a | |
422 | /// small amount of data. When not set, data is buffered until there is a | |
423 | /// sufficient amount to send out, thereby avoiding the frequent sending of | |
424 | /// small packets. | |
476ff2be SL |
425 | /// |
426 | /// # Examples | |
427 | /// | |
428 | /// ```no_run | |
429 | /// use std::net::TcpStream; | |
430 | /// | |
431 | /// let stream = TcpStream::connect("127.0.0.1:8080") | |
432 | /// .expect("Couldn't connect to the server..."); | |
433 | /// stream.set_nodelay(true).expect("set_nodelay call failed"); | |
434 | /// ``` | |
54a0048b SL |
435 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
436 | pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { | |
437 | self.0.set_nodelay(nodelay) | |
438 | } | |
439 | ||
440 | /// Gets the value of the `TCP_NODELAY` option on this socket. | |
441 | /// | |
442 | /// For more information about this option, see [`set_nodelay`][link]. | |
443 | /// | |
444 | /// [link]: #method.set_nodelay | |
476ff2be SL |
445 | /// |
446 | /// # Examples | |
447 | /// | |
448 | /// ```no_run | |
449 | /// use std::net::TcpStream; | |
450 | /// | |
451 | /// let stream = TcpStream::connect("127.0.0.1:8080") | |
452 | /// .expect("Couldn't connect to the server..."); | |
453 | /// stream.set_nodelay(true).expect("set_nodelay call failed"); | |
454 | /// assert_eq!(stream.nodelay().unwrap_or(false), true); | |
455 | /// ``` | |
54a0048b SL |
456 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
457 | pub fn nodelay(&self) -> io::Result<bool> { | |
458 | self.0.nodelay() | |
459 | } | |
460 | ||
461 | /// Sets the value for the `IP_TTL` option on this socket. | |
462 | /// | |
463 | /// This value sets the time-to-live field that is used in every packet sent | |
464 | /// from this socket. | |
476ff2be SL |
465 | /// |
466 | /// # Examples | |
467 | /// | |
468 | /// ```no_run | |
469 | /// use std::net::TcpStream; | |
470 | /// | |
471 | /// let stream = TcpStream::connect("127.0.0.1:8080") | |
472 | /// .expect("Couldn't connect to the server..."); | |
473 | /// stream.set_ttl(100).expect("set_ttl call failed"); | |
474 | /// ``` | |
54a0048b SL |
475 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
476 | pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { | |
477 | self.0.set_ttl(ttl) | |
478 | } | |
479 | ||
480 | /// Gets the value of the `IP_TTL` option for this socket. | |
481 | /// | |
482 | /// For more information about this option, see [`set_ttl`][link]. | |
483 | /// | |
484 | /// [link]: #method.set_ttl | |
476ff2be SL |
485 | /// |
486 | /// # Examples | |
487 | /// | |
488 | /// ```no_run | |
489 | /// use std::net::TcpStream; | |
490 | /// | |
491 | /// let stream = TcpStream::connect("127.0.0.1:8080") | |
492 | /// .expect("Couldn't connect to the server..."); | |
493 | /// stream.set_ttl(100).expect("set_ttl call failed"); | |
494 | /// assert_eq!(stream.ttl().unwrap_or(0), 100); | |
495 | /// ``` | |
54a0048b SL |
496 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
497 | pub fn ttl(&self) -> io::Result<u32> { | |
498 | self.0.ttl() | |
499 | } | |
500 | ||
9fa01778 | 501 | /// Gets the value of the `SO_ERROR` option on this socket. |
54a0048b SL |
502 | /// |
503 | /// This will retrieve the stored error in the underlying socket, clearing | |
504 | /// the field in the process. This can be useful for checking errors between | |
505 | /// calls. | |
476ff2be SL |
506 | /// |
507 | /// # Examples | |
508 | /// | |
509 | /// ```no_run | |
510 | /// use std::net::TcpStream; | |
511 | /// | |
512 | /// let stream = TcpStream::connect("127.0.0.1:8080") | |
513 | /// .expect("Couldn't connect to the server..."); | |
514 | /// stream.take_error().expect("No error was expected..."); | |
515 | /// ``` | |
54a0048b SL |
516 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
517 | pub fn take_error(&self) -> io::Result<Option<io::Error>> { | |
518 | self.0.take_error() | |
519 | } | |
520 | ||
521 | /// Moves this TCP stream into or out of nonblocking mode. | |
522 | /// | |
abe05a73 | 523 | /// This will result in `read`, `write`, `recv` and `send` operations |
0731742a | 524 | /// becoming nonblocking, i.e., immediately returning from their calls. |
abe05a73 XL |
525 | /// If the IO operation is successful, `Ok` is returned and no further |
526 | /// action is required. If the IO operation could not be completed and needs | |
527 | /// to be retried, an error with kind [`io::ErrorKind::WouldBlock`] is | |
528 | /// returned. | |
529 | /// | |
530 | /// On Unix platforms, calling this method corresponds to calling `fcntl` | |
531 | /// `FIONBIO`. On Windows calling this method corresponds to calling | |
532 | /// `ioctlsocket` `FIONBIO`. | |
476ff2be SL |
533 | /// |
534 | /// # Examples | |
535 | /// | |
abe05a73 XL |
536 | /// Reading bytes from a TCP stream in non-blocking mode: |
537 | /// | |
476ff2be | 538 | /// ```no_run |
abe05a73 | 539 | /// use std::io::{self, Read}; |
476ff2be SL |
540 | /// use std::net::TcpStream; |
541 | /// | |
abe05a73 XL |
542 | /// let mut stream = TcpStream::connect("127.0.0.1:7878") |
543 | /// .expect("Couldn't connect to the server..."); | |
476ff2be | 544 | /// stream.set_nonblocking(true).expect("set_nonblocking call failed"); |
abe05a73 XL |
545 | /// |
546 | /// # fn wait_for_fd() { unimplemented!() } | |
547 | /// let mut buf = vec![]; | |
548 | /// loop { | |
549 | /// match stream.read_to_end(&mut buf) { | |
550 | /// Ok(_) => break, | |
551 | /// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { | |
552 | /// // wait until network socket is ready, typically implemented | |
553 | /// // via platform-specific APIs such as epoll or IOCP | |
554 | /// wait_for_fd(); | |
555 | /// } | |
556 | /// Err(e) => panic!("encountered IO error: {}", e), | |
557 | /// }; | |
558 | /// }; | |
559 | /// println!("bytes: {:?}", buf); | |
476ff2be | 560 | /// ``` |
abe05a73 XL |
561 | /// |
562 | /// [`io::ErrorKind::WouldBlock`]: ../io/enum.ErrorKind.html#variant.WouldBlock | |
54a0048b SL |
563 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
564 | pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { | |
565 | self.0.set_nonblocking(nonblocking) | |
566 | } | |
85aaf69f SL |
567 | } |
568 | ||
c34b1796 | 569 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 570 | impl Read for TcpStream { |
60c5eb7d XL |
571 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
572 | self.0.read(buf) | |
573 | } | |
041b39d2 | 574 | |
48663c56 | 575 | fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { |
9fa01778 XL |
576 | self.0.read_vectored(bufs) |
577 | } | |
578 | ||
041b39d2 XL |
579 | #[inline] |
580 | unsafe fn initializer(&self) -> Initializer { | |
581 | Initializer::nop() | |
c1a9b12d | 582 | } |
85aaf69f | 583 | } |
c34b1796 | 584 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 585 | impl Write for TcpStream { |
60c5eb7d XL |
586 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
587 | self.0.write(buf) | |
588 | } | |
9fa01778 | 589 | |
48663c56 | 590 | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { |
9fa01778 XL |
591 | self.0.write_vectored(bufs) |
592 | } | |
593 | ||
60c5eb7d XL |
594 | fn flush(&mut self) -> io::Result<()> { |
595 | Ok(()) | |
596 | } | |
85aaf69f | 597 | } |
c34b1796 | 598 | #[stable(feature = "rust1", since = "1.0.0")] |
9fa01778 | 599 | impl Read for &TcpStream { |
60c5eb7d XL |
600 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
601 | self.0.read(buf) | |
602 | } | |
041b39d2 | 603 | |
48663c56 | 604 | fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { |
9fa01778 XL |
605 | self.0.read_vectored(bufs) |
606 | } | |
607 | ||
041b39d2 XL |
608 | #[inline] |
609 | unsafe fn initializer(&self) -> Initializer { | |
610 | Initializer::nop() | |
c1a9b12d | 611 | } |
85aaf69f | 612 | } |
c34b1796 | 613 | #[stable(feature = "rust1", since = "1.0.0")] |
9fa01778 | 614 | impl Write for &TcpStream { |
60c5eb7d XL |
615 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
616 | self.0.write(buf) | |
617 | } | |
9fa01778 | 618 | |
48663c56 | 619 | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { |
9fa01778 XL |
620 | self.0.write_vectored(bufs) |
621 | } | |
622 | ||
60c5eb7d XL |
623 | fn flush(&mut self) -> io::Result<()> { |
624 | Ok(()) | |
625 | } | |
85aaf69f SL |
626 | } |
627 | ||
628 | impl AsInner<net_imp::TcpStream> for TcpStream { | |
60c5eb7d XL |
629 | fn as_inner(&self) -> &net_imp::TcpStream { |
630 | &self.0 | |
631 | } | |
85aaf69f SL |
632 | } |
633 | ||
c34b1796 | 634 | impl FromInner<net_imp::TcpStream> for TcpStream { |
60c5eb7d XL |
635 | fn from_inner(inner: net_imp::TcpStream) -> TcpStream { |
636 | TcpStream(inner) | |
637 | } | |
c34b1796 AL |
638 | } |
639 | ||
c1a9b12d | 640 | impl IntoInner<net_imp::TcpStream> for TcpStream { |
60c5eb7d XL |
641 | fn into_inner(self) -> net_imp::TcpStream { |
642 | self.0 | |
643 | } | |
c1a9b12d SL |
644 | } |
645 | ||
92a42be0 | 646 | #[stable(feature = "rust1", since = "1.0.0")] |
d9579d0f | 647 | impl fmt::Debug for TcpStream { |
532ac7d7 | 648 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
d9579d0f AL |
649 | self.0.fmt(f) |
650 | } | |
651 | } | |
652 | ||
85aaf69f SL |
653 | impl TcpListener { |
654 | /// Creates a new `TcpListener` which will be bound to the specified | |
655 | /// address. | |
656 | /// | |
657 | /// The returned listener is ready for accepting connections. | |
658 | /// | |
659 | /// Binding with a port number of 0 will request that the OS assigns a port | |
660 | /// to this listener. The port allocated can be queried via the | |
cc61c64b | 661 | /// [`local_addr`] method. |
85aaf69f | 662 | /// |
cc61c64b | 663 | /// The address type can be any implementor of [`ToSocketAddrs`] trait. See |
85aaf69f | 664 | /// its documentation for concrete examples. |
476ff2be | 665 | /// |
ea8adc8c XL |
666 | /// If `addr` yields multiple addresses, `bind` will be attempted with |
667 | /// each of the addresses until one succeeds and returns the listener. If | |
668 | /// none of the addresses succeed in creating a listener, the error returned | |
669 | /// from the last attempt (the last address) is returned. | |
670 | /// | |
cc61c64b XL |
671 | /// [`local_addr`]: #method.local_addr |
672 | /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html | |
673 | /// | |
476ff2be SL |
674 | /// # Examples |
675 | /// | |
9fa01778 | 676 | /// Creates a TCP listener bound to `127.0.0.1:80`: |
ea8adc8c | 677 | /// |
476ff2be SL |
678 | /// ```no_run |
679 | /// use std::net::TcpListener; | |
680 | /// | |
681 | /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); | |
682 | /// ``` | |
ea8adc8c | 683 | /// |
9fa01778 | 684 | /// Creates a TCP listener bound to `127.0.0.1:80`. If that fails, create a |
ea8adc8c XL |
685 | /// TCP listener bound to `127.0.0.1:443`: |
686 | /// | |
687 | /// ```no_run | |
688 | /// use std::net::{SocketAddr, TcpListener}; | |
689 | /// | |
690 | /// let addrs = [ | |
691 | /// SocketAddr::from(([127, 0, 0, 1], 80)), | |
692 | /// SocketAddr::from(([127, 0, 0, 1], 443)), | |
693 | /// ]; | |
694 | /// let listener = TcpListener::bind(&addrs[..]).unwrap(); | |
695 | /// ``` | |
c34b1796 AL |
696 | #[stable(feature = "rust1", since = "1.0.0")] |
697 | pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> { | |
85aaf69f SL |
698 | super::each_addr(addr, net_imp::TcpListener::bind).map(TcpListener) |
699 | } | |
700 | ||
701 | /// Returns the local socket address of this listener. | |
476ff2be SL |
702 | /// |
703 | /// # Examples | |
704 | /// | |
705 | /// ```no_run | |
706 | /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpListener}; | |
707 | /// | |
708 | /// let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); | |
709 | /// assert_eq!(listener.local_addr().unwrap(), | |
710 | /// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080))); | |
711 | /// ``` | |
c34b1796 AL |
712 | #[stable(feature = "rust1", since = "1.0.0")] |
713 | pub fn local_addr(&self) -> io::Result<SocketAddr> { | |
85aaf69f SL |
714 | self.0.socket_addr() |
715 | } | |
716 | ||
9346a6ac | 717 | /// Creates a new independently owned handle to the underlying socket. |
85aaf69f | 718 | /// |
cc61c64b | 719 | /// The returned [`TcpListener`] is a reference to the same socket that this |
85aaf69f SL |
720 | /// object references. Both handles can be used to accept incoming |
721 | /// connections and options set on one listener will affect the other. | |
476ff2be | 722 | /// |
cc61c64b XL |
723 | /// [`TcpListener`]: ../../std/net/struct.TcpListener.html |
724 | /// | |
476ff2be SL |
725 | /// # Examples |
726 | /// | |
727 | /// ```no_run | |
728 | /// use std::net::TcpListener; | |
729 | /// | |
730 | /// let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); | |
731 | /// let listener_clone = listener.try_clone().unwrap(); | |
732 | /// ``` | |
c34b1796 | 733 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
734 | pub fn try_clone(&self) -> io::Result<TcpListener> { |
735 | self.0.duplicate().map(TcpListener) | |
736 | } | |
737 | ||
738 | /// Accept a new incoming connection from this listener. | |
739 | /// | |
740 | /// This function will block the calling thread until a new TCP connection | |
cc61c64b | 741 | /// is established. When established, the corresponding [`TcpStream`] and the |
85aaf69f | 742 | /// remote peer's address will be returned. |
476ff2be | 743 | /// |
cc61c64b XL |
744 | /// [`TcpStream`]: ../../std/net/struct.TcpStream.html |
745 | /// | |
476ff2be SL |
746 | /// # Examples |
747 | /// | |
748 | /// ```no_run | |
749 | /// use std::net::TcpListener; | |
750 | /// | |
751 | /// let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); | |
752 | /// match listener.accept() { | |
753 | /// Ok((_socket, addr)) => println!("new client: {:?}", addr), | |
754 | /// Err(e) => println!("couldn't get client: {:?}", e), | |
755 | /// } | |
756 | /// ``` | |
c34b1796 | 757 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 758 | pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { |
0731742a XL |
759 | // On WASM, `TcpStream` is uninhabited (as it's unsupported) and so |
760 | // the `a` variable here is technically unused. | |
761 | #[cfg_attr(target_arch = "wasm32", allow(unused_variables))] | |
85aaf69f SL |
762 | self.0.accept().map(|(a, b)| (TcpStream(a), b)) |
763 | } | |
764 | ||
765 | /// Returns an iterator over the connections being received on this | |
766 | /// listener. | |
767 | /// | |
476ff2be | 768 | /// The returned iterator will never return [`None`] and will also not yield |
cc61c64b XL |
769 | /// the peer's [`SocketAddr`] structure. Iterating over it is equivalent to |
770 | /// calling [`accept`] in a loop. | |
476ff2be SL |
771 | /// |
772 | /// [`None`]: ../../std/option/enum.Option.html#variant.None | |
773 | /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html | |
cc61c64b | 774 | /// [`accept`]: #method.accept |
476ff2be SL |
775 | /// |
776 | /// # Examples | |
777 | /// | |
778 | /// ```no_run | |
779 | /// use std::net::TcpListener; | |
780 | /// | |
781 | /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); | |
782 | /// | |
783 | /// for stream in listener.incoming() { | |
784 | /// match stream { | |
785 | /// Ok(stream) => { | |
786 | /// println!("new client!"); | |
787 | /// } | |
788 | /// Err(e) => { /* connection failed */ } | |
789 | /// } | |
790 | /// } | |
791 | /// ``` | |
c34b1796 | 792 | #[stable(feature = "rust1", since = "1.0.0")] |
532ac7d7 | 793 | pub fn incoming(&self) -> Incoming<'_> { |
85aaf69f SL |
794 | Incoming { listener: self } |
795 | } | |
54a0048b SL |
796 | |
797 | /// Sets the value for the `IP_TTL` option on this socket. | |
798 | /// | |
799 | /// This value sets the time-to-live field that is used in every packet sent | |
800 | /// from this socket. | |
476ff2be SL |
801 | /// |
802 | /// # Examples | |
803 | /// | |
804 | /// ```no_run | |
805 | /// use std::net::TcpListener; | |
806 | /// | |
807 | /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); | |
808 | /// listener.set_ttl(100).expect("could not set TTL"); | |
809 | /// ``` | |
54a0048b SL |
810 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
811 | pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { | |
812 | self.0.set_ttl(ttl) | |
813 | } | |
814 | ||
815 | /// Gets the value of the `IP_TTL` option for this socket. | |
816 | /// | |
cc61c64b | 817 | /// For more information about this option, see [`set_ttl`][link]. |
54a0048b SL |
818 | /// |
819 | /// [link]: #method.set_ttl | |
476ff2be SL |
820 | /// |
821 | /// # Examples | |
822 | /// | |
823 | /// ```no_run | |
824 | /// use std::net::TcpListener; | |
825 | /// | |
826 | /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); | |
827 | /// listener.set_ttl(100).expect("could not set TTL"); | |
828 | /// assert_eq!(listener.ttl().unwrap_or(0), 100); | |
829 | /// ``` | |
54a0048b SL |
830 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
831 | pub fn ttl(&self) -> io::Result<u32> { | |
832 | self.0.ttl() | |
833 | } | |
834 | ||
54a0048b | 835 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
60c5eb7d XL |
836 | #[rustc_deprecated( |
837 | since = "1.16.0", | |
838 | reason = "this option can only be set before the socket is bound" | |
839 | )] | |
32a655c1 | 840 | #[allow(missing_docs)] |
54a0048b SL |
841 | pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { |
842 | self.0.set_only_v6(only_v6) | |
843 | } | |
844 | ||
54a0048b | 845 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
60c5eb7d XL |
846 | #[rustc_deprecated( |
847 | since = "1.16.0", | |
848 | reason = "this option can only be set before the socket is bound" | |
849 | )] | |
32a655c1 | 850 | #[allow(missing_docs)] |
54a0048b SL |
851 | pub fn only_v6(&self) -> io::Result<bool> { |
852 | self.0.only_v6() | |
853 | } | |
854 | ||
9fa01778 | 855 | /// Gets the value of the `SO_ERROR` option on this socket. |
54a0048b SL |
856 | /// |
857 | /// This will retrieve the stored error in the underlying socket, clearing | |
858 | /// the field in the process. This can be useful for checking errors between | |
859 | /// calls. | |
476ff2be SL |
860 | /// |
861 | /// # Examples | |
862 | /// | |
863 | /// ```no_run | |
864 | /// use std::net::TcpListener; | |
865 | /// | |
866 | /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); | |
867 | /// listener.take_error().expect("No error was expected"); | |
868 | /// ``` | |
54a0048b SL |
869 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
870 | pub fn take_error(&self) -> io::Result<Option<io::Error>> { | |
871 | self.0.take_error() | |
872 | } | |
873 | ||
874 | /// Moves this TCP stream into or out of nonblocking mode. | |
875 | /// | |
abe05a73 | 876 | /// This will result in the `accept` operation becoming nonblocking, |
0731742a | 877 | /// i.e., immediately returning from their calls. If the IO operation is |
abe05a73 XL |
878 | /// successful, `Ok` is returned and no further action is required. If the |
879 | /// IO operation could not be completed and needs to be retried, an error | |
880 | /// with kind [`io::ErrorKind::WouldBlock`] is returned. | |
881 | /// | |
882 | /// On Unix platforms, calling this method corresponds to calling `fcntl` | |
883 | /// `FIONBIO`. On Windows calling this method corresponds to calling | |
884 | /// `ioctlsocket` `FIONBIO`. | |
476ff2be SL |
885 | /// |
886 | /// # Examples | |
887 | /// | |
abe05a73 XL |
888 | /// Bind a TCP listener to an address, listen for connections, and read |
889 | /// bytes in nonblocking mode: | |
890 | /// | |
476ff2be | 891 | /// ```no_run |
abe05a73 | 892 | /// use std::io; |
476ff2be SL |
893 | /// use std::net::TcpListener; |
894 | /// | |
abe05a73 | 895 | /// let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); |
476ff2be | 896 | /// listener.set_nonblocking(true).expect("Cannot set non-blocking"); |
abe05a73 XL |
897 | /// |
898 | /// # fn wait_for_fd() { unimplemented!() } | |
899 | /// # fn handle_connection(stream: std::net::TcpStream) { unimplemented!() } | |
900 | /// for stream in listener.incoming() { | |
901 | /// match stream { | |
902 | /// Ok(s) => { | |
903 | /// // do something with the TcpStream | |
904 | /// handle_connection(s); | |
905 | /// } | |
906 | /// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { | |
907 | /// // wait until network socket is ready, typically implemented | |
908 | /// // via platform-specific APIs such as epoll or IOCP | |
909 | /// wait_for_fd(); | |
910 | /// continue; | |
911 | /// } | |
912 | /// Err(e) => panic!("encountered IO error: {}", e), | |
913 | /// } | |
914 | /// } | |
476ff2be | 915 | /// ``` |
abe05a73 XL |
916 | /// |
917 | /// [`io::ErrorKind::WouldBlock`]: ../io/enum.ErrorKind.html#variant.WouldBlock | |
54a0048b SL |
918 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
919 | pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { | |
920 | self.0.set_nonblocking(nonblocking) | |
921 | } | |
85aaf69f SL |
922 | } |
923 | ||
c34b1796 | 924 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
925 | impl<'a> Iterator for Incoming<'a> { |
926 | type Item = io::Result<TcpStream>; | |
927 | fn next(&mut self) -> Option<io::Result<TcpStream>> { | |
928 | Some(self.listener.accept().map(|p| p.0)) | |
929 | } | |
930 | } | |
931 | ||
932 | impl AsInner<net_imp::TcpListener> for TcpListener { | |
60c5eb7d XL |
933 | fn as_inner(&self) -> &net_imp::TcpListener { |
934 | &self.0 | |
935 | } | |
85aaf69f SL |
936 | } |
937 | ||
c34b1796 AL |
938 | impl FromInner<net_imp::TcpListener> for TcpListener { |
939 | fn from_inner(inner: net_imp::TcpListener) -> TcpListener { | |
940 | TcpListener(inner) | |
941 | } | |
942 | } | |
943 | ||
c1a9b12d | 944 | impl IntoInner<net_imp::TcpListener> for TcpListener { |
60c5eb7d XL |
945 | fn into_inner(self) -> net_imp::TcpListener { |
946 | self.0 | |
947 | } | |
c1a9b12d SL |
948 | } |
949 | ||
92a42be0 | 950 | #[stable(feature = "rust1", since = "1.0.0")] |
d9579d0f | 951 | impl fmt::Debug for TcpListener { |
532ac7d7 | 952 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
d9579d0f AL |
953 | self.0.fmt(f) |
954 | } | |
955 | } | |
956 | ||
2c00a5a8 | 957 | #[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] |
85aaf69f | 958 | mod tests { |
532ac7d7 | 959 | use crate::fmt; |
532ac7d7 | 960 | use crate::io::prelude::*; |
60c5eb7d | 961 | use crate::io::{ErrorKind, IoSlice, IoSliceMut}; |
532ac7d7 | 962 | use crate::net::test::{next_test_ip4, next_test_ip6}; |
60c5eb7d | 963 | use crate::net::*; |
532ac7d7 | 964 | use crate::sync::mpsc::channel; |
532ac7d7 | 965 | use crate::thread; |
60c5eb7d | 966 | use crate::time::{Duration, Instant}; |
85aaf69f | 967 | |
8faf50e0 | 968 | fn each_ip(f: &mut dyn FnMut(SocketAddr)) { |
85aaf69f SL |
969 | f(next_test_ip4()); |
970 | f(next_test_ip6()); | |
971 | } | |
972 | ||
973 | macro_rules! t { | |
974 | ($e:expr) => { | |
975 | match $e { | |
976 | Ok(t) => t, | |
977 | Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), | |
978 | } | |
60c5eb7d | 979 | }; |
85aaf69f SL |
980 | } |
981 | ||
85aaf69f SL |
982 | #[test] |
983 | fn bind_error() { | |
c34b1796 | 984 | match TcpListener::bind("1.1.1.1:9999") { |
85aaf69f | 985 | Ok(..) => panic!(), |
60c5eb7d | 986 | Err(e) => assert_eq!(e.kind(), ErrorKind::AddrNotAvailable), |
85aaf69f SL |
987 | } |
988 | } | |
989 | ||
990 | #[test] | |
991 | fn connect_error() { | |
992 | match TcpStream::connect("0.0.0.0:1") { | |
993 | Ok(..) => panic!(), | |
60c5eb7d XL |
994 | Err(e) => assert!( |
995 | e.kind() == ErrorKind::ConnectionRefused | |
996 | || e.kind() == ErrorKind::InvalidInput | |
997 | || e.kind() == ErrorKind::AddrInUse | |
998 | || e.kind() == ErrorKind::AddrNotAvailable, | |
999 | "bad error: {} {:?}", | |
1000 | e, | |
1001 | e.kind() | |
1002 | ), | |
85aaf69f SL |
1003 | } |
1004 | } | |
1005 | ||
1006 | #[test] | |
1007 | fn listen_localhost() { | |
1008 | let socket_addr = next_test_ip4(); | |
1009 | let listener = t!(TcpListener::bind(&socket_addr)); | |
1010 | ||
1011 | let _t = thread::spawn(move || { | |
60c5eb7d | 1012 | let mut stream = t!(TcpStream::connect(&("localhost", socket_addr.port()))); |
85aaf69f SL |
1013 | t!(stream.write(&[144])); |
1014 | }); | |
1015 | ||
1016 | let mut stream = t!(listener.accept()).0; | |
1017 | let mut buf = [0]; | |
1018 | t!(stream.read(&mut buf)); | |
1019 | assert!(buf[0] == 144); | |
1020 | } | |
1021 | ||
1022 | #[test] | |
b039eaaf SL |
1023 | fn connect_loopback() { |
1024 | each_ip(&mut |addr| { | |
1025 | let acceptor = t!(TcpListener::bind(&addr)); | |
85aaf69f | 1026 | |
60c5eb7d | 1027 | let _t = thread::spawn(move || { |
b039eaaf SL |
1028 | let host = match addr { |
1029 | SocketAddr::V4(..) => "127.0.0.1", | |
1030 | SocketAddr::V6(..) => "::1", | |
1031 | }; | |
1032 | let mut stream = t!(TcpStream::connect(&(host, addr.port()))); | |
1033 | t!(stream.write(&[66])); | |
1034 | }); | |
85aaf69f | 1035 | |
b039eaaf SL |
1036 | let mut stream = t!(acceptor.accept()).0; |
1037 | let mut buf = [0]; | |
1038 | t!(stream.read(&mut buf)); | |
1039 | assert!(buf[0] == 66); | |
1040 | }) | |
85aaf69f SL |
1041 | } |
1042 | ||
1043 | #[test] | |
b039eaaf | 1044 | fn smoke_test() { |
85aaf69f SL |
1045 | each_ip(&mut |addr| { |
1046 | let acceptor = t!(TcpListener::bind(&addr)); | |
1047 | ||
1048 | let (tx, rx) = channel(); | |
60c5eb7d | 1049 | let _t = thread::spawn(move || { |
85aaf69f SL |
1050 | let mut stream = t!(TcpStream::connect(&addr)); |
1051 | t!(stream.write(&[99])); | |
c34b1796 | 1052 | tx.send(t!(stream.local_addr())).unwrap(); |
85aaf69f SL |
1053 | }); |
1054 | ||
1055 | let (mut stream, addr) = t!(acceptor.accept()); | |
1056 | let mut buf = [0]; | |
1057 | t!(stream.read(&mut buf)); | |
1058 | assert!(buf[0] == 99); | |
1059 | assert_eq!(addr, t!(rx.recv())); | |
1060 | }) | |
1061 | } | |
1062 | ||
1063 | #[test] | |
b039eaaf | 1064 | fn read_eof() { |
85aaf69f SL |
1065 | each_ip(&mut |addr| { |
1066 | let acceptor = t!(TcpListener::bind(&addr)); | |
1067 | ||
60c5eb7d | 1068 | let _t = thread::spawn(move || { |
85aaf69f SL |
1069 | let _stream = t!(TcpStream::connect(&addr)); |
1070 | // Close | |
1071 | }); | |
1072 | ||
1073 | let mut stream = t!(acceptor.accept()).0; | |
1074 | let mut buf = [0]; | |
1075 | let nread = t!(stream.read(&mut buf)); | |
1076 | assert_eq!(nread, 0); | |
1077 | let nread = t!(stream.read(&mut buf)); | |
1078 | assert_eq!(nread, 0); | |
1079 | }) | |
1080 | } | |
1081 | ||
1082 | #[test] | |
1083 | fn write_close() { | |
1084 | each_ip(&mut |addr| { | |
1085 | let acceptor = t!(TcpListener::bind(&addr)); | |
1086 | ||
1087 | let (tx, rx) = channel(); | |
60c5eb7d | 1088 | let _t = thread::spawn(move || { |
85aaf69f SL |
1089 | drop(t!(TcpStream::connect(&addr))); |
1090 | tx.send(()).unwrap(); | |
1091 | }); | |
1092 | ||
1093 | let mut stream = t!(acceptor.accept()).0; | |
1094 | rx.recv().unwrap(); | |
1095 | let buf = [0]; | |
1096 | match stream.write(&buf) { | |
1097 | Ok(..) => {} | |
1098 | Err(e) => { | |
60c5eb7d XL |
1099 | assert!( |
1100 | e.kind() == ErrorKind::ConnectionReset | |
1101 | || e.kind() == ErrorKind::BrokenPipe | |
1102 | || e.kind() == ErrorKind::ConnectionAborted, | |
1103 | "unknown error: {}", | |
1104 | e | |
1105 | ); | |
85aaf69f SL |
1106 | } |
1107 | } | |
1108 | }) | |
1109 | } | |
1110 | ||
1111 | #[test] | |
b039eaaf | 1112 | fn multiple_connect_serial() { |
85aaf69f SL |
1113 | each_ip(&mut |addr| { |
1114 | let max = 10; | |
1115 | let acceptor = t!(TcpListener::bind(&addr)); | |
1116 | ||
60c5eb7d | 1117 | let _t = thread::spawn(move || { |
85aaf69f SL |
1118 | for _ in 0..max { |
1119 | let mut stream = t!(TcpStream::connect(&addr)); | |
1120 | t!(stream.write(&[99])); | |
1121 | } | |
1122 | }); | |
1123 | ||
1124 | for stream in acceptor.incoming().take(max) { | |
1125 | let mut stream = t!(stream); | |
1126 | let mut buf = [0]; | |
1127 | t!(stream.read(&mut buf)); | |
1128 | assert_eq!(buf[0], 99); | |
1129 | } | |
1130 | }) | |
1131 | } | |
1132 | ||
1133 | #[test] | |
1134 | fn multiple_connect_interleaved_greedy_schedule() { | |
62682a34 | 1135 | const MAX: usize = 10; |
85aaf69f SL |
1136 | each_ip(&mut |addr| { |
1137 | let acceptor = t!(TcpListener::bind(&addr)); | |
1138 | ||
60c5eb7d | 1139 | let _t = thread::spawn(move || { |
85aaf69f SL |
1140 | let acceptor = acceptor; |
1141 | for (i, stream) in acceptor.incoming().enumerate().take(MAX) { | |
bd371182 | 1142 | // Start another thread to handle the connection |
60c5eb7d | 1143 | let _t = thread::spawn(move || { |
85aaf69f SL |
1144 | let mut stream = t!(stream); |
1145 | let mut buf = [0]; | |
1146 | t!(stream.read(&mut buf)); | |
1147 | assert!(buf[0] == i as u8); | |
1148 | }); | |
1149 | } | |
1150 | }); | |
1151 | ||
1152 | connect(0, addr); | |
1153 | }); | |
1154 | ||
1155 | fn connect(i: usize, addr: SocketAddr) { | |
60c5eb7d XL |
1156 | if i == MAX { |
1157 | return; | |
1158 | } | |
85aaf69f | 1159 | |
60c5eb7d | 1160 | let t = thread::spawn(move || { |
85aaf69f SL |
1161 | let mut stream = t!(TcpStream::connect(&addr)); |
1162 | // Connect again before writing | |
1163 | connect(i + 1, addr); | |
1164 | t!(stream.write(&[i as u8])); | |
1165 | }); | |
532ac7d7 | 1166 | t.join().ok().expect("thread panicked"); |
85aaf69f SL |
1167 | } |
1168 | } | |
1169 | ||
1170 | #[test] | |
b039eaaf | 1171 | fn multiple_connect_interleaved_lazy_schedule() { |
c34b1796 | 1172 | const MAX: usize = 10; |
85aaf69f SL |
1173 | each_ip(&mut |addr| { |
1174 | let acceptor = t!(TcpListener::bind(&addr)); | |
1175 | ||
60c5eb7d | 1176 | let _t = thread::spawn(move || { |
85aaf69f | 1177 | for stream in acceptor.incoming().take(MAX) { |
bd371182 | 1178 | // Start another thread to handle the connection |
60c5eb7d | 1179 | let _t = thread::spawn(move || { |
85aaf69f SL |
1180 | let mut stream = t!(stream); |
1181 | let mut buf = [0]; | |
1182 | t!(stream.read(&mut buf)); | |
1183 | assert!(buf[0] == 99); | |
1184 | }); | |
1185 | } | |
1186 | }); | |
1187 | ||
1188 | connect(0, addr); | |
1189 | }); | |
1190 | ||
1191 | fn connect(i: usize, addr: SocketAddr) { | |
60c5eb7d XL |
1192 | if i == MAX { |
1193 | return; | |
1194 | } | |
85aaf69f | 1195 | |
60c5eb7d | 1196 | let t = thread::spawn(move || { |
85aaf69f SL |
1197 | let mut stream = t!(TcpStream::connect(&addr)); |
1198 | connect(i + 1, addr); | |
1199 | t!(stream.write(&[99])); | |
1200 | }); | |
532ac7d7 | 1201 | t.join().ok().expect("thread panicked"); |
85aaf69f SL |
1202 | } |
1203 | } | |
1204 | ||
85aaf69f | 1205 | #[test] |
b039eaaf | 1206 | fn socket_and_peer_name() { |
85aaf69f SL |
1207 | each_ip(&mut |addr| { |
1208 | let listener = t!(TcpListener::bind(&addr)); | |
c34b1796 | 1209 | let so_name = t!(listener.local_addr()); |
85aaf69f | 1210 | assert_eq!(addr, so_name); |
60c5eb7d | 1211 | let _t = thread::spawn(move || { |
85aaf69f SL |
1212 | t!(listener.accept()); |
1213 | }); | |
1214 | ||
1215 | let stream = t!(TcpStream::connect(&addr)); | |
1216 | assert_eq!(addr, t!(stream.peer_addr())); | |
1217 | }) | |
1218 | } | |
1219 | ||
1220 | #[test] | |
1221 | fn partial_read() { | |
1222 | each_ip(&mut |addr| { | |
1223 | let (tx, rx) = channel(); | |
1224 | let srv = t!(TcpListener::bind(&addr)); | |
60c5eb7d | 1225 | let _t = thread::spawn(move || { |
85aaf69f SL |
1226 | let mut cl = t!(srv.accept()).0; |
1227 | cl.write(&[10]).unwrap(); | |
1228 | let mut b = [0]; | |
1229 | t!(cl.read(&mut b)); | |
1230 | tx.send(()).unwrap(); | |
1231 | }); | |
1232 | ||
1233 | let mut c = t!(TcpStream::connect(&addr)); | |
1234 | let mut b = [0; 10]; | |
c34b1796 | 1235 | assert_eq!(c.read(&mut b).unwrap(), 1); |
85aaf69f SL |
1236 | t!(c.write(&[1])); |
1237 | rx.recv().unwrap(); | |
1238 | }) | |
1239 | } | |
1240 | ||
9fa01778 XL |
1241 | #[test] |
1242 | fn read_vectored() { | |
1243 | each_ip(&mut |addr| { | |
1244 | let srv = t!(TcpListener::bind(&addr)); | |
1245 | let mut s1 = t!(TcpStream::connect(&addr)); | |
1246 | let mut s2 = t!(srv.accept()).0; | |
1247 | ||
1248 | let len = s1.write(&[10, 11, 12]).unwrap(); | |
1249 | assert_eq!(len, 3); | |
1250 | ||
1251 | let mut a = []; | |
1252 | let mut b = [0]; | |
1253 | let mut c = [0; 3]; | |
60c5eb7d XL |
1254 | let len = t!(s2.read_vectored(&mut [ |
1255 | IoSliceMut::new(&mut a), | |
1256 | IoSliceMut::new(&mut b), | |
1257 | IoSliceMut::new(&mut c) | |
1258 | ],)); | |
9fa01778 XL |
1259 | assert!(len > 0); |
1260 | assert_eq!(b, [10]); | |
1261 | // some implementations don't support readv, so we may only fill the first buffer | |
1262 | assert!(len == 1 || c == [11, 12, 0]); | |
1263 | }) | |
1264 | } | |
1265 | ||
1266 | #[test] | |
1267 | fn write_vectored() { | |
1268 | each_ip(&mut |addr| { | |
1269 | let srv = t!(TcpListener::bind(&addr)); | |
1270 | let mut s1 = t!(TcpStream::connect(&addr)); | |
1271 | let mut s2 = t!(srv.accept()).0; | |
1272 | ||
1273 | let a = []; | |
1274 | let b = [10]; | |
1275 | let c = [11, 12]; | |
48663c56 | 1276 | t!(s1.write_vectored(&[IoSlice::new(&a), IoSlice::new(&b), IoSlice::new(&c)])); |
9fa01778 XL |
1277 | |
1278 | let mut buf = [0; 4]; | |
1279 | let len = t!(s2.read(&mut buf)); | |
1280 | // some implementations don't support writev, so we may only write the first buffer | |
1281 | if len == 1 { | |
1282 | assert_eq!(buf, [10, 0, 0, 0]); | |
1283 | } else { | |
1284 | assert_eq!(len, 3); | |
1285 | assert_eq!(buf, [10, 11, 12, 0]); | |
1286 | } | |
1287 | }) | |
1288 | } | |
1289 | ||
85aaf69f SL |
1290 | #[test] |
1291 | fn double_bind() { | |
1292 | each_ip(&mut |addr| { | |
9fa01778 | 1293 | let listener1 = t!(TcpListener::bind(&addr)); |
85aaf69f | 1294 | match TcpListener::bind(&addr) { |
9fa01778 XL |
1295 | Ok(listener2) => panic!( |
1296 | "This system (perhaps due to options set by TcpListener::bind) \ | |
1297 | permits double binding: {:?} and {:?}", | |
1298 | listener1, listener2 | |
1299 | ), | |
85aaf69f | 1300 | Err(e) => { |
60c5eb7d XL |
1301 | assert!( |
1302 | e.kind() == ErrorKind::ConnectionRefused | |
1303 | || e.kind() == ErrorKind::Other | |
1304 | || e.kind() == ErrorKind::AddrInUse, | |
1305 | "unknown error: {} {:?}", | |
1306 | e, | |
1307 | e.kind() | |
1308 | ); | |
85aaf69f SL |
1309 | } |
1310 | } | |
1311 | }) | |
1312 | } | |
1313 | ||
85aaf69f SL |
1314 | #[test] |
1315 | fn tcp_clone_smoke() { | |
1316 | each_ip(&mut |addr| { | |
1317 | let acceptor = t!(TcpListener::bind(&addr)); | |
1318 | ||
60c5eb7d | 1319 | let _t = thread::spawn(move || { |
85aaf69f SL |
1320 | let mut s = t!(TcpStream::connect(&addr)); |
1321 | let mut buf = [0, 0]; | |
c34b1796 | 1322 | assert_eq!(s.read(&mut buf).unwrap(), 1); |
85aaf69f SL |
1323 | assert_eq!(buf[0], 1); |
1324 | t!(s.write(&[2])); | |
1325 | }); | |
1326 | ||
1327 | let mut s1 = t!(acceptor.accept()).0; | |
1328 | let s2 = t!(s1.try_clone()); | |
1329 | ||
1330 | let (tx1, rx1) = channel(); | |
1331 | let (tx2, rx2) = channel(); | |
60c5eb7d | 1332 | let _t = thread::spawn(move || { |
85aaf69f SL |
1333 | let mut s2 = s2; |
1334 | rx1.recv().unwrap(); | |
1335 | t!(s2.write(&[1])); | |
1336 | tx2.send(()).unwrap(); | |
1337 | }); | |
1338 | tx1.send(()).unwrap(); | |
1339 | let mut buf = [0, 0]; | |
c34b1796 | 1340 | assert_eq!(s1.read(&mut buf).unwrap(), 1); |
85aaf69f SL |
1341 | rx2.recv().unwrap(); |
1342 | }) | |
1343 | } | |
1344 | ||
1345 | #[test] | |
1346 | fn tcp_clone_two_read() { | |
1347 | each_ip(&mut |addr| { | |
1348 | let acceptor = t!(TcpListener::bind(&addr)); | |
1349 | let (tx1, rx) = channel(); | |
1350 | let tx2 = tx1.clone(); | |
1351 | ||
60c5eb7d | 1352 | let _t = thread::spawn(move || { |
85aaf69f SL |
1353 | let mut s = t!(TcpStream::connect(&addr)); |
1354 | t!(s.write(&[1])); | |
1355 | rx.recv().unwrap(); | |
1356 | t!(s.write(&[2])); | |
1357 | rx.recv().unwrap(); | |
1358 | }); | |
1359 | ||
1360 | let mut s1 = t!(acceptor.accept()).0; | |
1361 | let s2 = t!(s1.try_clone()); | |
1362 | ||
1363 | let (done, rx) = channel(); | |
60c5eb7d | 1364 | let _t = thread::spawn(move || { |
85aaf69f SL |
1365 | let mut s2 = s2; |
1366 | let mut buf = [0, 0]; | |
1367 | t!(s2.read(&mut buf)); | |
1368 | tx2.send(()).unwrap(); | |
1369 | done.send(()).unwrap(); | |
1370 | }); | |
1371 | let mut buf = [0, 0]; | |
1372 | t!(s1.read(&mut buf)); | |
1373 | tx1.send(()).unwrap(); | |
1374 | ||
1375 | rx.recv().unwrap(); | |
1376 | }) | |
1377 | } | |
1378 | ||
1379 | #[test] | |
1380 | fn tcp_clone_two_write() { | |
1381 | each_ip(&mut |addr| { | |
1382 | let acceptor = t!(TcpListener::bind(&addr)); | |
1383 | ||
60c5eb7d | 1384 | let _t = thread::spawn(move || { |
85aaf69f SL |
1385 | let mut s = t!(TcpStream::connect(&addr)); |
1386 | let mut buf = [0, 1]; | |
1387 | t!(s.read(&mut buf)); | |
1388 | t!(s.read(&mut buf)); | |
1389 | }); | |
1390 | ||
1391 | let mut s1 = t!(acceptor.accept()).0; | |
1392 | let s2 = t!(s1.try_clone()); | |
1393 | ||
1394 | let (done, rx) = channel(); | |
60c5eb7d | 1395 | let _t = thread::spawn(move || { |
85aaf69f SL |
1396 | let mut s2 = s2; |
1397 | t!(s2.write(&[1])); | |
1398 | done.send(()).unwrap(); | |
1399 | }); | |
1400 | t!(s1.write(&[2])); | |
1401 | ||
1402 | rx.recv().unwrap(); | |
1403 | }) | |
1404 | } | |
1405 | ||
1406 | #[test] | |
532ac7d7 XL |
1407 | // FIXME: https://github.com/fortanix/rust-sgx/issues/110 |
1408 | #[cfg_attr(target_env = "sgx", ignore)] | |
85aaf69f SL |
1409 | fn shutdown_smoke() { |
1410 | each_ip(&mut |addr| { | |
1411 | let a = t!(TcpListener::bind(&addr)); | |
60c5eb7d | 1412 | let _t = thread::spawn(move || { |
85aaf69f SL |
1413 | let mut c = t!(a.accept()).0; |
1414 | let mut b = [0]; | |
c34b1796 | 1415 | assert_eq!(c.read(&mut b).unwrap(), 0); |
85aaf69f SL |
1416 | t!(c.write(&[1])); |
1417 | }); | |
1418 | ||
1419 | let mut s = t!(TcpStream::connect(&addr)); | |
1420 | t!(s.shutdown(Shutdown::Write)); | |
1421 | assert!(s.write(&[1]).is_err()); | |
1422 | let mut b = [0, 0]; | |
1423 | assert_eq!(t!(s.read(&mut b)), 1); | |
1424 | assert_eq!(b[0], 1); | |
1425 | }) | |
1426 | } | |
1427 | ||
1428 | #[test] | |
532ac7d7 XL |
1429 | // FIXME: https://github.com/fortanix/rust-sgx/issues/110 |
1430 | #[cfg_attr(target_env = "sgx", ignore)] | |
85aaf69f SL |
1431 | fn close_readwrite_smoke() { |
1432 | each_ip(&mut |addr| { | |
1433 | let a = t!(TcpListener::bind(&addr)); | |
1434 | let (tx, rx) = channel::<()>(); | |
60c5eb7d | 1435 | let _t = thread::spawn(move || { |
85aaf69f SL |
1436 | let _s = t!(a.accept()); |
1437 | let _ = rx.recv(); | |
1438 | }); | |
1439 | ||
1440 | let mut b = [0]; | |
1441 | let mut s = t!(TcpStream::connect(&addr)); | |
1442 | let mut s2 = t!(s.try_clone()); | |
1443 | ||
1444 | // closing should prevent reads/writes | |
1445 | t!(s.shutdown(Shutdown::Write)); | |
1446 | assert!(s.write(&[0]).is_err()); | |
1447 | t!(s.shutdown(Shutdown::Read)); | |
c34b1796 | 1448 | assert_eq!(s.read(&mut b).unwrap(), 0); |
85aaf69f SL |
1449 | |
1450 | // closing should affect previous handles | |
1451 | assert!(s2.write(&[0]).is_err()); | |
c34b1796 | 1452 | assert_eq!(s2.read(&mut b).unwrap(), 0); |
85aaf69f SL |
1453 | |
1454 | // closing should affect new handles | |
1455 | let mut s3 = t!(s.try_clone()); | |
1456 | assert!(s3.write(&[0]).is_err()); | |
c34b1796 | 1457 | assert_eq!(s3.read(&mut b).unwrap(), 0); |
85aaf69f SL |
1458 | |
1459 | // make sure these don't die | |
1460 | let _ = s2.shutdown(Shutdown::Read); | |
1461 | let _ = s2.shutdown(Shutdown::Write); | |
1462 | let _ = s3.shutdown(Shutdown::Read); | |
1463 | let _ = s3.shutdown(Shutdown::Write); | |
1464 | drop(tx); | |
1465 | }) | |
1466 | } | |
1467 | ||
1468 | #[test] | |
32a655c1 | 1469 | #[cfg(unix)] // test doesn't work on Windows, see #31657 |
85aaf69f SL |
1470 | fn close_read_wakes_up() { |
1471 | each_ip(&mut |addr| { | |
1472 | let a = t!(TcpListener::bind(&addr)); | |
1473 | let (tx1, rx) = channel::<()>(); | |
60c5eb7d | 1474 | let _t = thread::spawn(move || { |
85aaf69f SL |
1475 | let _s = t!(a.accept()); |
1476 | let _ = rx.recv(); | |
1477 | }); | |
1478 | ||
1479 | let s = t!(TcpStream::connect(&addr)); | |
1480 | let s2 = t!(s.try_clone()); | |
1481 | let (tx, rx) = channel(); | |
60c5eb7d | 1482 | let _t = thread::spawn(move || { |
85aaf69f SL |
1483 | let mut s2 = s2; |
1484 | assert_eq!(t!(s2.read(&mut [0])), 0); | |
1485 | tx.send(()).unwrap(); | |
1486 | }); | |
bd371182 | 1487 | // this should wake up the child thread |
85aaf69f SL |
1488 | t!(s.shutdown(Shutdown::Read)); |
1489 | ||
1490 | // this test will never finish if the child doesn't wake up | |
1491 | rx.recv().unwrap(); | |
1492 | drop(tx1); | |
1493 | }) | |
1494 | } | |
1495 | ||
1496 | #[test] | |
1497 | fn clone_while_reading() { | |
1498 | each_ip(&mut |addr| { | |
1499 | let accept = t!(TcpListener::bind(&addr)); | |
1500 | ||
bd371182 | 1501 | // Enqueue a thread to write to a socket |
85aaf69f SL |
1502 | let (tx, rx) = channel(); |
1503 | let (txdone, rxdone) = channel(); | |
1504 | let txdone2 = txdone.clone(); | |
60c5eb7d | 1505 | let _t = thread::spawn(move || { |
85aaf69f SL |
1506 | let mut tcp = t!(TcpStream::connect(&addr)); |
1507 | rx.recv().unwrap(); | |
1508 | t!(tcp.write(&[0])); | |
1509 | txdone2.send(()).unwrap(); | |
1510 | }); | |
1511 | ||
1512 | // Spawn off a reading clone | |
1513 | let tcp = t!(accept.accept()).0; | |
1514 | let tcp2 = t!(tcp.try_clone()); | |
1515 | let txdone3 = txdone.clone(); | |
60c5eb7d | 1516 | let _t = thread::spawn(move || { |
85aaf69f SL |
1517 | let mut tcp2 = tcp2; |
1518 | t!(tcp2.read(&mut [0])); | |
1519 | txdone3.send(()).unwrap(); | |
1520 | }); | |
1521 | ||
1522 | // Try to ensure that the reading clone is indeed reading | |
1523 | for _ in 0..50 { | |
1524 | thread::yield_now(); | |
1525 | } | |
1526 | ||
1527 | // clone the handle again while it's reading, then let it finish the | |
1528 | // read. | |
1529 | let _ = t!(tcp.try_clone()); | |
1530 | tx.send(()).unwrap(); | |
1531 | rxdone.recv().unwrap(); | |
1532 | rxdone.recv().unwrap(); | |
1533 | }) | |
1534 | } | |
1535 | ||
1536 | #[test] | |
1537 | fn clone_accept_smoke() { | |
1538 | each_ip(&mut |addr| { | |
1539 | let a = t!(TcpListener::bind(&addr)); | |
1540 | let a2 = t!(a.try_clone()); | |
1541 | ||
60c5eb7d | 1542 | let _t = thread::spawn(move || { |
85aaf69f SL |
1543 | let _ = TcpStream::connect(&addr); |
1544 | }); | |
60c5eb7d | 1545 | let _t = thread::spawn(move || { |
85aaf69f SL |
1546 | let _ = TcpStream::connect(&addr); |
1547 | }); | |
1548 | ||
1549 | t!(a.accept()); | |
1550 | t!(a2.accept()); | |
1551 | }) | |
1552 | } | |
1553 | ||
1554 | #[test] | |
1555 | fn clone_accept_concurrent() { | |
1556 | each_ip(&mut |addr| { | |
1557 | let a = t!(TcpListener::bind(&addr)); | |
1558 | let a2 = t!(a.try_clone()); | |
1559 | ||
1560 | let (tx, rx) = channel(); | |
1561 | let tx2 = tx.clone(); | |
1562 | ||
60c5eb7d | 1563 | let _t = thread::spawn(move || { |
85aaf69f SL |
1564 | tx.send(t!(a.accept())).unwrap(); |
1565 | }); | |
60c5eb7d | 1566 | let _t = thread::spawn(move || { |
85aaf69f SL |
1567 | tx2.send(t!(a2.accept())).unwrap(); |
1568 | }); | |
1569 | ||
60c5eb7d | 1570 | let _t = thread::spawn(move || { |
85aaf69f SL |
1571 | let _ = TcpStream::connect(&addr); |
1572 | }); | |
60c5eb7d | 1573 | let _t = thread::spawn(move || { |
85aaf69f SL |
1574 | let _ = TcpStream::connect(&addr); |
1575 | }); | |
1576 | ||
1577 | rx.recv().unwrap(); | |
1578 | rx.recv().unwrap(); | |
1579 | }) | |
1580 | } | |
d9579d0f AL |
1581 | |
1582 | #[test] | |
1583 | fn debug() { | |
532ac7d7 XL |
1584 | #[cfg(not(target_env = "sgx"))] |
1585 | fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a { | |
1586 | addr | |
1587 | } | |
1588 | #[cfg(target_env = "sgx")] | |
1589 | fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a { | |
1590 | addr.to_string() | |
1591 | } | |
1592 | ||
532ac7d7 XL |
1593 | #[cfg(target_env = "sgx")] |
1594 | use crate::os::fortanix_sgx::io::AsRawFd; | |
60c5eb7d XL |
1595 | #[cfg(unix)] |
1596 | use crate::os::unix::io::AsRawFd; | |
532ac7d7 XL |
1597 | #[cfg(not(windows))] |
1598 | fn render_inner(addr: &dyn AsRawFd) -> impl fmt::Debug { | |
1599 | addr.as_raw_fd() | |
1600 | } | |
1601 | #[cfg(windows)] | |
1602 | fn render_inner(addr: &dyn crate::os::windows::io::AsRawSocket) -> impl fmt::Debug { | |
1603 | addr.as_raw_socket() | |
1604 | } | |
1605 | ||
60c5eb7d | 1606 | let inner_name = if cfg!(windows) { "socket" } else { "fd" }; |
d9579d0f AL |
1607 | let socket_addr = next_test_ip4(); |
1608 | ||
1609 | let listener = t!(TcpListener::bind(&socket_addr)); | |
60c5eb7d XL |
1610 | let compare = format!( |
1611 | "TcpListener {{ addr: {:?}, {}: {:?} }}", | |
1612 | render_socket_addr(&socket_addr), | |
1613 | inner_name, | |
1614 | render_inner(&listener) | |
1615 | ); | |
d9579d0f AL |
1616 | assert_eq!(format!("{:?}", listener), compare); |
1617 | ||
532ac7d7 | 1618 | let stream = t!(TcpStream::connect(&("localhost", socket_addr.port()))); |
60c5eb7d XL |
1619 | let compare = format!( |
1620 | "TcpStream {{ addr: {:?}, peer: {:?}, {}: {:?} }}", | |
1621 | render_socket_addr(&stream.local_addr().unwrap()), | |
1622 | render_socket_addr(&stream.peer_addr().unwrap()), | |
1623 | inner_name, | |
1624 | render_inner(&stream) | |
1625 | ); | |
d9579d0f AL |
1626 | assert_eq!(format!("{:?}", stream), compare); |
1627 | } | |
62682a34 | 1628 | |
48663c56 | 1629 | // FIXME: re-enabled openbsd tests once their socket timeout code |
62682a34 | 1630 | // no longer has rounding errors. |
e1599b0c XL |
1631 | // VxWorks ignores SO_SNDTIMEO. |
1632 | #[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks"), ignore)] | |
532ac7d7 | 1633 | #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 |
62682a34 SL |
1634 | #[test] |
1635 | fn timeouts() { | |
1636 | let addr = next_test_ip4(); | |
1637 | let listener = t!(TcpListener::bind(&addr)); | |
1638 | ||
1639 | let stream = t!(TcpStream::connect(&("localhost", addr.port()))); | |
1640 | let dur = Duration::new(15410, 0); | |
1641 | ||
1642 | assert_eq!(None, t!(stream.read_timeout())); | |
1643 | ||
1644 | t!(stream.set_read_timeout(Some(dur))); | |
1645 | assert_eq!(Some(dur), t!(stream.read_timeout())); | |
1646 | ||
1647 | assert_eq!(None, t!(stream.write_timeout())); | |
1648 | ||
1649 | t!(stream.set_write_timeout(Some(dur))); | |
1650 | assert_eq!(Some(dur), t!(stream.write_timeout())); | |
1651 | ||
1652 | t!(stream.set_read_timeout(None)); | |
1653 | assert_eq!(None, t!(stream.read_timeout())); | |
1654 | ||
1655 | t!(stream.set_write_timeout(None)); | |
1656 | assert_eq!(None, t!(stream.write_timeout())); | |
9cc50fc6 | 1657 | drop(listener); |
62682a34 SL |
1658 | } |
1659 | ||
1660 | #[test] | |
532ac7d7 | 1661 | #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 |
62682a34 SL |
1662 | fn test_read_timeout() { |
1663 | let addr = next_test_ip4(); | |
1664 | let listener = t!(TcpListener::bind(&addr)); | |
1665 | ||
1666 | let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); | |
1667 | t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); | |
1668 | ||
1669 | let mut buf = [0; 10]; | |
9cc50fc6 | 1670 | let start = Instant::now(); |
a1dfa0c6 | 1671 | let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); |
60c5eb7d XL |
1672 | assert!( |
1673 | kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, | |
1674 | "unexpected_error: {:?}", | |
1675 | kind | |
1676 | ); | |
9cc50fc6 SL |
1677 | assert!(start.elapsed() > Duration::from_millis(400)); |
1678 | drop(listener); | |
62682a34 SL |
1679 | } |
1680 | ||
1681 | #[test] | |
532ac7d7 | 1682 | #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 |
62682a34 SL |
1683 | fn test_read_with_timeout() { |
1684 | let addr = next_test_ip4(); | |
1685 | let listener = t!(TcpListener::bind(&addr)); | |
1686 | ||
1687 | let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); | |
1688 | t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); | |
1689 | ||
1690 | let mut other_end = t!(listener.accept()).0; | |
1691 | t!(other_end.write_all(b"hello world")); | |
1692 | ||
1693 | let mut buf = [0; 11]; | |
1694 | t!(stream.read(&mut buf)); | |
1695 | assert_eq!(b"hello world", &buf[..]); | |
1696 | ||
9cc50fc6 | 1697 | let start = Instant::now(); |
a1dfa0c6 | 1698 | let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); |
60c5eb7d XL |
1699 | assert!( |
1700 | kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, | |
1701 | "unexpected_error: {:?}", | |
1702 | kind | |
1703 | ); | |
9cc50fc6 SL |
1704 | assert!(start.elapsed() > Duration::from_millis(400)); |
1705 | drop(listener); | |
62682a34 | 1706 | } |
54a0048b | 1707 | |
0531ce1d XL |
1708 | // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors |
1709 | // when passed zero Durations | |
1710 | #[test] | |
1711 | fn test_timeout_zero_duration() { | |
1712 | let addr = next_test_ip4(); | |
1713 | ||
1714 | let listener = t!(TcpListener::bind(&addr)); | |
1715 | let stream = t!(TcpStream::connect(&addr)); | |
1716 | ||
1717 | let result = stream.set_write_timeout(Some(Duration::new(0, 0))); | |
1718 | let err = result.unwrap_err(); | |
1719 | assert_eq!(err.kind(), ErrorKind::InvalidInput); | |
1720 | ||
1721 | let result = stream.set_read_timeout(Some(Duration::new(0, 0))); | |
1722 | let err = result.unwrap_err(); | |
1723 | assert_eq!(err.kind(), ErrorKind::InvalidInput); | |
1724 | ||
1725 | drop(listener); | |
1726 | } | |
1727 | ||
54a0048b | 1728 | #[test] |
532ac7d7 | 1729 | #[cfg_attr(target_env = "sgx", ignore)] |
54a0048b SL |
1730 | fn nodelay() { |
1731 | let addr = next_test_ip4(); | |
1732 | let _listener = t!(TcpListener::bind(&addr)); | |
1733 | ||
1734 | let stream = t!(TcpStream::connect(&("localhost", addr.port()))); | |
1735 | ||
1736 | assert_eq!(false, t!(stream.nodelay())); | |
1737 | t!(stream.set_nodelay(true)); | |
1738 | assert_eq!(true, t!(stream.nodelay())); | |
1739 | t!(stream.set_nodelay(false)); | |
1740 | assert_eq!(false, t!(stream.nodelay())); | |
1741 | } | |
1742 | ||
1743 | #[test] | |
532ac7d7 | 1744 | #[cfg_attr(target_env = "sgx", ignore)] |
54a0048b SL |
1745 | fn ttl() { |
1746 | let ttl = 100; | |
1747 | ||
1748 | let addr = next_test_ip4(); | |
1749 | let listener = t!(TcpListener::bind(&addr)); | |
1750 | ||
1751 | t!(listener.set_ttl(ttl)); | |
1752 | assert_eq!(ttl, t!(listener.ttl())); | |
1753 | ||
1754 | let stream = t!(TcpStream::connect(&("localhost", addr.port()))); | |
1755 | ||
1756 | t!(stream.set_ttl(ttl)); | |
1757 | assert_eq!(ttl, t!(stream.ttl())); | |
1758 | } | |
1759 | ||
1760 | #[test] | |
532ac7d7 | 1761 | #[cfg_attr(target_env = "sgx", ignore)] |
54a0048b SL |
1762 | fn set_nonblocking() { |
1763 | let addr = next_test_ip4(); | |
1764 | let listener = t!(TcpListener::bind(&addr)); | |
1765 | ||
1766 | t!(listener.set_nonblocking(true)); | |
1767 | t!(listener.set_nonblocking(false)); | |
1768 | ||
1769 | let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); | |
1770 | ||
1771 | t!(stream.set_nonblocking(false)); | |
1772 | t!(stream.set_nonblocking(true)); | |
1773 | ||
1774 | let mut buf = [0]; | |
1775 | match stream.read(&mut buf) { | |
1776 | Ok(_) => panic!("expected error"), | |
1777 | Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} | |
1778 | Err(e) => panic!("unexpected error {}", e), | |
1779 | } | |
1780 | } | |
8bb4bdeb XL |
1781 | |
1782 | #[test] | |
532ac7d7 | 1783 | #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 |
8bb4bdeb XL |
1784 | fn peek() { |
1785 | each_ip(&mut |addr| { | |
1786 | let (txdone, rxdone) = channel(); | |
1787 | ||
1788 | let srv = t!(TcpListener::bind(&addr)); | |
60c5eb7d | 1789 | let _t = thread::spawn(move || { |
8bb4bdeb | 1790 | let mut cl = t!(srv.accept()).0; |
60c5eb7d | 1791 | cl.write(&[1, 3, 3, 7]).unwrap(); |
8bb4bdeb XL |
1792 | t!(rxdone.recv()); |
1793 | }); | |
1794 | ||
1795 | let mut c = t!(TcpStream::connect(&addr)); | |
1796 | let mut b = [0; 10]; | |
1797 | for _ in 1..3 { | |
1798 | let len = c.peek(&mut b).unwrap(); | |
1799 | assert_eq!(len, 4); | |
1800 | } | |
1801 | let len = c.read(&mut b).unwrap(); | |
1802 | assert_eq!(len, 4); | |
1803 | ||
1804 | t!(c.set_nonblocking(true)); | |
1805 | match c.peek(&mut b) { | |
1806 | Ok(_) => panic!("expected error"), | |
1807 | Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} | |
1808 | Err(e) => panic!("unexpected error {}", e), | |
1809 | } | |
1810 | t!(txdone.send(())); | |
1811 | }) | |
1812 | } | |
041b39d2 | 1813 | |
abe05a73 | 1814 | #[test] |
532ac7d7 | 1815 | #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 |
041b39d2 XL |
1816 | fn connect_timeout_valid() { |
1817 | let listener = TcpListener::bind("127.0.0.1:0").unwrap(); | |
1818 | let addr = listener.local_addr().unwrap(); | |
1819 | TcpStream::connect_timeout(&addr, Duration::from_secs(2)).unwrap(); | |
1820 | } | |
85aaf69f | 1821 | } |