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::{
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 BinaryEncoder<RequestHeader> for RequestHeader {
90    fn byte_len(&self) -> usize {
91        let mut size: usize = 0;
92        size += self.authentication_token.byte_len();
93        size += self.timestamp.byte_len();
94        size += self.request_handle.byte_len();
95        size += self.return_diagnostics.bits().byte_len();
96        size += self.audit_entry_id.byte_len();
97        size += self.timeout_hint.byte_len();
98        size += self.additional_header.byte_len();
99        size
100    }
101
102    fn encode<S: Write>(&self, stream: &mut S) -> EncodingResult<usize> {
103        let mut size: usize = 0;
104        size += self.authentication_token.encode(stream)?;
105        size += self.timestamp.encode(stream)?;
106        size += self.request_handle.encode(stream)?;
107        size += self.return_diagnostics.bits().encode(stream)?;
108        size += self.audit_entry_id.encode(stream)?;
109        size += self.timeout_hint.encode(stream)?;
110        size += self.additional_header.encode(stream)?;
111        Ok(size)
112    }
113
114    fn decode<S: Read>(stream: &mut S, decoding_options: &DecodingOptions) -> EncodingResult<Self> {
115        let authentication_token = NodeId::decode(stream, decoding_options)?;
116        let timestamp = UtcTime::decode(stream, decoding_options)?;
117        let request_handle = IntegerId::decode(stream, decoding_options)?;
118        let return_diagnostics =
119            DiagnosticBits::from_bits_truncate(u32::decode(stream, decoding_options)?);
120        let audit_entry_id = UAString::decode(stream, decoding_options)?;
121        let timeout_hint = u32::decode(stream, decoding_options)?;
122        let additional_header = ExtensionObject::decode(stream, decoding_options)?;
123        Ok(RequestHeader {
124            authentication_token,
125            timestamp,
126            request_handle,
127            return_diagnostics,
128            audit_entry_id,
129            timeout_hint,
130            additional_header,
131        })
132    }
133}
134
135impl RequestHeader {
136    pub fn new(
137        authentication_token: &NodeId,
138        timestamp: &DateTime,
139        request_handle: IntegerId,
140    ) -> RequestHeader {
141        RequestHeader {
142            authentication_token: authentication_token.clone(),
143            timestamp: *timestamp,
144            request_handle,
145            return_diagnostics: DiagnosticBits::empty(),
146            audit_entry_id: UAString::null(),
147            timeout_hint: 0,
148            additional_header: ExtensionObject::null(),
149        }
150    }
151
152    pub fn dummy() -> RequestHeader {
153        RequestHeader::new(&NodeId::null(), &DateTime::now(), 1)
154    }
155}