266 lines
7.5 KiB
Rust
266 lines
7.5 KiB
Rust
#![cfg(nightly)]
|
|
#![feature(test)]
|
|
|
|
extern crate test;
|
|
|
|
use std::env;
|
|
use std::fs::{DirBuilder, File};
|
|
use std::mem;
|
|
use std::net::{Ipv4Addr, SocketAddr, ToSocketAddrs};
|
|
use std::path::Path;
|
|
use std::process::{Child, Command, Stdio};
|
|
use std::str::FromStr;
|
|
use std::sync::Arc;
|
|
use std::thread;
|
|
use std::time::Duration;
|
|
|
|
use futures::Future;
|
|
use test::Bencher;
|
|
use tokio::net::TcpStream;
|
|
use tokio::net::UdpSocket;
|
|
use tokio::runtime::Runtime;
|
|
|
|
use hickory_client::client::*;
|
|
use hickory_client::op::*;
|
|
use hickory_client::rr::*;
|
|
use hickory_client::tcp::*;
|
|
use hickory_client::udp::*;
|
|
use hickory_proto::error::*;
|
|
use hickory_proto::iocompat::AsyncIoTokioAsStd;
|
|
use hickory_proto::op::NoopMessageFinalizer;
|
|
use hickory_proto::xfer::*;
|
|
|
|
fn find_test_port() -> u16 {
|
|
let server = std::net::UdpSocket::bind(("0.0.0.0", 0)).unwrap();
|
|
let server_addr = server.local_addr().unwrap();
|
|
server_addr.port()
|
|
}
|
|
|
|
struct NamedProcess {
|
|
named: Child,
|
|
}
|
|
|
|
impl Drop for NamedProcess {
|
|
fn drop(&mut self) {
|
|
self.named.kill().expect("could not kill process");
|
|
self.named.wait().expect("waiting failed");
|
|
}
|
|
}
|
|
|
|
fn wrap_process(named: Child, server_port: u16) -> NamedProcess {
|
|
let mut started = false;
|
|
|
|
for _ in 0..20 {
|
|
let io_loop = Runtime::new().unwrap();
|
|
let addr: SocketAddr = ("127.0.0.1", server_port)
|
|
.to_socket_addrs()
|
|
.unwrap()
|
|
.next()
|
|
.unwrap();
|
|
let stream = UdpClientStream::<UdpSocket>::new(addr);
|
|
let client = AsyncClient::connect(stream);
|
|
let (mut client, bg) = io_loop.block_on(client).expect("failed to create client");
|
|
io_loop.spawn(bg);
|
|
|
|
let name = domain::Name::from_str("www.example.com.").unwrap();
|
|
let response = io_loop.block_on(client.query(name.clone(), DNSClass::IN, RecordType::A));
|
|
|
|
if response.is_ok() {
|
|
started = true;
|
|
break;
|
|
} else {
|
|
// wait for the server to start
|
|
thread::sleep(Duration::from_millis(500));
|
|
}
|
|
}
|
|
|
|
assert!(started, "server did not startup...");
|
|
// return handle to child process
|
|
NamedProcess { named }
|
|
}
|
|
|
|
/// Returns a NamedProcess (cleans the process up on drop), and a socket addr for connecting
|
|
/// to the server.
|
|
fn hickory_process() -> (NamedProcess, u16) {
|
|
// find a random port to listen on
|
|
let test_port = find_test_port();
|
|
|
|
let ws_root = env::var("WORKSPACE_ROOT").unwrap_or_else(|_| "..".to_owned());
|
|
let named_path = env!("CARGO_BIN_EXE_hickory-dns");
|
|
let config_path = format!("{}/tests/test-data/test_configs/example.toml", ws_root);
|
|
let zone_dir = format!("{}/tests/test-data/test_configs", ws_root);
|
|
|
|
File::open(&named_path).expect(&named_path);
|
|
File::open(&config_path).expect(&config_path);
|
|
File::open(&zone_dir).expect(&zone_dir);
|
|
|
|
let named = Command::new(&named_path)
|
|
.stdout(Stdio::null())
|
|
.arg("-q") // TODO: need to rethink this one...
|
|
.arg(&format!("--config={}", config_path))
|
|
.arg(&format!("--zonedir={}", zone_dir))
|
|
.arg(&format!("--port={}", test_port))
|
|
.spawn()
|
|
.expect("failed to start hickory-dns");
|
|
//
|
|
|
|
let process = wrap_process(named, test_port);
|
|
|
|
// return handle to child process
|
|
(process, test_port)
|
|
}
|
|
|
|
/// Runs the bench tesk using the specified client
|
|
fn bench<F, S>(b: &mut Bencher, stream: F)
|
|
where
|
|
F: Future<Output = Result<S, ProtoError>> + 'static + Send + Unpin,
|
|
S: DnsRequestSender,
|
|
{
|
|
let io_loop = Runtime::new().unwrap();
|
|
let client = AsyncClient::connect(stream);
|
|
let (mut client, bg) = io_loop.block_on(client).expect("failed to create client");
|
|
io_loop.spawn(bg);
|
|
|
|
let name = domain::Name::from_str("www.example.com.").unwrap();
|
|
|
|
// validate the request
|
|
let query = client.query(name.clone(), DNSClass::IN, RecordType::A);
|
|
let response = io_loop.block_on(query).expect("Request failed");
|
|
|
|
assert_eq!(response.response_code(), ResponseCode::NoError);
|
|
|
|
let record = &response.answers()[0];
|
|
if let Some(RData::A(ref address)) = record.data() {
|
|
assert_eq!(address, &Ipv4Addr::new(127, 0, 0, 1));
|
|
} else {
|
|
unreachable!();
|
|
}
|
|
|
|
b.iter(|| {
|
|
let response = io_loop.block_on(client.query(name.clone(), DNSClass::IN, RecordType::A));
|
|
response.unwrap();
|
|
});
|
|
}
|
|
|
|
#[bench]
|
|
fn hickory_udp_bench(b: &mut Bencher) {
|
|
let (named, server_port) = hickory_process();
|
|
|
|
let addr: SocketAddr = ("127.0.0.1", server_port)
|
|
.to_socket_addrs()
|
|
.unwrap()
|
|
.next()
|
|
.unwrap();
|
|
let stream = UdpClientStream::<UdpSocket>::new(addr);
|
|
bench(b, stream);
|
|
|
|
// cleaning up the named process
|
|
drop(named);
|
|
}
|
|
|
|
#[bench]
|
|
#[ignore]
|
|
fn hickory_udp_bench_prof(b: &mut Bencher) {
|
|
let server_port = 6363;
|
|
|
|
let addr: SocketAddr = ("127.0.0.1", server_port)
|
|
.to_socket_addrs()
|
|
.unwrap()
|
|
.next()
|
|
.unwrap();
|
|
let stream = UdpClientStream::<UdpSocket>::new(addr);
|
|
bench(b, stream);
|
|
}
|
|
|
|
#[bench]
|
|
fn hickory_tcp_bench(b: &mut Bencher) {
|
|
let (named, server_port) = hickory_process();
|
|
|
|
let addr: SocketAddr = ("127.0.0.1", server_port)
|
|
.to_socket_addrs()
|
|
.unwrap()
|
|
.next()
|
|
.unwrap();
|
|
let (stream, sender) = TcpClientStream::<AsyncIoTokioAsStd<TcpStream>>::new(addr);
|
|
let mp = DnsMultiplexer::new(stream, sender, None::<Arc<NoopMessageFinalizer>>);
|
|
bench(b, mp);
|
|
|
|
// cleaning up the named process
|
|
drop(named);
|
|
}
|
|
|
|
// downloaded from https://www.isc.org/downloads/file/bind-9-11-0-p1/
|
|
// cd bind-9-11-0-p1
|
|
// .configure
|
|
// make
|
|
// export TDNS_BIND_PATH=${PWD}/bin/named/named
|
|
fn bind_process() -> (NamedProcess, u16) {
|
|
let test_port = find_test_port();
|
|
|
|
let bind_path = env::var("TDNS_BIND_PATH").unwrap_or_else(|_| "".to_owned());
|
|
let server_path = env::var("TDNS_WORKSPACE_ROOT").unwrap_or_else(|_| "..".to_owned());
|
|
|
|
let bind_path = format!("{}/sbin/named", bind_path);
|
|
|
|
// create the work directory
|
|
let working_dir = format!("{}/../target/bind_pwd", server_path);
|
|
if !Path::new(&working_dir).exists() {
|
|
DirBuilder::new()
|
|
.create(&working_dir)
|
|
.expect("failed to create dir");
|
|
}
|
|
|
|
let mut named = Command::new(bind_path)
|
|
.current_dir(&working_dir)
|
|
.stderr(Stdio::piped())
|
|
.arg("-c")
|
|
.arg("../../server/benches/bind_conf/example.conf")
|
|
//.arg("-d").arg("0")
|
|
.arg("-D")
|
|
.arg("Hickory DNS cmp bench")
|
|
.arg("-g")
|
|
.arg("-p")
|
|
.arg(&format!("{}", test_port))
|
|
.spawn()
|
|
.expect("failed to start named");
|
|
|
|
mem::replace(&mut named.stderr, None).unwrap();
|
|
let process = wrap_process(named, test_port);
|
|
(process, test_port)
|
|
}
|
|
|
|
#[bench]
|
|
#[ignore]
|
|
fn bind_udp_bench(b: &mut Bencher) {
|
|
let (named, server_port) = bind_process();
|
|
|
|
let addr: SocketAddr = ("127.0.0.1", server_port)
|
|
.to_socket_addrs()
|
|
.unwrap()
|
|
.next()
|
|
.unwrap();
|
|
let stream = UdpClientStream::<UdpSocket>::new(addr);
|
|
bench(b, stream);
|
|
|
|
// cleaning up the named process
|
|
drop(named);
|
|
}
|
|
|
|
#[bench]
|
|
#[ignore]
|
|
fn bind_tcp_bench(b: &mut Bencher) {
|
|
let (named, server_port) = bind_process();
|
|
|
|
let addr: SocketAddr = ("127.0.0.1", server_port)
|
|
.to_socket_addrs()
|
|
.unwrap()
|
|
.next()
|
|
.unwrap();
|
|
let (stream, sender) = TcpClientStream::<AsyncIoTokioAsStd<TcpStream>>::new(addr);
|
|
let mp = DnsMultiplexer::new(stream, sender, None::<Arc<NoopMessageFinalizer>>);
|
|
bench(b, mp);
|
|
|
|
// cleaning up the named process
|
|
drop(named);
|
|
}
|