ironrdp_pdu/rdp/
server_error_info.rs

1use ironrdp_core::{
2    ensure_fixed_part_size, invalid_field_err, Decode, DecodeResult, Encode, EncodeResult, ReadCursor, WriteCursor,
3};
4use num_derive::{FromPrimitive, ToPrimitive};
5use num_traits::{FromPrimitive, ToPrimitive};
6
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct ServerSetErrorInfoPdu(pub ErrorInfo);
9
10impl ServerSetErrorInfoPdu {
11    const NAME: &'static str = "ServerSetErrorInfoPdu";
12
13    const FIXED_PART_SIZE: usize = 4 /* errorInfo */;
14}
15
16impl Encode for ServerSetErrorInfoPdu {
17    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
18        ensure_fixed_part_size!(in: dst);
19
20        dst.write_u32(self.0.to_u32().unwrap());
21
22        Ok(())
23    }
24
25    fn name(&self) -> &'static str {
26        Self::NAME
27    }
28
29    fn size(&self) -> usize {
30        Self::FIXED_PART_SIZE
31    }
32}
33
34impl<'de> Decode<'de> for ServerSetErrorInfoPdu {
35    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
36        ensure_fixed_part_size!(in: src);
37
38        let error_info = src.read_u32();
39        let error_info =
40            ErrorInfo::from_u32(error_info).ok_or_else(|| invalid_field_err!("errorInfo", "unexpected info code"))?;
41
42        Ok(Self(error_info))
43    }
44}
45
46#[derive(Debug, Copy, Clone, PartialEq, Eq)]
47pub enum ErrorInfo {
48    ProtocolIndependentCode(ProtocolIndependentCode),
49    ProtocolIndependentLicensingCode(ProtocolIndependentLicensingCode),
50    ProtocolIndependentConnectionBrokerCode(ProtocolIndependentConnectionBrokerCode),
51    RdpSpecificCode(RdpSpecificCode),
52}
53
54impl ErrorInfo {
55    pub fn description(self) -> String {
56        match self {
57            Self::ProtocolIndependentCode(c) => {
58                format!("[Protocol independent error] {}", c.description())
59            }
60            Self::ProtocolIndependentLicensingCode(c) => {
61                format!("[Protocol independent licensing error] {}", c.description())
62            }
63            Self::ProtocolIndependentConnectionBrokerCode(c) => {
64                format!("[Protocol independent connection broker error] {}", c.description())
65            }
66            Self::RdpSpecificCode(c) => format!("[RDP specific code]: {}", c.description()),
67        }
68    }
69}
70
71impl FromPrimitive for ErrorInfo {
72    fn from_i64(n: i64) -> Option<Self> {
73        if let Some(v) = ProtocolIndependentCode::from_i64(n) {
74            Some(Self::ProtocolIndependentCode(v))
75        } else if let Some(v) = ProtocolIndependentLicensingCode::from_i64(n) {
76            Some(Self::ProtocolIndependentLicensingCode(v))
77        } else if let Some(v) = ProtocolIndependentConnectionBrokerCode::from_i64(n) {
78            Some(Self::ProtocolIndependentConnectionBrokerCode(v))
79        } else {
80            RdpSpecificCode::from_i64(n).map(Self::RdpSpecificCode)
81        }
82    }
83
84    fn from_u64(n: u64) -> Option<Self> {
85        if let Some(v) = ProtocolIndependentCode::from_u64(n) {
86            Some(Self::ProtocolIndependentCode(v))
87        } else if let Some(v) = ProtocolIndependentLicensingCode::from_u64(n) {
88            Some(Self::ProtocolIndependentLicensingCode(v))
89        } else if let Some(v) = ProtocolIndependentConnectionBrokerCode::from_u64(n) {
90            Some(Self::ProtocolIndependentConnectionBrokerCode(v))
91        } else {
92            RdpSpecificCode::from_u64(n).map(Self::RdpSpecificCode)
93        }
94    }
95}
96
97impl ToPrimitive for ErrorInfo {
98    fn to_i64(&self) -> Option<i64> {
99        match self {
100            Self::ProtocolIndependentCode(c) => c.to_i64(),
101            Self::ProtocolIndependentLicensingCode(c) => c.to_i64(),
102            Self::ProtocolIndependentConnectionBrokerCode(c) => c.to_i64(),
103            Self::RdpSpecificCode(c) => c.to_i64(),
104        }
105    }
106
107    fn to_u64(&self) -> Option<u64> {
108        match self {
109            Self::ProtocolIndependentCode(c) => c.to_u64(),
110            Self::ProtocolIndependentLicensingCode(c) => c.to_u64(),
111            Self::ProtocolIndependentConnectionBrokerCode(c) => c.to_u64(),
112            Self::RdpSpecificCode(c) => c.to_u64(),
113        }
114    }
115}
116
117#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
118pub enum ProtocolIndependentCode {
119    None = 0x0000_0000,
120    RpcInitiatedDisconnect = 0x0000_0001,
121    RpcInitiatedLogoff = 0x0000_0002,
122    IdleTimeout = 0x0000_0003,
123    LogonTimeout = 0x0000_0004,
124    DisconnectedByOtherconnection = 0x0000_0005,
125    OutOfMemory = 0x0000_0006,
126    ServerDeniedConnection = 0x0000_0007,
127    ServerInsufficientPrivileges = 0x0000_0009,
128    ServerFreshCredentialsRequired = 0x0000_000A,
129    RpcInitiatedDisconnectByuser = 0x0000_000B,
130    LogoffByUser = 0x0000_000C,
131    CloseStackOnDriverNotReady = 0x0000_000F,
132    ServerDwmCrash = 0x0000_0010,
133    CloseStackOnDriverFailure = 0x0000_0011,
134    CloseStackOnDriverIfaceFailure = 0x0000_0012,
135    ServerWinlogonCrash = 0x0000_0017,
136    ServerCsrssCrash = 0x0000_0018,
137}
138
139impl ProtocolIndependentCode {
140    pub fn description(&self) -> &str {
141        match self {
142            Self::None => "No error has occurred",
143            Self::RpcInitiatedDisconnect => "The disconnection was initiated by an administrative tool on the server in another session",
144            Self::RpcInitiatedLogoff => "The disconnection was due to a forced logoff initiated by an administrative tool on the server in another session",
145            Self::IdleTimeout => "The idle session limit timer on the server has elapsed",
146            Self::LogonTimeout => "The active session limit timer on the server has elapsed",
147            Self::DisconnectedByOtherconnection => "Another user connected to the server, forcing the disconnection of the current connection",
148            Self::OutOfMemory => "The server ran out of available memory resources",
149            Self::ServerDeniedConnection => "The server denied the connection",
150            Self::ServerInsufficientPrivileges => "The user cannot connect to the server due to insufficient access privileges",
151            Self::ServerFreshCredentialsRequired => "The server does not accept saved user credentials and requires that the user enter their credentials for each connection",
152            Self::RpcInitiatedDisconnectByuser => "The disconnection was initiated by an administrative tool on the server running in the user's session",
153            Self::LogoffByUser => "The disconnection was initiated by the user logging off his or her session on the server",
154            Self::CloseStackOnDriverNotReady => "The display driver in the remote session did not report any status within the time allotted for startup",
155            Self::ServerDwmCrash => "The DWM process running in the remote session terminated unexpectedly",
156            Self::CloseStackOnDriverFailure => "The display driver in the remote session was unable to complete all the tasks required for startup",
157            Self::CloseStackOnDriverIfaceFailure => "The display driver in the remote session started up successfully, but due to internal failures was not usable by the remoting stack",
158            Self::ServerWinlogonCrash => "The Winlogon process running in the remote session terminated unexpectedly",
159            Self::ServerCsrssCrash => "The CSRSS process running in the remote session terminated unexpectedly",
160        }
161    }
162}
163
164#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
165pub enum ProtocolIndependentLicensingCode {
166    Internal = 0x0000_0100,
167    NoLicenseServer = 0x0000_0101,
168    NoLicense = 0x0000_0102,
169    BadClientMsg = 0x0000_0103,
170    HwidDoesntMatchLicense = 0x0000_0104,
171    BadClientLicense = 0x0000_0105,
172    CantFinishProtocol = 0x0000_0106,
173    ClientEndedProtocol = 0x0000_0107,
174    BadClientEncryption = 0x0000_0108,
175    CantUpgradeLicense = 0x0000_0109,
176    NoRemoteConnections = 0x0000_010A,
177}
178
179impl ProtocolIndependentLicensingCode {
180    pub fn description(&self) -> &str {
181        match self {
182            Self::Internal => "An internal error has occurred in the Terminal Services licensing component",
183            Self::NoLicenseServer => "A Remote Desktop License Server could not be found to provide a license",
184            Self::NoLicense => "There are no Client Access Licenses available for the target remote computer",
185            Self::BadClientMsg => "The remote computer received an invalid licensing message from the client",
186            Self::HwidDoesntMatchLicense => "The Client Access License stored by the client has been modified",
187            Self::BadClientLicense => "The Client Access License stored by the client is in an invalid format",
188            Self::CantFinishProtocol => "Network problems have caused the licensing protocol to be terminated",
189            Self::ClientEndedProtocol => "The client prematurely ended the licensing protocol",
190            Self::BadClientEncryption => "A licensing message was incorrectly encrypted",
191            Self::CantUpgradeLicense => {
192                "The Client Access License stored by the client could not be upgraded or renewed"
193            }
194            Self::NoRemoteConnections => "The remote computer is not licensed to accept remote connections",
195        }
196    }
197}
198
199#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
200pub enum ProtocolIndependentConnectionBrokerCode {
201    DestinationNotFound = 0x0000_0400,
202    LoadingDestination = 0x0000_0402,
203    RedirectingToDestination = 0x0000_0404,
204    SessionOnlineVmWake = 0x0000_0405,
205    SessionOnlineVmBoot = 0x0000_0406,
206    SessionOnlineVmNoDns = 0x0000_0407,
207    DestinationPoolNotFree = 0x0000_0408,
208    ConnectionCancelled = 0x0000_0409,
209    ConnectionErrorInvalidSettings = 0x0000_0410,
210    SessionOnlineVmBootTimeout = 0x0000_0411,
211    SessionOnlineVmSessmonFailed = 0x0000_0412,
212}
213
214impl ProtocolIndependentConnectionBrokerCode {
215    pub fn description(&self) -> &str {
216        match self {
217            Self::DestinationNotFound => "The target endpoint could not be found",
218            Self::LoadingDestination => "The target endpoint to which the client is being redirected is disconnecting from the Connection Broker",
219            Self::RedirectingToDestination => "An error occurred while the connection was being redirected to the target endpoint",
220            Self::SessionOnlineVmWake => "An error occurred while the target endpoint (a virtual machine) was being awakened",
221            Self::SessionOnlineVmBoot => "An error occurred while the target endpoint (a virtual machine) was being started",
222            Self::SessionOnlineVmNoDns => "The IP address of the target endpoint (a virtual machine) cannot be determined",
223            Self::DestinationPoolNotFree => "There are no available endpoints in the pool managed by the Connection Broker",
224            Self::ConnectionCancelled => "Processing of the connection has been canceled",
225            Self::ConnectionErrorInvalidSettings => "The settings contained in the routingToken field of the X.224 Connection Request PDU cannot be validated",
226            Self::SessionOnlineVmBootTimeout => "A time-out occurred while the target endpoint (a virtual machine) was being started",
227            Self::SessionOnlineVmSessmonFailed => "A session monitoring error occurred while the target endpoint (a virtual machine) was being started",
228        }
229    }
230}
231
232#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
233pub enum RdpSpecificCode {
234    UnknownPduType2 = 0x0000_10C9,
235    UnknownPduType = 0x0000_10CA,
236    DataPdusEquence = 0x0000_10CB,
237    ControlPduSequence = 0x0000_10CD,
238    InvalidControlPduAction = 0x0000_10CE,
239    InvalidInputPduType = 0x0000_10CF,
240    InvalidInputPduMouse = 0x0000_10D0,
241    InvalidRefreshRectPdu = 0x0000_10D1,
242    CreateUserDataFailed = 0x0000_10D2,
243    ConnectFailed = 0x0000_10D3,
244    ConfirmActiveWrongShareId = 0x0000_10D4,
245    ConfirmActiveWrongOriginator = 0x0000_10D5,
246    PersistentKeyPduBadLength = 0x0000_10DA,
247    PersistentKeyPduIllegalFirst = 0x0000_10DB,
248    PersistentKeyPduTooManyTotalKeys = 0x0000_10DC,
249    PersistentKeyPduTooManyCacheKeys = 0x0000_10DD,
250    InputPduBadLength = 0x0000_10DE,
251    BitmapCacheErrorPduBadLength = 0x0000_10DF,
252    SecurityDataTooShort = 0x0000_10E0,
253    VcHannelDataTooShort = 0x0000_10E1,
254    ShareDataTooShort = 0x0000_10E2,
255    BadSuppressOutputPdu = 0x0000_10E3,
256    ConfirmActivePduTooShort = 0x0000_10E5,
257    CapabilitySetTooSmall = 0x0000_10E7,
258    CapabilitySetTooLarge = 0x0000_10E8,
259    NoCursorCache = 0x0000_10E9,
260    BadCapabilities = 0x0000_10EA,
261    VirtualChannelDecompressionError = 0x0000_10EC,
262    InvalidVcCompressionType = 0x0000_10ED,
263    InvalidChannelId = 0x0000_10EF,
264    VirtualChannelsTooMany = 0x0000_10F0,
265    RemoteAppsNotEnabled = 0x0000_10F3,
266    CacheCapabilityNotSet = 0x0000_10F4,
267    BitmapCacheErrorPduBadLength2 = 0x0000_10F5,
268    OffscrCacheErrorPduBadLength = 0x0000_10F6,
269    DngCacheErrorPduBadLength = 0x0000_10F7,
270    GdiPlusPduBadLength = 0x0000_10F8,
271    SecurityDataTooShort2 = 0x0000_1111,
272    SecurityDataTooShort3 = 0x0000_1112,
273    SecurityDataTooShort4 = 0x0000_1113,
274    SecurityDataTooShort5 = 0x0000_1114,
275    SecurityDataTooShort6 = 0x0000_1115,
276    SecurityDataTooShort7 = 0x0000_1116,
277    SecurityDataTooShort8 = 0x0000_1117,
278    SecurityDataTooShort9 = 0x0000_1118,
279    SecurityDataTooShort10 = 0x0000_1119,
280    SecurityDataTooShort11 = 0x0000_111A,
281    SecurityDataTooShort12 = 0x0000_111B,
282    SecurityDataTooShort13 = 0x0000_111C,
283    SecurityDataTooShort14 = 0x0000_111D,
284    SecurityDataTooShort15 = 0x0000_111E,
285    SecurityDataTooShort16 = 0x0000_111F,
286    SecurityDataTooShort17 = 0x0000_1120,
287    SecurityDataTooShort18 = 0x0000_1121,
288    SecurityDataTooShort19 = 0x0000_1122,
289    SecurityDataTooShort20 = 0x0000_1123,
290    SecurityDataTooShort21 = 0x0000_1124,
291    SecurityDataTooShort22 = 0x0000_1125,
292    SecurityDataTooShort23 = 0x0000_1126,
293    BadMonitorData = 0x0000_1129,
294    VcDecompressedReassembleFailed = 0x0000_112A,
295    VcDataTooLong = 0x0000_112B,
296    BadFrameAckData = 0x0000_112C,
297    GraphicsModeNotSupported = 0x0000_112D,
298    GraphicsSubsystemResetFailed = 0x0000_112E,
299    GraphicsSubsystemFailed = 0x0000_112F,
300    TimezoneKeyNameLengthTooShort = 0x0000_1130,
301    TimezoneKeyNameLengthTooLong = 0x0000_1131,
302    DynamicDstDisabledFieldMissing = 0x0000_1132,
303    VcDecodingError = 0x0000_1133,
304    VirtualDesktopTooLarge = 0x0000_1134,
305    MonitorGeometryValidationFailed = 0x0000_1135,
306    InvalidMonitorCount = 0x0000_1136,
307    UpdateSessionKeyFailed = 0x0000_1191,
308    DecryptFailed = 0x0000_1192,
309    EncryptFailed = 0x0000_1193,
310    EncPkgMismatch = 0x0000_1194,
311    DecryptFailed2 = 0x0000_1195,
312}
313
314impl RdpSpecificCode {
315    pub fn description(&self) -> &str {
316        match self {
317            Self::UnknownPduType2 => "Unknown pduType2 field in a received Share Data Header",
318            Self::UnknownPduType => "Unknown pduType field in a received Share Control Header",
319            Self::DataPdusEquence => "An out-of-sequence Slow-Path Data PDU has been received",
320            Self::ControlPduSequence => "An out-of-sequence Slow-Path Non-Data PDU has been received",
321            Self::InvalidControlPduAction => "A Control PDU has been received with an invalid action field",
322            Self::InvalidInputPduType => "One of two possible errors: A Slow-Path Input Event has been received with an invalid messageType field; or A Fast-Path Input Event has been received with an invalid eventCode field",
323            Self::InvalidInputPduMouse => "One of two possible errors: A Slow-Path Mouse Event or Extended Mouse Event has been received with an invalid pointerFlags field; or A Fast-Path Mouse Event or Fast-Path Extended Mouse Event has been received with an invalid pointerFlags field",
324            Self::InvalidRefreshRectPdu => "An invalid Refresh Rect PDU has been received",
325            Self::CreateUserDataFailed => "The server failed to construct the GCC Conference Create Response user data",
326            Self::ConnectFailed => "Processing during the Channel Connection phase of the RDP Connection Sequence has failed",
327            Self::ConfirmActiveWrongShareId => "A Confirm Active PDU was received from the client with an invalid shareID field",
328            Self::ConfirmActiveWrongOriginator => "A Confirm Active PDU was received from the client with an invalid originatorID field",
329            Self::PersistentKeyPduBadLength => "There is not enough data to process a Persistent Key List PDU",
330            Self::PersistentKeyPduIllegalFirst => "A Persistent Key List PDU marked as PERSIST_PDU_FIRST (0x01) was received after the reception of a prior Persistent Key List PDU also marked as PERSIST_PDU_FIRST",
331            Self::PersistentKeyPduTooManyTotalKeys => "A Persistent Key List PDU was received which specified a total number of bitmap cache entries larger than 262144",
332            Self::PersistentKeyPduTooManyCacheKeys => "A Persistent Key List PDU was received which specified an invalid total number of keys for a bitmap cache (the number of entries that can be stored within each bitmap cache is specified in the Revision 1 or 2 Bitmap Cache Capability Set that is sent from client to server)",
333            Self::InputPduBadLength => "There is not enough data to process Input Event PDU Data or a Fast-Path Input Event PDU",
334            Self::BitmapCacheErrorPduBadLength => "There is not enough data to process the shareDataHeader, NumInfoBlocks, Pad1, and Pad2 fields of the Bitmap Cache Error PDU Data",
335            Self::SecurityDataTooShort => "One of two possible errors: The dataSignature field of the Fast-Path Input Event PDU does not contain enough data; or The fipsInformation and dataSignature fields of the Fast-Path Input Event PDU do not contain enough data",
336            Self::VcHannelDataTooShort => "One of two possible errors: There is not enough data in the Client Network Data to read the virtual channel configuration data; or There is not enough data to read a complete Channel PDU Header",
337            Self::ShareDataTooShort => "One of four possible errors: There is not enough data to process Control PDU Data; or There is not enough data to read a complete Share Control Header; or There is not enough data to read a complete Share Data Header of a Slow-Path Data PDU; or There is not enough data to process Font List PDU Data",
338            Self::BadSuppressOutputPdu => "One of two possible errors: There is not enough data to process Suppress Output PDU Data; or The allowDisplayUpdates field of the Suppress Output PDU Data is invalid",
339            Self::ConfirmActivePduTooShort => "One of two possible errors: There is not enough data to read the shareControlHeader, shareID, originatorID, lengthSourceDescriptor, and lengthCombinedCapabilities fields of the Confirm Active PDU Data; or There is not enough data to read the sourceDescriptor, numberCapabilities, pad2Octets, and capabilitySets fields of the Confirm Active PDU Data",
340            Self::CapabilitySetTooSmall => "There is not enough data to read the capabilitySetType and the lengthCapability fields in a received Capability Set",
341            Self::CapabilitySetTooLarge => "A Capability Set has been received with a lengthCapability field that contains a value greater than the total length of the data received",
342            Self::NoCursorCache => "One of two possible errors: Both the colorPointerCacheSize and pointerCacheSize fields in the Pointer Capability Set are set to zero; or The pointerCacheSize field in the Pointer Capability Set is not present, and the colorPointerCacheSize field is set to zero",
343            Self::BadCapabilities => "The capabilities received from the client in the Confirm Active PDU were not accepted by the server",
344            Self::VirtualChannelDecompressionError => "An error occurred while using the bulk compressor to decompress a Virtual Channel PDU",
345            Self::InvalidVcCompressionType => "An invalid bulk compression package was specified in the flags field of the Channel PDU Header",
346            Self::InvalidChannelId => "An invalid MCS channel ID was specified in the mcsPdu field of the Virtual Channel PDU)",
347            Self::VirtualChannelsTooMany => "The client requested more than the maximum allowed 31 static virtual channels in the Client Network Data",
348            Self::RemoteAppsNotEnabled => "The INFO_RAIL flag (0x0000_8000) MUST be set in the flags field of the Info Packet as the session on the remote server can only host remote applications",
349            Self::CacheCapabilityNotSet => "The client sent a Persistent Key List PDU without including the prerequisite Revision 2 Bitmap Cache Capability Set in the Confirm Active PDU",
350            Self::BitmapCacheErrorPduBadLength2 => "The NumInfoBlocks field in the Bitmap Cache Error PDU Data is inconsistent with the amount of data in the Info field",
351            Self::OffscrCacheErrorPduBadLength => "There is not enough data to process an Offscreen Bitmap Cache Error PDU",
352            Self::DngCacheErrorPduBadLength => "There is not enough data to process a DrawNineGrid Cache Error PDU",
353            Self::GdiPlusPduBadLength => "There is not enough data to process a GDI+ Error PDU",
354            Self::SecurityDataTooShort2 => "There is not enough data to read a Basic Security Header",
355            Self::SecurityDataTooShort3 => "There is not enough data to read a Non-FIPS Security Header or FIPS Security Header",
356            Self::SecurityDataTooShort4 => "There is not enough data to read the basicSecurityHeader and length fields of the Security Exchange PDU Data",
357            Self::SecurityDataTooShort5 => "There is not enough data to read the CodePage, flags, cbDomain, cbUserName, cbPassword, cbAlternateShell, cbWorkingDir, Domain, UserName, Password, AlternateShell, and WorkingDir fields in the Info Packet",
358            Self::SecurityDataTooShort6 => "There is not enough data to read the CodePage, flags, cbDomain, cbUserName, cbPassword, cbAlternateShell, and cbWorkingDir fields in the Info Packet",
359            Self::SecurityDataTooShort7 => "There is not enough data to read the clientAddressFamily and cbClientAddress fields in the Extended Info Packet",
360            Self::SecurityDataTooShort8 => "There is not enough data to read the clientAddress field in the Extended Info Packet",
361            Self::SecurityDataTooShort9 => "There is not enough data to read the cbClientDir field in the Extended Info Packet",
362            Self::SecurityDataTooShort10 => "There is not enough data to read the clientDir field in the Extended Info Packet",
363            Self::SecurityDataTooShort11 => "There is not enough data to read the clientTimeZone field in the Extended Info Packet",
364            Self::SecurityDataTooShort12 => "There is not enough data to read the clientSessionId field in the Extended Info Packet",
365            Self::SecurityDataTooShort13 => "There is not enough data to read the performanceFlags field in the Extended Info Packet",
366            Self::SecurityDataTooShort14 => "There is not enough data to read the cbAutoReconnectCookie field in the Extended Info Packet",
367            Self::SecurityDataTooShort15 => "There is not enough data to read the autoReconnectCookie field in the Extended Info Packet",
368            Self::SecurityDataTooShort16 => "The cbAutoReconnectCookie field in the Extended Info Packet contains a value which is larger than the maximum allowed length of 128 bytes",
369            Self::SecurityDataTooShort17 => "There is not enough data to read the clientAddressFamily and cbClientAddress fields in the Extended Info Packet",
370            Self::SecurityDataTooShort18 => "There is not enough data to read the clientAddress field in the Extended Info Packet",
371            Self::SecurityDataTooShort19 => "There is not enough data to read the cbClientDir field in the Extended Info Packet",
372            Self::SecurityDataTooShort20 => "There is not enough data to read the clientDir field in the Extended Info Packet",
373            Self::SecurityDataTooShort21 => "There is not enough data to read the clientTimeZone field in the Extended Info Packet",
374            Self::SecurityDataTooShort22 => "There is not enough data to read the clientSessionId field in the Extended Info Packet",
375            Self::SecurityDataTooShort23 => "There is not enough data to read the Client Info PDU Data",
376            Self::BadMonitorData => "The number of TS_MONITOR_DEF structures present in the monitorDefArray field of the Client Monitor Data is less than the value specified in monitorCount field",
377            Self::VcDecompressedReassembleFailed => "The server-side decompression buffer is invalid, or the size of the decompressed VC data exceeds the chunking size specified in the Virtual Channel Capability Set",
378            Self::VcDataTooLong => "The size of a received Virtual Channel PDU exceeds the chunking size specified in the Virtual Channel Capability Set",
379            Self::BadFrameAckData => "There is not enough data to read a TS_FRAME_ACKNOWLEDGE_PDU",
380            Self::GraphicsModeNotSupported => "The graphics mode requested by the client is not supported by the server",
381            Self::GraphicsSubsystemResetFailed => "The server-side graphics subsystem failed to reset",
382            Self::GraphicsSubsystemFailed => "The server-side graphics subsystem is in an error state and unable to continue graphics encoding",
383            Self::TimezoneKeyNameLengthTooShort => "There is not enough data to read the cbDynamicDSTTimeZoneKeyName field in the Extended Info Packet",
384            Self::TimezoneKeyNameLengthTooLong => "The length reported in the cbDynamicDSTTimeZoneKeyName field of the Extended Info Packet is too long",
385            Self::DynamicDstDisabledFieldMissing => "The dynamicDaylightTimeDisabled field is not present in the Extended Info Packet",
386            Self::VcDecodingError => "An error occurred when processing dynamic virtual channel data",
387            Self::VirtualDesktopTooLarge => "The width or height of the virtual desktop defined by the monitor layout in the Client Monitor Data is larger than the maximum allowed value of 32,766",
388            Self::MonitorGeometryValidationFailed => "The monitor geometry defined by the Client Monitor Data is invalid",
389            Self::InvalidMonitorCount => "The monitorCount field in the Client Monitor Data is too large",
390            Self::UpdateSessionKeyFailed => "An attempt to update the session keys while using Standard RDP Security mechanisms failed",
391            Self::DecryptFailed => "One of two possible error conditions: Decryption using Standard RDP Security mechanisms failed; or Session key creation using Standard RDP Security mechanisms failed",
392            Self::EncryptFailed => "Encryption using Standard RDP Security mechanisms failed",
393            Self::EncPkgMismatch => "Failed to find a usable Encryption Method in the encryptionMethods field of the Client Security Data",
394            Self::DecryptFailed2 => "Unencrypted data was encountered in a protocol stream which is meant to be encrypted with Standard RDP Security mechanisms",
395        }
396    }
397}
398
399#[cfg(test)]
400mod tests {
401    use ironrdp_core::{decode, encode_vec};
402
403    use super::*;
404
405    const SERVER_SET_ERROR_INFO_BUFFER: [u8; 4] = [0x00, 0x01, 0x00, 0x00];
406
407    const SERVER_SET_ERROR_INFO: ServerSetErrorInfoPdu = ServerSetErrorInfoPdu(
408        ErrorInfo::ProtocolIndependentLicensingCode(ProtocolIndependentLicensingCode::Internal),
409    );
410
411    #[test]
412    fn from_buffer_correctly_parses_server_set_error_info() {
413        assert_eq!(
414            SERVER_SET_ERROR_INFO,
415            decode(SERVER_SET_ERROR_INFO_BUFFER.as_ref()).unwrap()
416        );
417    }
418
419    #[test]
420    fn to_buffer_correctly_serializes_server_set_error_info() {
421        let expected = SERVER_SET_ERROR_INFO_BUFFER.as_ref();
422
423        let buffer = encode_vec(&SERVER_SET_ERROR_INFO).unwrap();
424        assert_eq!(expected, buffer.as_slice());
425    }
426
427    #[test]
428    fn buffer_length_is_correct_for_server_set_error_info() {
429        assert_eq!(SERVER_SET_ERROR_INFO_BUFFER.len(), SERVER_SET_ERROR_INFO.size());
430    }
431}