Skip to main content

opcua/types/
request_header.rs

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