Skip to content

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

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(())
    })
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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