Skip to content

Commit

Permalink
Check interface addr matches in test
Browse files Browse the repository at this point in the history
  • Loading branch information
WilliamVenner committed Sep 26, 2023
1 parent 3986d2d commit cc0cca2
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 50 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Add Searchlight to your [`Cargo.toml`](https://doc.rust-lang.org/cargo/reference

```toml
[dependencies]
searchlight = "0.3.1"
searchlight = "0.3.2"
```

To learn more about how to use Searchlight, see the [documentation](https://docs.rs/searchlight/).
Expand Down
148 changes: 99 additions & 49 deletions tests/client_and_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ use searchlight::{
};
use std::{
collections::BTreeSet,
net::{IpAddr, Ipv4Addr, Ipv6Addr},
net::{IpAddr, SocketAddr, UdpSocket},
num::NonZeroU32,
str::FromStr,
sync::{Arc, Mutex},
time::Duration,
};
Expand All @@ -19,47 +18,80 @@ fn client_and_server() {
let (test_tx, test_rx) = std::sync::mpsc::sync_channel(0);

std::thread::spawn(move || {
let (tx, rx) = std::sync::mpsc::sync_channel(0);
for (ip_version_name, ip_version) in [("IPv6", IpVersion::V6), ("IPv4", IpVersion::V4)] {
let interface_addr = match ip_version {
IpVersion::V4 => UdpSocket::bind("0.0.0.0:0").and_then(|socket| {
socket.connect("1.1.1.1:53")?;
socket.local_addr()
}),
IpVersion::V6 => UdpSocket::bind("[::]:0").and_then(|socket| {
socket.connect("[2606:4700:4700::1111]:53")?;
socket.local_addr()
}),
_ => unreachable!(),
};

let interface_addr = match interface_addr {
Ok(addr) => {
println!("Testing on interface {}", addr.ip());
addr
}
Err(err) => {
println!("Skipping {ip_version_name} test: {err:?}");
continue;
}
};

let service = ServiceBuilder::new("_searchlight-test._udp.local", "searchlighttest", 1337)
.unwrap()
.add_txt("key=value")
.add_txt_truncated("key2=value2");

println!("Starting server");
let mut server = BroadcasterBuilder::new().loopback();

let server = Arc::new(Mutex::new(Some(
BroadcasterBuilder::new()
let mut client = DiscoveryBuilder::new()
.service("_searchlight-test._udp.local")
.unwrap()
.loopback()
.interface_v4(TargetInterface::Specific(Ipv4Addr::LOCALHOST))
.interface_v6(TargetInterface::Specific(Ipv6Interface::from_raw(NonZeroU32::new(1).unwrap())))
.add_service(
ServiceBuilder::new("_searchlight-test._udp.local", "searchlighttest", 1337)
.unwrap()
.add_ip_address(IpAddr::V4(Ipv4Addr::from_str("192.168.1.69").unwrap()))
.add_ip_address(IpAddr::V6(Ipv6Addr::from_str("fe80::18e4:b943:8756:d855").unwrap()))
.add_txt("key=value")
.add_txt_truncated("key2=value2")
.build()
.interval(Duration::from_secs(1));

(server, client) = match ip_version {
IpVersion::V4 => {
let target = TargetInterface::Specific(match interface_addr.ip() {
IpAddr::V4(v4) => v4,
_ => unreachable!(),
});
(server.interface_v4(target.clone()), client.interface_v4(target))
}

IpVersion::V6 => {
let target = TargetInterface::Specific(
Ipv6Interface::from_addr(&match interface_addr.ip() {
IpAddr::V6(v6) => v6,
_ => unreachable!(),
})
.unwrap(),
)
.build(IpVersion::Both)
.expect("Failed to create mDNS broadcaster")
.run_in_background(),
)));

println!("Server is running");

println!("Starting client");

let server_ref = server.clone();
let client = DiscoveryBuilder::new()
.service("_searchlight-test._udp.local")
.unwrap()
.loopback()
.interface_v4(TargetInterface::Specific(Ipv4Addr::LOCALHOST))
.interface_v6(TargetInterface::Specific(Ipv6Interface::from_raw(NonZeroU32::new(1).unwrap())))
.build(IpVersion::Both)
.unwrap()
.run_in_background(move |event| {
);
(server.interface_v6(target.clone()), client.interface_v6(target))
}

_ => unreachable!(),
};

let server = Arc::new(Mutex::new(Some(
server
.add_service(service.add_ip_address(interface_addr.ip()).build().unwrap())
.build(ip_version)
.expect("Failed to create mDNS broadcaster")
.run_in_background(),
)));

let (tx, rx) = std::sync::mpsc::sync_channel(0);
let server_ref = server.clone();
let client = client.build(ip_version).unwrap().run_in_background(move |event| {
if let DiscoveryEvent::ResponderFound(responder) | DiscoveryEvent::ResponderLost(responder) = &event {
println!(
"Got {} from server with names {:?}",
"Got {} from server with names {:?} and address {:?}",
match event {
DiscoveryEvent::ResponderFound(_) => "ResponderFound",
DiscoveryEvent::ResponderLost(_) => "ResponderLost",
Expand All @@ -70,7 +102,8 @@ fn client_and_server() {
.answers()
.iter()
.map(|answer| answer.name().to_string())
.collect::<BTreeSet<_>>()
.collect::<BTreeSet<_>>(),
responder.addr
);

let is_test_responder = responder
Expand All @@ -80,6 +113,22 @@ fn client_and_server() {
.any(|answer| answer.name().to_string() == "searchlighttest._searchlight-test._udp.local.");

if is_test_responder {
// Check if this is the address we expected
match (responder.addr, interface_addr) {
(SocketAddr::V6(addr_v6), SocketAddr::V6(iface_v6)) => {
assert!(Ipv6Interface::from_raw(NonZeroU32::new(addr_v6.scope_id()).unwrap())
.addrs()
.unwrap()
.contains(iface_v6.ip()));
}

(SocketAddr::V4(addr_v4), SocketAddr::V4(iface_v4)) => {
assert_eq!(addr_v4.ip(), iface_v4.ip());
}

_ => assert!(false),
}

if matches!(&event, DiscoveryEvent::ResponderFound(_)) {
println!("Got ResponderFound from server");
// Shut down the server so we can get a ResponderLost event
Expand All @@ -95,21 +144,22 @@ fn client_and_server() {
}
});

println!("Client is running");
println!("Client is running");

let res = rx.recv_timeout(Duration::from_secs(30));
let res = rx.recv_timeout(Duration::from_secs(30));

println!("Shutting down server");
if let Some(server) = server.lock().unwrap().take() {
println!("Server status: {:?}", server.shutdown());
} else {
println!("Server status: Shutdown");
}
println!("Shutting down server");
if let Some(server) = server.lock().unwrap().take() {
println!("Server status: {:?}", server.shutdown());
} else {
println!("Server status: Shutdown");
}

println!("Shutting down client");
println!("Client status: {:?}", client.shutdown());
println!("Shutting down client");
println!("Client status: {:?}", client.shutdown());

res.expect("Timed out waiting for server to respond");
res.expect("Timed out waiting for server to respond");
}

test_tx.send(()).ok();
});
Expand Down

0 comments on commit cc0cca2

Please sign in to comment.