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 | /// socket.set_nodelay(true)?; |
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 socket = TcpSocket::new_v4()?; |
449 | /// |
450 | /// println!("{:?}" , socket.nodelay()?); |
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 | target_os = "haiku" |
473 | )))] |
474 | #[cfg_attr ( |
475 | docsrs, |
476 | doc(cfg(not(any( |
477 | target_os = "fuchsia" , |
478 | target_os = "redox" , |
479 | target_os = "solaris" , |
480 | target_os = "illumos" , |
481 | target_os = "haiku" |
482 | )))) |
483 | )] |
484 | pub fn tos(&self) -> io::Result<u32> { |
485 | self.inner.tos() |
486 | } |
487 | |
488 | /// Sets the value for the `IP_TOS` option on this socket. |
489 | /// |
490 | /// This value sets the type-of-service field that is used in every packet |
491 | /// sent from this socket. |
492 | /// |
493 | /// **NOTE:** On Windows, `IP_TOS` is only supported on [Windows 8+ or |
494 | /// Windows Server 2012+.](https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options) |
495 | // https://docs.rs/socket2/0.5.3/src/socket2/socket.rs.html#1446 |
496 | #[cfg (not(any( |
497 | target_os = "fuchsia" , |
498 | target_os = "redox" , |
499 | target_os = "solaris" , |
500 | target_os = "illumos" , |
501 | target_os = "haiku" |
502 | )))] |
503 | #[cfg_attr ( |
504 | docsrs, |
505 | doc(cfg(not(any( |
506 | target_os = "fuchsia" , |
507 | target_os = "redox" , |
508 | target_os = "solaris" , |
509 | target_os = "illumos" , |
510 | target_os = "haiku" |
511 | )))) |
512 | )] |
513 | pub fn set_tos(&self, tos: u32) -> io::Result<()> { |
514 | self.inner.set_tos(tos) |
515 | } |
516 | |
517 | /// Gets the value for the `SO_BINDTODEVICE` option on this socket |
518 | /// |
519 | /// This value gets the socket binded device's interface name. |
520 | #[cfg (any(target_os = "android" , target_os = "fuchsia" , target_os = "linux" ,))] |
521 | #[cfg_attr ( |
522 | docsrs, |
523 | doc(cfg(any(target_os = "android" , target_os = "fuchsia" , target_os = "linux" ,))) |
524 | )] |
525 | pub fn device(&self) -> io::Result<Option<Vec<u8>>> { |
526 | self.inner.device() |
527 | } |
528 | |
529 | /// Sets the value for the `SO_BINDTODEVICE` option on this socket |
530 | /// |
531 | /// If a socket is bound to an interface, only packets received from that |
532 | /// particular interface are processed by the socket. Note that this only |
533 | /// works for some socket types, particularly `AF_INET` sockets. |
534 | /// |
535 | /// If `interface` is `None` or an empty string it removes the binding. |
536 | #[cfg (any(target_os = "android" , target_os = "fuchsia" , target_os = "linux" ))] |
537 | #[cfg_attr ( |
538 | docsrs, |
539 | doc(cfg(all(any(target_os = "android" , target_os = "fuchsia" , target_os = "linux" )))) |
540 | )] |
541 | pub fn bind_device(&self, interface: Option<&[u8]>) -> io::Result<()> { |
542 | self.inner.bind_device(interface) |
543 | } |
544 | |
545 | /// Gets the local address of this socket. |
546 | /// |
547 | /// Will fail on windows if called before `bind`. |
548 | /// |
549 | /// # Examples |
550 | /// |
551 | /// ```no_run |
552 | /// use tokio::net::TcpSocket; |
553 | /// |
554 | /// use std::io; |
555 | /// |
556 | /// #[tokio::main] |
557 | /// async fn main() -> io::Result<()> { |
558 | /// let addr = "127.0.0.1:8080" .parse().unwrap(); |
559 | /// |
560 | /// let socket = TcpSocket::new_v4()?; |
561 | /// socket.bind(addr)?; |
562 | /// assert_eq!(socket.local_addr().unwrap().to_string(), "127.0.0.1:8080" ); |
563 | /// let listener = socket.listen(1024)?; |
564 | /// Ok(()) |
565 | /// } |
566 | /// ``` |
567 | pub fn local_addr(&self) -> io::Result<SocketAddr> { |
568 | self.inner.local_addr().and_then(convert_address) |
569 | } |
570 | |
571 | /// Returns the value of the `SO_ERROR` option. |
572 | pub fn take_error(&self) -> io::Result<Option<io::Error>> { |
573 | self.inner.take_error() |
574 | } |
575 | |
576 | /// Binds the socket to the given address. |
577 | /// |
578 | /// This calls the `bind(2)` operating-system function. Behavior is |
579 | /// platform specific. Refer to the target platform's documentation for more |
580 | /// details. |
581 | /// |
582 | /// # Examples |
583 | /// |
584 | /// Bind a socket before listening. |
585 | /// |
586 | /// ```no_run |
587 | /// use tokio::net::TcpSocket; |
588 | /// |
589 | /// use std::io; |
590 | /// |
591 | /// #[tokio::main] |
592 | /// async fn main() -> io::Result<()> { |
593 | /// let addr = "127.0.0.1:8080" .parse().unwrap(); |
594 | /// |
595 | /// let socket = TcpSocket::new_v4()?; |
596 | /// socket.bind(addr)?; |
597 | /// |
598 | /// let listener = socket.listen(1024)?; |
599 | /// # drop(listener); |
600 | /// |
601 | /// Ok(()) |
602 | /// } |
603 | /// ``` |
604 | pub fn bind(&self, addr: SocketAddr) -> io::Result<()> { |
605 | self.inner.bind(&addr.into()) |
606 | } |
607 | |
608 | /// Establishes a TCP connection with a peer at the specified socket address. |
609 | /// |
610 | /// The `TcpSocket` is consumed. Once the connection is established, a |
611 | /// connected [`TcpStream`] is returned. If the connection fails, the |
612 | /// encountered error is returned. |
613 | /// |
614 | /// [`TcpStream`]: TcpStream |
615 | /// |
616 | /// This calls the `connect(2)` operating-system function. Behavior is |
617 | /// platform specific. Refer to the target platform's documentation for more |
618 | /// details. |
619 | /// |
620 | /// # Examples |
621 | /// |
622 | /// Connecting to a peer. |
623 | /// |
624 | /// ```no_run |
625 | /// use tokio::net::TcpSocket; |
626 | /// |
627 | /// use std::io; |
628 | /// |
629 | /// #[tokio::main] |
630 | /// async fn main() -> io::Result<()> { |
631 | /// let addr = "127.0.0.1:8080" .parse().unwrap(); |
632 | /// |
633 | /// let socket = TcpSocket::new_v4()?; |
634 | /// let stream = socket.connect(addr).await?; |
635 | /// # drop(stream); |
636 | /// |
637 | /// Ok(()) |
638 | /// } |
639 | /// ``` |
640 | pub async fn connect(self, addr: SocketAddr) -> io::Result<TcpStream> { |
641 | if let Err(err) = self.inner.connect(&addr.into()) { |
642 | #[cfg (unix)] |
643 | if err.raw_os_error() != Some(libc::EINPROGRESS) { |
644 | return Err(err); |
645 | } |
646 | #[cfg (windows)] |
647 | if err.kind() != io::ErrorKind::WouldBlock { |
648 | return Err(err); |
649 | } |
650 | } |
651 | #[cfg (unix)] |
652 | let mio = { |
653 | use std::os::unix::io::{FromRawFd, IntoRawFd}; |
654 | |
655 | let raw_fd = self.inner.into_raw_fd(); |
656 | unsafe { mio::net::TcpStream::from_raw_fd(raw_fd) } |
657 | }; |
658 | |
659 | #[cfg (windows)] |
660 | let mio = { |
661 | use std::os::windows::io::{FromRawSocket, IntoRawSocket}; |
662 | |
663 | let raw_socket = self.inner.into_raw_socket(); |
664 | unsafe { mio::net::TcpStream::from_raw_socket(raw_socket) } |
665 | }; |
666 | |
667 | TcpStream::connect_mio(mio).await |
668 | } |
669 | |
670 | /// Converts the socket into a `TcpListener`. |
671 | /// |
672 | /// `backlog` defines the maximum number of pending connections are queued |
673 | /// by the operating system at any given time. Connection are removed from |
674 | /// the queue with [`TcpListener::accept`]. When the queue is full, the |
675 | /// operating-system will start rejecting connections. |
676 | /// |
677 | /// [`TcpListener::accept`]: TcpListener::accept |
678 | /// |
679 | /// This calls the `listen(2)` operating-system function, marking the socket |
680 | /// as a passive socket. Behavior is platform specific. Refer to the target |
681 | /// platform's documentation for more details. |
682 | /// |
683 | /// # Examples |
684 | /// |
685 | /// Create a `TcpListener`. |
686 | /// |
687 | /// ```no_run |
688 | /// use tokio::net::TcpSocket; |
689 | /// |
690 | /// use std::io; |
691 | /// |
692 | /// #[tokio::main] |
693 | /// async fn main() -> io::Result<()> { |
694 | /// let addr = "127.0.0.1:8080" .parse().unwrap(); |
695 | /// |
696 | /// let socket = TcpSocket::new_v4()?; |
697 | /// socket.bind(addr)?; |
698 | /// |
699 | /// let listener = socket.listen(1024)?; |
700 | /// # drop(listener); |
701 | /// |
702 | /// Ok(()) |
703 | /// } |
704 | /// ``` |
705 | pub fn listen(self, backlog: u32) -> io::Result<TcpListener> { |
706 | self.inner.listen(backlog as i32)?; |
707 | #[cfg (unix)] |
708 | let mio = { |
709 | use std::os::unix::io::{FromRawFd, IntoRawFd}; |
710 | |
711 | let raw_fd = self.inner.into_raw_fd(); |
712 | unsafe { mio::net::TcpListener::from_raw_fd(raw_fd) } |
713 | }; |
714 | |
715 | #[cfg (windows)] |
716 | let mio = { |
717 | use std::os::windows::io::{FromRawSocket, IntoRawSocket}; |
718 | |
719 | let raw_socket = self.inner.into_raw_socket(); |
720 | unsafe { mio::net::TcpListener::from_raw_socket(raw_socket) } |
721 | }; |
722 | |
723 | TcpListener::new(mio) |
724 | } |
725 | |
726 | /// Converts a [`std::net::TcpStream`] into a `TcpSocket`. The provided |
727 | /// socket must not have been connected prior to calling this function. This |
728 | /// function is typically used together with crates such as [`socket2`] to |
729 | /// configure socket options that are not available on `TcpSocket`. |
730 | /// |
731 | /// [`std::net::TcpStream`]: struct@std::net::TcpStream |
732 | /// [`socket2`]: https://docs.rs/socket2/ |
733 | /// |
734 | /// # Notes |
735 | /// |
736 | /// The caller is responsible for ensuring that the socket is in |
737 | /// non-blocking mode. Otherwise all I/O operations on the socket |
738 | /// will block the thread, which will cause unexpected behavior. |
739 | /// Non-blocking mode can be set using [`set_nonblocking`]. |
740 | /// |
741 | /// [`set_nonblocking`]: std::net::TcpStream::set_nonblocking |
742 | /// |
743 | /// # Examples |
744 | /// |
745 | /// ``` |
746 | /// # if cfg!(miri) { return } // No `socket` in miri. |
747 | /// use tokio::net::TcpSocket; |
748 | /// use socket2::{Domain, Socket, Type}; |
749 | /// |
750 | /// #[tokio::main] |
751 | /// async fn main() -> std::io::Result<()> { |
752 | /// let socket2_socket = Socket::new(Domain::IPV4, Type::STREAM, None)?; |
753 | /// socket2_socket.set_nonblocking(true)?; |
754 | /// |
755 | /// let socket = TcpSocket::from_std_stream(socket2_socket.into()); |
756 | /// |
757 | /// Ok(()) |
758 | /// } |
759 | /// ``` |
760 | pub fn from_std_stream(std_stream: std::net::TcpStream) -> TcpSocket { |
761 | #[cfg (unix)] |
762 | { |
763 | use std::os::unix::io::{FromRawFd, IntoRawFd}; |
764 | |
765 | let raw_fd = std_stream.into_raw_fd(); |
766 | unsafe { TcpSocket::from_raw_fd(raw_fd) } |
767 | } |
768 | |
769 | #[cfg (windows)] |
770 | { |
771 | use std::os::windows::io::{FromRawSocket, IntoRawSocket}; |
772 | |
773 | let raw_socket = std_stream.into_raw_socket(); |
774 | unsafe { TcpSocket::from_raw_socket(raw_socket) } |
775 | } |
776 | } |
777 | } |
778 | |
779 | fn convert_address(address: socket2::SockAddr) -> io::Result<SocketAddr> { |
780 | match address.as_socket() { |
781 | Some(address: SocketAddr) => Ok(address), |
782 | None => Err(io::Error::new( |
783 | kind:io::ErrorKind::InvalidInput, |
784 | error:"invalid address family (not IPv4 or IPv6)" , |
785 | )), |
786 | } |
787 | } |
788 | |
789 | impl fmt::Debug for TcpSocket { |
790 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
791 | self.inner.fmt(fmt) |
792 | } |
793 | } |
794 | |
795 | // These trait implementations can't be build on Windows, so we completely |
796 | // ignore them, even when building documentation. |
797 | #[cfg (unix)] |
798 | cfg_unix! { |
799 | impl AsRawFd for TcpSocket { |
800 | fn as_raw_fd(&self) -> RawFd { |
801 | self.inner.as_raw_fd() |
802 | } |
803 | } |
804 | |
805 | impl AsFd for TcpSocket { |
806 | fn as_fd(&self) -> BorrowedFd<'_> { |
807 | unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) } |
808 | } |
809 | } |
810 | |
811 | impl FromRawFd for TcpSocket { |
812 | /// Converts a `RawFd` to a `TcpSocket`. |
813 | /// |
814 | /// # Notes |
815 | /// |
816 | /// The caller is responsible for ensuring that the socket is in |
817 | /// non-blocking mode. |
818 | unsafe fn from_raw_fd(fd: RawFd) -> TcpSocket { |
819 | let inner = socket2::Socket::from_raw_fd(fd); |
820 | TcpSocket { inner } |
821 | } |
822 | } |
823 | |
824 | impl IntoRawFd for TcpSocket { |
825 | fn into_raw_fd(self) -> RawFd { |
826 | self.inner.into_raw_fd() |
827 | } |
828 | } |
829 | } |
830 | |
831 | cfg_windows! { |
832 | impl IntoRawSocket for TcpSocket { |
833 | fn into_raw_socket(self) -> RawSocket { |
834 | self.inner.into_raw_socket() |
835 | } |
836 | } |
837 | |
838 | impl AsRawSocket for TcpSocket { |
839 | fn as_raw_socket(&self) -> RawSocket { |
840 | self.inner.as_raw_socket() |
841 | } |
842 | } |
843 | |
844 | impl AsSocket for TcpSocket { |
845 | fn as_socket(&self) -> BorrowedSocket<'_> { |
846 | unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) } |
847 | } |
848 | } |
849 | |
850 | impl FromRawSocket for TcpSocket { |
851 | /// Converts a `RawSocket` to a `TcpStream`. |
852 | /// |
853 | /// # Notes |
854 | /// |
855 | /// The caller is responsible for ensuring that the socket is in |
856 | /// non-blocking mode. |
857 | unsafe fn from_raw_socket(socket: RawSocket) -> TcpSocket { |
858 | let inner = socket2::Socket::from_raw_socket(socket); |
859 | TcpSocket { inner } |
860 | } |
861 | } |
862 | } |
863 | |