#udp #mio #ipv6-recvpktinfo #ip-pktinfo #udp-server

udp_sas_mio

Source address selection for UDP mio sockets

2 unstable releases

0.2.0 Dec 28, 2020
0.1.2 Apr 28, 2018

#21 in #udp-server

MIT/Apache

10KB

udp_sas_mio

Build Status Crates.io

Source address selection for UDP mio sockets in Rust

This crate provides an extension trait for mio::net::UdpSocket that supports source address selection for outgoing UDP datagrams. This is useful for implementing a UDP server that binds multiple network interfaces.

The implementation relies on crate udp_sas


lib.rs:

This crate provides an extension trait for mio::net::UdpSocket that supports source address selection for outgoing UDP datagrams. This is useful for implementing a UDP server that binds multiple network interfaces.

The implementation relies on socket options IP_PKTINFO (for IPv4) and IPV6_RECVPKTINFO (for IPv6).

extern crate mio;
extern crate udp_sas_mio;

use std::net::SocketAddr;
use std::time::Duration;

use mio::{Events,Interest,Poll,Token};
use mio::net::UdpSocket;

use udp_sas_mio::UdpSas;

fn main() {
    demo().unwrap();
}
fn demo() -> std::io::Result<()>
{
    let mut buf = [0u8;128];

    // Create the server socket and bind it to 0.0.0.0:30012
    //
    // Note: we will use 127.0.0.23 as source/destination address
    //       for our datagrams (to demonstrate the crate features)
    //
    let mut srv = UdpSocket::bind_sas("0.0.0.0:30012".parse::<SocketAddr>().unwrap())?;
    let srv_addr : SocketAddr = "127.0.0.23:30012".parse().unwrap();

    // Create the client socket and bind it to an anonymous port
    //
    // Note: we will use 127.0.0.45 as source/destination address
    //       for our datagrams (to demonstrate the crate features)
    //
    let mut cli = UdpSocket::bind_sas("0.0.0.0:0".parse::<SocketAddr>().unwrap())?;
    let cli_addr = SocketAddr::new(
        "127.0.0.45".parse().unwrap(),
        cli.local_addr().unwrap().port());
    assert_ne!(cli_addr.port(), 0);
    
    // Messages to be sent
    let msg1 = "What do you get if you multiply six by nine?";
    let msg2 = "Forty-two";

    // create the Poll object and register the sockets
    let mut poll = Poll::new()?;
    const SRV : Token = Token(0);
    const CLI : Token = Token(1);
    poll.registry().register(&mut cli, CLI, Interest::WRITABLE)?;
    poll.registry().register(&mut srv, SRV, Interest::READABLE)?;
    
    let timeout = Some(Duration::from_millis(100));
    let mut events = Events::with_capacity(1);
    loop
    {
        let nb = poll.poll(&mut events, timeout)?;
        assert!(!events.is_empty(), "timeout");
        
        for event in events.iter()
        {
            match event.token() {
                CLI if event.is_writable() => {
                    // send a request (msg1) from the client to the server
                    let nb = cli.send_sas(msg1.as_bytes(), &srv_addr, &cli_addr.ip())?;
                    assert_eq!(nb, msg1.as_bytes().len());
                    
                    poll.registry().reregister(&mut cli, CLI, Interest::READABLE)?;
                },
                
                SRV if event.is_readable() => {
                    // receive the request on the server
                    let (nb, peer, local) = srv.recv_sas(&mut buf)?;
                    assert_eq!(peer,  cli_addr);
                    assert_eq!(local, srv_addr.ip());
                    assert_eq!(nb,          msg1.as_bytes().len());
                    assert_eq!(&buf[0..nb], msg1.as_bytes());
                    
                    poll.registry().reregister(&mut srv, SRV, Interest::WRITABLE)?;
                },
                
                SRV if event.is_writable() => {
                    // send a reply (msg2) from the server to the client
                    let nb = srv.send_sas(msg2.as_bytes(), &cli_addr, &srv_addr.ip())?;
                    assert_eq!(nb, msg2.as_bytes().len());
                },
                
                CLI if event.is_readable() => {
                    // receive the reply on the client
                    let (nb, peer, local) = cli.recv_sas(&mut buf)?;
                    assert_eq!(peer,  srv_addr);
                    assert_eq!(local, cli_addr.ip());
                    assert_eq!(nb,          msg2.as_bytes().len());
                    assert_eq!(&buf[0..nb], msg2.as_bytes());
                    
                    return Ok(());
                },
            
                token => panic!("unexpected token: {:?}", token)
            }
        }
    }
}

Dependencies

~0.5–1MB
~18K SLoC