1
\$\begingroup\$

I've written my first ever Rust application, I'm looking for advice and criticism.

It is a very small application, using Tokio async, and is meant to be single threaded.

Mostly I'd like to know if I am writing idiomatic Rust.

The full source code can be found at https://github.com/arontsang/rust-doh-nut

fn main() -> Result<(), Box<dyn Error>> {
    let mut rt = Runtime::new()?;
    let local = task::LocalSet::new();

    local.block_on(&mut rt, async {
        let binding_socket = SocketAddr::from(([0, 0, 0, 0], 15353));
        let resolver = HyperResolver::new().await;
        let resolver = resolver.map(|x| async_std::sync::Arc::new(x));
        let success = resolver.map(|x| crate::listener::udp::start(binding_socket, x));
        let success = match success {
            Ok(future) => future.await,
            Err(err) => Err(err),
        };
        match success {
            Ok(()) => {},
            Err(e) =>{
                eprintln!("Application error: {}", e);
            }
        }
    });
    Result::Ok(())
}

The following is the Http DNS Client

pub struct HyperResolver {
    client : Client
}


impl HyperResolver {

    pub async fn new() -> Result<HyperResolver, Box<dyn Error>> {

        let client = reqwest::Client::builder()
            .tcp_nodelay()
            .build()?;

        Result::Ok(HyperResolver { client })
    }

}

#[async_trait]
impl DnsResolver for HyperResolver {

    async fn resolve(&self, query: Bytes) -> Result<Bytes, Box<dyn Error>> {

        let client = &self.client;

        let request = client.request(Method::POST, "https://1.1.1.1/dns-query")
            .header("accept", "application/dns-message")
            .header("content-type", "application/dns-message")
            .header("content-length", query.len().to_string())
            .body(Body::from(query));

        let response = request.send().await?;
        let body = response.bytes().await?;

        Result::Ok(body)
    }
}

This is the UDP DNS server component

pub async fn start<T : DnsResolver + 'static >(bind_address: SocketAddr, resolver: async_std::sync::Arc<T>) -> Result<(), Box<dyn Error>> {


    let socket = tokio::net::UdpSocket::bind(bind_address).await;
    let socket = socket?;

    let (mut receiver, mut sender) = socket.split();

    let (reply_queue, reply_tasks) = tokio::sync::mpsc::channel::<(SocketAddr, Bytes)>(100);

    let listen_request_task = task::spawn_local(async move {
        let mut queue = reply_tasks;
        loop {
            let success = match queue.recv().await {
                Some((client, payload)) =>
                    Some(sender.send_to(&payload, &client).await),
                None => None,
            };
            match success {
                Some(Ok(_)) => {},
                Some(Err(error)) =>
                    println!("Error sending reply: {}", error),
                None => {},
            }
        }
    });


    let request_dispatch_task = task::spawn_local(async move {
        loop {
            let mut local_reply_queue = reply_queue.clone();
            let local_resolver_copy = resolver.clone();
            let mut buffer = BytesMut::with_capacity(1500);
            {
                let mut read_buffer = arr![0u8; 1500];
                match receiver.recv_from(&mut read_buffer).await{
                    Ok((length, client)) => {
                        buffer.put(&read_buffer[0..length]);

                        let query = buffer.freeze();

                        task::spawn_local(async move {

                            match local_resolver_copy.resolve(query).await{
                                Err(error) => println!("Error resolving packet: {}", error),
                                Ok(reply) =>
                                    match local_reply_queue.send((client, reply)).await{
                                        Err(error) => println!("Error replying packet: {}", error),
                                        Ok(_) => {},
                                    }
                            };
                        });
                    },
                    Err(error) =>
                        println!("Error receiving packet: {}", error),
                }
            }
        }
    });

    listen_request_task.await?;
    request_dispatch_task.await?;
    Ok(())
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.