summaryrefslogtreecommitdiff
path: root/dhcp-client/src
diff options
context:
space:
mode:
Diffstat (limited to 'dhcp-client/src')
-rw-r--r--dhcp-client/src/com.redhat.dhcp3
-rw-r--r--dhcp-client/src/com_redhat.rs203
-rw-r--r--dhcp-client/src/main.rs233
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(())
+}