Skip to content

Improvement: SmolSocket works with other runtimes, could be aliased #32

@tarka

Description

@tarka

I appears SmolSocket is general enough that it will work with other async runtimes; in particular it seems to work fine with compio. It might be worth aliasing the type to a more general name?

Working code:

use std::{future, net::{IpAddr, Ipv4Addr}};

use anyhow::{bail, Context, Result};
use futures::{stream, TryStreamExt};
use rtnetlink::{new_connection_with_socket, packet_route::{address::AddressAttribute, AddressFamily}, sys::SmolSocket};


const IFNAME: &str = "test0";

async fn get_if_addr(ifname: &str) -> Result<Ipv4Addr> {

    let (connection, handle, _msgs) =
        new_connection_with_socket::<SmolSocket>()?;

    compio::runtime::spawn(connection)
        .detach();

    let link = handle
        .link()
        .get()
        .match_name(ifname.to_string())
        .execute()
        .try_next().await?
        .context("Failed to find interface {ifname}")?;

    // Fetch link addresses
    let addrs = handle
        .address()
        .get()
        .set_link_index_filter(link.header.index)
        .execute()
        // Extract attributes
        .try_filter_map(|a| {
            future::ready(if a.header.family == AddressFamily::Inet {
                Ok(Some(a.attributes))
            } else {
                Ok(None)
            })
        })
        .map_ok(|attrs| {
            stream::iter(
                attrs
                    .into_iter()
                    .map(Ok::<AddressAttribute, rtnetlink::Error>),
            )
        })
        .try_flatten()
        .try_collect::<Vec<AddressAttribute>>().await?
        // Extract relevant addresses
        .into_iter()
        .flat_map(|a| {
            if let AddressAttribute::Address(addr) = a {
                Some(addr)
            } else {
                None
            }
        })
        .collect::<Vec<IpAddr>>();

    if let IpAddr::V4(ipaddr) = addrs[0] {
        Ok(ipaddr)
    } else if addrs.is_empty() {
        bail!("No IPv4 address found for interface {ifname}");
    } else if addrs.len() > 1 {
        bail!("Multiple IPv4 addresses found on for interface {ifname}")
    } else {
        bail!("Found non-IPv4 address on {ifname}; this is an internal logic error")
    }

}

fn main() -> Result<()> {
    compio::runtime::Runtime::new()?.block_on(async {
        let ipaddr = get_if_addr(IFNAME).await?;

        println!("IP is {ipaddr}");

        Ok(())
    })
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions