opcua_types/
request_header.rs

1// OPCUA for Rust
2// SPDX-License-Identifier: MPL-2.0
3// Copyright (C) 2017-2024 Adam Lock
4
5//! Message header for requests.
6
7use std::{
8    self,
9    io::{Read, Write},
10};
11
12use crate::{
13    data_types::*,
14    date_time::DateTime,
15    diagnostic_info::DiagnosticBits,
16    encoding::{BinaryDecodable, BinaryEncodable, EncodingResult},
17    extension_object::ExtensionObject,
18    node_id::NodeId,
19    string::UAString,
20    Error,
21};
22
23#[allow(unused)]
24mod opcua {
25    pub(super) use crate as types;
26}
27
28/// The `RequestHeader` contains information common to every request from a client to the server.
29#[derive(Debug, Clone, PartialEq, crate::UaNullable)]
30#[cfg_attr(
31    feature = "json",
32    derive(opcua_macros::JsonEncodable, opcua_macros::JsonDecodable)
33)]
34#[cfg_attr(
35    feature = "xml",
36    derive(crate::XmlEncodable, crate::XmlDecodable, crate::XmlType)
37)]
38pub struct RequestHeader {
39    /// The secret Session identifier used to verify that the request is associated with
40    /// the Session. The SessionAuthenticationToken type is defined in 7.31.
41    pub authentication_token: NodeId,
42    /// The time the Client sent the request. The parameter is only used for diagnostic and logging
43    /// purposes in the server.
44    pub timestamp: UtcTime,
45    ///  A requestHandle associated with the request. This client defined handle can be
46    /// used to cancel the request. It is also returned in the response.
47    pub request_handle: IntegerId,
48    /// A bit mask that identifies the types of vendor-specific diagnostics to be returned
49    /// in diagnosticInfo response parameters. The value of this parameter may consist of
50    /// zero, one or more of the following values. No value indicates that diagnostics
51    /// are not to be returned.
52    ///
53    /// Bit Value   Diagnostics to return
54    /// 0x0000 0001 ServiceLevel / SymbolicId
55    /// 0x0000 0002 ServiceLevel / LocalizedText
56    /// 0x0000 0004 ServiceLevel / AdditionalInfo
57    /// 0x0000 0008 ServiceLevel / Inner StatusCode
58    /// 0x0000 0010 ServiceLevel / Inner Diagnostics
59    /// 0x0000 0020 OperationLevel / SymbolicId
60    /// 0x0000 0040 OperationLevel / LocalizedText
61    /// 0x0000 0080 OperationLevel / AdditionalInfo
62    /// 0x0000 0100 OperationLevel / Inner StatusCode
63    /// 0x0000 0200 OperationLevel / Inner Diagnostics
64    ///
65    /// Each of these values is composed of two components, level and type, as described
66    /// below. If none are requested, as indicated by a 0 value, or if no diagnostic
67    /// information was encountered in processing of the request, then diagnostics information
68    /// is not returned.
69    ///
70    /// Level:
71    ///   ServiceLevel return diagnostics in the diagnosticInfo of the Service.
72    ///   OperationLevel return diagnostics in the diagnosticInfo defined for individual
73    ///   operations requested in the Service.
74    ///
75    /// Type:
76    ///   SymbolicId  return a namespace-qualified, symbolic identifier for an error
77    ///     or condition. The maximum length of this identifier is 32 characters.
78    ///   LocalizedText return up to 256 bytes of localized text that describes the
79    ///     symbolic id.
80    ///   AdditionalInfo return a byte string that contains additional diagnostic
81    ///     information, such as a memory image. The format of this byte string is
82    ///     vendor-specific, and may depend on the type of error or condition encountered.
83    ///   InnerStatusCode return the inner StatusCode associated with the operation or Service.
84    ///   InnerDiagnostics return the inner diagnostic info associated with the operation or Service.
85    ///     The contents of the inner diagnostic info structure are determined by other bits in the
86    ///     mask. Note that setting this bit could cause multiple levels of nested
87    ///     diagnostic info structures to be returned.
88    pub return_diagnostics: DiagnosticBits,
89    /// An identifier that identifies the Client’s security audit log entry associated with
90    /// this request. An empty string value means that this parameter is not used. The AuditEntryId
91    /// typically contains who initiated the action and from where it was initiated.
92    /// The AuditEventId is included in the AuditEvent to allow human readers to correlate an Event
93    /// with the initiating action. More details of the Audit mechanisms are defined in 6.2
94    /// and in Part 3.
95    pub audit_entry_id: UAString,
96    /// This timeout in milliseconds is used in the Client side Communication Stack to set the
97    /// timeout on a per-call base. For a Server this timeout is only a hint and can be
98    /// used to cancel long running operations to free resources. If the Server detects a
99    /// timeout, he can cancel the operation by sending the Service result BadTimeout.
100    /// The Server should wait at minimum the timeout after he received the request before
101    /// cancelling the operation. The Server shall check the timeoutHint parameter of a
102    /// PublishRequest before processing a PublishResponse. If the request timed out, a
103    /// BadTimeout Service result is sent and another PublishRequest is used.  The
104    /// value of 0 indicates no timeout.
105    pub timeout_hint: u32,
106    /// Reserved for future use. Applications that do not understand the header should ignore it.
107    pub additional_header: ExtensionObject,
108}
109
110impl Default for RequestHeader {
111    fn default() -> Self {
112        Self {
113            authentication_token: NodeId::default(),
114            timestamp: DateTime::default(),
115            request_handle: 0,
116            return_diagnostics: DiagnosticBits::empty(),
117            audit_entry_id: Default::default(),
118            timeout_hint: 0,
119            additional_header: Default::default(),
120        }
121    }
122}
123
124impl BinaryEncodable for RequestHeader {
125    fn byte_len(&self, ctx: &opcua::types::Context<'_>) -> usize {
126        let mut size: usize = 0;
127        size += self.authentication_token.byte_len(ctx);
128        size += self.timestamp.byte_len(ctx);
129        size += self.request_handle.byte_len(ctx);
130        size += self.return_diagnostics.bits().byte_len(ctx);
131        size += self.audit_entry_id.byte_len(ctx);
132        size += self.timeout_hint.byte_len(ctx);
133        size += self.additional_header.byte_len(ctx);
134        size
135    }
136
137    fn encode<S: Write + ?Sized>(
138        &self,
139        stream: &mut S,
140        ctx: &crate::Context<'_>,
141    ) -> EncodingResult<()> {
142        self.authentication_token.encode(stream, ctx)?;
143        self.timestamp.encode(stream, ctx)?;
144        self.request_handle.encode(stream, ctx)?;
145        self.return_diagnostics.bits().encode(stream, ctx)?;
146        self.audit_entry_id.encode(stream, ctx)?;
147        self.timeout_hint.encode(stream, ctx)?;
148        self.additional_header.encode(stream, ctx)
149    }
150}
151
152impl BinaryDecodable for RequestHeader {
153    fn decode<S: Read + ?Sized>(stream: &mut S, ctx: &crate::Context<'_>) -> EncodingResult<Self> {
154        let authentication_token = NodeId::decode(stream, ctx)?;
155        let timestamp = UtcTime::decode(stream, ctx)?;
156        let request_handle = IntegerId::decode(stream, ctx)?;
157        let (return_diagnostics, audit_entry_id, timeout_hint, additional_header) = (|| {
158            let return_diagnostics = DiagnosticBits::from_bits_truncate(u32::decode(stream, ctx)?);
159            let audit_entry_id = UAString::decode(stream, ctx)?;
160            let timeout_hint = u32::decode(stream, ctx)?;
161            let additional_header = ExtensionObject::decode(stream, ctx)?;
162            Ok((
163                return_diagnostics,
164                audit_entry_id,
165                timeout_hint,
166                additional_header,
167            ))
168        })()
169        .map_err(|e: Error| e.with_request_handle(request_handle))?;
170
171        Ok(RequestHeader {
172            authentication_token,
173            timestamp,
174            request_handle,
175            return_diagnostics,
176            audit_entry_id,
177            timeout_hint,
178            additional_header,
179        })
180    }
181}
182
183impl RequestHeader {
184    /// Create a new request header.
185    pub fn new(
186        authentication_token: &NodeId,
187        timestamp: &DateTime,
188        request_handle: IntegerId,
189    ) -> RequestHeader {
190        RequestHeader {
191            authentication_token: authentication_token.clone(),
192            timestamp: *timestamp,
193            request_handle,
194            return_diagnostics: DiagnosticBits::empty(),
195            audit_entry_id: UAString::null(),
196            timeout_hint: 0,
197            additional_header: ExtensionObject::null(),
198        }
199    }
200
201    /// Create a new dummy request header.
202    pub fn dummy() -> RequestHeader {
203        RequestHeader::new(&NodeId::null(), &DateTime::now(), 1)
204    }
205}