1/*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16use std::ffi::{CString, c_char, c_int, c_uint, c_longlong, c_ulonglong, c_void};
17
18use crate::{EventType, WatchRule, QueryArg, QueryRule};
19
20/// Length limit for event domain definition.
21const MAX_LENGTH_OF_EVENT_DOMAIN: usize = 17;
22
23/// Length limit for event name definition.
24const MAX_LENGTH_OF_EVENT_NAME: usize = 33;
25
26/// Length limit for event tag definition.
27const MAX_LENGTH_OF_EVENT_TAG: usize = 85;
28
29/// Length limit for timezone definition.
30const MAX_LENGTH_OF_TIME_ZONE: usize = 6;
31
32/// Length limit for event list.
33const MAX_NUMBER_OF_EVENT_LIST: usize = 10;
34
35/// Length limit for event list definition.
36const MAX_EVENT_LIST_LEN: usize = 339;
37
38/// This type represent to HiSysEventWatchRule defined in C.
39#[repr(C)]
40#[derive(Copy, Clone)]
41struct HiSysEventWatchRule {
42    /// The domain of the event.
43    pub domain: [u8; MAX_LENGTH_OF_EVENT_DOMAIN],
44
45    /// The name of the event.
46    pub name: [u8; MAX_LENGTH_OF_EVENT_NAME],
47
48    /// The tag of the event.
49    pub tag: [u8; MAX_LENGTH_OF_EVENT_TAG],
50
51    /// The rule of match system event.
52    pub rule_type: c_int,
53
54    /// The type of match system event.
55    pub event_type: c_int,
56}
57
58/// This type represent to HiSysEventQueryArg defined in C.
59#[repr(C)]
60#[derive(Copy, Clone)]
61struct HiSysEventQueryArg {
62    /// Begin time.
63    pub begin_time: c_longlong,
64
65    /// End time.
66    pub end_time: c_longlong,
67
68    /// Max number of receive system event.
69    pub max_events: c_int,
70}
71
72/// This type represent to HiSysEventQueryRuleWrapper defined in C.
73#[repr(C)]
74#[derive(Copy, Clone)]
75struct HiSysEventQueryRuleWrapper {
76    // The domain of the event.
77    pub domain: [u8; MAX_LENGTH_OF_EVENT_DOMAIN],
78
79    /// List of event name.
80    pub event_list: [u8; MAX_EVENT_LIST_LEN],
81
82    /// Size of event name list.
83    pub event_list_size: c_uint,
84
85    /// extra condition for event query.
86    pub condition: *const c_char,
87}
88
89/// This type represent to HiSysEventRecord defined in C.
90#[repr(C)]
91#[derive(Copy, Clone)]
92pub struct HiSysEventRecord {
93    /// Domain.
94    domain: [u8; MAX_LENGTH_OF_EVENT_DOMAIN],
95
96    /// Event name.
97    event_name: [u8; MAX_LENGTH_OF_EVENT_NAME],
98
99    /// Event type.
100    event_type: c_int,
101
102    /// Timestamp.
103    time: c_ulonglong,
104
105    /// Timezone.
106    tz: [u8; MAX_LENGTH_OF_TIME_ZONE],
107
108    /// Process id.
109    pid: c_longlong,
110
111    /// Thread id.
112    tid: c_longlong,
113
114    /// User id.
115    uid: c_longlong,
116
117    /// Trace id.
118    trace_id: c_ulonglong,
119
120    /// Span id.
121    spand_id: c_ulonglong,
122
123    /// Parent span id.
124    pspan_id: c_ulonglong,
125
126    /// Trace flag.
127    trace_flag: c_int,
128
129    /// Level.
130    level: *const c_char,
131
132    /// Tag.
133    tag: *const c_char,
134
135    /// Event content.
136    json_str: *const c_char,
137}
138
139impl HiSysEventRecord {
140
141    /// Get domain name
142    pub fn get_domain(&self) -> String {
143        std::str::from_utf8(&self.domain).expect("need valid domain array")
144            .trim_end_matches(char::from(0)).to_string()
145    }
146
147    /// Get event name
148    pub fn get_event_name(&self) -> String {
149        std::str::from_utf8(&self.event_name).expect("need valid event name array")
150            .trim_end_matches(char::from(0)).to_string()
151    }
152
153    /// Get event name
154    pub fn get_event_type(&self) -> EventType {
155        match self.event_type {
156            1 => EventType::Fault,
157            2 => EventType::Statistic,
158            3 => EventType::Security,
159            4 => EventType::Behavior,
160            _ => EventType::Fault,
161        }
162    }
163
164    /// Get time
165    pub fn get_time(&self) -> u64 {
166        self.time
167    }
168
169    /// Get time zone
170    pub fn get_time_zone(&self) -> String {
171        std::str::from_utf8(&self.tz).expect("need valid time zone array")
172            .trim_end_matches(char::from(0)).to_string()
173    }
174
175    /// Get process id
176    pub fn get_pid(&self) -> i64 {
177        self.pid
178    }
179
180    /// Get thread id
181    pub fn get_tid(&self) -> i64 {
182        self.tid
183    }
184
185    /// Get user id
186    pub fn get_uid(&self) -> i64 {
187        self.uid
188    }
189
190    /// Get trace id
191    pub fn get_trace_id(&self) -> u64 {
192        self.trace_id
193    }
194
195    /// Get span id
196    pub fn get_span_id(&self) -> u64 {
197        self.spand_id
198    }
199
200    /// Get parent span id
201    pub fn get_parent_span_id(&self) -> u64 {
202        self.pspan_id
203    }
204
205    /// Get trace flag
206    pub fn get_trace_flag(&self) -> i32 {
207        self.trace_flag
208    }
209
210    /// Get level
211    pub fn get_level(&self) -> String {
212        let level_arr = unsafe {
213            std::ffi::CString::from_raw(self.level as *mut std::ffi::c_char)
214        };
215        std::str::from_utf8(level_arr.to_bytes()).expect("need valid level pointer")
216            .trim_end_matches(char::from(0)).to_owned()
217    }
218
219    /// Get tag
220    pub fn get_tag(&self) -> String {
221        let tag_arr = unsafe {
222            std::ffi::CString::from_raw(self.tag as *mut std::ffi::c_char)
223        };
224        let tag = std::str::from_utf8(tag_arr.to_bytes()).expect("need valid tag pointer")
225            .trim_end_matches(char::from(0));
226        String::from(tag)
227    }
228
229    /// Get json string
230    pub fn get_json_str(&self) -> String {
231        let json_str_arr = unsafe {
232            std::ffi::CString::from_raw(self.json_str as *mut std::ffi::c_char)
233        };
234        let json_str = std::str::from_utf8(json_str_arr.to_bytes()).expect("need valid json str pointer")
235            .trim_end_matches(char::from(0));
236        String::from(json_str)
237    }
238}
239
240/// Callback for handling query result, the query result will be send in several times.
241pub type OnQuery = unsafe extern "C" fn (
242    callback: *mut c_void,
243    records: *const HiSysEventRecord,
244    size: c_uint
245);
246
247/// Callback when event quering finish.
248pub type OnComplete = unsafe extern "C" fn (
249    callback: *mut c_void,
250    reason: c_int,
251    total: c_int
252);
253
254/// This type represent a rust HiSysEventRustQuerierC which like C++ HiSysEventRustQuerierC.
255#[repr(C)]
256struct HiSysEventRustQuerierC {
257    pub on_query_cb: *mut c_void,
258    pub on_query_wrapper_cb: OnQuery,
259    pub on_complete_cb: *mut c_void,
260    pub on_complete_wrapper_cb: OnComplete,
261}
262
263/// This type represent a rust interfaces.
264#[allow(dead_code)]
265pub struct Querier {
266    /// Native event querier.
267    native: *mut HiSysEventRustQuerierC,
268
269    /// Customized rust callback on query.
270    on_query_callback: *mut c_void,
271
272    /// Customized rust callback on complete.
273    on_complete_callback: *mut c_void,
274}
275
276impl Querier {
277    /// Create a rust HiSysEventRustQuerierC object with callbacks in a querier.
278    pub fn new<F1, F2>(on_query_callback: F1, on_complete_callback: F2) -> Option<Self>
279    where
280        F1: Fn(&[HiSysEventRecord]) + Send + Sync + 'static,
281        F2: Fn(i32, i32) + Send + Sync + 'static,
282    {
283        let on_query_callback = Box::into_raw(Box::new(on_query_callback));
284        let on_complete_callback = Box::into_raw(Box::new(on_complete_callback));
285        let native = unsafe {
286            CreateRustEventQuerier(on_query_callback as *mut c_void, Self::on_query_callback::<F1>,
287                on_complete_callback as *mut c_void, Self::on_complete_callback::<F2>)
288        };
289        if native.is_null() {
290            None
291        } else {
292            Some(Self {
293                native,
294                on_query_callback: on_query_callback as *mut c_void,
295                on_complete_callback: on_complete_callback as *mut c_void,
296            })
297        }
298    }
299
300    /// Callback for handling query result, the query result will be send in several times.
301    ///
302    /// # Safety
303    ///
304    /// The callback parameter will be kept valid during native
305    /// HiSysEventRustQuerierC object lifetime.
306    ///
307    unsafe extern "C" fn on_query_callback<F>(callback: *mut c_void, records: *const HiSysEventRecord,
308        size: c_uint)
309    where
310        F: Fn(&[HiSysEventRecord]) + Send + Sync + 'static,
311    {
312        let mut transalted_records: Vec<HiSysEventRecord> = vec![];
313        for i in 0..size {
314            let record_item = unsafe {
315                GetHiSysEventRecordByIndexWrapper(records, size, i as c_uint)
316            };
317            transalted_records.push(record_item);
318        }
319        let callback = (callback as *const F).as_ref().unwrap();
320        callback(transalted_records.as_slice());
321    }
322
323    /// Callback when event quering finish.
324    ///
325    /// # Safety
326    ///
327    /// The callback parameter will be kept valid during native
328    /// HiSysEventRustQuerierC object lifetime.
329    ///
330    unsafe extern "C" fn on_complete_callback<F>(callback: *mut c_void, reason: c_int,
331        total: c_int)
332    where
333        F: Fn(i32, i32) + Send + Sync + 'static,
334    {
335        let callback = (callback as *const F).as_ref().unwrap();
336        callback(reason, total);
337    }
338
339    /// free memories allocated for Querier
340    pub fn try_to_recycle(&self) {
341        unsafe {
342            RecycleRustEventQuerier(self.as_raw())
343        }
344    }
345}
346
347/// Implement trait AsRawPtr for Querier
348///
349/// # Safety
350///
351/// A `Querier` is always constructed with a valid raw pointer
352/// to a `HiSysEventRustQuerierC`.
353///
354unsafe impl AsRawPtr<HiSysEventRustQuerierC> for Querier {
355    fn as_raw(&self) -> *const HiSysEventRustQuerierC {
356        self.native
357    }
358
359    fn as_mut_raw(&mut self) -> *mut HiSysEventRustQuerierC {
360        self.native
361    }
362}
363
364/// Query system event.
365pub(crate) fn query(query_arg: &QueryArg, query_rules: &[QueryRule], querier: &Querier) -> i32 {
366    let query_arg_wrapper = HiSysEventQueryArg {
367        begin_time: query_arg.begin_time as c_longlong,
368        end_time: query_arg.end_time as c_longlong,
369        max_events: query_arg.max_events as c_int,
370    };
371    let mut query_rules_wrapper: Vec<HiSysEventQueryRuleWrapper> = vec![];
372    for i in 0..query_rules.len() {
373        let condition_wrapper = CString::new(query_rules[i].condition).expect("Need a condition for query.");
374        query_rules_wrapper.push(HiSysEventQueryRuleWrapper {
375            domain: [0; MAX_LENGTH_OF_EVENT_DOMAIN],
376            event_list: [0; MAX_EVENT_LIST_LEN],
377            event_list_size: MAX_NUMBER_OF_EVENT_LIST as c_uint,
378            condition: condition_wrapper.as_ptr() as *const c_char,
379        });
380        crate::utils::trans_slice_to_array(query_rules[i].domain, &mut query_rules_wrapper[i].domain);
381        let src_len = query_rules[i].event_list.len();
382        let dest_len = query_rules_wrapper[i].event_list.len();
383        let total_cnt = if src_len <= dest_len {
384            src_len
385        } else {
386            dest_len
387        };
388        query_rules_wrapper[i].event_list_size = total_cnt as c_uint;
389        let src_str = query_rules[i].event_list.join("|");
390        let src_str = &src_str[..];
391        crate::utils::trans_slice_to_array(src_str, &mut query_rules_wrapper[i].event_list);
392    }
393    // Safty: call C ffi border function, all risks are under control.
394    unsafe {
395        HiSysEventQueryWrapper(&query_arg_wrapper as *const HiSysEventQueryArg,
396            query_rules_wrapper.as_mut_ptr(),
397            query_rules.len() as c_uint,
398            querier.as_raw(),
399        )
400    }
401}
402
403/// Callback when receive system event.
404pub type OnEvent = unsafe extern "C" fn (
405    callback: *mut c_void,
406    record: HiSysEventRecord
407);
408
409/// Callback when hisysevent service shutdown.
410pub type OnServiceDied = unsafe extern "C" fn (
411    callback: *mut c_void,
412);
413
414/// This type represent a rust HiSysEventWatcher which like C++ HiSysEventWatcher.
415#[repr(C)]
416struct HiSysEventRustWatcherC {
417    pub on_event_cb: *mut c_void,
418    pub on_event_wrapper_cb: OnEvent,
419    pub on_service_died_cb: *mut c_void,
420    pub on_service_died_wrapper_cb: OnServiceDied,
421}
422
423/// This type represent a rust interfaces.
424#[allow(dead_code)]
425pub struct Watcher {
426    /// Native event listener instance
427    native: *mut HiSysEventRustWatcherC,
428
429    /// Customized rust callback on event
430    on_event_callback: *mut c_void,
431
432    /// Customized rust callback on service died
433    on_service_died_callback: *mut c_void,
434}
435
436impl Watcher {
437    /// Create a rust HiSysEventRustWatcherC object with callbacks in a watcher.
438    pub fn new<F1, F2>(on_event_callback: F1, on_service_died_callback: F2) -> Option<Self>
439    where
440        F1: Fn(HiSysEventRecord) + Send + Sync + 'static,
441        F2: Fn() + Send + Sync + 'static,
442    {
443        let on_event_callback = Box::into_raw(Box::new(on_event_callback));
444        let on_service_died_callback = Box::into_raw(Box::new(on_service_died_callback));
445        let native = unsafe {
446            CreateRustEventWatcher(on_event_callback as *mut c_void, Self::on_event::<F1>,
447                on_service_died_callback as *mut c_void, Self::on_service_died::<F2>)
448        };
449        if native.is_null() {
450            None
451        } else {
452            Some(Self {
453                native,
454                on_event_callback: on_event_callback as *mut c_void,
455                on_service_died_callback: on_service_died_callback as *mut c_void,
456            })
457        }
458    }
459
460    /// Callback when receive system event.
461    ///
462    /// # Safety
463    ///
464    /// The callback parameter will be kept valid during native
465    /// HiSysEventRustWatcherC object lifetime.
466    ///
467    unsafe extern "C" fn on_event<F>(callback: *mut c_void, record: HiSysEventRecord)
468    where
469        F: Fn(HiSysEventRecord) + Send + Sync + 'static,
470    {
471        let callback = (callback as *const F).as_ref().unwrap();
472        callback(record);
473    }
474
475    /// Callback when hisysevent service shutdown.
476    ///
477    /// # Safety
478    ///
479    /// The callback parameter will be kept valid during native
480    /// HiSysEventRustWatcherC object lifetime.
481    ///
482    unsafe extern "C" fn on_service_died<F>(callback: *mut c_void)
483    where
484        F: Fn() + Send + Sync + 'static,
485    {
486        let callback = (callback as *const F).as_ref().unwrap();
487        callback();
488    }
489
490    /// free memories allocated for Watcher
491    pub fn try_to_recycle(&self) {
492        unsafe {
493            RecycleRustEventWatcher(self.as_raw())
494        }
495    }
496}
497
498/// Implement trait AsRawPtr for Watcher
499///
500/// # Safety
501///
502/// A `Watcher` is always constructed with a valid raw pointer
503/// to a `HiSysEventRustWatcherC`.
504///
505unsafe impl AsRawPtr<HiSysEventRustWatcherC> for Watcher {
506    fn as_raw(&self) -> *const HiSysEventRustWatcherC {
507        self.native
508    }
509
510    fn as_mut_raw(&mut self) -> *mut HiSysEventRustWatcherC {
511        self.native
512    }
513}
514
515/// Add watcher to watch system event.
516pub(crate) fn add_watcher(watcher: &Watcher, watch_rules: &[WatchRule]) -> i32 {
517    let mut watch_rules_wrapper: Vec<HiSysEventWatchRule> = vec![];
518    for i in 0..watch_rules.len() {
519        watch_rules_wrapper.push(HiSysEventWatchRule {
520            domain: [0; MAX_LENGTH_OF_EVENT_DOMAIN],
521            name: [0; MAX_LENGTH_OF_EVENT_NAME],
522            tag: [0; MAX_LENGTH_OF_EVENT_TAG],
523            rule_type: 0,
524            event_type: 0,
525        });
526        crate::utils::trans_slice_to_array(watch_rules[i].domain, &mut watch_rules_wrapper[i].domain);
527        crate::utils::trans_slice_to_array(watch_rules[i].name, &mut watch_rules_wrapper[i].name);
528        crate::utils::trans_slice_to_array(watch_rules[i].tag, &mut watch_rules_wrapper[i].tag);
529        watch_rules_wrapper[i].rule_type = watch_rules[i].rule_type as i32 as c_int;
530        watch_rules_wrapper[i].event_type = watch_rules[i].event_type as i32 as c_int;
531    }
532    // Safty: call C ffi border function, all risks are under control.
533    unsafe {
534        HiSysEventAddWatcherWrapper(watcher.as_raw(),
535            watch_rules_wrapper.as_mut_ptr(),
536            watch_rules.len() as c_uint)
537    }
538}
539
540/// Remove watcher.
541pub(crate) fn remove_watcher(watcher: &Watcher) -> i32 {
542    // Safty: call C ffi border function, all risks are under control.
543    unsafe {
544        HiSysEventRemoveWatcherWrapper(watcher.as_raw())
545    }
546}
547
548/// Trait for transparent Rust wrappers around native raw pointer types.
549///
550/// # Safety
551///
552/// The pointer return by this trait's methods should be immediately passed to
553/// native and not stored by Rust. The pointer is valid only as long as the
554/// underlying native object is alive, so users must be careful to take this into
555/// account, as Rust cannot enforce this.
556///
557/// For this trait to be a correct implementation, `T` must be a valid native
558/// type. Since we cannot constrain this via the type system, this trait is
559/// marked as unsafe.
560///
561unsafe trait AsRawPtr<T> {
562    /// Return a pointer to the native version of `self`
563    fn as_raw(&self) -> *const T;
564
565    /// Return a mutable pointer to the native version of `self`
566    fn as_mut_raw(&mut self) -> *mut T;
567}
568
569extern "C" {
570    /// ffi border function.
571    fn HiSysEventAddWatcherWrapper(watcher: *const HiSysEventRustWatcherC, rules: *const HiSysEventWatchRule,
572        rule_size: c_uint) -> c_int;
573
574    /// ffi border function.
575    fn HiSysEventRemoveWatcherWrapper(watcher: *const HiSysEventRustWatcherC) -> c_int;
576
577    /// ffi border function.
578    fn HiSysEventQueryWrapper(query_arg: *const HiSysEventQueryArg, rules: *const HiSysEventQueryRuleWrapper,
579        rule_size: c_uint, querier: *const HiSysEventRustQuerierC) -> c_int;
580
581    /// ffi border function.
582    fn GetHiSysEventRecordByIndexWrapper(records: *const HiSysEventRecord, total: c_uint,
583        index: c_uint) -> HiSysEventRecord;
584
585    /// ffi border function.
586    fn CreateRustEventWatcher(on_event_callback: *const c_void,
587        on_event_wrapper_callback: OnEvent,
588        on_service_died_callback: *const c_void,
589        on_service_died_wrapper_callback: OnServiceDied) -> *mut HiSysEventRustWatcherC;
590
591    /// ffi border function.
592    fn RecycleRustEventWatcher(watcher: *const HiSysEventRustWatcherC);
593
594    /// ffi border function.
595    fn CreateRustEventQuerier(on_query_callback: *const c_void,
596        on_query_wrapper_callback: OnQuery,
597        on_complete_callback: *const c_void,
598        on_complete_wrapper_callback: OnComplete) -> *mut HiSysEventRustQuerierC;
599
600    /// ffi border function.
601    fn RecycleRustEventQuerier(querier: *const HiSysEventRustQuerierC);
602}
603