Skip to content

Commit

Permalink
bind every outgoing IPv4 (#36)
Browse files Browse the repository at this point in the history
  • Loading branch information
keepsimple1 authored Jun 24, 2022
1 parent cf191aa commit 88aa4d7
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 13 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ default = ["async"]

[dependencies]
flume = { version = "0.10", default-features = false } # channel between threads
if-addrs = "0.7" # get local IP addresses
log = "0.4.14" # logging
polling = "2.1.0" # select/poll sockets
socket2 = { version = "0.4", features = ["all"] } # socket APIs
53 changes: 40 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ use std::{
convert::TryInto,
fmt,
io::Read,
net::{Ipv4Addr, SocketAddrV4},
net::{IpAddr, Ipv4Addr, SocketAddrV4},
str::{self, FromStr},
thread,
time::{Duration, SystemTime},
Expand Down Expand Up @@ -584,7 +584,7 @@ impl ServiceDaemon {

/// Creates a new UDP socket to bind to `port` with REUSEPORT option.
/// `non_block` indicates whether to set O_NONBLOCK for the socket.
fn new_socket(port: u16, non_block: bool) -> Result<Socket> {
fn new_socket(ipv4: Ipv4Addr, port: u16, non_block: bool) -> Result<Socket> {
let fd = Socket::new(socket2::Domain::IPV4, socket2::Type::DGRAM, None)
.map_err(|e| e_fmt!("create socket failed: {}", e))?;

Expand All @@ -599,15 +599,43 @@ fn new_socket(port: u16, non_block: bool) -> Result<Socket> {
.map_err(|e| e_fmt!("set O_NONBLOCK: {}", e))?;
}

let ipv4_any = Ipv4Addr::new(0, 0, 0, 0);
let inet_addr = SocketAddrV4::new(ipv4_any, port);
let inet_addr = SocketAddrV4::new(ipv4, port);
fd.bind(&inet_addr.into())
.map_err(|e| e_fmt!("socket bind failed: {}", e))?;

debug!("new socket bind to {}", &inet_addr);
Ok(fd)
}

/// Returns the list of IPv4 addrs assigned to this host, excluding loopback or multicast addrs.
/// If something goes wrong, returns an empty list and logs an error message.
fn my_ipv4_addrs() -> Vec<Ipv4Addr> {
let mut result = Vec::new();

match if_addrs::get_if_addrs() {
Ok(addr_list) => {
for addr in addr_list {
if addr.is_loopback() {
continue;
}
match addr.ip() {
IpAddr::V4(v4_addr) => {
if v4_addr.is_multicast() {
continue;
}
result.push(v4_addr);
}
IpAddr::V6(_) => {}
}
}
}
Err(e) => error!("get_if_addrs: {}", e),
}
debug!("IPv4 addrs: {:?}", &result);

result
}

fn current_time_millis() -> u64 {
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
Expand All @@ -628,10 +656,8 @@ struct Zeroconf {
/// This socket will not be able to read unicast packets.
listen_socket: Socket,

/// Sockets for outgoing packets.
/// NOTE: For now we only support multicast and this Vec has only one socket.
/// If we support unicast, we will have one respond socket for each
/// valid interface, and read unicast packets from these sockets.
/// Sockets for outgoing packets. One socket for each non-loopback assigned IPv4.
/// NOTE: For now we only support multicast.
respond_sockets: Vec<Socket>,

/// Local registered services
Expand Down Expand Up @@ -659,19 +685,20 @@ struct Zeroconf {
impl Zeroconf {
fn new(udp_port: u16) -> Result<Self> {
let poller = Poller::new().map_err(|e| e_fmt!("create Poller: {}", e))?;
let listen_socket = new_socket(udp_port, true)?;
let listen_socket = new_socket(Ipv4Addr::new(0, 0, 0, 0), udp_port, true)?;
debug!("created listening socket: {:?}", &listen_socket);

let group_addr = Ipv4Addr::new(224, 0, 0, 251);
listen_socket
.join_multicast_v4(&group_addr, &Ipv4Addr::new(0, 0, 0, 0))
.map_err(|e| e_fmt!("join multicast group: {}", e))?;

// We are not setting specific outgoing interface for this socket.
// It will use the default outgoing interface set by the OS.
// We create a socket for every outgoing IPv4 interface.
let mut respond_sockets = Vec::new();
let respond_socket = new_socket(udp_port, false)?;
respond_sockets.push(respond_socket);
for ipv4_addr in my_ipv4_addrs() {
let respond_socket = new_socket(ipv4_addr, udp_port, false)?;
respond_sockets.push(respond_socket);
}

let broadcast_addr = SocketAddrV4::new(group_addr, MDNS_PORT).into();

Expand Down

0 comments on commit 88aa4d7

Please sign in to comment.