1use std::io::{Cursor, Read, Write};
9
10use opcua_types::{status_code::StatusCode, *};
11
12use crate::comms::{
13 message_chunk_info::ChunkInfo,
14 secure_channel::SecureChannel,
15 security_header::{
16 AsymmetricSecurityHeader, SecurityHeader, SequenceHeader, SymmetricSecurityHeader,
17 },
18 tcp_types::{
19 CHUNK_FINAL, CHUNK_FINAL_ERROR, CHUNK_INTERMEDIATE, CHUNK_MESSAGE,
20 CLOSE_SECURE_CHANNEL_MESSAGE, MIN_CHUNK_SIZE, OPEN_SECURE_CHANNEL_MESSAGE,
21 },
22};
23
24pub const MESSAGE_CHUNK_HEADER_SIZE: usize = 12;
26
27#[derive(Debug, Clone, Copy, PartialEq)]
28pub enum MessageChunkType {
29 Message,
30 OpenSecureChannel,
31 CloseSecureChannel,
32}
33
34impl MessageChunkType {
35 pub fn is_open_secure_channel(&self) -> bool {
36 *self == MessageChunkType::OpenSecureChannel
37 }
38}
39
40#[derive(Debug, Clone, Copy, PartialEq)]
41pub enum MessageIsFinalType {
42 Intermediate,
44 Final,
46 FinalError,
48}
49
50#[derive(Debug, Clone, PartialEq)]
51pub struct MessageChunkHeader {
52 pub message_type: MessageChunkType,
54 pub is_final: MessageIsFinalType,
56 pub message_size: u32,
58 pub secure_channel_id: u32,
60}
61
62impl BinaryEncoder<MessageChunkHeader> for MessageChunkHeader {
63 fn byte_len(&self) -> usize {
64 MESSAGE_CHUNK_HEADER_SIZE
65 }
66
67 fn encode<S: Write>(&self, stream: &mut S) -> EncodingResult<usize> {
68 let message_type = match self.message_type {
69 MessageChunkType::Message => CHUNK_MESSAGE,
70 MessageChunkType::OpenSecureChannel => OPEN_SECURE_CHANNEL_MESSAGE,
71 MessageChunkType::CloseSecureChannel => CLOSE_SECURE_CHANNEL_MESSAGE,
72 };
73
74 let is_final = match self.is_final {
75 MessageIsFinalType::Intermediate => CHUNK_INTERMEDIATE,
76 MessageIsFinalType::Final => CHUNK_FINAL,
77 MessageIsFinalType::FinalError => CHUNK_FINAL_ERROR,
78 };
79
80 let mut size = 0;
81 size += process_encode_io_result(stream.write(message_type))?;
82 size += write_u8(stream, is_final)?;
83 size += write_u32(stream, self.message_size)?;
84 size += write_u32(stream, self.secure_channel_id)?;
85 assert_eq!(size, self.byte_len());
86 Ok(size)
87 }
88
89 fn decode<S: Read>(stream: &mut S, _: &DecodingOptions) -> EncodingResult<Self> {
90 let mut message_type_code = [0u8; 3];
91 process_decode_io_result(stream.read_exact(&mut message_type_code))?;
92 let message_type = if message_type_code == CHUNK_MESSAGE {
93 MessageChunkType::Message
94 } else if message_type_code == OPEN_SECURE_CHANNEL_MESSAGE {
95 MessageChunkType::OpenSecureChannel
96 } else if message_type_code == CLOSE_SECURE_CHANNEL_MESSAGE {
97 MessageChunkType::CloseSecureChannel
98 } else {
99 error!("Invalid message code");
100 return Err(StatusCode::BadDecodingError);
101 };
102
103 let chunk_type_code = read_u8(stream)?;
104 let is_final = match chunk_type_code {
105 CHUNK_FINAL => MessageIsFinalType::Final,
106 CHUNK_INTERMEDIATE => MessageIsFinalType::Intermediate,
107 CHUNK_FINAL_ERROR => MessageIsFinalType::FinalError,
108 _ => {
109 error!("Invalid chunk type");
110 return Err(StatusCode::BadDecodingError);
111 }
112 };
113
114 let message_size = read_u32(stream)?;
115 let secure_channel_id = read_u32(stream)?;
116
117 Ok(MessageChunkHeader {
118 message_type,
119 is_final,
120 message_size,
121 secure_channel_id,
122 })
123 }
124}
125
126impl MessageChunkHeader {}
127
128#[derive(Debug)]
132pub struct MessageChunk {
133 pub data: Vec<u8>,
135}
136
137impl BinaryEncoder<MessageChunk> for MessageChunk {
138 fn byte_len(&self) -> usize {
139 self.data.len()
140 }
141
142 fn encode<S: Write>(&self, stream: &mut S) -> EncodingResult<usize> {
143 stream.write(&self.data).map_err(|_| {
144 error!("Encoding error while writing to stream");
145 StatusCode::BadEncodingError
146 })
147 }
148
149 fn decode<S: Read>(
150 in_stream: &mut S,
151 decoding_options: &DecodingOptions,
152 ) -> EncodingResult<Self> {
153 let chunk_header =
155 MessageChunkHeader::decode(in_stream, decoding_options).map_err(|err| {
156 error!("Cannot decode chunk header {:?}", err);
157 StatusCode::BadCommunicationError
158 })?;
159
160 let message_size = chunk_header.message_size as usize;
161 if decoding_options.max_chunk_count > 0 && message_size > decoding_options.max_chunk_count {
162 Err(StatusCode::BadTcpMessageTooLarge)
164 } else {
165 let data = vec![0u8; message_size];
167 let mut stream = Cursor::new(data);
168
169 let chunk_header_size = chunk_header.encode(&mut stream)?;
171 assert_eq!(chunk_header_size, MESSAGE_CHUNK_HEADER_SIZE);
172
173 let mut data = stream.into_inner();
175
176 let _ = in_stream.read_exact(&mut data[chunk_header_size..]);
178
179 Ok(MessageChunk { data })
180 }
181 }
182}
183
184impl MessageChunk {
185 pub fn new(
186 sequence_number: u32,
187 request_id: u32,
188 message_type: MessageChunkType,
189 is_final: MessageIsFinalType,
190 secure_channel: &SecureChannel,
191 data: &[u8],
192 ) -> Result<MessageChunk, StatusCode> {
193 let security_header = secure_channel.make_security_header(message_type);
195 let sequence_header = SequenceHeader {
196 sequence_number,
197 request_id,
198 };
199
200 let mut message_size = MESSAGE_CHUNK_HEADER_SIZE;
202 message_size += security_header.byte_len();
203 message_size += sequence_header.byte_len();
204 message_size += data.len();
205
206 trace!(
207 "Creating a chunk with a size of {}, data excluding padding & signature",
208 message_size
209 );
210 let secure_channel_id = secure_channel.secure_channel_id();
211 let chunk_header = MessageChunkHeader {
212 message_type,
213 is_final,
214 message_size: message_size as u32,
215 secure_channel_id,
216 };
217
218 let mut stream = Cursor::new(vec![0u8; message_size]);
219 let _ = chunk_header.encode(&mut stream);
221 let _ = security_header.encode(&mut stream);
223 let _ = sequence_header.encode(&mut stream);
225 let _ = stream.write(data);
227
228 Ok(MessageChunk {
229 data: stream.into_inner(),
230 })
231 }
232
233 pub fn body_size_from_message_size(
237 message_type: MessageChunkType,
238 secure_channel: &SecureChannel,
239 message_size: usize,
240 ) -> Result<usize, ()> {
241 if message_size < MIN_CHUNK_SIZE {
242 error!(
243 "message size {} is less than minimum allowed by the spec",
244 message_size
245 );
246 Err(())
247 } else {
248 let security_header = secure_channel.make_security_header(message_type);
249
250 let mut data_size = MESSAGE_CHUNK_HEADER_SIZE;
251 data_size += security_header.byte_len();
252 data_size += (SequenceHeader {
253 sequence_number: 0,
254 request_id: 0,
255 })
256 .byte_len();
257
258 let signature_size = secure_channel.signature_size(&security_header);
260 data_size += secure_channel
261 .padding_size(&security_header, 1, signature_size)
262 .0;
263
264 data_size += signature_size;
266
267 Ok(message_size - data_size)
269 }
270 }
271
272 pub fn message_header(
273 &self,
274 decoding_options: &DecodingOptions,
275 ) -> Result<MessageChunkHeader, StatusCode> {
276 let mut stream = Cursor::new(&self.data);
278 MessageChunkHeader::decode(&mut stream, decoding_options)
279 }
280
281 pub fn security_header(
282 &self,
283 decoding_options: &DecodingOptions,
284 ) -> Result<SecurityHeader, StatusCode> {
285 let mut stream = Cursor::new(&self.data);
287 let message_header = MessageChunkHeader::decode(&mut stream, decoding_options)?;
288 let security_header = if message_header.message_type == MessageChunkType::OpenSecureChannel
289 {
290 SecurityHeader::Asymmetric(AsymmetricSecurityHeader::decode(
291 &mut stream,
292 decoding_options,
293 )?)
294 } else {
295 SecurityHeader::Symmetric(SymmetricSecurityHeader::decode(
296 &mut stream,
297 decoding_options,
298 )?)
299 };
300 Ok(security_header)
301 }
302
303 pub fn is_open_secure_channel(&self, decoding_options: &DecodingOptions) -> bool {
304 if let Ok(message_header) = self.message_header(decoding_options) {
305 message_header.message_type.is_open_secure_channel()
306 } else {
307 false
308 }
309 }
310
311 pub fn chunk_info(
312 &self,
313 secure_channel: &SecureChannel,
314 ) -> std::result::Result<ChunkInfo, StatusCode> {
315 ChunkInfo::new(self, secure_channel)
316 }
317}