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