librqbit_dualstack_sockets/
connect.rs1use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};
2
3use socket2::SockRef;
4
5use crate::{Error, bind_device::BindDevice};
6
7#[derive(Clone, Copy, Debug, Default)]
8pub struct ConnectOpts<'a> {
9 pub source_port: Option<u16>,
10 pub bind_device: Option<&'a BindDevice>,
11}
12
13pub async fn tcp_connect<'a>(
14 addr: SocketAddr,
15 opts: ConnectOpts<'a>,
16) -> crate::Result<tokio::net::TcpStream> {
17 let (sock, bind_addr) = if addr.is_ipv6() {
18 (
19 tokio::net::TcpSocket::new_v6().map_err(Error::SocketNew)?,
20 SocketAddr::from((Ipv6Addr::UNSPECIFIED, opts.source_port.unwrap_or(0))),
21 )
22 } else {
23 (
24 tokio::net::TcpSocket::new_v4().map_err(Error::SocketNew)?,
25 SocketAddr::from((Ipv4Addr::UNSPECIFIED, opts.source_port.unwrap_or(0))),
26 )
27 };
28 let sref = SockRef::from(&sock);
29
30 if let Some(bd) = opts.bind_device {
31 bd.bind_sref(&sref, addr.is_ipv6())?;
32 }
33
34 if bind_addr.port() > 0 {
35 #[cfg(not(windows))]
36 sref.set_reuse_port(true).map_err(Error::ReusePort)?;
37 sref.set_reuse_address(true).map_err(Error::ReuseAddress)?;
38 sref.bind(&bind_addr.into()).map_err(Error::Bind)?;
39 }
40
41 sock.connect(addr).await.map_err(Error::Connect)
42}