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}