diff --git a/Cargo.lock b/Cargo.lock index 92849c3..c5ac929 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -53,6 +53,12 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.9.0" @@ -65,6 +71,26 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "gimli" version = "0.31.1" @@ -73,9 +99,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "libc" -version = "0.2.168" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "lock_api" @@ -98,14 +124,16 @@ name = "micodus_server" version = "0.1.0" dependencies = [ "bcd-convert", + "encoding_rs", + "rand", "tokio", ] [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" dependencies = [ "adler2", ] @@ -123,9 +151,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.5" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] @@ -159,6 +187,15 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + [[package]] name = "proc-macro2" version = "1.0.92" @@ -170,13 +207,43 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "redox_syscall" version = "0.5.8" @@ -225,9 +292,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.90" +version = "2.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "70ae51629bf965c5c098cc9e87908a3df5301051a9e087d6f9bef5c9771ed126" dependencies = [ "proc-macro2", "quote", @@ -367,3 +434,24 @@ name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index df4e370..9c3d74e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,5 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -bcd-convert = "0.1.0" +bcd-convert = { version = "0.1" } +encoding_rs = { version = "0.8" } +rand = { version = "0.8" } tokio = { version = "1.42", features = ["full", "sync"] } diff --git a/src/main.rs b/src/main.rs index 0dcaa63..6518d5f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ pub mod parser; +pub use crate::parser::body::*; pub use crate::parser::*; use std::io; @@ -36,7 +37,12 @@ pub async fn apiserver() -> io::Result<()> { match socket.readable().await { Ok(_) => { match socket.try_read(&mut buf) { - Ok(_) => handle(&buf), + Ok(_) => match handle(&buf) { + Some(o) => { + let _ = socket.try_write(&o).unwrap(); + } + None => {} + }, Err(e) => { println!("error: {e}"); continue; @@ -58,14 +64,28 @@ pub async fn apiserver() -> io::Result<()> { Ok(()) } -pub fn handle(buf: &Vec) { +pub fn handle(buf: &Vec) -> Option> { let mut rawdata = DataWrapper::new(buf.to_vec()); - match parse_inbound_msg(&mut rawdata) { + let reply = match parse_inbound_msg(&mut rawdata) { Ok(o) => { - println!("msg: {}", o); + println!("query: {}", o); + println!("raw query: {:?}", o.to_raw()); + Message::set_reply(o) } Err(e) => { println!("parse inbound message error: {}", e); + return None; } }; + + match reply { + Some(o) => { + println!("reply: {}", o); + println!("raw reply {:?}", o.to_raw()); + return Some(o.to_raw().into()); + } + None => { + return None; + } + } } diff --git a/src/parser/body.rs b/src/parser/body.rs index 9afbcb2..c9601ef 100644 --- a/src/parser/body.rs +++ b/src/parser/body.rs @@ -1,9 +1,14 @@ +use encoding_rs::*; + macro_rules! generate_impl { ($($t:ty),*) => { $( - impl BodyMessage for $t { - fn build() {} - } + //impl BodyMessage for $t { + // fn build() {} + // fn body_to_iter<'a>(&'a self, rawbody: &'a Vec) -> std::slice::Iter<'a, u8> { + // rawbody.into_iter() + // } + //} impl $t { pub fn new(rawbody: &Vec) -> Self { let mut res = Self::default(); @@ -15,16 +20,19 @@ macro_rules! generate_impl { } pub trait BodyMessage { - fn build() {} + fn build(&self) {} fn body_to_iter<'a>(&'a self, rawbody: &'a Vec) -> std::slice::Iter<'a, u8> { rawbody.into_iter() } fn print(&mut self, rawbody: &Vec) { println!("{:?}", rawbody); } + fn to_raw(&self) -> Vec { + vec![] + } } -#[derive(Default, Debug)] +#[derive(Default, Debug, Clone)] pub struct TerminalUniversalResponse { pub answer_serial_no: u16, pub answer_id: u16, @@ -38,7 +46,9 @@ impl TerminalUniversalResponse { pub fn debug() {} } -#[derive(Default, Debug)] +impl BodyMessage for TerminalUniversalResponse {} + +#[derive(Default, Debug, Clone)] pub struct PlatformUniversalResponse { pub answer_serial_no: u16, pub answer_id: u16, @@ -51,7 +61,21 @@ impl PlatformUniversalResponse { pub fn parse(&mut self, rawbody: &Vec) {} } -#[derive(Default, Debug)] +impl BodyMessage for PlatformUniversalResponse { + fn to_raw(&self) -> Vec { + let mut res: Vec = vec![]; + for b in self.answer_serial_no.to_be_bytes() { + res.push(b); + } + for b in self.answer_id.to_be_bytes() { + res.push(b); + } + res.push(self.result); + res + } +} + +#[derive(Default, Debug, Clone)] pub struct TerminalHeartbeat {} impl TerminalHeartbeat { @@ -59,7 +83,7 @@ impl TerminalHeartbeat { pub fn parse(&mut self, rawbody: &Vec) {} } -#[derive(Default, Debug)] +#[derive(Default, Debug, Clone)] pub struct TerminalRegistration { pub provincial_id: u16, pub city_and_prefecture_id: u16, @@ -96,16 +120,21 @@ impl TerminalRegistration { } self.license_plate_color = *bd.next().unwrap(); + let plate_decode: &mut Vec = &mut vec![]; while let Some(i) = bd.next() { - let c = char::from(*i); - self.license_plate.push(c); + plate_decode.push(*i); } + + let (cow, _encoding_used, _had_errors) = GBK.decode(plate_decode); + self.license_plate = cow.into(); } + pub fn generate_reply(&self, terminal_id: Vec, serial: u16) -> TerminalRegistrationReply { let mut res = TerminalRegistrationReply::default(); res.answer_serial_no = serial; res.result = TerminalRegistrationResult::Success as u8; - res.authentication_code = String::from_utf8(terminal_id).unwrap(); + //res.authentication_code = String::from_utf8(terminal_id).unwrap(); + res.authentication_code = vec![0x36, 0x31, 0x33, 0x32, 0x31, 0x31, 0x38]; res } } @@ -134,31 +163,35 @@ enum TerminalRegistrationResult { VehicleNotInDatabase2, } -#[derive(Default, Debug)] +#[derive(Default, Debug, Clone)] pub struct TerminalRegistrationReply { pub answer_serial_no: u16, pub result: u8, - pub authentication_code: String, + pub authentication_code: Vec, } impl TerminalRegistrationReply { pub const ID: u16 = 0x8100; pub fn parse(&mut self, rawbody: &Vec) {} - pub fn body_to_vec(&self) -> Vec { +} + +impl BodyMessage for TerminalRegistrationReply { + fn to_raw(&self) -> Vec { let mut res: Vec = vec![]; for b in self.answer_serial_no.to_be_bytes() { res.push(b); } res.push(self.result); - for b in self.authentication_code.as_bytes() { + //for b in self.authentication_code.as_bytes() { + for b in self.authentication_code.iter() { res.push(*b); } res } } -#[derive(Default, Debug)] +#[derive(Default, Debug, Clone)] pub struct TerminalLogout {} impl TerminalLogout { @@ -173,7 +206,7 @@ impl std::fmt::Display for TerminalLogout { } } -#[derive(Default, Debug)] +#[derive(Default, Debug, Clone)] pub struct TerminalAuthentication { pub authentication_code: String, } @@ -181,10 +214,27 @@ pub struct TerminalAuthentication { impl TerminalAuthentication { pub const ID: u16 = 0x0102; - pub fn parse(&mut self, rawbody: &Vec) {} + pub fn parse(&mut self, rawbody: &Vec) { + let mut bd = rawbody.into_iter(); + let plate_decode: &mut Vec = &mut vec![]; + while let Some(i) = bd.next() { + plate_decode.push(*i); + } + + let (cow, _encoding_used, _had_errors) = GBK.decode(plate_decode); + self.authentication_code = cow.into(); + } + + pub fn generate_reply(&self, answer_id: u16, serial: u16) -> PlatformUniversalResponse { + let mut res = PlatformUniversalResponse::default(); + res.answer_serial_no = serial; + res.answer_id = answer_id; + res.result = TerminalRegistrationResult::Success as u8; + res + } } -#[derive(Default, Debug)] +#[derive(Default, Debug, Clone)] pub struct TerminalParameterSetting { pub total_parameters: u8, pub parameters: Vec, @@ -196,7 +246,7 @@ impl TerminalParameterSetting { pub fn parse(&mut self, rawbody: &Vec) {} } -#[derive(Default, Debug)] +#[derive(Default, Debug, Clone)] pub struct TerminalParameterData { pub parameter_id: u32, pub parameter_length: u8, @@ -207,7 +257,7 @@ impl TerminalParameterData { pub fn parse(&mut self, rawbody: &Vec) {} } -#[derive(Default, Debug)] +#[derive(Default, Debug, Clone)] pub struct QueryTerminalParameter {} impl QueryTerminalParameter { pub const ID: u16 = 0x8104; @@ -215,7 +265,7 @@ impl QueryTerminalParameter { pub fn parse(&mut self, rawbody: &Vec) {} } -#[derive(Default, Debug)] +#[derive(Default, Debug, Clone)] pub struct QueryTerminalParameterResponse { pub response_serial_no: u16, pub response_parameter_quantity: u16, @@ -228,7 +278,7 @@ impl QueryTerminalParameterResponse { pub fn parse(&mut self, rawbody: &Vec) {} } -#[derive(Default, Debug)] +#[derive(Default, Debug, Clone)] pub struct TerminalControl { pub command_word: u8, pub command_parameter: String, @@ -240,7 +290,7 @@ impl TerminalControl { pub fn parse(&mut self, rawbody: &Vec) {} } -#[derive(Default, Debug)] +#[derive(Default, Debug, Clone)] pub struct LocationInformationReport { pub alert_mark: u32, pub status: u32, @@ -257,7 +307,7 @@ impl LocationInformationReport { pub fn parse(&mut self, rawbody: &Vec) {} } -#[derive(Default, Debug)] +#[derive(Default, Debug, Clone)] pub struct StartOfTrip {} impl StartOfTrip { pub const ID: u16 = 0x0202; @@ -265,7 +315,7 @@ impl StartOfTrip { pub fn parse(&mut self, rawbody: &Vec) {} } -#[derive(Default, Debug)] +#[derive(Default, Debug, Clone)] pub struct EndOfTrip {} impl EndOfTrip { pub const ID: u16 = 0x0203; diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 31084f9..32359b3 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1,10 +1,13 @@ -mod body; -mod error; +pub mod body; +pub mod error; use body::*; use error::*; +use std::collections::VecDeque; + use bcd_convert::BcdNumber; +use rand::prelude::*; const FLAGDELIMITER: u8 = 0x7E; @@ -35,13 +38,16 @@ pub fn parse_inbound_msg(rawdata: &mut DataWrapper) -> std::result::Result, + pub data: VecDeque, pub count: usize, } impl DataWrapper { pub fn new(data: Vec) -> DataWrapper { - DataWrapper { data, count: 0 } + DataWrapper { + data: data.into(), + count: 0, + } } } @@ -52,7 +58,7 @@ impl Iterator for DataWrapper { let res: Option; if self.count < 6 { - res = self.data.pop() + res = self.data.pop_front() } else { res = None } @@ -216,21 +222,67 @@ impl Message { self.content = MessageType::StartOfTrip(StartOfTrip::new(&self.body)) } EndOfTrip::ID => self.content = MessageType::EndOfTrip(EndOfTrip::new(&self.body)), - _ => self.content = MessageType::None, + _ => { + self.content = MessageType::TerminalUniversalResponse( + TerminalUniversalResponse::new(&self.body), + ) + } } } - pub fn set_reply(msg: Message) -> Message { - let mut reply = Message::default(); - match msg.content { + pub fn set_reply(inmsg: Message) -> Option { + let mut reply: Message = Message::default(); + let mut rng = rand::thread_rng(); + match inmsg.content { MessageType::TerminalRegistration(t) => { - reply.content = MessageType::TerminalRegistrationReply( - t.generate_reply(msg.header.raw_terminal_id.into(), msg.header.serial_number), + let cnt = t.generate_reply( + inmsg.header.raw_terminal_id.into(), + inmsg.header.serial_number, ); + reply.header.id = TerminalRegistrationReply::ID; + reply.header.properties = cnt.to_raw().len() as u16; + reply.header.raw_terminal_id = inmsg.header.raw_terminal_id; + reply.header.serial_number = rng.gen(); + reply.content = MessageType::TerminalRegistrationReply(cnt); + } + MessageType::TerminalAuthentication(t) => { + let cnt = t.generate_reply(TerminalAuthentication::ID, inmsg.header.serial_number); + reply.header.id = PlatformUniversalResponse::ID; + reply.header.raw_terminal_id = inmsg.header.raw_terminal_id; + reply.header.properties = cnt.to_raw().len() as u16; + reply.header.serial_number = rng.gen(); + reply.content = MessageType::PlatformUniversalResponse(cnt); + } + _ => { + println!("no type"); + return None; } - _ => {} } - reply + Some(reply) + } + + pub fn to_raw(&self) -> VecDeque { + let mut resp: VecDeque = vec![].into(); + + let mut checksum: u8 = 0; + + for b in self.header.to_raw() { + resp.push_back(b); + } + + for b in self.content.to_raw() { + resp.push_back(b); + } + + for b in resp.iter() { + checksum = checksum ^ b; + } + + resp.push_back(checksum); + + resp.push_front(FLAGDELIMITER); + resp.push_back(FLAGDELIMITER); + resp } } @@ -248,17 +300,36 @@ pub struct MessageHeader { pub serial_number: u16, } +impl MessageHeader { + fn to_raw(&self) -> Vec { + let mut r: Vec = vec![]; + for b in self.id.to_be_bytes() { + r.push(b); + } + for b in self.properties.to_be_bytes() { + r.push(b); + } + for b in self.raw_terminal_id.into_iter() { + r.push(b); + } + for b in self.serial_number.to_be_bytes() { + r.push(b); + } + r + } +} + impl std::fmt::Display for MessageHeader { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!( f, - "message header: id: {:X?}, length: {}, terminal id: {}, serial: {}", + "message header: id: {:X?}, length: {}, terminal id: {}, serial: {:X?}", self.id, self.bodylength, self.terminal_id, self.serial_number ) } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum MessageType { None, TerminalUniversalResponse(TerminalUniversalResponse), @@ -283,8 +354,40 @@ impl Default for MessageType { } } +impl BodyMessage for MessageType { + fn to_raw(&self) -> Vec { + let res = match self { + MessageType::TerminalRegistrationReply(o) => o.to_raw(), + MessageType::PlatformUniversalResponse(o) => o.to_raw(), + //MessageType::TerminalHeartbeat(o) => o.to_raw(), + _ => vec![], + }; + res + } +} + impl std::fmt::Display for MessageType { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{:?}", self) } } + +/* +macro_rules! generate_switch { + ($($t:ty),*) => { + $( + //impl BodyMessage for $t { + // fn build() {} + // fn body_to_iter<'a>(&'a self, rawbody: &'a Vec) -> std::slice::Iter<'a, u8> { + // rawbody.into_iter() + // } + //} + impl $t { + pub fn new(rawbody: &Vec) -> Self { + let mut res = Self::default(); + res.parse(rawbody); + res + } + })* + }; +}*/