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