use crate::ipcon_error::IpconError;
use std::ffi::CStr;
use std::fmt;
use std::os::raw::c_char;
#[allow(unused)]
use {
error_stack::{Context, IntoReport, Result, ResultExt},
jlogger_tracing::{jdebug, jerror, jinfo, jtrace, jwarn},
};
pub const IPCON_MAX_PAYLOAD_LEN: usize = 2048;
pub const IPCON_MAX_NAME_LEN: usize = 32;
pub type IpconKeventType = std::os::raw::c_int;
pub const IPCON_KEVENT_TYPE_PEER_ADD: IpconKeventType = 0;
pub const IPCON_KEVENT_TYPE_PEER_REMOVE: IpconKeventType = 1;
pub const IPCON_KEVENT_TYPE_GROUP_ADD: IpconKeventType = 2;
pub const IPCON_KEVENT_TYPE_GROUP_REMOVE: IpconKeventType = 3;
#[repr(C)]
#[derive(Clone, Copy)]
pub struct IpconKeventGroup {
pub group_name: [std::os::raw::c_char; IPCON_MAX_NAME_LEN],
pub peer_name: [std::os::raw::c_char; IPCON_MAX_NAME_LEN],
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct IpconKeventPeer {
pub peer_name: [std::os::raw::c_char; IPCON_MAX_NAME_LEN],
}
#[repr(C)]
#[derive(Clone, Copy)]
pub union IpconKeventUnion {
pub peer: IpconKeventPeer,
pub group: IpconKeventGroup,
}
fn c_str_name(name: &[std::os::raw::c_char; IPCON_MAX_NAME_LEN]) -> Result<&str, IpconError> {
#[cfg(target_arch = "x86_64")]
let name: &[u8; IPCON_MAX_NAME_LEN] = unsafe { std::mem::transmute(name) };
let mut end = 0;
loop {
if name[end] == b'\0' {
break;
}
if end == IPCON_MAX_NAME_LEN - 1 {
break;
}
end += 1;
}
CStr::from_bytes_with_nul(&name[0..=end])
.into_report()
.change_context(IpconError::InvalidName)
.attach_printable(format!(
"Name: {:?}\n End: {}",
name.map(|c| c as char),
end
))?
.to_str()
.into_report()
.change_context(IpconError::InvalidName)
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct IpconKevent {
pub ke_type: IpconKeventType,
pub u: IpconKeventUnion,
}
impl IpconKevent {
pub fn get_string(&self) -> Result<String, IpconError> {
let result = match self.ke_type {
IPCON_KEVENT_TYPE_PEER_ADD => format!(
"peer {} added",
c_str_name(unsafe { &self.u.peer.peer_name })?
),
IPCON_KEVENT_TYPE_PEER_REMOVE => format!(
"peer {} removed",
c_str_name(unsafe { &self.u.peer.peer_name })?
),
IPCON_KEVENT_TYPE_GROUP_ADD => format!(
"group {}@{} added",
c_str_name(unsafe { &self.u.group.group_name })?,
c_str_name(unsafe { &self.u.group.peer_name })?
),
IPCON_KEVENT_TYPE_GROUP_REMOVE => format!(
"group {}@{} removed",
c_str_name(unsafe { &self.u.group.group_name })?,
c_str_name(unsafe { &self.u.group.peer_name })?
),
_ => {
return Err(IpconError::InvalidKevent)
.into_report()
.attach_printable(format!("Invalid kevent type {}", self.ke_type))
}
};
Ok(result)
}
pub fn peer_added(&self) -> Option<String> {
match self.ke_type {
IPCON_KEVENT_TYPE_PEER_ADD => c_str_name(unsafe { &self.u.peer.peer_name })
.map_or(None, |name| Some(name.to_owned())),
_ => None,
}
}
pub fn peer_removed(&self) -> Option<String> {
match self.ke_type {
IPCON_KEVENT_TYPE_PEER_REMOVE => c_str_name(unsafe { &self.u.peer.peer_name })
.map_or(None, |name| Some(name.to_owned())),
_ => None,
}
}
pub fn group_added(&self) -> Option<(String, String)> {
match self.ke_type {
IPCON_KEVENT_TYPE_GROUP_ADD => {
if let (Ok(peer_name), Ok(group_name)) = (
c_str_name(unsafe { &self.u.group.peer_name }),
c_str_name(unsafe { &self.u.group.group_name }),
) {
Some((peer_name.to_owned(), group_name.to_owned()))
} else {
None
}
}
_ => None,
}
}
pub fn group_removed(&self) -> Option<(String, String)> {
match self.ke_type {
IPCON_KEVENT_TYPE_GROUP_REMOVE => {
if let (Ok(peer_name), Ok(group_name)) = (
c_str_name(unsafe { &self.u.group.peer_name }),
c_str_name(unsafe { &self.u.group.group_name }),
) {
Some((peer_name.to_owned(), group_name.to_owned()))
} else {
None
}
}
_ => None,
}
}
}
impl fmt::Display for IpconKevent {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.get_string().unwrap_or_else(|e| e.to_string()))
}
}
pub type LibIpconMsgType = std::os::raw::c_int;
pub const LIBIPCON_MSG_TYPE_NORMAL: LibIpconMsgType = 0;
pub const LIBIPCON_MSG_TYPE_GROUP: LibIpconMsgType = 1;
pub const LIBIPCON_MSG_TYPE_KEVENT: LibIpconMsgType = 2;
pub const LIBIPCON_MSG_TYPE_INVALID: LibIpconMsgType = 3;
#[repr(C)]
#[derive(Clone, Copy)]
pub union IpconMsgUnion {
buf: [std::os::raw::c_uchar; IPCON_MAX_PAYLOAD_LEN],
kevent: IpconKevent,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct LibIpconMsg {
msg_type: LibIpconMsgType,
pub group: [c_char; IPCON_MAX_NAME_LEN],
pub peer: [c_char; IPCON_MAX_NAME_LEN],
len: u32,
u: IpconMsgUnion,
}
impl LibIpconMsg {
pub fn new() -> LibIpconMsg {
LibIpconMsg {
msg_type: LIBIPCON_MSG_TYPE_INVALID,
peer: [0; IPCON_MAX_NAME_LEN],
group: [0; IPCON_MAX_NAME_LEN],
len: 0,
u: IpconMsgUnion {
buf: [0; IPCON_MAX_PAYLOAD_LEN],
},
}
}
}
impl Default for LibIpconMsg {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum IpconMsgType {
IpconMsgTypeNormal,
IpconMsgTypeGroup,
IpconMsgTypeKevent,
IpconMsgTypeInvalid,
}
pub struct IpconMsgBody {
pub msg_type: IpconMsgType,
pub peer: String,
pub group: Option<String>,
pub buf: Vec<u8>,
}
pub enum IpconMsg {
IpconMsgUser(IpconMsgBody),
IpconMsgKevent(IpconKevent),
IpconMsgInvalid,
}
impl From<LibIpconMsg> for Result<IpconMsg, IpconError> {
fn from(msg: LibIpconMsg) -> Self {
match msg.msg_type {
LIBIPCON_MSG_TYPE_NORMAL => {
let m = IpconMsgBody {
msg_type: IpconMsgType::IpconMsgTypeNormal,
peer: c_str_name(&msg.peer)?.to_owned(),
group: None,
buf: unsafe { msg.u.buf[..msg.len as usize].to_vec() },
};
Ok(IpconMsg::IpconMsgUser(m))
}
LIBIPCON_MSG_TYPE_GROUP => {
let m = IpconMsgBody {
msg_type: IpconMsgType::IpconMsgTypeGroup,
peer: c_str_name(&msg.peer)?.to_owned(),
group: Some(c_str_name(&msg.group)?.to_owned()),
buf: unsafe { msg.u.buf[..msg.len as usize].to_vec() },
};
Ok(IpconMsg::IpconMsgUser(m))
}
LIBIPCON_MSG_TYPE_KEVENT => Ok(IpconMsg::IpconMsgKevent(unsafe { msg.u.kevent })),
LIBIPCON_MSG_TYPE_INVALID => Ok(IpconMsg::IpconMsgInvalid),
_ => Ok(IpconMsg::IpconMsgInvalid),
}
}
}