1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#[cfg(test)]
mod tests;
use std::io;
use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt};
use bytes::BytesMut;
use num_derive::{FromPrimitive, ToPrimitive};
use num_traits::{FromPrimitive, ToPrimitive};
pub const TPKT_HEADER_LENGTH: usize = 4;
pub const TPDU_DATA_LENGTH: usize = TPKT_HEADER_LENGTH + TPDU_DATA_HEADER_LENGTH;
pub const TPDU_REQUEST_LENGTH: usize = TPKT_HEADER_LENGTH + TPDU_REQUEST_HEADER_LENGTH;
const TPDU_DATA_HEADER_LENGTH: usize = 3;
const TPDU_REQUEST_HEADER_LENGTH: usize = 7;
#[derive(Copy, Clone, Debug, PartialEq, FromPrimitive, ToPrimitive)]
pub enum X224TPDUType {
ConnectionRequest = 0xE0,
ConnectionConfirm = 0xD0,
DisconnectRequest = 0x80,
Data = 0xF0,
Error = 0x70,
}
pub fn decode_x224(input: &mut BytesMut) -> io::Result<(X224TPDUType, BytesMut)> {
let mut stream = input.as_ref();
let len = read_tpkt_len(&mut stream)? as usize;
if input.len() < len {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"The buffer length is less then the real length",
));
}
let (_, code) = parse_tdpu_header(&mut stream)?;
let mut tpdu = input.split_to(len as usize);
let header_len = tpdu_header_length(code);
if header_len <= tpdu.len() {
tpdu.advance(header_len);
Ok((code, tpdu))
} else {
Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"TPKT len is too small",
))
}
}
pub fn encode_x224(code: X224TPDUType, data: BytesMut, output: &mut BytesMut) -> io::Result<()> {
let tpdu_length = match code {
X224TPDUType::Data => TPDU_DATA_LENGTH,
_ => TPDU_REQUEST_LENGTH,
};
let length = tpdu_length + data.len();
let mut output_slice = output.as_mut();
write_tpkt_header(&mut output_slice, length as u16)?;
write_tpdu_header(
&mut output_slice,
length as u8 - TPKT_HEADER_LENGTH as u8,
code,
0,
)?;
output.extend_from_slice(&data);
Ok(())
}
pub fn tpdu_header_length(code: X224TPDUType) -> usize {
match code {
X224TPDUType::Data => TPDU_DATA_LENGTH,
_ => TPDU_REQUEST_LENGTH,
}
}
pub fn write_tpkt_header(mut stream: impl io::Write, length: u16) -> io::Result<()> {
let version = 3;
stream.write_u8(version)?;
stream.write_u8(0)?;
stream.write_u16::<BigEndian>(length)?;
Ok(())
}
pub fn read_tpkt_len(mut stream: impl io::Read) -> io::Result<u64> {
let version = stream.read_u8()?;
if version != 3 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"not a tpkt header",
));
}
let _reserved = stream.read_u8()?;
let len = u64::from(stream.read_u16::<BigEndian>()?);
Ok(len)
}
fn write_tpdu_header(
mut stream: impl io::Write,
length: u8,
code: X224TPDUType,
src_ref: u16,
) -> io::Result<()> {
let tpdu_length = match code {
X224TPDUType::Data => 2,
_ => length - 1,
};
stream.write_u8(tpdu_length)?;
stream.write_u8(code.to_u8().unwrap())?;
if code == X224TPDUType::Data {
let eot = 0x80;
stream.write_u8(eot)?;
} else {
let dst_ref = 0;
stream.write_u16::<LittleEndian>(dst_ref)?;
stream.write_u16::<LittleEndian>(src_ref)?;
let class = 0;
stream.write_u8(class)?;
}
Ok(())
}
fn parse_tdpu_header(mut stream: impl io::Read) -> io::Result<(u8, X224TPDUType)> {
let length = stream.read_u8()?;
let code = X224TPDUType::from_u8(stream.read_u8()?)
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "invalid X224 TPDU type"))?;
if code == X224TPDUType::Data {
let _eof = stream.read_u8()?;
} else {
let _dst_ref = stream.read_u16::<LittleEndian>()?;
let _src_ref = stream.read_u16::<LittleEndian>()?;
let _class = stream.read_u8()?;
}
Ok((length, code))
}