Skip to content
This repository has been archived by the owner on Jan 28, 2021. It is now read-only.

Commit

Permalink
dist/tools/vaina: add VAINA client
Browse files Browse the repository at this point in the history
Signed-off-by: Jean Pierre Dudey <[email protected]>
  • Loading branch information
jeandudey committed May 11, 2020
1 parent 34348b9 commit 627267d
Show file tree
Hide file tree
Showing 8 changed files with 614 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ targetConfigs/
setenv
.DS_Store
bin/
dist/tools/vaina/target
219 changes: 219 additions & 0 deletions dist/tools/vaina/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions dist/tools/vaina/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "vaina"
version = "0.1.0"
authors = ["Locha Inc"]
edition = "2018"

[dependencies]
clap = { version = "2", features = ["color"] }
bytes = "0.5"
snafu = "0.6"
nix = "0.17"

[patch.crates-io]
nix = { git = "https://github.com/nix-rust/nix" }
77 changes: 77 additions & 0 deletions dist/tools/vaina/src/client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use std::ffi::OsString;
use std::net::{Ipv6Addr, SocketAddr, UdpSocket};
use std::os::unix::io::FromRawFd;
use std::str::FromStr;

use nix::sys::socket::sockopt::{BindToDevice, Ipv6AddMembership};
use nix::sys::socket::{
bind, setsockopt, socket, AddressFamily, InetAddr, Ipv6Addr as NixIpv6Addr,
Ipv6MembershipRequest, SockAddr, SockFlag, SockProtocol, SockType,
};

use snafu::ResultExt;

use crate::*;
use crate::msg::Message;

/// VAINA multicast address
pub const VAINA_MCAST_ADDR: &str = "ff15::42";
pub const VAINA_PORT: u16 = 1337;

#[derive(Debug)]
pub struct VainaClient {
seqno: u8,
pending_acks: Vec<u8>,
sock: UdpSocket,
group: SocketAddr,
}

impl VainaClient {
/// New `VainaClient`
pub fn new(netif: &OsString) -> Result<VainaClient, Error> {
let group = Ipv6Addr::from_str(VAINA_MCAST_ADDR).unwrap();
let stdaddr = SocketAddr::new(group.clone().into(), VAINA_PORT);
let sockaddr = SockAddr::new_inet(InetAddr::from_std(&stdaddr));
let fd = socket(
AddressFamily::Inet6,
SockType::Datagram,
SockFlag::empty(),
SockProtocol::Udp,
)
.context(VainaSocket)?;

setsockopt(fd, BindToDevice, netif).context(VainaSocket)?;
bind(fd, &sockaddr).context(VainaSocket)?;

let group_req = Ipv6MembershipRequest::new(NixIpv6Addr::from_std(&group));
setsockopt(fd, Ipv6AddMembership, &group_req).context(VainaSocket)?;

Ok(VainaClient {
seqno: 0u8,
pending_acks: Vec::new(),
sock: unsafe { UdpSocket::from_raw_fd(fd) },
group: stdaddr,
})
}

/// Craft a new sequence number
pub fn craft_seqno(&mut self) -> u8 {
let seqno = self.seqno;
self.seqno += 1;
seqno
}

/// Send a message
pub fn send_message(&mut self, msg: &Message) -> Result<(), Error> {
// Verify if well wait for an ACK!
if !msg.is_ack() {
self.pending_acks.push(msg.seqno());
}

let bytes = msg.serialize();

self.sock.send_to(bytes.as_ref(), &self.group).context(FailedSend)?;

Ok(())
}
}
71 changes: 71 additions & 0 deletions dist/tools/vaina/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use clap::{App, Arg, SubCommand};
use snafu::Snafu;

mod client;
mod msg;
mod rcs;

#[derive(Debug, Snafu)]
pub enum Error {
#[snafu(display("Could not create socket for VAINA: {}", source))]
VainaSocket { source: nix::Error },
#[snafu(display("Could not send data to VAINA: {}", source))]
FailedSend { source: std::io::Error },
}

fn main() {
let matches = App::new("vaina")
.version("0.1.0")
.author("Locha Inc <[email protected]>")
.about("VAINA client")
.subcommand(
SubCommand::with_name("rcs")
.about("Router Client Set")
.subcommand(
SubCommand::with_name("add")
.about("Add IPv6 address to RCS")
.arg(
Arg::with_name("interface")
.help("Network interface")
.takes_value(true)
.required(true),
)
.arg(
Arg::with_name("IP")
.help("IPv6 address")
.takes_value(true)
.required(true),
),
)
.subcommand(
SubCommand::with_name("del")
.about("Delete an IPv6 address from RCS")
.arg(
Arg::with_name("interface")
.help("Network interface")
.takes_value(true)
.required(true),
)
.arg(
Arg::with_name("IP")
.help("IPv6 address")
.takes_value(true)
.required(true),
),
),
)
.get_matches();

let result = match matches.subcommand() {
("rcs", Some(rcs_matches)) => rcs::handle_matches(rcs_matches),
_ => {
println!("{}", matches.usage());
Ok(())
}
};

match result {
Ok(()) => (),
Err(e) => println!("{}", e),
}
}
Loading

0 comments on commit 627267d

Please sign in to comment.