opcua_core/
lib.rs

1// OPCUA for Rust
2// SPDX-License-Identifier: MPL-2.0
3// Copyright (C) 2017-2022 Adam Lock
4
5//! The OPC UA Core module holds functionality that is common to server and clients that make use of OPC UA.
6//! It contains message chunking, cryptography / pki, communications and standard handshake messages.
7
8#[macro_use]
9extern crate lazy_static;
10#[macro_use]
11extern crate log;
12#[macro_use]
13extern crate serde_derive;
14#[cfg(test)]
15extern crate tempdir;
16
17#[macro_export]
18macro_rules! supported_message_as {
19    ($v: expr, $i: ident) => {
20        if let SupportedMessage::$i(value) = $v {
21            *value
22        } else {
23            panic!();
24        }
25    };
26}
27
28/// Tracing macro for obtaining a lock on a `Mutex`. Sometimes deadlocks can happen in code,
29/// and if they do, this macro is useful for finding out where they happened.
30#[macro_export]
31macro_rules! trace_lock {
32    ( $x:expr ) => {
33        {
34//            use std::thread;
35//            trace!("Thread {:?}, {} locking at {}, line {}", thread::current().id(), stringify!($x), file!(), line!());
36            let v = $x.lock().unwrap();
37//            trace!("Thread {:?}, {} lock completed", thread::current().id(), stringify!($x));
38            v
39        }
40    }
41}
42
43/// Tracing macro for obtaining a read lock on a `RwLock`.
44#[macro_export]
45macro_rules! trace_read_lock {
46    ( $x:expr ) => {
47        {
48//            use std::thread;
49//            trace!("Thread {:?}, {} read locking at {}, line {}", thread::current().id(), stringify!($x), file!(), line!());
50            let v = $x.read().unwrap();
51//            trace!("Thread {:?}, {} read lock completed", thread::current().id(), stringify!($x));
52            v
53        }
54    }
55}
56
57/// Tracing macro for obtaining a write lock on a `RwLock`.
58#[macro_export]
59macro_rules! trace_write_lock {
60    ( $x:expr ) => {
61        {
62//            use std::thread;
63//            trace!("Thread {:?}, {} write locking at {}, line {}", thread::current().id(), stringify!($x), file!(), line!());
64            let v = $x.write().unwrap();
65//            trace!("Thread {:?}, {} write lock completed", thread::current().id(), stringify!($x));
66            v
67        }
68    }
69}
70
71lazy_static! {
72    pub static ref RUNTIME: crate::runtime::Runtime = crate::runtime::Runtime::default();
73}
74
75/// Returns a vector of all currently existing runtime components as a vector of strings.
76#[macro_export]
77macro_rules! runtime_components {
78    () => {{
79        use opcua_core::RUNTIME;
80        RUNTIME.components()
81    }};
82}
83
84/// This macro is for debugging purposes - code register a running component (e.g. tokio task) when it starts
85/// and calls the corresponding deregister macro when it finishes. This enables the code to print
86/// out a list of components in existence at any time to ensure they were properly cleaned up.
87#[macro_export]
88macro_rules! register_runtime_component {
89    ( $component_name:expr ) => {
90        RUNTIME.register_component($component_name);
91    };
92}
93
94/// See `register_runtime_component`
95#[macro_export]
96macro_rules! deregister_runtime_component {
97    ( $component_name:expr ) => {
98        RUNTIME.deregister_component($component_name);
99    };
100}
101
102/// Contains debugging utility helper functions
103pub mod debug {
104    /// Prints out the content of a slice in hex and visible char format to aid debugging. Format
105    /// is similar to corresponding functionality in node-opcua
106    pub fn log_buffer(message: &str, buf: &[u8]) {
107        // No point doing anything unless debug level is on
108        if !log_enabled!(target: "hex", log::Level::Trace) {
109            return;
110        }
111
112        let line_len = 32;
113        let len = buf.len();
114        let last_line_padding = ((len / line_len) + 1) * line_len - len;
115
116        trace!(target: "hex", "{}", message);
117
118        let mut char_line = String::new();
119        let mut hex_line = format!("{:08x}: ", 0);
120
121        for (i, b) in buf.iter().enumerate() {
122            let value = *b as u8;
123            if i > 0 && i % line_len == 0 {
124                trace!(target: "hex", "{} {}", hex_line, char_line);
125                hex_line = format!("{:08}: ", i);
126                char_line.clear();
127            }
128            hex_line = format!("{} {:02x}", hex_line, value);
129            char_line.push(if value >= 32 && value <= 126 {
130                value as char
131            } else {
132                '.'
133            });
134        }
135        if last_line_padding > 0 {
136            for _ in 0..last_line_padding {
137                hex_line.push_str("   ");
138            }
139            trace!(target: "hex", "{} {}", hex_line, char_line);
140        }
141    }
142}
143
144#[cfg(test)]
145mod tests;
146
147pub mod comms;
148pub mod config;
149pub mod handle;
150pub mod runtime;
151#[rustfmt::skip]
152pub mod supported_message;
153
154/// Contains most of the things that are typically required from a client / server.
155pub mod prelude {
156    pub use crate::comms::prelude::*;
157    pub use crate::config::Config;
158    pub use crate::supported_message::*;
159    pub use opcua_types::status_code::StatusCode;
160    pub use opcua_types::*;
161}