ironrdp_pdu/gcc/
conference_create.rs

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        // ConnectData::Key: select type OBJECT_IDENTIFIER
43        per::write_choice(dst, OBJECT_IDENTIFIER_KEY);
44        // ConnectData::Key: value
45        per::write_object_id(dst, CONFERENCE_REQUEST_OBJECT_ID);
46
47        // ConnectData::connectPDU: length
48        per::write_length(
49            dst,
50            cast_length!(
51                "gccBlocksLen",
52                gcc_blocks_buffer_length + CONFERENCE_REQUEST_CONNECT_PDU_SIZE
53            )?,
54        );
55        // ConnectGCCPDU (CHOICE): Select conferenceCreateRequest (0) of type ConferenceCreateRequest
56        per::write_choice(dst, CONNECT_GCC_PDU_CONFERENCE_REQUEST_CHOICE);
57        // ConferenceCreateRequest::Selection: select optional userData from ConferenceCreateRequest
58        per::write_selection(dst, CONFERENCE_REQUEST_USER_DATA_SELECTION);
59        // ConferenceCreateRequest::ConferenceName
60        per::write_numeric_string(dst, CONFERENCE_NAME, 1).map_err(|e| other_err!("confName", source: e))?;
61        per::write_padding(dst, 1);
62        // UserData (SET OF SEQUENCE)
63        // one set of UserData
64        per::write_number_of_sets(dst, USER_DATA_NUMBER_OF_SETS);
65        // select h221NonStandard
66        per::write_choice(dst, USER_DATA_H221_NON_STANDARD_CHOICE);
67        // h221NonStandard: client-to-server H.221 key, "Duca"
68        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        // H221NonStandardIdentifier (octet string)
75        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        // ConnectData
104
105        // ConnectData::Key: select object (0) of type OBJECT_IDENTIFIER
106        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        // ConnectData::Key: value (OBJECT_IDENTIFIER)
111        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        // ConnectData::connectPDU: length
119        let _length = per::read_length(src).map_err(|e| other_err!("len", source: e))?;
120        // ConnectGCCPDU (CHOICE): Select conferenceCreateRequest (0) of type ConferenceCreateRequest
121        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        // ConferenceCreateRequest::Selection: select optional userData from ConferenceCreateRequest
129        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        // ConferenceCreateRequest::ConferenceName
137        per::read_numeric_string(src, 1).map_err(|e| other_err!("confName", source: e))?;
138        // padding
139        per::read_padding(src, 1);
140
141        // UserData (SET OF SEQUENCE)
142        // one set of UserData
143        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        // select h221NonStandard
151        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        // h221NonStandard: client-to-server H.221 key, "Duca"
159        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        // H221NonStandardIdentifier (octet string)
169        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        // ConnectData::Key: select type OBJECT_IDENTIFIER
191        per::write_choice(dst, OBJECT_IDENTIFIER_KEY);
192        // ConnectData::Key: value
193        per::write_object_id(dst, CONFERENCE_REQUEST_OBJECT_ID);
194
195        // ConnectData::connectPDU: length (MUST be ignored by the client according to [MS-RDPBCGR])
196        per::write_length(
197            dst,
198            cast_length!(
199                "gccBlocksLen",
200                gcc_blocks_buffer_length + CONFERENCE_RESPONSE_CONNECT_PDU_SIZE + 1
201            )?,
202        );
203        // ConnectGCCPDU (CHOICE): Select conferenceCreateResponse (1) of type ConferenceCreateResponse
204        per::write_choice(dst, CONNECT_GCC_PDU_CONFERENCE_RESPONSE_CHOICE);
205        // ConferenceCreateResponse::nodeID (UserID)
206        per::write_u16(dst, self.user_id, CONFERENCE_REQUEST_U16_MIN).map_err(|e| other_err!("userId", source: e))?;
207        // ConferenceCreateResponse::tag (INTEGER)
208        per::write_u32(dst, CONFERENCE_RESPONSE_TAG);
209        // ConferenceCreateResponse::result (ENUMERATED)
210        per::write_enum(dst, CONFERENCE_RESPONSE_RESULT);
211        per::write_number_of_sets(dst, USER_DATA_NUMBER_OF_SETS);
212        // select h221NonStandard
213        per::write_choice(dst, USER_DATA_H221_NON_STANDARD_CHOICE);
214        // h221NonStandard, server-to-client H.221 key, "McDn"
215        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        // H221NonStandardIdentifier (octet string)
222        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        // ConnectData::Key: select type OBJECT_IDENTIFIER
251        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        // ConnectData::Key: value
256        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        // ConnectData::connectPDU: length (MUST be ignored by the client according to [MS-RDPBCGR])
263        let _length = per::read_length(src).map_err(|e| other_err!("len", source: e))?;
264        // ConnectGCCPDU (CHOICE): Select conferenceCreateResponse (1) of type ConferenceCreateResponse
265        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        // ConferenceCreateResponse::nodeID (UserID)
273        let user_id = per::read_u16(src, CONFERENCE_REQUEST_U16_MIN).map_err(|e| other_err!("userId", source: e))?;
274        // ConferenceCreateResponse::tag (INTEGER)
275        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        // ConferenceCreateResponse::result (ENUMERATED)
282        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        // select h221NonStandard
298        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        // h221NonStandard, server-to-client H.221 key, "McDn"
306        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}