1use ironrdp_core::{
2 cast_length, ensure_size, invalid_field_err, other_err, Decode, DecodeResult, Encode, EncodeResult, ReadCursor,
3 WriteCursor,
4};
5
6use super::{ClientGccBlocks, ServerGccBlocks};
7use crate::{mcs, per};
8
9const CONFERENCE_REQUEST_OBJECT_ID: [u8; 6] = [0, 0, 20, 124, 0, 1];
10const CONFERENCE_REQUEST_CLIENT_TO_SERVER_H221_NON_STANDARD: &[u8; 4] = b"Duca";
11const CONFERENCE_REQUEST_SERVER_TO_CLIENT_H221_NON_STANDARD: &[u8; 4] = b"McDn";
12const CONFERENCE_REQUEST_U16_MIN: u16 = 1001;
13
14const CONFERENCE_REQUEST_CONNECT_PDU_SIZE: usize = 12;
15const CONFERENCE_RESPONSE_CONNECT_PDU_SIZE: usize = 13;
16const OBJECT_IDENTIFIER_KEY: u8 = 0;
17const CONNECT_GCC_PDU_CONFERENCE_REQUEST_CHOICE: u8 = 0;
18const CONNECT_GCC_PDU_CONFERENCE_RESPONSE_CHOICE: u8 = 0x14;
19const CONFERENCE_REQUEST_USER_DATA_SELECTION: u8 = 8;
20const USER_DATA_NUMBER_OF_SETS: u8 = 1;
21const USER_DATA_H221_NON_STANDARD_CHOICE: u8 = 0xc0;
22const CONFERENCE_RESPONSE_TAG: u32 = 1;
23const CONFERENCE_RESPONSE_RESULT: u8 = 0;
24const H221_NON_STANDARD_MIN_LENGTH: usize = 4;
25const CONFERENCE_NAME: &[u8] = b"1";
26
27#[derive(Clone, Debug, PartialEq, Eq)]
28pub struct ConferenceCreateRequest {
29 pub gcc_blocks: ClientGccBlocks,
30}
31
32impl ConferenceCreateRequest {
33 const NAME: &'static str = "ConferenceCreateRequest";
34}
35
36impl Encode for ConferenceCreateRequest {
37 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
38 ensure_size!(in:dst, size: self.size());
39
40 let gcc_blocks_buffer_length = self.gcc_blocks.size();
41
42 per::write_choice(dst, OBJECT_IDENTIFIER_KEY);
44 per::write_object_id(dst, CONFERENCE_REQUEST_OBJECT_ID);
46
47 per::write_length(
49 dst,
50 cast_length!(
51 "gccBlocksLen",
52 gcc_blocks_buffer_length + CONFERENCE_REQUEST_CONNECT_PDU_SIZE
53 )?,
54 );
55 per::write_choice(dst, CONNECT_GCC_PDU_CONFERENCE_REQUEST_CHOICE);
57 per::write_selection(dst, CONFERENCE_REQUEST_USER_DATA_SELECTION);
59 per::write_numeric_string(dst, CONFERENCE_NAME, 1).map_err(|e| other_err!("confName", source: e))?;
61 per::write_padding(dst, 1);
62 per::write_number_of_sets(dst, USER_DATA_NUMBER_OF_SETS);
65 per::write_choice(dst, USER_DATA_H221_NON_STANDARD_CHOICE);
67 per::write_octet_string(
69 dst,
70 CONFERENCE_REQUEST_CLIENT_TO_SERVER_H221_NON_STANDARD,
71 H221_NON_STANDARD_MIN_LENGTH,
72 )
73 .map_err(|e| other_err!("client-to-server", source: e))?;
74 per::write_length(dst, cast_length!("gccBlocksLen", gcc_blocks_buffer_length)?);
76 self.gcc_blocks.encode(dst)?;
77
78 Ok(())
79 }
80
81 fn name(&self) -> &'static str {
82 Self::NAME
83 }
84
85 fn size(&self) -> usize {
86 let gcc_blocks_buffer_length = self.gcc_blocks.size();
87 let req_length: DecodeResult<u16> = cast_length!(
88 "gccBlocksLen",
89 CONFERENCE_REQUEST_CONNECT_PDU_SIZE + gcc_blocks_buffer_length
90 );
91 let length: DecodeResult<u16> = cast_length!("gccBlocksLen", gcc_blocks_buffer_length);
92 per::CHOICE_SIZE
93 + CONFERENCE_REQUEST_OBJECT_ID.len()
94 + per::sizeof_length(req_length.unwrap())
95 + CONFERENCE_REQUEST_CONNECT_PDU_SIZE
96 + per::sizeof_length(length.unwrap())
97 + gcc_blocks_buffer_length
98 }
99}
100
101impl<'de> Decode<'de> for ConferenceCreateRequest {
102 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
103 ensure_size!(in: src, size: per::CHOICE_SIZE);
107 if per::read_choice(src) != OBJECT_IDENTIFIER_KEY {
108 return Err(invalid_field_err!("ConnectData::Key", "Got unexpected ConnectData key"));
109 }
110 if per::read_object_id(src).map_err(|e| other_err!("value", source: e))? != CONFERENCE_REQUEST_OBJECT_ID {
112 return Err(invalid_field_err!(
113 "ConnectData::Key",
114 "Got unexpected ConnectData key value"
115 ));
116 }
117
118 let _length = per::read_length(src).map_err(|e| other_err!("len", source: e))?;
120 ensure_size!(in: src, size: per::CHOICE_SIZE);
122 if per::read_choice(src) != CONNECT_GCC_PDU_CONFERENCE_REQUEST_CHOICE {
123 return Err(invalid_field_err!(
124 "ConnectData::connectPdu",
125 "Got invalid ConnectGCCPDU choice (expected ConferenceCreateRequest)"
126 ));
127 }
128 ensure_size!(in: src, size: per::CHOICE_SIZE);
130 if per::read_selection(src) != CONFERENCE_REQUEST_USER_DATA_SELECTION {
131 return Err(invalid_field_err!(
132 "ConferenceCreateRequest::Selection",
133 "Got invalid ConferenceCreateRequest selection (expected UserData)",
134 ));
135 }
136 per::read_numeric_string(src, 1).map_err(|e| other_err!("confName", source: e))?;
138 per::read_padding(src, 1);
140
141 ensure_size!(in: src, size: per::CHOICE_SIZE);
144 if per::read_number_of_sets(src) != USER_DATA_NUMBER_OF_SETS {
145 return Err(invalid_field_err!(
146 "ConferenceCreateRequest",
147 "Got invalid ConferenceCreateRequest number of sets (expected 1)",
148 ));
149 }
150 ensure_size!(in: src, size: per::CHOICE_SIZE);
152 if per::read_choice(src) != USER_DATA_H221_NON_STANDARD_CHOICE {
153 return Err(invalid_field_err!(
154 "ConferenceCreateRequest",
155 "Expected UserData H221NonStandard choice",
156 ));
157 }
158 if per::read_octet_string(src, H221_NON_STANDARD_MIN_LENGTH)
160 .map_err(|e| other_err!("client-to-server", source: e))?
161 != CONFERENCE_REQUEST_CLIENT_TO_SERVER_H221_NON_STANDARD
162 {
163 return Err(invalid_field_err!(
164 "ConferenceCreateRequest",
165 "Got invalid H221NonStandard client-to-server key",
166 ));
167 }
168 let (_gcc_blocks_buffer_length, _) = per::read_length(src).map_err(|e| other_err!("len", source: e))?;
170 let gcc_blocks = ClientGccBlocks::decode(src)?;
171
172 Ok(Self { gcc_blocks })
173 }
174}
175
176#[derive(Clone, Debug, PartialEq, Eq)]
177pub struct ConferenceCreateResponse {
178 pub user_id: u16,
179 pub gcc_blocks: ServerGccBlocks,
180}
181
182impl ConferenceCreateResponse {
183 const NAME: &'static str = "ConferenceCreateResponse";
184}
185
186impl Encode for ConferenceCreateResponse {
187 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
188 let gcc_blocks_buffer_length = self.gcc_blocks.size();
189
190 per::write_choice(dst, OBJECT_IDENTIFIER_KEY);
192 per::write_object_id(dst, CONFERENCE_REQUEST_OBJECT_ID);
194
195 per::write_length(
197 dst,
198 cast_length!(
199 "gccBlocksLen",
200 gcc_blocks_buffer_length + CONFERENCE_RESPONSE_CONNECT_PDU_SIZE + 1
201 )?,
202 );
203 per::write_choice(dst, CONNECT_GCC_PDU_CONFERENCE_RESPONSE_CHOICE);
205 per::write_u16(dst, self.user_id, CONFERENCE_REQUEST_U16_MIN).map_err(|e| other_err!("userId", source: e))?;
207 per::write_u32(dst, CONFERENCE_RESPONSE_TAG);
209 per::write_enum(dst, CONFERENCE_RESPONSE_RESULT);
211 per::write_number_of_sets(dst, USER_DATA_NUMBER_OF_SETS);
212 per::write_choice(dst, USER_DATA_H221_NON_STANDARD_CHOICE);
214 per::write_octet_string(
216 dst,
217 CONFERENCE_REQUEST_SERVER_TO_CLIENT_H221_NON_STANDARD,
218 H221_NON_STANDARD_MIN_LENGTH,
219 )
220 .map_err(|e| other_err!("server-to-client", source: e))?;
221 per::write_length(dst, gcc_blocks_buffer_length as u16);
223 self.gcc_blocks.encode(dst)?;
224
225 Ok(())
226 }
227
228 fn name(&self) -> &'static str {
229 Self::NAME
230 }
231
232 fn size(&self) -> usize {
233 let gcc_blocks_buffer_length = self.gcc_blocks.size();
234 let req_length: DecodeResult<u16> = cast_length!(
235 "gccBlocksLen",
236 CONFERENCE_RESPONSE_CONNECT_PDU_SIZE + gcc_blocks_buffer_length
237 );
238 let length: DecodeResult<u16> = cast_length!("gccBlocksLen", gcc_blocks_buffer_length);
239 per::CHOICE_SIZE
240 + CONFERENCE_REQUEST_OBJECT_ID.len()
241 + per::sizeof_length(req_length.unwrap())
242 + CONFERENCE_RESPONSE_CONNECT_PDU_SIZE
243 + per::sizeof_length(length.unwrap())
244 + gcc_blocks_buffer_length
245 }
246}
247
248impl<'de> Decode<'de> for ConferenceCreateResponse {
249 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
250 ensure_size!(in: src, size: per::CHOICE_SIZE);
252 if per::read_choice(src) != OBJECT_IDENTIFIER_KEY {
253 return Err(invalid_field_err!("ConnectData::Key", "Got unexpected ConnectData key"));
254 }
255 if per::read_object_id(src).map_err(|e| other_err!("value", source: e))? != CONFERENCE_REQUEST_OBJECT_ID {
257 return Err(invalid_field_err!(
258 "ConnectData::Key",
259 "Got unexpected ConnectData key value"
260 ));
261 };
262 let _length = per::read_length(src).map_err(|e| other_err!("len", source: e))?;
264 ensure_size!(in: src, size: per::CHOICE_SIZE);
266 if per::read_choice(src) != CONNECT_GCC_PDU_CONFERENCE_RESPONSE_CHOICE {
267 return Err(invalid_field_err!(
268 "ConnectData::connectPdu",
269 "Got invalid ConnectGCCPDU choice (expected ConferenceCreateResponse)"
270 ));
271 }
272 let user_id = per::read_u16(src, CONFERENCE_REQUEST_U16_MIN).map_err(|e| other_err!("userId", source: e))?;
274 if per::read_u32(src).map_err(|e| other_err!("tag", source: e))? != CONFERENCE_RESPONSE_TAG {
276 return Err(invalid_field_err!(
277 "ConferenceCreateResponse::tag",
278 "Got unexpected ConferenceCreateResponse tag",
279 ));
280 }
281 if per::read_enum(src, mcs::RESULT_ENUM_LENGTH).map_err(|e| other_err!("result", source: e))?
283 != CONFERENCE_RESPONSE_RESULT
284 {
285 return Err(invalid_field_err!(
286 "ConferenceCreateResponse::result",
287 "Got invalid ConferenceCreateResponse result",
288 ));
289 }
290 ensure_size!(in: src, size: per::CHOICE_SIZE);
291 if per::read_number_of_sets(src) != USER_DATA_NUMBER_OF_SETS {
292 return Err(invalid_field_err!(
293 "ConferenceCreateResponse",
294 "Got invalid ConferenceCreateResponse number of sets (expected 1)",
295 ));
296 }
297 ensure_size!(in: src, size: per::CHOICE_SIZE);
299 if per::read_choice(src) != USER_DATA_H221_NON_STANDARD_CHOICE {
300 return Err(invalid_field_err!(
301 "ConferenceCreateResponse",
302 "Expected UserData H221NonStandard choice",
303 ));
304 }
305 if per::read_octet_string(src, H221_NON_STANDARD_MIN_LENGTH)
307 .map_err(|e| other_err!("server-to-client", source: e))?
308 != CONFERENCE_REQUEST_SERVER_TO_CLIENT_H221_NON_STANDARD
309 {
310 return Err(invalid_field_err!(
311 "ConferenceCreateResponse",
312 "Got invalid H221NonStandard server-to-client key",
313 ));
314 }
315 let (_gcc_blocks_buffer_length, _) = per::read_length(src).map_err(|e| other_err!("len", source: e))?;
316 let gcc_blocks = ServerGccBlocks::decode(src)?;
317
318 Ok(Self { user_id, gcc_blocks })
319 }
320}