Skip to main content

librqbit_dualstack_sockets/
connect.rs

1use 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}