1use crate::error::{DVRIPError, Result};
2use byteorder::{ByteOrder, LittleEndian};
3use serde_json::Value;
4use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
5
6pub struct PacketHeader {
7 pub head: u8,
8 pub version: u8,
9 pub session: u32,
10 pub packet_count: u32,
11 pub msg_id: u16,
12 pub data_len: u32,
13}
14
15impl PacketHeader {
16 pub const SIZE: usize = 20;
17
18 pub fn encode(&self) -> Vec<u8> {
19 let mut buf = vec![0u8; Self::SIZE];
20 buf[0] = self.head;
21 buf[1] = self.version;
22 LittleEndian::write_u32(&mut buf[4..8], self.session);
23 LittleEndian::write_u32(&mut buf[8..12], self.packet_count);
24 LittleEndian::write_u16(&mut buf[14..16], self.msg_id);
25 LittleEndian::write_u32(&mut buf[16..20], self.data_len);
26 buf
27 }
28
29 pub fn decode(data: &[u8]) -> Result<Self> {
30 if data.len() < Self::SIZE {
31 return Err(DVRIPError::ProtocolError("Header too small".to_string()));
32 }
33 Ok(Self {
34 head: data[0],
35 version: data[1],
36 session: LittleEndian::read_u32(&data[4..8]),
37 packet_count: LittleEndian::read_u32(&data[8..12]),
38 msg_id: LittleEndian::read_u16(&data[14..16]),
39 data_len: LittleEndian::read_u32(&data[16..20]),
40 })
41 }
42}
43
44pub async fn send_packet<W: AsyncWrite + Unpin>(
45 writer: &mut W,
46 session: u32,
47 packet_count: u32,
48 msg_id: u16,
49 data: &[u8],
50 version: u8,
51) -> Result<()> {
52 let tail: &[u8] = if version == 0 { b"\x0a\x00" } else { b"\x00" };
53 let data_len = (data.len() + tail.len()) as u32;
54
55 let header = PacketHeader {
56 head: 255,
57 version,
58 session,
59 packet_count,
60 msg_id,
61 data_len,
62 };
63
64 let mut packet = header.encode();
65 packet.extend_from_slice(data);
66 packet.extend_from_slice(tail);
67
68 writer.write_all(&packet).await?;
69 writer.flush().await?;
70 Ok(())
71}
72
73pub async fn receive_packet_header<R: AsyncRead + Unpin>(reader: &mut R) -> Result<PacketHeader> {
74 let mut buf = vec![0u8; PacketHeader::SIZE];
75 let mut received = 0;
76
77 while received < PacketHeader::SIZE {
79 match reader.read(&mut buf[received..]).await {
80 Ok(0) => {
81 return Err(DVRIPError::ConnectionError(
82 "Connection closed by peer".to_string(),
83 ));
84 }
85 Ok(n) => {
86 received += n;
87 }
88 Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
89 return Err(DVRIPError::ConnectionError(
90 "Connection closed unexpectedly".to_string(),
91 ));
92 }
93 Err(e) => {
94 return Err(DVRIPError::IoError(e));
95 }
96 }
97 }
98
99 PacketHeader::decode(&buf)
100}
101
102pub async fn receive_data<R: AsyncRead + Unpin>(
103 reader: &mut R,
104 length: usize,
105 timeout: tokio::time::Duration,
106) -> Result<Vec<u8>> {
107 let mut buf = vec![0u8; length];
108 let mut received = 0;
109
110 while received < length {
111 let remaining = length - received;
112 let result = tokio::time::timeout(
113 timeout,
114 reader.read(&mut buf[received..received + remaining]),
115 )
116 .await;
117
118 let chunk = match result {
119 Ok(Ok(n)) => n,
120 Ok(Err(e)) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
121 return Err(DVRIPError::ConnectionError(
122 "Connection closed unexpectedly during read".to_string(),
123 ));
124 }
125 Ok(Err(e)) => {
126 return Err(DVRIPError::IoError(e));
127 }
128 Err(_) => {
129 return Err(DVRIPError::ConnectionError(
130 "Timeout receiving data".to_string(),
131 ));
132 }
133 };
134
135 if chunk == 0 {
136 return Err(DVRIPError::ConnectionError(
137 "Connection closed by peer".to_string(),
138 ));
139 }
140 received += chunk;
141 }
142
143 Ok(buf)
144}
145
146pub async fn receive_json<R: AsyncRead + Unpin>(
147 reader: &mut R,
148 length: usize,
149 timeout: tokio::time::Duration,
150) -> Result<Value> {
151 let data = receive_data(reader, length, timeout).await?;
152 let json_data =
154 if data.len() >= 2 && data[data.len() - 2] == 0x0a && data[data.len() - 1] == 0x00 {
155 &data[..data.len() - 2]
156 } else if data.len() >= 1 && data[data.len() - 1] == 0x00 {
157 &data[..data.len() - 1]
158 } else {
159 &data
160 };
161
162 let json_str = String::from_utf8_lossy(json_data);
163 serde_json::from_str(&json_str)
164 .map_err(|e| DVRIPError::SerializationError(format!("Error parsing JSON: {}", e)))
165}
166
167pub fn sofia_hash(password: &str) -> String {
168 let digest = md5::compute(password.as_bytes());
169
170 let chars: Vec<char> = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
171 .chars()
172 .collect();
173
174 let mut result = String::new();
175 for i in (0..digest.len()).step_by(2) {
176 if i + 1 < digest.len() {
177 let sum = digest[i] as usize + digest[i + 1] as usize;
178 result.push(chars[sum % 62]);
179 }
180 }
181 result
182}