use std::io;
use std::net::{SocketAddr, ToSocketAddrs};
use std::thread;
use crossbeam_channel::{Receiver, Sender};
pub(crate) struct ResolveRequest {
pub(crate) host: String,
pub(crate) port: u16,
pub(crate) request_id: u64,
pub(crate) response_tx: Sender<ResolveResponse>,
pub(crate) wake_handle: crate::wakeup::WakeHandle,
}
pub(crate) struct ResolveResponse {
pub(crate) request_id: u64,
pub(crate) result: io::Result<SocketAddr>,
}
pub(crate) struct ResolverPool {
pub(crate) request_tx: Sender<ResolveRequest>,
_threads: Vec<thread::JoinHandle<()>>,
}
impl ResolverPool {
pub(crate) fn start(num_threads: usize) -> Self {
let (request_tx, request_rx) = crossbeam_channel::unbounded::<ResolveRequest>();
let mut threads = Vec::with_capacity(num_threads);
for i in 0..num_threads {
let rx = request_rx.clone();
let handle = thread::Builder::new()
.name(format!("ringline-resolver-{i}"))
.spawn(move || resolver_thread(rx))
.expect("failed to spawn resolver thread");
threads.push(handle);
}
ResolverPool {
request_tx,
_threads: threads,
}
}
}
fn resolver_thread(rx: Receiver<ResolveRequest>) {
while let Ok(req) = rx.recv() {
let result = resolve_blocking(&req.host, req.port);
let _ = req.response_tx.send(ResolveResponse {
request_id: req.request_id,
result,
});
req.wake_handle.wake();
}
}
fn resolve_blocking(host: &str, port: u16) -> io::Result<SocketAddr> {
(host, port)
.to_socket_addrs()?
.next()
.ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "no addresses found"))
}