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\$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.