ipcon_sys/
ipcon_msg.rs

1use crate::ipcon_error::IpconError;
2use std::ffi::CStr;
3use std::fmt;
4use std::os::raw::c_char;
5#[allow(unused)]
6use {
7    error_stack::{Context, Report, Result, ResultExt},
8    jlogger_tracing::{jdebug, jerror, jinfo, jtrace, jwarn},
9};
10
11pub const IPCON_MAX_PAYLOAD_LEN: usize = 2048;
12pub const IPCON_MAX_NAME_LEN: usize = 32;
13
14pub type IpconKeventType = std::os::raw::c_int;
15pub const IPCON_KEVENT_TYPE_PEER_ADD: IpconKeventType = 0;
16pub const IPCON_KEVENT_TYPE_PEER_REMOVE: IpconKeventType = 1;
17pub const IPCON_KEVENT_TYPE_GROUP_ADD: IpconKeventType = 2;
18pub const IPCON_KEVENT_TYPE_GROUP_REMOVE: IpconKeventType = 3;
19
20/// Group information of IpconKevent.
21#[repr(C)]
22#[derive(Clone, Copy)]
23pub struct IpconKeventGroup {
24    pub group_name: [std::os::raw::c_char; IPCON_MAX_NAME_LEN],
25    pub peer_name: [std::os::raw::c_char; IPCON_MAX_NAME_LEN],
26}
27
28/// Peer information of IpconKevent.
29#[repr(C)]
30#[derive(Clone, Copy)]
31pub struct IpconKeventPeer {
32    pub peer_name: [std::os::raw::c_char; IPCON_MAX_NAME_LEN],
33}
34
35#[repr(C)]
36#[derive(Clone, Copy)]
37pub union IpconKeventUnion {
38    pub peer: IpconKeventPeer,
39    pub group: IpconKeventGroup,
40}
41
42fn c_str_name(name: &[std::os::raw::c_char; IPCON_MAX_NAME_LEN]) -> Result<&str, IpconError> {
43    #[cfg(target_arch = "x86_64")]
44    let name: &[u8; IPCON_MAX_NAME_LEN] = unsafe { std::mem::transmute(name) };
45
46    let mut end = 0;
47    loop {
48        if name[end] == b'\0' {
49            break;
50        }
51
52        if end == IPCON_MAX_NAME_LEN - 1 {
53            break;
54        }
55
56        end += 1;
57    }
58
59    CStr::from_bytes_with_nul(&name[0..=end])
60        .map_err(|_| Report::new(IpconError::InvalidName))
61        .attach_printable(format!(
62            "Name: {:?}\n End: {}",
63            name.map(|c| c as char),
64            end
65        ))?
66        .to_str()
67        .map_err(|_| Report::new(IpconError::InvalidName))
68}
69
70/// IpconKevent is a group message delivered from the IPCON_KERNEL_GROUP_NAME group of IPCON
71/// kernel module peer named IPCON_KERNEL_NAME. It deliveries the following messages to peer:
72/// * Peer added
73/// * Peer exited
74/// * Group of a peer added
75/// * Group of a peer removed
76///
77#[repr(C)]
78#[derive(Clone, Copy)]
79pub struct IpconKevent {
80    pub ke_type: IpconKeventType,
81    pub u: IpconKeventUnion,
82}
83
84impl IpconKevent {
85    /// Get a string of the events like following:
86    /// ```
87    /// "peer <peer name> added"
88    /// "peer <peer name> removed"
89    /// "group <group name>@<peer name> added"
90    /// "group <group name>@<peer name> removed"
91    /// ```
92    pub fn get_string(&self) -> Result<String, IpconError> {
93        let result = match self.ke_type {
94            IPCON_KEVENT_TYPE_PEER_ADD => format!(
95                "peer {} added",
96                c_str_name(unsafe { &self.u.peer.peer_name })?
97            ),
98
99            IPCON_KEVENT_TYPE_PEER_REMOVE => format!(
100                "peer {} removed",
101                c_str_name(unsafe { &self.u.peer.peer_name })?
102            ),
103            IPCON_KEVENT_TYPE_GROUP_ADD => format!(
104                "group {}@{} added",
105                c_str_name(unsafe { &self.u.group.group_name })?,
106                c_str_name(unsafe { &self.u.group.peer_name })?
107            ),
108
109            IPCON_KEVENT_TYPE_GROUP_REMOVE => format!(
110                "group {}@{} removed",
111                c_str_name(unsafe { &self.u.group.group_name })?,
112                c_str_name(unsafe { &self.u.group.peer_name })?
113            ),
114            _ => {
115                return Err(Report::new(IpconError::InvalidKevent))
116                    .attach_printable(format!("Invalid kevent type {}", self.ke_type))
117            }
118        };
119
120        Ok(result)
121    }
122
123    /// Get the name of peer newly added.
124    /// IPCON kernel module will not delivery this event of an anonymous peer.
125    pub fn peer_added(&self) -> Option<String> {
126        match self.ke_type {
127            IPCON_KEVENT_TYPE_PEER_ADD => c_str_name(unsafe { &self.u.peer.peer_name })
128                .map_or(None, |name| Some(name.to_owned())),
129            _ => None,
130        }
131    }
132
133    /// Get the name of peer removed.
134    /// IPCON kernel module will not delivery this event of an anonymous peer.
135    pub fn peer_removed(&self) -> Option<String> {
136        match self.ke_type {
137            IPCON_KEVENT_TYPE_PEER_REMOVE => c_str_name(unsafe { &self.u.peer.peer_name })
138                .map_or(None, |name| Some(name.to_owned())),
139            _ => None,
140        }
141    }
142
143    /// Get the newly added group information.
144    /// The first element of the tuple stores the name of peer who owns the group, and the second
145    /// element stores the group name.
146    pub fn group_added(&self) -> Option<(String, String)> {
147        match self.ke_type {
148            IPCON_KEVENT_TYPE_GROUP_ADD => {
149                if let (Ok(peer_name), Ok(group_name)) = (
150                    c_str_name(unsafe { &self.u.group.peer_name }),
151                    c_str_name(unsafe { &self.u.group.group_name }),
152                ) {
153                    Some((peer_name.to_owned(), group_name.to_owned()))
154                } else {
155                    None
156                }
157            }
158            _ => None,
159        }
160    }
161
162    /// Get the newly removed group information.
163    /// The first element of the tuple stores the name of peer who owns the group, and the second
164    /// element stores the group name.
165    pub fn group_removed(&self) -> Option<(String, String)> {
166        match self.ke_type {
167            IPCON_KEVENT_TYPE_GROUP_REMOVE => {
168                if let (Ok(peer_name), Ok(group_name)) = (
169                    c_str_name(unsafe { &self.u.group.peer_name }),
170                    c_str_name(unsafe { &self.u.group.group_name }),
171                ) {
172                    Some((peer_name.to_owned(), group_name.to_owned()))
173                } else {
174                    None
175                }
176            }
177            _ => None,
178        }
179    }
180}
181
182impl fmt::Display for IpconKevent {
183    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
184        write!(f, "{}", self.get_string().unwrap_or_else(|e| e.to_string()))
185    }
186}
187
188pub type LibIpconMsgType = std::os::raw::c_int;
189pub const LIBIPCON_MSG_TYPE_NORMAL: LibIpconMsgType = 0;
190pub const LIBIPCON_MSG_TYPE_GROUP: LibIpconMsgType = 1;
191pub const LIBIPCON_MSG_TYPE_KEVENT: LibIpconMsgType = 2;
192pub const LIBIPCON_MSG_TYPE_INVALID: LibIpconMsgType = 3;
193
194#[repr(C)]
195#[derive(Clone, Copy)]
196pub union IpconMsgUnion {
197    buf: [std::os::raw::c_uchar; IPCON_MAX_PAYLOAD_LEN],
198    kevent: IpconKevent,
199}
200
201/// Message interface to libipcon.
202#[repr(C)]
203#[derive(Clone, Copy)]
204pub struct LibIpconMsg {
205    msg_type: LibIpconMsgType,
206    pub group: [c_char; IPCON_MAX_NAME_LEN],
207    pub peer: [c_char; IPCON_MAX_NAME_LEN],
208    len: u32,
209    u: IpconMsgUnion,
210}
211
212impl LibIpconMsg {
213    pub fn new() -> LibIpconMsg {
214        LibIpconMsg {
215            msg_type: LIBIPCON_MSG_TYPE_INVALID,
216            peer: [0; IPCON_MAX_NAME_LEN],
217            group: [0; IPCON_MAX_NAME_LEN],
218            len: 0,
219            u: IpconMsgUnion {
220                buf: [0; IPCON_MAX_PAYLOAD_LEN],
221            },
222        }
223    }
224}
225
226impl Default for LibIpconMsg {
227    fn default() -> Self {
228        Self::new()
229    }
230}
231
232#[derive(Clone, Copy, Debug, PartialEq, Eq)]
233pub enum IpconMsgType {
234    IpconMsgTypeNormal,
235    IpconMsgTypeGroup,
236    IpconMsgTypeKevent,
237    IpconMsgTypeInvalid,
238}
239
240/// The body of a IPCON message.
241///
242/// * msg_type  
243///   * IpconMsgTypeNormal : a normal message.
244///   * IpconMsgTypeGroup  : a multicast group message.
245///   * IpconMsgTypeKevent : a IPCON kernel module message
246///   * IpconMsgTypeInvalid: an invalid IPCON message
247/// * peer  
248///   The name of peer who sent this message.
249/// * group  
250///   The group of this message. It will be None if the message is not a multicast group message.
251/// * buf  
252///   Message content.
253///
254pub struct IpconMsgBody {
255    pub msg_type: IpconMsgType,
256    pub peer: String,
257    pub group: Option<String>,
258    pub buf: Vec<u8>,
259}
260
261/// IPCON message.
262pub enum IpconMsg {
263    IpconMsgUser(IpconMsgBody),
264    IpconMsgKevent(IpconKevent),
265    IpconMsgInvalid,
266}
267
268impl From<LibIpconMsg> for Result<IpconMsg, IpconError> {
269    fn from(msg: LibIpconMsg) -> Self {
270        match msg.msg_type {
271            LIBIPCON_MSG_TYPE_NORMAL => {
272                let m = IpconMsgBody {
273                    msg_type: IpconMsgType::IpconMsgTypeNormal,
274                    peer: c_str_name(&msg.peer)?.to_owned(),
275                    group: None,
276                    buf: unsafe { msg.u.buf[..msg.len as usize].to_vec() },
277                };
278
279                Ok(IpconMsg::IpconMsgUser(m))
280            }
281
282            LIBIPCON_MSG_TYPE_GROUP => {
283                let m = IpconMsgBody {
284                    msg_type: IpconMsgType::IpconMsgTypeGroup,
285                    peer: c_str_name(&msg.peer)?.to_owned(),
286                    group: Some(c_str_name(&msg.group)?.to_owned()),
287                    buf: unsafe { msg.u.buf[..msg.len as usize].to_vec() },
288                };
289                Ok(IpconMsg::IpconMsgUser(m))
290            }
291
292            LIBIPCON_MSG_TYPE_KEVENT => Ok(IpconMsg::IpconMsgKevent(unsafe { msg.u.kevent })),
293            LIBIPCON_MSG_TYPE_INVALID => Ok(IpconMsg::IpconMsgInvalid),
294            _ => Ok(IpconMsg::IpconMsgInvalid),
295        }
296    }
297}