diff options
Diffstat (limited to 'dhcp-client/src')
-rw-r--r-- | dhcp-client/src/com.redhat.dhcp | 3 | ||||
-rw-r--r-- | dhcp-client/src/com_redhat.rs | 203 | ||||
-rw-r--r-- | dhcp-client/src/main.rs | 233 |
3 files changed, 439 insertions, 0 deletions
diff --git a/dhcp-client/src/com.redhat.dhcp b/dhcp-client/src/com.redhat.dhcp new file mode 100644 index 0000000000..05e5b92b7d --- /dev/null +++ b/dhcp-client/src/com.redhat.dhcp @@ -0,0 +1,3 @@ +interface com.redhat.dhcp + +method Ping(ping: string) -> (pong: string) diff --git a/dhcp-client/src/com_redhat.rs b/dhcp-client/src/com_redhat.rs new file mode 100644 index 0000000000..e903eff2f0 --- /dev/null +++ b/dhcp-client/src/com_redhat.rs @@ -0,0 +1,203 @@ +#![doc = "This file was automatically generated by the varlink rust generator"] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +use serde_derive::{Deserialize, Serialize}; +use serde_json; +use std::io::BufRead; +use std::sync::{Arc, RwLock}; +use varlink::{self, CallTrait}; +#[allow(dead_code)] +#[derive(Clone, PartialEq, Debug)] +pub enum ErrorKind { + Varlink_Error, + VarlinkReply_Error, +} +impl ::std::fmt::Display for ErrorKind { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + match self { + ErrorKind::Varlink_Error => write!(f, "Varlink Error"), + ErrorKind::VarlinkReply_Error => write!(f, "Varlink error reply"), + } + } +} +pub struct Error( + pub ErrorKind, + pub Option<Box<dyn std::error::Error + 'static + Send + Sync>>, + pub Option<&'static str>, +); +impl Error { + #[allow(dead_code)] + pub fn kind(&self) -> &ErrorKind { + &self.0 + } +} +impl From<ErrorKind> for Error { + fn from(e: ErrorKind) -> Self { + Error(e, None, None) + } +} +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + self.1 + .as_ref() + .map(|e| e.as_ref() as &(dyn std::error::Error + 'static)) + } +} +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + std::fmt::Display::fmt(&self.0, f) + } +} +impl std::fmt::Debug for Error { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + use std::error::Error as StdError; + if let Some(ref o) = self.2 { + std::fmt::Display::fmt(o, f)?; + } + std::fmt::Debug::fmt(&self.0, f)?; + if let Some(e) = self.source() { + std::fmt::Display::fmt("\nCaused by:\n", f)?; + std::fmt::Debug::fmt(&e, f)?; + } + Ok(()) + } +} +#[allow(dead_code)] +pub type Result<T> = std::result::Result<T, Error>; +impl From<varlink::Error> for Error { + fn from(e: varlink::Error) -> Self { + match e.kind() { + varlink::ErrorKind::VarlinkErrorReply(r) => Error( + ErrorKind::from(r), + Some(Box::from(e)), + Some(concat!(file!(), ":", line!(), ": ")), + ), + _ => Error( + ErrorKind::Varlink_Error, + Some(Box::from(e)), + Some(concat!(file!(), ":", line!(), ": ")), + ), + } + } +} +#[allow(dead_code)] +impl Error { + pub fn source_varlink_kind(&self) -> Option<&varlink::ErrorKind> { + use std::error::Error as StdError; + let mut s: &dyn StdError = self; + while let Some(c) = s.source() { + let k = self + .source() + .and_then(|e| e.downcast_ref::<varlink::Error>()) + .and_then(|e| Some(e.kind())); + if k.is_some() { + return k; + } + s = c; + } + None + } +} +impl From<&varlink::Reply> for ErrorKind { + #[allow(unused_variables)] + fn from(e: &varlink::Reply) -> Self { + match e { + _ => ErrorKind::VarlinkReply_Error, + } + } +} +pub trait VarlinkCallError: varlink::CallTrait {} +impl<'a> VarlinkCallError for varlink::Call<'a> {} +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct Ping_Reply { + pub r#pong: String, +} +impl varlink::VarlinkReply for Ping_Reply {} +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct Ping_Args { + pub r#ping: String, +} +pub trait Call_Ping: VarlinkCallError { + fn reply(&mut self, r#pong: String) -> varlink::Result<()> { + self.reply_struct(Ping_Reply { r#pong }.into()) + } +} +impl<'a> Call_Ping for varlink::Call<'a> {} +pub trait VarlinkInterface { + fn ping(&self, call: &mut dyn Call_Ping, r#ping: String) -> varlink::Result<()>; + fn call_upgraded( + &self, + _call: &mut varlink::Call, + _bufreader: &mut dyn BufRead, + ) -> varlink::Result<Vec<u8>> { + Ok(Vec::new()) + } +} +pub trait VarlinkClientInterface { + fn ping(&mut self, r#ping: String) -> varlink::MethodCall<Ping_Args, Ping_Reply, Error>; +} +#[allow(dead_code)] +pub struct VarlinkClient { + connection: Arc<RwLock<varlink::Connection>>, +} +impl VarlinkClient { + #[allow(dead_code)] + pub fn new(connection: Arc<RwLock<varlink::Connection>>) -> Self { + VarlinkClient { connection } + } +} +impl VarlinkClientInterface for VarlinkClient { + fn ping(&mut self, r#ping: String) -> varlink::MethodCall<Ping_Args, Ping_Reply, Error> { + varlink::MethodCall::<Ping_Args, Ping_Reply, Error>::new( + self.connection.clone(), + "com.redhat.dhcp.Ping", + Ping_Args { r#ping }, + ) + } +} +#[allow(dead_code)] +pub struct VarlinkInterfaceProxy { + inner: Box<dyn VarlinkInterface + Send + Sync>, +} +#[allow(dead_code)] +pub fn new(inner: Box<dyn VarlinkInterface + Send + Sync>) -> VarlinkInterfaceProxy { + VarlinkInterfaceProxy { inner } +} +impl varlink::Interface for VarlinkInterfaceProxy { + fn get_description(&self) -> &'static str { + "interface com.redhat.dhcp\n\nmethod Ping(ping: string) -> (pong: string)\n" + } + fn get_name(&self) -> &'static str { + "com.redhat.dhcp" + } + fn call_upgraded( + &self, + call: &mut varlink::Call, + bufreader: &mut dyn BufRead, + ) -> varlink::Result<Vec<u8>> { + self.inner.call_upgraded(call, bufreader) + } + fn call(&self, call: &mut varlink::Call) -> varlink::Result<()> { + let req = call.request.unwrap(); + match req.method.as_ref() { + "com.redhat.dhcp.Ping" => { + if let Some(args) = req.parameters.clone() { + let args: Ping_Args = match serde_json::from_value(args) { + Ok(v) => v, + Err(e) => { + let es = format!("{}", e); + let _ = call.reply_invalid_parameter(es.clone()); + return Err( + varlink::context!(varlink::ErrorKind::SerdeJsonDe(es)).into() + ); + } + }; + self.inner.ping(call as &mut dyn Call_Ping, args.r#ping) + } else { + call.reply_invalid_parameter("parameters".into()) + } + } + m => call.reply_method_not_found(String::from(m)), + } + } +} diff --git a/dhcp-client/src/main.rs b/dhcp-client/src/main.rs new file mode 100644 index 0000000000..03573c3cd1 --- /dev/null +++ b/dhcp-client/src/main.rs @@ -0,0 +1,233 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#[allow(improper_ctypes)] + +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); + +mod com_redhat; + +use std::convert::From; +use std::env; +use std::ffi::CStr; +use std::fmt; +use std::fs; +use std::io::prelude::*; +use std::marker::Send; +use std::ops::Fn; +use std::ops::{Deref, Drop}; +use std::ptr::null_mut; +use std::sync::Arc; +use std::thread; + +#[repr(u32)] +#[derive(Debug)] +enum NDHCP4Event { + N_DHCP4_CLIENT_EVENT_DOWN, + N_DHCP4_CLIENT_EVENT_OFFER, + N_DHCP4_CLIENT_EVENT_GRANTED, + N_DHCP4_CLIENT_EVENT_RETRACTED, + N_DHCP4_CLIENT_EVENT_EXTENDED, + N_DHCP4_CLIENT_EVENT_EXPIRED, + N_DHCP4_CLIENT_EVENT_CANCELLED, + N_DHCP4_CLIENT_EVENT_LOG, +} + +impl From<u32> for NDHCP4Event { + fn from(u: u32) -> Self { + unsafe { std::mem::transmute::<u32, NDHCP4Event>(u) } + } +} + +impl fmt::Display for NDHCP4Event { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self) + } +} + +struct NDHCP4ClientConfig(*mut NDhcp4ClientConfig); + +impl NDHCP4ClientConfig { + fn new(ifindex: i32, mac_addr: &Vec<u8>) -> Result<NDHCP4ClientConfig, &'static str> { + let mut configp = null_mut(); + + unsafe { + if n_dhcp4_client_config_new(&mut configp) == 0 { + let bcast_mac_addr: [u8; 6] = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]; + let mut client_id = vec![0x1]; + + n_dhcp4_client_config_set_ifindex(configp, ifindex); + n_dhcp4_client_config_set_transport(configp, N_DHCP4_TRANSPORT_ETHERNET); + n_dhcp4_client_config_set_mac(configp, mac_addr.as_ptr(), 6); + n_dhcp4_client_config_set_broadcast_mac(configp, bcast_mac_addr.as_ptr(), 6); + + client_id.extend(mac_addr); + n_dhcp4_client_config_set_client_id( + configp, + client_id.as_ptr(), + client_id.len() as u64, + ); + + Ok(NDHCP4ClientConfig(configp)) + } else { + Err("n_dhcp4_client_config_new() failed") + } + } + } +} + +impl Deref for NDHCP4ClientConfig { + type Target = *mut NDhcp4ClientConfig; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Drop for NDHCP4ClientConfig { + fn drop(&mut self) { + unsafe { + n_dhcp4_client_config_free(self.0); + } + } +} + +struct NDHCP4Client(Arc<*mut NDhcp4Client>); + +impl NDHCP4Client { + fn new(config: NDHCP4ClientConfig) -> Result<NDHCP4Client, &'static str> { + let mut client = null_mut(); + + unsafe { + if n_dhcp4_client_new(&mut client, *config) == 0 { + n_dhcp4_client_set_log_level(client, 7); + + let mut probe_config = null_mut(); + if n_dhcp4_client_probe_config_new(&mut probe_config) != 0 { + return Err("n_dhcp4_client_probe_config_new() failed"); + } + + n_dhcp4_client_probe_config_set_start_delay(probe_config, 1); + + let mut probe = null_mut(); + if n_dhcp4_client_probe(client, &mut probe, probe_config) != 0 { + return Err("n_dhcp4_client_probe() failed"); + } + + Ok(NDHCP4Client(Arc::new(client))) + } else { + Err("invalid config") + } + } + } + + fn run<F>(&self, f: F) + where + F: Fn(NDHCP4Event, Option<&str>), + { + unsafe { + loop { + if n_dhcp4_client_dispatch(*self.0) == 0 { + let mut event = null_mut(); + + if n_dhcp4_client_pop_event(*self.0, &mut event) == 0 && event != null_mut() { + let mut log = None; + let event_enum = NDHCP4Event::from((*event).event); + + if let NDHCP4Event::N_DHCP4_CLIENT_EVENT_LOG = event_enum { + log = if let Ok(s) = + CStr::from_ptr((*event).__bindgen_anon_1.log.message).to_str() + { + Some(s) + } else { + None + }; + } + + f(event_enum, log); + } + } + } + } + } +} + +impl Drop for NDHCP4Client { + fn drop(&mut self) { + unsafe { + n_dhcp4_client_unref(*self.0); + } + } +} + +unsafe impl Send for NDHCP4Client {} + +struct DHCPClientVarlink; + +impl com_redhat::VarlinkInterface for DHCPClientVarlink { + fn ping(&self, call: &mut dyn com_redhat::Call_Ping, ping: String) -> varlink::Result<()> { + println!("Varlink: {}", ping); + call.reply(ping) + } +} + +fn main() -> std::result::Result<(), Box<dyn std::error::Error>> { + if let Some(iface) = env::args().skip(1).next() { + let mut file = fs::File::open(format!("/sys/class/net/{}/address", iface))?; + let mut contents = String::new(); + file.read_to_string(&mut contents)?; + contents.pop(); + + eprintln!( + "dhcp-client started on {} with mac_addr {}", + iface, contents + ); + + let mac_addr = contents.into_bytes(); + let mut client_id = Vec::from(mac_addr.clone()); + client_id.insert(0, 0x1); + + let mut file = fs::File::open(format!("/sys/class/net/{}/ifindex", iface))?; + let mut contents = String::new(); + file.read_to_string(&mut contents)?; + contents.pop(); + let ifindex = contents.parse::<i32>().unwrap(); + + let client = + NDHCP4Client::new(NDHCP4ClientConfig::new(ifindex, &mac_addr).unwrap()).unwrap(); + + let handle = thread::spawn(move || { + client.run(|event, log_msg| match event { + NDHCP4Event::N_DHCP4_CLIENT_EVENT_LOG if log_msg.is_some() => { + println!("{}", log_msg.unwrap()); + } + _ => println!("Event: {}", event), + }) + }); + + let service = varlink::VarlinkService::new( + "com.redhat.dhcp", + "test service", + "0.1", + "https://gitlab.freedesktop.org/NetworkManager/NetworkManager", + vec![Box::new(com_redhat::new(Box::new(DHCPClientVarlink)))], + ); + + println!("Start varlink unix socket"); + if let Err(e) = varlink::listen( + service, + "unix:com.redhat.dhcp", + &varlink::ListenConfig { + idle_timeout: 0, + ..Default::default() + }, + ) { + eprintln!("{}", e); + } + + // handle.join(); + } else { + eprintln!("no interface name supplied"); + } + Ok(()) +} |