Skip to content

Commit

Permalink
tcp: Add source address option
Browse files Browse the repository at this point in the history
This option allows to specify the source address and port for outgoing
TCP connections.

Signed-off-by: Konrad Gräfe <[email protected]>
  • Loading branch information
kgraefe committed May 3, 2023
1 parent 73b71a1 commit 6cd8a6d
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 3 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ version = "0.26.2"
default-features = false
features = ["socket", "uio", "net"]

[target.'cfg(target_os = "linux")'.dependencies.libc]
[target.'cfg(unix)'.dependencies.libc]
version = "0.2.137"
default-features = false

Expand Down
34 changes: 32 additions & 2 deletions src/adapters/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::network::{RemoteAddr, Readiness, TransportConnect, TransportListen};
use mio::net::{TcpListener, TcpStream};
use mio::event::{Source};

use socket2::{Socket};
use socket2::{Socket, Domain, Type, Protocol};

use std::net::{SocketAddr};
use std::io::{self, ErrorKind, Read, Write};
Expand All @@ -27,6 +27,7 @@ pub const INPUT_BUFFER_SIZE: usize = u16::MAX as usize; // 2^16 - 1

#[derive(Clone, Debug, Default)]
pub struct TcpConnectConfig {
source_address: Option<SocketAddr>,
keepalive: Option<TcpKeepalive>,
}

Expand All @@ -36,6 +37,12 @@ impl TcpConnectConfig {
self.keepalive = Some(keepalive);
self
}

/// Specify the source address and port.
pub fn with_source_address(mut self, source_address: SocketAddr) -> Self {
self.source_address = Some(source_address);
self
}
}

#[derive(Clone, Debug, Default)]
Expand Down Expand Up @@ -78,7 +85,30 @@ impl Remote for RemoteResource {
_ => panic!("Internal error: Got wrong config"),
};
let peer_addr = *remote_addr.socket_addr();
let stream = TcpStream::connect(peer_addr)?;

let socket = Socket::new(
match peer_addr {
SocketAddr::V4 { .. } => Domain::IPV4,
SocketAddr::V6 { .. } => Domain::IPV6,
},
Type::STREAM,
Some(Protocol::TCP),
)?;
socket.set_nonblocking(true)?;

if let Some(source_address) = config.source_address {
socket.bind(&source_address.into())?;
}

match socket.connect(&peer_addr.into()) {
#[cfg(unix)]
Err(e) if e.raw_os_error() != Some(libc::EINPROGRESS) => return Err(e),
#[cfg(windows)]
Err(e) if e.kind() != io::ErrorKind::WouldBlock => return Err(e),
_ => {}
}

let stream = TcpStream::from_std(socket.into());
let local_addr = stream.local_addr()?;
Ok(ConnectionInfo {
remote: Self { stream, keepalive: config.keepalive },
Expand Down

0 comments on commit 6cd8a6d

Please sign in to comment.