Announcing udp-stream

Since, IoT and embedded development are one of Rust objectives and many IoT/Embedded devices protocols such as COAP, RTP family, SIP, Openvpn, DTLS, etc are available on UDP. Hence, I have written a lightweight library which can make easier to working with UDP, which is implemented the same as TcpStream.
The library in top of tokio and at this time has some limitation which is described after the example.
The following code shows a DTLS echo server example.

use std::{net::SocketAddr, str::FromStr, time::Duration};

use openssl::{
    pkey::PKey,
    ssl::{SslAcceptor, SslMethod},
    x509::X509,
};

use tokio::{
    io::{AsyncReadExt, AsyncWriteExt},
    time::timeout,
};

use udp_stream::UdpListener;

const UDP_BUFFER_SIZE: usize = 17480; // 17kb
const UDP_TIMEOUT: u64 = 10 * 1000; // 10sec

static SERVER_CERT: &'static [u8] = include_bytes!("server-cert.pem");
static SERVER_KEY: &'static [u8] = include_bytes!("server-key.pem");

fn ssl_acceptor(certificate: &[u8], private_key: &[u8]) -> std::io::Result<SslAcceptor> {
    let mut acceptor_builder = SslAcceptor::mozilla_intermediate(SslMethod::dtls())?;
    acceptor_builder.set_certificate(&&X509::from_pem(certificate)?)?;
    acceptor_builder.set_private_key(&&PKey::private_key_from_pem(private_key)?)?;
    acceptor_builder.check_private_key()?;
    let acceptor = acceptor_builder.build();
    Ok(acceptor)
}

#[tokio::main]
async fn main() -> std::io::Result<()> {
    let mut listener = UdpListener::bind(SocketAddr::from_str("127.0.0.1:8080").unwrap()).await?;
    loop {
        let (socket, _) = listener.accept().await?;
        tokio::spawn(async move {
            let acceptor = ssl_acceptor(SERVER_CERT, SERVER_KEY).unwrap();
            let stream = tokio_openssl::accept(&acceptor, socket).await;
            match stream {
                Ok(mut socket) => {
                    let mut buf = vec![0u8; UDP_BUFFER_SIZE];
                    loop {
                        let n = match timeout(
                            Duration::from_millis(UDP_TIMEOUT),
                            socket.read(&mut buf),
                        )
                        .await
                        .unwrap()
                        {
                            Ok(len) => len,
                            Err(_) => {
                                socket.get_ref().shutdown(std::net::Shutdown::Both);
                                return;
                            }
                        };

                        socket.write_all(&buf[0..n]).await.unwrap();
                    }
                }
                Err(_) => unimplemented!(),
            }
        });
    }
}

The library in the early stages, it has some limitations.
Limitations :

  1. Lake of documentation.
  2. As the UDP protocol is connection less, closing the connections are undetectable. To fix the problem, connections should close after a specific timeout (Timeout feature will be implemented as soon as possible. At this time, you have handled manually).
  3. At this time, unsuccessful connection is not detectable and I have problem to fix, I'm working on it in this topic.
  4. Internally, UDP server could not remove the ended connection in its pool, I will fix it immediately after fixing #3 problem.

I would be happy if you have contributed to this project


Update: Example and library have updated to Tokio 0.2

4 Likes