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}