1 | use crate::net::{TcpListener, TcpStream}; |
2 | |
3 | use std::fmt; |
4 | use std::io; |
5 | use std::net::SocketAddr; |
6 | |
7 | #[cfg (unix)] |
8 | use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; |
9 | use std::time::Duration; |
10 | |
11 | cfg_windows! { |
12 | use crate::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket, AsSocket, BorrowedSocket}; |
13 | } |
14 | |
15 | cfg_net! { |
16 | /// A TCP socket that has not yet been converted to a `TcpStream` or |
17 | /// `TcpListener`. |
18 | /// |
19 | /// `TcpSocket` wraps an operating system socket and enables the caller to |
20 | /// configure the socket before establishing a TCP connection or accepting |
21 | /// inbound connections. The caller is able to set socket option and explicitly |
22 | /// bind the socket with a socket address. |
23 | /// |
24 | /// The underlying socket is closed when the `TcpSocket` value is dropped. |
25 | /// |
26 | /// `TcpSocket` should only be used directly if the default configuration used |
27 | /// by `TcpStream::connect` and `TcpListener::bind` does not meet the required |
28 | /// use case. |
29 | /// |
30 | /// Calling `TcpStream::connect("127.0.0.1:8080")` is equivalent to: |
31 | /// |
32 | /// ```no_run |
33 | /// use tokio::net::TcpSocket; |
34 | /// |
35 | /// use std::io; |
36 | /// |
37 | /// #[tokio::main] |
38 | /// async fn main() -> io::Result<()> { |
39 | /// let addr = "127.0.0.1:8080".parse().unwrap(); |
40 | /// |
41 | /// let socket = TcpSocket::new_v4()?; |
42 | /// let stream = socket.connect(addr).await?; |
43 | /// # drop(stream); |
44 | /// |
45 | /// Ok(()) |
46 | /// } |
47 | /// ``` |
48 | /// |
49 | /// Calling `TcpListener::bind("127.0.0.1:8080")` is equivalent to: |
50 | /// |
51 | /// ```no_run |
52 | /// use tokio::net::TcpSocket; |
53 | /// |
54 | /// use std::io; |
55 | /// |
56 | /// #[tokio::main] |
57 | /// async fn main() -> io::Result<()> { |
58 | /// let addr = "127.0.0.1:8080".parse().unwrap(); |
59 | /// |
60 | /// let socket = TcpSocket::new_v4()?; |
61 | /// // On platforms with Berkeley-derived sockets, this allows to quickly |
62 | /// // rebind a socket, without needing to wait for the OS to clean up the |
63 | /// // previous one. |
64 | /// // |
65 | /// // On Windows, this allows rebinding sockets which are actively in use, |
66 | /// // which allows “socket hijacking”, so we explicitly don't set it here. |
67 | /// // https://docs.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse |
68 | /// socket.set_reuseaddr(true)?; |
69 | /// socket.bind(addr)?; |
70 | /// |
71 | /// let listener = socket.listen(1024)?; |
72 | /// # drop(listener); |
73 | /// |
74 | /// Ok(()) |
75 | /// } |
76 | /// ``` |
77 | /// |
78 | /// Setting socket options not explicitly provided by `TcpSocket` may be done by |
79 | /// accessing the `RawFd`/`RawSocket` using [`AsRawFd`]/[`AsRawSocket`] and |
80 | /// setting the option with a crate like [`socket2`]. |
81 | /// |
82 | /// [`RawFd`]: https://doc.rust-lang.org/std/os/unix/io/type.RawFd.html |
83 | /// [`RawSocket`]: https://doc.rust-lang.org/std/os/windows/io/type.RawSocket.html |
84 | /// [`AsRawFd`]: https://doc.rust-lang.org/std/os/unix/io/trait.AsRawFd.html |
85 | /// [`AsRawSocket`]: https://doc.rust-lang.org/std/os/windows/io/trait.AsRawSocket.html |
86 | /// [`socket2`]: https://docs.rs/socket2/ |
87 | #[cfg_attr (docsrs, doc(alias = "connect_std" ))] |
88 | pub struct TcpSocket { |
89 | inner: socket2::Socket, |
90 | } |
91 | } |
92 | |
93 | impl TcpSocket { |
94 | /// Creates a new socket configured for IPv4. |
95 | /// |
96 | /// Calls `socket(2)` with `AF_INET` and `SOCK_STREAM`. |
97 | /// |
98 | /// # Returns |
99 | /// |
100 | /// On success, the newly created `TcpSocket` is returned. If an error is |
101 | /// encountered, it is returned instead. |
102 | /// |
103 | /// # Examples |
104 | /// |
105 | /// Create a new IPv4 socket and start listening. |
106 | /// |
107 | /// ```no_run |
108 | /// use tokio::net::TcpSocket; |
109 | /// |
110 | /// use std::io; |
111 | /// |
112 | /// #[tokio::main] |
113 | /// async fn main() -> io::Result<()> { |
114 | /// let addr = "127.0.0.1:8080" .parse().unwrap(); |
115 | /// let socket = TcpSocket::new_v4()?; |
116 | /// socket.bind(addr)?; |
117 | /// |
118 | /// let listener = socket.listen(128)?; |
119 | /// # drop(listener); |
120 | /// Ok(()) |
121 | /// } |
122 | /// ``` |
123 | pub fn new_v4() -> io::Result<TcpSocket> { |
124 | TcpSocket::new(socket2::Domain::IPV4) |
125 | } |
126 | |
127 | /// Creates a new socket configured for IPv6. |
128 | /// |
129 | /// Calls `socket(2)` with `AF_INET6` and `SOCK_STREAM`. |
130 | /// |
131 | /// # Returns |
132 | /// |
133 | /// On success, the newly created `TcpSocket` is returned. If an error is |
134 | /// encountered, it is returned instead. |
135 | /// |
136 | /// # Examples |
137 | /// |
138 | /// Create a new IPv6 socket and start listening. |
139 | /// |
140 | /// ```no_run |
141 | /// use tokio::net::TcpSocket; |
142 | /// |
143 | /// use std::io; |
144 | /// |
145 | /// #[tokio::main] |
146 | /// async fn main() -> io::Result<()> { |
147 | /// let addr = "[::1]:8080" .parse().unwrap(); |
148 | /// let socket = TcpSocket::new_v6()?; |
149 | /// socket.bind(addr)?; |
150 | /// |
151 | /// let listener = socket.listen(128)?; |
152 | /// # drop(listener); |
153 | /// Ok(()) |
154 | /// } |
155 | /// ``` |
156 | pub fn new_v6() -> io::Result<TcpSocket> { |
157 | TcpSocket::new(socket2::Domain::IPV6) |
158 | } |
159 | |
160 | fn new(domain: socket2::Domain) -> io::Result<TcpSocket> { |
161 | let ty = socket2::Type::STREAM; |
162 | #[cfg (any( |
163 | target_os = "android" , |
164 | target_os = "dragonfly" , |
165 | target_os = "freebsd" , |
166 | target_os = "fuchsia" , |
167 | target_os = "illumos" , |
168 | target_os = "linux" , |
169 | target_os = "netbsd" , |
170 | target_os = "openbsd" |
171 | ))] |
172 | let ty = ty.nonblocking(); |
173 | let inner = socket2::Socket::new(domain, ty, Some(socket2::Protocol::TCP))?; |
174 | #[cfg (not(any( |
175 | target_os = "android" , |
176 | target_os = "dragonfly" , |
177 | target_os = "freebsd" , |
178 | target_os = "fuchsia" , |
179 | target_os = "illumos" , |
180 | target_os = "linux" , |
181 | target_os = "netbsd" , |
182 | target_os = "openbsd" |
183 | )))] |
184 | inner.set_nonblocking(true)?; |
185 | Ok(TcpSocket { inner }) |
186 | } |
187 | |
188 | /// Sets value for the `SO_KEEPALIVE` option on this socket. |
189 | pub fn set_keepalive(&self, keepalive: bool) -> io::Result<()> { |
190 | self.inner.set_keepalive(keepalive) |
191 | } |
192 | |
193 | /// Gets the value of the `SO_KEEPALIVE` option on this socket. |
194 | pub fn keepalive(&self) -> io::Result<bool> { |
195 | self.inner.keepalive() |
196 | } |
197 | |
198 | /// Allows the socket to bind to an in-use address. |
199 | /// |
200 | /// Behavior is platform specific. Refer to the target platform's |
201 | /// documentation for more details. |
202 | /// |
203 | /// # Examples |
204 | /// |
205 | /// ```no_run |
206 | /// use tokio::net::TcpSocket; |
207 | /// |
208 | /// use std::io; |
209 | /// |
210 | /// #[tokio::main] |
211 | /// async fn main() -> io::Result<()> { |
212 | /// let addr = "127.0.0.1:8080" .parse().unwrap(); |
213 | /// |
214 | /// let socket = TcpSocket::new_v4()?; |
215 | /// socket.set_reuseaddr(true)?; |
216 | /// socket.bind(addr)?; |
217 | /// |
218 | /// let listener = socket.listen(1024)?; |
219 | /// # drop(listener); |
220 | /// |
221 | /// Ok(()) |
222 | /// } |
223 | /// ``` |
224 | pub fn set_reuseaddr(&self, reuseaddr: bool) -> io::Result<()> { |
225 | self.inner.set_reuse_address(reuseaddr) |
226 | } |
227 | |
228 | /// Retrieves the value set for `SO_REUSEADDR` on this socket. |
229 | /// |
230 | /// # Examples |
231 | /// |
232 | /// ```no_run |
233 | /// use tokio::net::TcpSocket; |
234 | /// |
235 | /// use std::io; |
236 | /// |
237 | /// #[tokio::main] |
238 | /// async fn main() -> io::Result<()> { |
239 | /// let addr = "127.0.0.1:8080" .parse().unwrap(); |
240 | /// |
241 | /// let socket = TcpSocket::new_v4()?; |
242 | /// socket.set_reuseaddr(true)?; |
243 | /// assert!(socket.reuseaddr().unwrap()); |
244 | /// socket.bind(addr)?; |
245 | /// |
246 | /// let listener = socket.listen(1024)?; |
247 | /// Ok(()) |
248 | /// } |
249 | /// ``` |
250 | pub fn reuseaddr(&self) -> io::Result<bool> { |
251 | self.inner.reuse_address() |
252 | } |
253 | |
254 | /// Allows the socket to bind to an in-use port. Only available for unix systems |
255 | /// (excluding Solaris & Illumos). |
256 | /// |
257 | /// Behavior is platform specific. Refer to the target platform's |
258 | /// documentation for more details. |
259 | /// |
260 | /// # Examples |
261 | /// |
262 | /// ```no_run |
263 | /// use tokio::net::TcpSocket; |
264 | /// |
265 | /// use std::io; |
266 | /// |
267 | /// #[tokio::main] |
268 | /// async fn main() -> io::Result<()> { |
269 | /// let addr = "127.0.0.1:8080" .parse().unwrap(); |
270 | /// |
271 | /// let socket = TcpSocket::new_v4()?; |
272 | /// socket.set_reuseport(true)?; |
273 | /// socket.bind(addr)?; |
274 | /// |
275 | /// let listener = socket.listen(1024)?; |
276 | /// Ok(()) |
277 | /// } |
278 | /// ``` |
279 | #[cfg (all(unix, not(target_os = "solaris" ), not(target_os = "illumos" )))] |
280 | #[cfg_attr ( |
281 | docsrs, |
282 | doc(cfg(all(unix, not(target_os = "solaris" ), not(target_os = "illumos" )))) |
283 | )] |
284 | pub fn set_reuseport(&self, reuseport: bool) -> io::Result<()> { |
285 | self.inner.set_reuse_port(reuseport) |
286 | } |
287 | |
288 | /// Allows the socket to bind to an in-use port. Only available for unix systems |
289 | /// (excluding Solaris & Illumos). |
290 | /// |
291 | /// Behavior is platform specific. Refer to the target platform's |
292 | /// documentation for more details. |
293 | /// |
294 | /// # Examples |
295 | /// |
296 | /// ```no_run |
297 | /// use tokio::net::TcpSocket; |
298 | /// |
299 | /// use std::io; |
300 | /// |
301 | /// #[tokio::main] |
302 | /// async fn main() -> io::Result<()> { |
303 | /// let addr = "127.0.0.1:8080" .parse().unwrap(); |
304 | /// |
305 | /// let socket = TcpSocket::new_v4()?; |
306 | /// socket.set_reuseport(true)?; |
307 | /// assert!(socket.reuseport().unwrap()); |
308 | /// socket.bind(addr)?; |
309 | /// |
310 | /// let listener = socket.listen(1024)?; |
311 | /// Ok(()) |
312 | /// } |
313 | /// ``` |
314 | #[cfg (all(unix, not(target_os = "solaris" ), not(target_os = "illumos" )))] |
315 | #[cfg_attr ( |
316 | docsrs, |
317 | doc(cfg(all(unix, not(target_os = "solaris" ), not(target_os = "illumos" )))) |
318 | )] |
319 | pub fn reuseport(&self) -> io::Result<bool> { |
320 | self.inner.reuse_port() |
321 | } |
322 | |
323 | /// Sets the size of the TCP send buffer on this socket. |
324 | /// |
325 | /// On most operating systems, this sets the `SO_SNDBUF` socket option. |
326 | pub fn set_send_buffer_size(&self, size: u32) -> io::Result<()> { |
327 | self.inner.set_send_buffer_size(size as usize) |
328 | } |
329 | |
330 | /// Returns the size of the TCP send buffer for this socket. |
331 | /// |
332 | /// On most operating systems, this is the value of the `SO_SNDBUF` socket |
333 | /// option. |
334 | /// |
335 | /// Note that if [`set_send_buffer_size`] has been called on this socket |
336 | /// previously, the value returned by this function may not be the same as |
337 | /// the argument provided to `set_send_buffer_size`. This is for the |
338 | /// following reasons: |
339 | /// |
340 | /// * Most operating systems have minimum and maximum allowed sizes for the |
341 | /// send buffer, and will clamp the provided value if it is below the |
342 | /// minimum or above the maximum. The minimum and maximum buffer sizes are |
343 | /// OS-dependent. |
344 | /// * Linux will double the buffer size to account for internal bookkeeping |
345 | /// data, and returns the doubled value from `getsockopt(2)`. As per `man |
346 | /// 7 socket`: |
347 | /// > Sets or gets the maximum socket send buffer in bytes. The |
348 | /// > kernel doubles this value (to allow space for bookkeeping |
349 | /// > overhead) when it is set using `setsockopt(2)`, and this doubled |
350 | /// > value is returned by `getsockopt(2)`. |
351 | /// |
352 | /// [`set_send_buffer_size`]: #method.set_send_buffer_size |
353 | pub fn send_buffer_size(&self) -> io::Result<u32> { |
354 | self.inner.send_buffer_size().map(|n| n as u32) |
355 | } |
356 | |
357 | /// Sets the size of the TCP receive buffer on this socket. |
358 | /// |
359 | /// On most operating systems, this sets the `SO_RCVBUF` socket option. |
360 | pub fn set_recv_buffer_size(&self, size: u32) -> io::Result<()> { |
361 | self.inner.set_recv_buffer_size(size as usize) |
362 | } |
363 | |
364 | /// Returns the size of the TCP receive buffer for this socket. |
365 | /// |
366 | /// On most operating systems, this is the value of the `SO_RCVBUF` socket |
367 | /// option. |
368 | /// |
369 | /// Note that if [`set_recv_buffer_size`] has been called on this socket |
370 | /// previously, the value returned by this function may not be the same as |
371 | /// the argument provided to `set_send_buffer_size`. This is for the |
372 | /// following reasons: |
373 | /// |
374 | /// * Most operating systems have minimum and maximum allowed sizes for the |
375 | /// receive buffer, and will clamp the provided value if it is below the |
376 | /// minimum or above the maximum. The minimum and maximum buffer sizes are |
377 | /// OS-dependent. |
378 | /// * Linux will double the buffer size to account for internal bookkeeping |
379 | /// data, and returns the doubled value from `getsockopt(2)`. As per `man |
380 | /// 7 socket`: |
381 | /// > Sets or gets the maximum socket send buffer in bytes. The |
382 | /// > kernel doubles this value (to allow space for bookkeeping |
383 | /// > overhead) when it is set using `setsockopt(2)`, and this doubled |
384 | /// > value is returned by `getsockopt(2)`. |
385 | /// |
386 | /// [`set_recv_buffer_size`]: #method.set_recv_buffer_size |
387 | pub fn recv_buffer_size(&self) -> io::Result<u32> { |
388 | self.inner.recv_buffer_size().map(|n| n as u32) |
389 | } |
390 | |
391 | /// Sets the linger duration of this socket by setting the `SO_LINGER` option. |
392 | /// |
393 | /// This option controls the action taken when a stream has unsent messages and the stream is |
394 | /// closed. If `SO_LINGER` is set, the system shall block the process until it can transmit the |
395 | /// data or until the time expires. |
396 | /// |
397 | /// If `SO_LINGER` is not specified, and the socket is closed, the system handles the call in a |
398 | /// way that allows the process to continue as quickly as possible. |
399 | pub fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> { |
400 | self.inner.set_linger(dur) |
401 | } |
402 | |
403 | /// Reads the linger duration for this socket by getting the `SO_LINGER` |
404 | /// option. |
405 | /// |
406 | /// For more information about this option, see [`set_linger`]. |
407 | /// |
408 | /// [`set_linger`]: TcpSocket::set_linger |
409 | pub fn linger(&self) -> io::Result<Option<Duration>> { |
410 | self.inner.linger() |
411 | } |
412 | |
413 | /// Sets the value of the `TCP_NODELAY` option on this socket. |
414 | /// |
415 | /// If set, this option disables the Nagle algorithm. This means that segments are always |
416 | /// sent as soon as possible, even if there is only a small amount of data. When not set, |
417 | /// data is buffered until there is a sufficient amount to send out, thereby avoiding |
418 | /// the frequent sending of small packets. |
419 | /// |
420 | /// # Examples |
421 | /// |
422 | /// ```no_run |
423 | /// use tokio::net::TcpSocket; |
424 | /// |
425 | /// # async fn dox() -> Result<(), Box<dyn std::error::Error>> { |
426 | /// let socket = TcpSocket::new_v4()?; |
427 | /// |
428 | /// println!("{:?}" , socket.nodelay()?); |
429 | /// # Ok(()) |
430 | /// # } |
431 | /// ``` |
432 | pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { |
433 | self.inner.set_nodelay(nodelay) |
434 | } |
435 | |
436 | /// Gets the value of the `TCP_NODELAY` option on this socket. |
437 | /// |
438 | /// For more information about this option, see [`set_nodelay`]. |
439 | /// |
440 | /// [`set_nodelay`]: TcpSocket::set_nodelay |
441 | /// |
442 | /// # Examples |
443 | /// |
444 | /// ```no_run |
445 | /// use tokio::net::TcpSocket; |
446 | /// |
447 | /// # async fn dox() -> Result<(), Box<dyn std::error::Error>> { |
448 | /// let stream = TcpSocket::new_v4()?; |
449 | /// |
450 | /// stream.set_nodelay(true)?; |
451 | /// # Ok(()) |
452 | /// # } |
453 | /// ``` |
454 | pub fn nodelay(&self) -> io::Result<bool> { |
455 | self.inner.nodelay() |
456 | } |
457 | |
458 | /// Gets the value of the `IP_TOS` option for this socket. |
459 | /// |
460 | /// For more information about this option, see [`set_tos`]. |
461 | /// |
462 | /// **NOTE:** On Windows, `IP_TOS` is only supported on [Windows 8+ or |
463 | /// Windows Server 2012+.](https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options) |
464 | /// |
465 | /// [`set_tos`]: Self::set_tos |
466 | // https://docs.rs/socket2/0.5.3/src/socket2/socket.rs.html#1464 |
467 | #[cfg (not(any( |
468 | target_os = "fuchsia" , |
469 | target_os = "redox" , |
470 | target_os = "solaris" , |
471 | target_os = "illumos" , |
472 | )))] |
473 | #[cfg_attr ( |
474 | docsrs, |
475 | doc(cfg(not(any( |
476 | target_os = "fuchsia" , |
477 | target_os = "redox" , |
478 | target_os = "solaris" , |
479 | target_os = "illumos" , |
480 | )))) |
481 | )] |
482 | pub fn tos(&self) -> io::Result<u32> { |
483 | self.inner.tos() |
484 | } |
485 | |
486 | /// Sets the value for the `IP_TOS` option on this socket. |
487 | /// |
488 | /// This value sets the type-of-service field that is used in every packet |
489 | /// sent from this socket. |
490 | /// |
491 | /// **NOTE:** On Windows, `IP_TOS` is only supported on [Windows 8+ or |
492 | /// Windows Server 2012+.](https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options) |
493 | // https://docs.rs/socket2/0.5.3/src/socket2/socket.rs.html#1446 |
494 | #[cfg (not(any( |
495 | target_os = "fuchsia" , |
496 | target_os = "redox" , |
497 | target_os = "solaris" , |
498 | target_os = "illumos" , |
499 | )))] |
500 | #[cfg_attr ( |
501 | docsrs, |
502 | doc(cfg(not(any( |
503 | target_os = "fuchsia" , |
504 | target_os = "redox" , |
505 | target_os = "solaris" , |
506 | target_os = "illumos" , |
507 | )))) |
508 | )] |
509 | pub fn set_tos(&self, tos: u32) -> io::Result<()> { |
510 | self.inner.set_tos(tos) |
511 | } |
512 | |
513 | /// Gets the value for the `SO_BINDTODEVICE` option on this socket |
514 | /// |
515 | /// This value gets the socket binded device's interface name. |
516 | #[cfg (any(target_os = "android" , target_os = "fuchsia" , target_os = "linux" ,))] |
517 | #[cfg_attr ( |
518 | docsrs, |
519 | doc(cfg(any(target_os = "android" , target_os = "fuchsia" , target_os = "linux" ,))) |
520 | )] |
521 | pub fn device(&self) -> io::Result<Option<Vec<u8>>> { |
522 | self.inner.device() |
523 | } |
524 | |
525 | /// Sets the value for the `SO_BINDTODEVICE` option on this socket |
526 | /// |
527 | /// If a socket is bound to an interface, only packets received from that |
528 | /// particular interface are processed by the socket. Note that this only |
529 | /// works for some socket types, particularly `AF_INET` sockets. |
530 | /// |
531 | /// If `interface` is `None` or an empty string it removes the binding. |
532 | #[cfg (any(target_os = "android" , target_os = "fuchsia" , target_os = "linux" ))] |
533 | #[cfg_attr ( |
534 | docsrs, |
535 | doc(cfg(all(any(target_os = "android" , target_os = "fuchsia" , target_os = "linux" )))) |
536 | )] |
537 | pub fn bind_device(&self, interface: Option<&[u8]>) -> io::Result<()> { |
538 | self.inner.bind_device(interface) |
539 | } |
540 | |
541 | /// Gets the local address of this socket. |
542 | /// |
543 | /// Will fail on windows if called before `bind`. |
544 | /// |
545 | /// # Examples |
546 | /// |
547 | /// ```no_run |
548 | /// use tokio::net::TcpSocket; |
549 | /// |
550 | /// use std::io; |
551 | /// |
552 | /// #[tokio::main] |
553 | /// async fn main() -> io::Result<()> { |
554 | /// let addr = "127.0.0.1:8080" .parse().unwrap(); |
555 | /// |
556 | /// let socket = TcpSocket::new_v4()?; |
557 | /// socket.bind(addr)?; |
558 | /// assert_eq!(socket.local_addr().unwrap().to_string(), "127.0.0.1:8080" ); |
559 | /// let listener = socket.listen(1024)?; |
560 | /// Ok(()) |
561 | /// } |
562 | /// ``` |
563 | pub fn local_addr(&self) -> io::Result<SocketAddr> { |
564 | self.inner.local_addr().and_then(convert_address) |
565 | } |
566 | |
567 | /// Returns the value of the `SO_ERROR` option. |
568 | pub fn take_error(&self) -> io::Result<Option<io::Error>> { |
569 | self.inner.take_error() |
570 | } |
571 | |
572 | /// Binds the socket to the given address. |
573 | /// |
574 | /// This calls the `bind(2)` operating-system function. Behavior is |
575 | /// platform specific. Refer to the target platform's documentation for more |
576 | /// details. |
577 | /// |
578 | /// # Examples |
579 | /// |
580 | /// Bind a socket before listening. |
581 | /// |
582 | /// ```no_run |
583 | /// use tokio::net::TcpSocket; |
584 | /// |
585 | /// use std::io; |
586 | /// |
587 | /// #[tokio::main] |
588 | /// async fn main() -> io::Result<()> { |
589 | /// let addr = "127.0.0.1:8080" .parse().unwrap(); |
590 | /// |
591 | /// let socket = TcpSocket::new_v4()?; |
592 | /// socket.bind(addr)?; |
593 | /// |
594 | /// let listener = socket.listen(1024)?; |
595 | /// # drop(listener); |
596 | /// |
597 | /// Ok(()) |
598 | /// } |
599 | /// ``` |
600 | pub fn bind(&self, addr: SocketAddr) -> io::Result<()> { |
601 | self.inner.bind(&addr.into()) |
602 | } |
603 | |
604 | /// Establishes a TCP connection with a peer at the specified socket address. |
605 | /// |
606 | /// The `TcpSocket` is consumed. Once the connection is established, a |
607 | /// connected [`TcpStream`] is returned. If the connection fails, the |
608 | /// encountered error is returned. |
609 | /// |
610 | /// [`TcpStream`]: TcpStream |
611 | /// |
612 | /// This calls the `connect(2)` operating-system function. Behavior is |
613 | /// platform specific. Refer to the target platform's documentation for more |
614 | /// details. |
615 | /// |
616 | /// # Examples |
617 | /// |
618 | /// Connecting to a peer. |
619 | /// |
620 | /// ```no_run |
621 | /// use tokio::net::TcpSocket; |
622 | /// |
623 | /// use std::io; |
624 | /// |
625 | /// #[tokio::main] |
626 | /// async fn main() -> io::Result<()> { |
627 | /// let addr = "127.0.0.1:8080" .parse().unwrap(); |
628 | /// |
629 | /// let socket = TcpSocket::new_v4()?; |
630 | /// let stream = socket.connect(addr).await?; |
631 | /// # drop(stream); |
632 | /// |
633 | /// Ok(()) |
634 | /// } |
635 | /// ``` |
636 | pub async fn connect(self, addr: SocketAddr) -> io::Result<TcpStream> { |
637 | if let Err(err) = self.inner.connect(&addr.into()) { |
638 | #[cfg (unix)] |
639 | if err.raw_os_error() != Some(libc::EINPROGRESS) { |
640 | return Err(err); |
641 | } |
642 | #[cfg (windows)] |
643 | if err.kind() != io::ErrorKind::WouldBlock { |
644 | return Err(err); |
645 | } |
646 | } |
647 | #[cfg (unix)] |
648 | let mio = { |
649 | use std::os::unix::io::{FromRawFd, IntoRawFd}; |
650 | |
651 | let raw_fd = self.inner.into_raw_fd(); |
652 | unsafe { mio::net::TcpStream::from_raw_fd(raw_fd) } |
653 | }; |
654 | |
655 | #[cfg (windows)] |
656 | let mio = { |
657 | use std::os::windows::io::{FromRawSocket, IntoRawSocket}; |
658 | |
659 | let raw_socket = self.inner.into_raw_socket(); |
660 | unsafe { mio::net::TcpStream::from_raw_socket(raw_socket) } |
661 | }; |
662 | |
663 | TcpStream::connect_mio(mio).await |
664 | } |
665 | |
666 | /// Converts the socket into a `TcpListener`. |
667 | /// |
668 | /// `backlog` defines the maximum number of pending connections are queued |
669 | /// by the operating system at any given time. Connection are removed from |
670 | /// the queue with [`TcpListener::accept`]. When the queue is full, the |
671 | /// operating-system will start rejecting connections. |
672 | /// |
673 | /// [`TcpListener::accept`]: TcpListener::accept |
674 | /// |
675 | /// This calls the `listen(2)` operating-system function, marking the socket |
676 | /// as a passive socket. Behavior is platform specific. Refer to the target |
677 | /// platform's documentation for more details. |
678 | /// |
679 | /// # Examples |
680 | /// |
681 | /// Create a `TcpListener`. |
682 | /// |
683 | /// ```no_run |
684 | /// use tokio::net::TcpSocket; |
685 | /// |
686 | /// use std::io; |
687 | /// |
688 | /// #[tokio::main] |
689 | /// async fn main() -> io::Result<()> { |
690 | /// let addr = "127.0.0.1:8080" .parse().unwrap(); |
691 | /// |
692 | /// let socket = TcpSocket::new_v4()?; |
693 | /// socket.bind(addr)?; |
694 | /// |
695 | /// let listener = socket.listen(1024)?; |
696 | /// # drop(listener); |
697 | /// |
698 | /// Ok(()) |
699 | /// } |
700 | /// ``` |
701 | pub fn listen(self, backlog: u32) -> io::Result<TcpListener> { |
702 | self.inner.listen(backlog as i32)?; |
703 | #[cfg (unix)] |
704 | let mio = { |
705 | use std::os::unix::io::{FromRawFd, IntoRawFd}; |
706 | |
707 | let raw_fd = self.inner.into_raw_fd(); |
708 | unsafe { mio::net::TcpListener::from_raw_fd(raw_fd) } |
709 | }; |
710 | |
711 | #[cfg (windows)] |
712 | let mio = { |
713 | use std::os::windows::io::{FromRawSocket, IntoRawSocket}; |
714 | |
715 | let raw_socket = self.inner.into_raw_socket(); |
716 | unsafe { mio::net::TcpListener::from_raw_socket(raw_socket) } |
717 | }; |
718 | |
719 | TcpListener::new(mio) |
720 | } |
721 | |
722 | /// Converts a [`std::net::TcpStream`] into a `TcpSocket`. The provided |
723 | /// socket must not have been connected prior to calling this function. This |
724 | /// function is typically used together with crates such as [`socket2`] to |
725 | /// configure socket options that are not available on `TcpSocket`. |
726 | /// |
727 | /// [`std::net::TcpStream`]: struct@std::net::TcpStream |
728 | /// [`socket2`]: https://docs.rs/socket2/ |
729 | /// |
730 | /// # Notes |
731 | /// |
732 | /// The caller is responsible for ensuring that the socket is in |
733 | /// non-blocking mode. Otherwise all I/O operations on the socket |
734 | /// will block the thread, which will cause unexpected behavior. |
735 | /// Non-blocking mode can be set using [`set_nonblocking`]. |
736 | /// |
737 | /// [`set_nonblocking`]: std::net::TcpStream::set_nonblocking |
738 | /// |
739 | /// # Examples |
740 | /// |
741 | /// ``` |
742 | /// use tokio::net::TcpSocket; |
743 | /// use socket2::{Domain, Socket, Type}; |
744 | /// |
745 | /// #[tokio::main] |
746 | /// async fn main() -> std::io::Result<()> { |
747 | /// let socket2_socket = Socket::new(Domain::IPV4, Type::STREAM, None)?; |
748 | /// socket2_socket.set_nonblocking(true)?; |
749 | /// |
750 | /// let socket = TcpSocket::from_std_stream(socket2_socket.into()); |
751 | /// |
752 | /// Ok(()) |
753 | /// } |
754 | /// ``` |
755 | pub fn from_std_stream(std_stream: std::net::TcpStream) -> TcpSocket { |
756 | #[cfg (unix)] |
757 | { |
758 | use std::os::unix::io::{FromRawFd, IntoRawFd}; |
759 | |
760 | let raw_fd = std_stream.into_raw_fd(); |
761 | unsafe { TcpSocket::from_raw_fd(raw_fd) } |
762 | } |
763 | |
764 | #[cfg (windows)] |
765 | { |
766 | use std::os::windows::io::{FromRawSocket, IntoRawSocket}; |
767 | |
768 | let raw_socket = std_stream.into_raw_socket(); |
769 | unsafe { TcpSocket::from_raw_socket(raw_socket) } |
770 | } |
771 | } |
772 | } |
773 | |
774 | fn convert_address(address: socket2::SockAddr) -> io::Result<SocketAddr> { |
775 | match address.as_socket() { |
776 | Some(address: SocketAddr) => Ok(address), |
777 | None => Err(io::Error::new( |
778 | kind:io::ErrorKind::InvalidInput, |
779 | error:"invalid address family (not IPv4 or IPv6)" , |
780 | )), |
781 | } |
782 | } |
783 | |
784 | impl fmt::Debug for TcpSocket { |
785 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
786 | self.inner.fmt(fmt) |
787 | } |
788 | } |
789 | |
790 | cfg_unix! { |
791 | impl AsRawFd for TcpSocket { |
792 | fn as_raw_fd(&self) -> RawFd { |
793 | self.inner.as_raw_fd() |
794 | } |
795 | } |
796 | |
797 | impl AsFd for TcpSocket { |
798 | fn as_fd(&self) -> BorrowedFd<'_> { |
799 | unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) } |
800 | } |
801 | } |
802 | |
803 | impl FromRawFd for TcpSocket { |
804 | /// Converts a `RawFd` to a `TcpSocket`. |
805 | /// |
806 | /// # Notes |
807 | /// |
808 | /// The caller is responsible for ensuring that the socket is in |
809 | /// non-blocking mode. |
810 | unsafe fn from_raw_fd(fd: RawFd) -> TcpSocket { |
811 | let inner = socket2::Socket::from_raw_fd(fd); |
812 | TcpSocket { inner } |
813 | } |
814 | } |
815 | |
816 | impl IntoRawFd for TcpSocket { |
817 | fn into_raw_fd(self) -> RawFd { |
818 | self.inner.into_raw_fd() |
819 | } |
820 | } |
821 | } |
822 | |
823 | cfg_windows! { |
824 | impl IntoRawSocket for TcpSocket { |
825 | fn into_raw_socket(self) -> RawSocket { |
826 | self.inner.into_raw_socket() |
827 | } |
828 | } |
829 | |
830 | impl AsRawSocket for TcpSocket { |
831 | fn as_raw_socket(&self) -> RawSocket { |
832 | self.inner.as_raw_socket() |
833 | } |
834 | } |
835 | |
836 | impl AsSocket for TcpSocket { |
837 | fn as_socket(&self) -> BorrowedSocket<'_> { |
838 | unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) } |
839 | } |
840 | } |
841 | |
842 | impl FromRawSocket for TcpSocket { |
843 | /// Converts a `RawSocket` to a `TcpStream`. |
844 | /// |
845 | /// # Notes |
846 | /// |
847 | /// The caller is responsible for ensuring that the socket is in |
848 | /// non-blocking mode. |
849 | unsafe fn from_raw_socket(socket: RawSocket) -> TcpSocket { |
850 | let inner = socket2::Socket::from_raw_socket(socket); |
851 | TcpSocket { inner } |
852 | } |
853 | } |
854 | } |
855 | |