diff options
| author | Max Audron <audron@cocaine.farm> | 2020-01-14 12:35:46 +0100 |
|---|---|---|
| committer | Max Audron <audron@cocaine.farm> | 2020-01-17 10:48:27 +0100 |
| commit | 5d50a5f0c03baf460fee394decce5898812dbd2c (patch) | |
| tree | fc53a8ea19786be4dc57f9736cd4bf4e76026227 /src/protocol/message | |
| parent | initial implementation done (diff) | |
refactor parse impl
Diffstat (limited to 'src/protocol/message')
| -rw-r--r-- | src/protocol/message/handshake.rs | 99 | ||||
| -rw-r--r-- | src/protocol/message/handshake/types.rs | 92 | ||||
| -rw-r--r-- | src/protocol/message/mod.rs | 3 |
3 files changed, 194 insertions, 0 deletions
diff --git a/src/protocol/message/handshake.rs b/src/protocol/message/handshake.rs new file mode 100644 index 0000000..918c424 --- /dev/null +++ b/src/protocol/message/handshake.rs @@ -0,0 +1,99 @@ +use crate::protocol::primitive::{String, StringList, Variant, VariantList}; +use crate::protocol::primitive::{serialize, deserialize, qread}; + +mod types; +pub use types::{VariantMap, HandshakeDeserialize, HandshakeSerialize, HandshakeQRead}; + +use crate::match_variant; +#[derive(Debug)] +pub struct ClientInit { + pub client_version: String, // Version of the client + pub client_date: String, // Build date of the client + pub client_features: u32, + pub feature_list: StringList // List of supported extended features +} + +impl HandshakeSerialize for ClientInit { + fn serialize(&self) -> Vec<u8> { + let mut values: VariantMap = VariantMap::with_capacity(5); + values.insert("MsgType".to_string(), Variant::String("ClientInit".to_string())); + values.insert("ClientVersion".to_string(), Variant::String(self.client_version.clone())); + values.insert("ClientDate".to_string(), Variant::String(self.client_date.clone())); + values.insert("Features".to_string(), Variant::u32(self.client_features)); + values.insert("FeatureList".to_string(), Variant::StringList(self.feature_list.clone())); + return HandshakeSerialize::serialize(&values); + } +} + +impl HandshakeDeserialize for ClientInit { + fn parse(b: &[u8]) -> (usize, Self) { + let (len, values): (usize, VariantMap) = HandshakeDeserialize::parse(b); + + return (len, Self { + client_version: match_variant!(values, Variant::String, "ClientVersion"), + client_date: match_variant!(values, Variant::String, "ClientDate"), + feature_list: match_variant!(values, Variant::StringList, "FeatureList"), + client_features: match_variant!(values, Variant::u32, "Features") + }); + } +} + +#[derive(Debug)] +pub struct ClientInitReject { + pub error_string: String +} + +impl HandshakeSerialize for ClientInitReject { + fn serialize(&self) -> Vec<u8> { + let mut values: VariantMap = VariantMap::with_capacity(2); + values.insert("MsgProtocol::Primitive".to_string(), Variant::String("ClientInitReject".to_string())); + values.insert("ErrorString".to_string(), Variant::String(self.error_string.clone())); + return HandshakeSerialize::serialize(&values); + } +} + +impl HandshakeDeserialize for ClientInitReject { + fn parse(b: &[u8]) -> (usize, Self) { + let (len, values): (usize, VariantMap) = HandshakeDeserialize::parse(b); + + return (len, Self { + error_string: match_variant!(values, Variant::String, "ErrorString") + }); + } +} + +#[derive(Debug)] +pub struct ClientInitAck { + pub core_features: u32, // Flags of supported legacy features + pub core_configured: bool, // If the core has already been configured + pub backend_info: VariantList, // List of VariantMaps of info on available backends + pub authenticator_info: VariantList, // List of VariantMaps of info on available authenticators + pub feature_list: StringList, // List of supported extended features +} + +impl HandshakeSerialize for ClientInitAck { + fn serialize(&self) -> Vec<u8> { + let mut values: VariantMap = VariantMap::with_capacity(2); + values.insert("MsgProtocol::Primitive".to_string(), Variant::String("ClientInitAck".to_string())); + values.insert("CoreFeatures".to_string(), Variant::u32(self.core_features)); + values.insert("CoreConfigured".to_string(), Variant::bool(self.core_configured)); + values.insert("BackendInfo".to_string(), Variant::VariantList(self.backend_info.clone())); + values.insert("AuthenticatorInfo".to_string(), Variant::VariantList(self.authenticator_info.clone())); + values.insert("FeatureList".to_string(), Variant::StringList(self.feature_list.clone())); + return HandshakeSerialize::serialize(&values); + } +} + +impl HandshakeDeserialize for ClientInitAck { + fn parse(b: &[u8]) -> (usize, Self) { + let (len, values): (usize, VariantMap) = HandshakeDeserialize::parse(b); + + return (len, Self { + core_features: match_variant!(values, Variant::u32, "CoreFeatures"), + core_configured: match_variant!(values, Variant::bool, "CoreConfigured"), + backend_info: match_variant!(values, Variant::VariantList, "BackendInfo"), + authenticator_info: match_variant!(values, Variant::VariantList, "AuthenticatorInfo"), + feature_list: match_variant!(values, Variant::StringList, "FeatureList") + }); + } +} diff --git a/src/protocol/message/handshake/types.rs b/src/protocol/message/handshake/types.rs new file mode 100644 index 0000000..d6ea346 --- /dev/null +++ b/src/protocol/message/handshake/types.rs @@ -0,0 +1,92 @@ +use std::io::Read; +use std::vec::Vec; +use std::net::TcpStream; +use std::convert::TryInto; +use std::collections::HashMap; + +use crate::util; +use crate::protocol::primitive::{String, Variant}; +use crate::protocol::primitive::serialize::Serialize; +use crate::protocol::primitive::deserialize::Deserialize; +use crate::protocol::primitive::qread::QRead; + +pub trait HandshakeSerialize { + fn serialize(&self) -> Vec<u8>; +} + +pub trait HandshakeDeserialize { + fn parse(b: &[u8]) -> (usize, Self); +} + +pub trait HandshakeQRead { + fn read(stream: &mut std::net::TcpStream, buf: &mut [u8]) -> usize; +} + + +pub type VariantMap = HashMap<String, Variant>; + +impl HandshakeSerialize for VariantMap { + fn serialize<'a>(&'a self) -> Vec<u8> { + let mut res: Vec<u8> = Vec::new(); + + for (k, v) in self { + let key = Variant::String(k.clone()); + res.extend(key.serialize()); + res.extend(v.serialize()); + } + + util::insert_bytes(0, &mut res, &mut [0, 0, 0, 10]); + + let len: i32 = res.len().try_into().unwrap(); + util::insert_bytes(0, &mut res, &mut ((len + 4).to_be_bytes())); + println!("len: {:?}", len + 4); + + return res; + } +} + +impl HandshakeDeserialize for VariantMap { + fn parse(b: &[u8]) -> (usize, Self) { + let (_, len) = i32::parse(&b[0..4]); + + let mut pos: usize = 8; + let mut map = VariantMap::new(); + let ulen: usize = len as usize; + loop { + if (pos) >= ulen { break; } + let (nlen, name) = Variant::parse(&b[(pos)..]); + pos += nlen; + + let (vlen, value) = Variant::parse(&b[(pos)..]); + pos += vlen; + + if let Variant::StringUTF8(x) = name { + map.insert(x, value); + } + } + + return (pos, map); + } +} + +impl HandshakeQRead for VariantMap { + fn read(mut s: &mut TcpStream, b: &mut [u8]) -> usize { + s.read(&mut b[0..4]).unwrap(); + let (_, len) = i32::parse(&b[0..4]); + println!("len: {:?}", len); + + // Read the 00 00 00 0a VariantType bytes and discard + let mut tbuf = [0; 4]; + s.read(&mut tbuf).unwrap(); + + let mut pos = 4; + let len: usize = len as usize; + loop { + if pos >= (len - 4) { break; } + pos += Variant::read(&mut s, &mut b[pos..]); + pos += Variant::read(&mut s, &mut b[(pos+4..)]); + } + + return pos; + } +} diff --git a/src/protocol/message/mod.rs b/src/protocol/message/mod.rs new file mode 100644 index 0000000..3b6d1a8 --- /dev/null +++ b/src/protocol/message/mod.rs @@ -0,0 +1,3 @@ +pub mod handshake; + +pub use handshake::*; |
