diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/net.rs | 17 | ||||
| -rw-r--r-- | src/protocol/error/mod.rs | 28 | ||||
| -rw-r--r-- | src/protocol/message/handshake.rs | 94 | ||||
| -rw-r--r-- | src/protocol/message/handshake/types.rs | 44 | ||||
| -rw-r--r-- | src/protocol/mod.rs | 1 | ||||
| -rw-r--r-- | src/protocol/primitive/basic.rs | 149 | ||||
| -rw-r--r-- | src/protocol/primitive/mod.rs | 17 | ||||
| -rw-r--r-- | src/protocol/primitive/variant.rs | 177 | ||||
| -rw-r--r-- | src/tests/base_types.rs | 16 | ||||
| -rw-r--r-- | src/tests/handshake_types.rs | 8 | ||||
| -rw-r--r-- | src/tests/variant_types.rs | 31 |
11 files changed, 327 insertions, 255 deletions
@@ -10,6 +10,7 @@ extern crate log; use crate::protocol::message; +use crate::protocol::error::ErrorKind; pub struct Client { tcp_stream: TcpStream, @@ -24,10 +25,10 @@ impl Client { use crate::protocol::message::handshake::{HandshakeDeserialize, HandshakeSerialize, HandshakeQRead, VariantMap}; use crate::protocol::message::handshake::{ClientInit, ClientInitAck}; - self.tcp_stream.write(&client.serialize()).unwrap(); + self.tcp_stream.write(&client.serialize().unwrap()).unwrap(); let mut buf: Vec<u8> = [0; 2048].to_vec(); - let len = VariantMap::read(&mut self.tcp_stream, &mut buf); + let len = VariantMap::read(&mut self.tcp_stream, &mut buf).unwrap(); buf.truncate(len); let res = ClientInitAck::parse(&buf); @@ -67,18 +68,18 @@ pub fn connect(address: &'static str, port: u32, tls: bool, compression: bool) - } impl Deserialize for ConnAck { - fn parse(b: &[u8]) -> (usize, Self) { - let (flen, flags) = u8::parse(b); - let (elen, extra) = i16::parse(&b[flen..]); - let (vlen, version) = i8::parse(&b[(flen+elen)..]); + fn parse(b: &[u8]) -> Result<(usize, Self), ErrorKind> { + let (flen, flags) = u8::parse(b)?; + let (elen, extra) = i16::parse(&b[flen..])?; + let (vlen, version) = i8::parse(&b[(flen+elen)..])?; - return (flen+elen+vlen, Self {flags, extra, version}); + return Ok((flen+elen+vlen, Self {flags, extra, version})); } } let mut buf = [0; 4]; s.read_exact(&mut buf)?; - let (_, val) = ConnAck::parse(&buf); + let (_, val) = ConnAck::parse(&buf).unwrap(); println!("Received: {:?}", val); let server: Client = Client { diff --git a/src/protocol/error/mod.rs b/src/protocol/error/mod.rs new file mode 100644 index 0000000..488ae0d --- /dev/null +++ b/src/protocol/error/mod.rs @@ -0,0 +1,28 @@ +#[derive(Debug)] +pub enum ErrorKind { + WrongMsgType, + BoolOutOfRange, + UnknownVariant, + WrongVariant, + IOError(std::io::Error), + TryFromIntError(std::num::TryFromIntError), + Utf8Error(std::string::FromUtf8Error), +} + +impl std::convert::From<std::io::Error> for ErrorKind { + fn from(error: std::io::Error) -> Self { + ErrorKind::IOError(error) + } +} + +impl std::convert::From<std::num::TryFromIntError> for ErrorKind { + fn from(error: std::num::TryFromIntError) -> Self { + ErrorKind::TryFromIntError(error) + } +} + +impl std::convert::From<std::string::FromUtf8Error> for ErrorKind { + fn from(error: std::string::FromUtf8Error) -> Self { + ErrorKind::Utf8Error(error) + } +} diff --git a/src/protocol/message/handshake.rs b/src/protocol/message/handshake.rs index b346d8e..7713ed9 100644 --- a/src/protocol/message/handshake.rs +++ b/src/protocol/message/handshake.rs @@ -1,5 +1,7 @@ +use std::result::Result; + +use crate::protocol::error::ErrorKind; use crate::protocol::primitive::{String, StringList, Variant, VariantList}; -use crate::protocol::primitive::{serialize, deserialize, qread}; mod types; pub use types::{VariantMap, HandshakeDeserialize, HandshakeSerialize, HandshakeQRead}; @@ -14,7 +16,7 @@ pub struct ClientInit { } impl HandshakeSerialize for ClientInit { - fn serialize(&self) -> Vec<u8> { + fn serialize(&self) -> Result<Vec<u8>, ErrorKind> { 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())); @@ -26,15 +28,27 @@ impl HandshakeSerialize for ClientInit { } 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") - }); + fn parse(b: &[u8]) -> Result<(usize, Self), ErrorKind> { + let (len, values): (usize, VariantMap) = HandshakeDeserialize::parse(b)?; + + let msgtypev = &values["MsgType"]; + let msgtype; + match msgtypev { + Variant::String(x) => msgtype = x, + Variant::StringUTF8(x) => msgtype = x, + _ => return Err(ErrorKind::WrongVariant) + }; + + if msgtype == "ClientInit" { + return Ok((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") + })); + } else { + return Err(ErrorKind::WrongMsgType); + } } } @@ -44,7 +58,7 @@ pub struct ClientInitReject { } impl HandshakeSerialize for ClientInitReject { - fn serialize(&self) -> Vec<u8> { + fn serialize(&self) -> Result<Vec<u8>, ErrorKind> { let mut values: VariantMap = VariantMap::with_capacity(2); values.insert("MsgType".to_string(), Variant::String("ClientInitReject".to_string())); values.insert("ErrorString".to_string(), Variant::String(self.error_string.clone())); @@ -53,12 +67,24 @@ impl HandshakeSerialize for ClientInitReject { } impl HandshakeDeserialize for ClientInitReject { - fn parse(b: &[u8]) -> (usize, Self) { - let (len, values): (usize, VariantMap) = HandshakeDeserialize::parse(b); + fn parse(b: &[u8]) -> Result<(usize, Self), ErrorKind> { + let (len, values): (usize, VariantMap) = HandshakeDeserialize::parse(b)?; - return (len, Self { - error_string: match_variant!(values, Variant::String, "ErrorString") - }); + let msgtypev = &values["MsgType"]; + let msgtype; + match msgtypev { + Variant::String(x) => msgtype = x, + Variant::StringUTF8(x) => msgtype = x, + _ => return Err(ErrorKind::WrongVariant) + }; + + if msgtype == "ClientInitReject" { + return Ok((len, Self { + error_string: match_variant!(values, Variant::String, "ErrorString") + })); + } else { + return Err(ErrorKind::WrongMsgType); + } } } @@ -72,7 +98,7 @@ pub struct ClientInitAck { } impl HandshakeSerialize for ClientInitAck { - fn serialize(&self) -> Vec<u8> { + fn serialize(&self) -> Result<Vec<u8>, ErrorKind> { let mut values: VariantMap = VariantMap::with_capacity(2); values.insert("MsgType".to_string(), Variant::String("ClientInitAck".to_string())); values.insert("CoreFeatures".to_string(), Variant::u32(self.core_features)); @@ -85,15 +111,27 @@ impl HandshakeSerialize for ClientInitAck { } impl HandshakeDeserialize for ClientInitAck { - fn parse(b: &[u8]) -> (usize, Self) { - let (len, values): (usize, VariantMap) = HandshakeDeserialize::parse(b); - - return (len, Self { - core_features: 0x00008000, - core_configured: match_variant!(values, Variant::bool, "Configured"), - storage_backends: match_variant!(values, Variant::VariantList, "StorageBackends"), - authenticators: match_variant!(values, Variant::VariantList, "Authenticators"), - feature_list: match_variant!(values, Variant::StringList, "FeatureList") - }); + fn parse(b: &[u8]) -> Result<(usize, Self), ErrorKind> { + let (len, values): (usize, VariantMap) = HandshakeDeserialize::parse(b)?; + + let msgtypev = &values["MsgType"]; + let msgtype; + match msgtypev { + Variant::String(x) => msgtype = x, + Variant::StringUTF8(x) => msgtype = x, + _ => return Err(ErrorKind::WrongVariant) + }; + + if msgtype == "ClientInitAck" { + return Ok((len, Self { + core_features: 0x00008000, + core_configured: match_variant!(values, Variant::bool, "Configured"), + storage_backends: match_variant!(values, Variant::VariantList, "StorageBackends"), + authenticators: match_variant!(values, Variant::VariantList, "Authenticators"), + feature_list: match_variant!(values, Variant::StringList, "FeatureList") + })); + } else { + return Err(ErrorKind::WrongMsgType); + } } } diff --git a/src/protocol/message/handshake/types.rs b/src/protocol/message/handshake/types.rs index dadd058..be290e9 100644 --- a/src/protocol/message/handshake/types.rs +++ b/src/protocol/message/handshake/types.rs @@ -1,5 +1,6 @@ use std::io::Read; use std::vec::Vec; +use std::result::Result; use std::convert::TryInto; use std::collections::HashMap; @@ -8,82 +9,83 @@ use crate::protocol::primitive::{String, Variant}; use crate::protocol::primitive::serialize::Serialize; use crate::protocol::primitive::deserialize::Deserialize; use crate::protocol::primitive::qread::QRead; +use crate::protocol::error::ErrorKind; pub trait HandshakeSerialize { - fn serialize(&self) -> Vec<u8>; + fn serialize(&self) -> Result<Vec<u8>, ErrorKind>; } pub trait HandshakeDeserialize { - fn parse(b: &[u8]) -> (usize, Self); + fn parse(b: &[u8]) -> Result<(usize, Self), ErrorKind> where Self: std::marker::Sized ; } pub trait HandshakeQRead { - fn read<T: Read>(stream: &mut T, buf: &mut [u8]) -> usize; + fn read<T: Read>(stream: &mut T, buf: &mut [u8]) -> Result<usize, ErrorKind>; } pub type VariantMap = HashMap<String, Variant>; impl HandshakeSerialize for VariantMap { - fn serialize<'a>(&'a self) -> Vec<u8> { + fn serialize<'a>(&'a self) -> Result<Vec<u8>, ErrorKind> { 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()); + 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(); + let len: i32 = res.len().try_into()?; util::insert_bytes(0, &mut res, &mut ((len).to_be_bytes())); - return res; + return Ok(res); } } impl HandshakeDeserialize for VariantMap { - fn parse(b: &[u8]) -> (usize, Self) { - let (_, len) = i32::parse(&b[0..4]); + fn parse(b: &[u8]) -> Result<(usize, Self), ErrorKind> { + 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..]); + let (nlen, name) = Variant::parse(&b[pos..])?; pos += nlen; - let (vlen, value) = Variant::parse(&b[pos..]); + let (vlen, value) = Variant::parse(&b[pos..])?; pos += vlen; match name { Variant::String(x) => map.insert(x, value), Variant::StringUTF8(x) => map.insert(x, value), - _ => panic!() + _ => return Err(ErrorKind::WrongVariant) }; } - return (pos, map); + return Ok((pos, map)); } } impl HandshakeQRead for VariantMap { - fn read<T: Read>(s: &mut T, b: &mut [u8]) -> usize { - s.read(&mut b[0..4]).unwrap(); - let (_, len) = i32::parse(&b[0..4]); + fn read<T: Read>(s: &mut T, b: &mut [u8]) -> Result<usize, ErrorKind> { + s.read(&mut b[0..4])?; + let (_, len) = i32::parse(&b[0..4])?; // Read the 00 00 00 0a VariantType bytes and discard - s.read(&mut b[4..8]).unwrap(); + s.read(&mut b[4..8])?; let mut pos = 8; let len: usize = len as usize; loop { if pos >= (len - 4) { break; } - pos += Variant::read(s, &mut b[pos..]); - pos += Variant::read(s, &mut b[pos..]); + pos += Variant::read(s, &mut b[pos..])?; + pos += Variant::read(s, &mut b[pos..])?; } - return pos; + return Ok(pos); } } diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 044a28b..8739fd8 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -1,2 +1,3 @@ pub mod message; pub mod primitive; +pub mod error; diff --git a/src/protocol/primitive/basic.rs b/src/protocol/primitive/basic.rs index 30de1c7..15b712f 100644 --- a/src/protocol/primitive/basic.rs +++ b/src/protocol/primitive/basic.rs @@ -29,122 +29,133 @@ pub const UCHAR: u32 = 0x00000086; // uint8_t extern crate byteorder; use std::io::Cursor; -use byteorder::{ByteOrder, BigEndian, ReadBytesExt}; +use byteorder::{BigEndian, ReadBytesExt}; -use std::io::Read; use std::vec::Vec; +use std::result::Result; use std::convert::TryInto; use crate::util; +use crate::protocol::error::ErrorKind; use crate::protocol::primitive::{deserialize, serialize, qread}; impl deserialize::Deserialize for bool { - fn parse(b: &[u8]) -> (usize, Self) { - if b[0] == 0 { return (1, false) } else { return (1, true) }; + fn parse(b: &[u8]) -> Result<(usize, Self), ErrorKind> { + if b[0] == 0 { + return Ok((1, false)) + } else if b[0] == 1 { + return Ok((1, true)) + } else { + return Err(ErrorKind::BoolOutOfRange); + }; } } impl qread::QRead for bool { - fn read<T: Read>(s: &mut T, b: &mut [u8]) -> usize { - s.read(&mut b[0..1]).unwrap() + fn read<T: std::io::Read>(s: &mut T, b: &mut [u8]) -> Result<usize, ErrorKind> { + Ok(s.read(&mut b[0..1])?) } } impl deserialize::Deserialize for u64 { - fn parse(b: &[u8]) -> (usize, Self) { - return (8, BigEndian::read_u64(b)); + fn parse(b: &[u8]) -> Result<(usize, Self), ErrorKind> { + let mut rdr = Cursor::new(&b[0..8]); + return Ok((8, rdr.read_u64::<BigEndian>()?)); } } impl qread::QRead for u64 { - fn read<T: Read>(s: &mut T, b: &mut [u8]) -> usize { - s.read(&mut b[0..8]).unwrap() + fn read<T: std::io::Read>(s: &mut T, b: &mut [u8]) -> Result<usize, ErrorKind> { + Ok(s.read(&mut b[0..8])?) } } impl deserialize::Deserialize for u32 { - fn parse(b: &[u8]) -> (usize, Self) { - // self = &rdr.read_u32::<BigEndian>().unwrap() - return (4, BigEndian::read_u32(b)); + fn parse(b: &[u8]) -> Result<(usize, Self), ErrorKind> { + let mut rdr = Cursor::new(&b[0..4]); + return Ok((4, rdr.read_u32::<BigEndian>()?)); } } impl qread::QRead for u32 { - fn read<T: Read>(s: &mut T, b: &mut [u8]) -> usize { - s.read(&mut b[0..4]).unwrap() + fn read<T: std::io::Read>(s: &mut T, b: &mut [u8]) -> Result<usize, ErrorKind> { + Ok(s.read(&mut b[0..4])?) } } impl deserialize::Deserialize for u16 { - fn parse(b: &[u8]) -> (usize, Self) { - return (2, BigEndian::read_u16(b)); + fn parse(b: &[u8]) -> Result<(usize, Self), ErrorKind> { + let mut rdr = Cursor::new(&b[0..2]); + return Ok((2, rdr.read_u16::<BigEndian>()?)); } } impl qread::QRead for u16 { - fn read<T: Read>(s: &mut T, b: &mut [u8]) -> usize { - s.read(&mut b[0..2]).unwrap() + fn read<T: std::io::Read>(s: &mut T, b: &mut [u8]) -> Result<usize, ErrorKind> { + Ok(s.read(&mut b[0..2])?) } } impl deserialize::Deserialize for u8 { - fn parse(b: &[u8]) -> (usize, Self) { - return (1, b[0]); + fn parse(b: &[u8]) -> Result<(usize, Self), ErrorKind> { + return Ok((1, b[0])); } } impl qread::QRead for u8 { - fn read<T: Read>(s: &mut T, b: &mut [u8]) -> usize { - s.read(&mut [b[0]]).unwrap() + fn read<T: std::io::Read>(s: &mut T, b: &mut [u8]) -> Result<usize, ErrorKind> { + Ok(s.read(&mut [b[0]])?) } } impl deserialize::Deserialize for i64 { - fn parse(b: &[u8]) -> (usize, Self) { - return (8, BigEndian::read_i64(b)); + fn parse(b: &[u8]) -> Result<(usize, Self), ErrorKind> { + let mut rdr = Cursor::new(&b[0..8]); + return Ok((8, rdr.read_i64::<BigEndian>()?)); } } impl qread::QRead for i64 { - fn read<T: Read>(s: &mut T, b: &mut [u8]) -> usize { - s.read(&mut b[0..8]).unwrap() + fn read<T: std::io::Read>(s: &mut T, b: &mut [u8]) -> Result<usize, ErrorKind> { + Ok(s.read(&mut b[0..8])?) } } impl deserialize::Deserialize for i32 { - fn parse(b: &[u8]) -> (usize, Self) { + fn parse(b: &[u8]) -> Result<(usize, Self), ErrorKind> { let mut rdr = Cursor::new(&b[0..4]); - return (4, rdr.read_i32::<BigEndian>().unwrap()); + return Ok((4, rdr.read_i32::<BigEndian>()?)); } } impl qread::QRead for i32 { - fn read<T: Read>(s: &mut T, b: &mut [u8]) -> usize { - s.read(&mut b[0..4]).unwrap() + fn read<T: std::io::Read>(s: &mut T, b: &mut [u8]) -> Result<usize, ErrorKind> { + Ok(s.read(&mut b[0..4])?) } } impl deserialize::Deserialize for i16 { - fn parse(b: &[u8]) -> (usize, Self) { - return (2, BigEndian::read_i16(b)); + fn parse(b: &[u8]) -> Result<(usize, Self), ErrorKind> { + let mut rdr = Cursor::new(&b[0..2]); + return Ok((2, rdr.read_i16::<BigEndian>()?)); } } impl qread::QRead for i16 { - fn read<T: Read>(s: &mut T, b: &mut [u8]) -> usize { - s.read(&mut b[0..2]).unwrap() + fn read<T: std::io::Read>(s: &mut T, b: &mut [u8]) -> Result<usize, ErrorKind> { + Ok(s.read(&mut b[0..2])?) } } impl deserialize::Deserialize for i8 { - fn parse(b: &[u8]) -> (usize, Self) { - return (1, b[0].try_into().unwrap()); + fn parse(b: &[u8]) -> Result<(usize, Self), ErrorKind> { + return Ok((1, b[0].try_into()?)); } } impl qread::QRead for i8 { - fn read<T: Read>(s: &mut T, b: &mut [u8]) -> usize { - s.read(&mut [b[0]]).unwrap() + fn read<T: std::io::Read>(s: &mut T, b: &mut [u8]) -> Result<usize, ErrorKind> { + return Ok(s.read(&mut [b[0]])?) } } @@ -152,7 +163,7 @@ impl qread::QRead for i8 { pub type String = std::string::String; impl serialize::Serialize for String { - fn serialize(&self) -> Vec<u8> { + fn serialize(&self) -> Result<Vec<u8>, ErrorKind> { let mut res: Vec<u8> = Vec::new(); let utf16: Vec<u16> = self.encode_utf16().collect(); @@ -161,109 +172,109 @@ impl serialize::Serialize for String { } util::prepend_byte_len(&mut res); - return res; + return Ok(res); } } impl serialize::SerializeUTF8 for String { - fn serialize_utf8(&self) -> Vec<u8> { + fn serialize_utf8(&self) -> Result<Vec<u8>, ErrorKind> { let mut res: Vec<u8> = Vec::new(); res.extend(self.clone().into_bytes()); util::prepend_byte_len(&mut res); - return res; + return Ok(res); } } impl deserialize::Deserialize for String { - fn parse(b: &[u8]) -> (usize, Self) { - let (_, len) = i32::parse(&b[0..4]); + fn parse(b: &[u8]) -> Result<(usize, Self), ErrorKind> { + let (_, len) = i32::parse(&b[0..4])?; let ulen = len as usize; let mut pos: usize = 4; let mut chars: Vec<u16> = Vec::new(); loop { if pos >= (ulen + 4) { break; } - let (slen, uchar) = u16::parse(&b[pos..(pos+2)]); + let (slen, uchar) = u16::parse(&b[pos..(pos+2)])?; chars.push(uchar); pos += slen; } let res: String = String::from_utf16(&chars).unwrap(); - return (pos, res); + return Ok((pos, res)); } } impl deserialize::DeserializeUTF8 for String { - fn parse_utf8(b: &[u8]) -> (usize, Self) { + fn parse_utf8(b: &[u8]) -> Result<(usize, Self), ErrorKind> { use crate::protocol::primitive::deserialize::Deserialize; - let (_, len) = i32::parse(&b[0..4]); + let (_, len) = i32::parse(&b[0..4])?; let ulen = len as usize; - let res: String = String::from_utf8(b[4..(ulen+4)].to_vec()).unwrap(); - return (ulen + 4, res); + let res: String = String::from_utf8(b[4..(ulen+4)].to_vec())?; + return Ok((ulen + 4, res)); } } impl qread::QRead for String { - fn read<T: Read>(s: &mut T, b: &mut [u8]) -> usize { + fn read<T: std::io::Read>(s: &mut T, b: &mut [u8]) -> Result<usize, ErrorKind> { use crate::protocol::primitive::deserialize::Deserialize; - s.read(&mut b[0..4]).unwrap(); - let (_, len) = i32::parse(&b[0..4]); + s.read(&mut b[0..4])?; + let (_, len) = i32::parse(&b[0..4])?; let ulen = len as usize; - s.read(&mut b[4..(4+ulen)]).unwrap(); + s.read(&mut b[4..(4+ulen)])?; - return 4 + ulen; + return Ok(4 + ulen); } } pub type StringList = Vec<String>; impl serialize::Serialize for StringList { - fn serialize(&self) -> Vec<u8> { - let len: i32 = self.len().try_into().unwrap(); + fn serialize(&self) -> Result<Vec<u8>, ErrorKind> { + let len: i32 = self.len().try_into()?; let mut res: Vec<u8> = Vec::new(); res.extend(len.to_be_bytes().iter()); for x in self { - res.extend(x.serialize()); + res.extend(x.serialize()?); } - return res; + return Ok(res); } } impl deserialize::Deserialize for StringList { - fn parse(b: &[u8]) -> (usize, Self) { - let (_, len) = i32::parse(&b[0..4]); + fn parse(b: &[u8]) -> Result<(usize, Self), ErrorKind> { + let (_, len) = i32::parse(&b[0..4])?; let mut res: StringList = StringList::new(); let mut pos = 4; if len > 0 { for _ in 0..len { - let (lpos, val) = String::parse(&b[pos..]); + let (lpos, val) = String::parse(&b[pos..])?; pos += lpos; res.push(val); } } - return (pos, res); + return Ok((pos, res)); } } impl qread::QRead for StringList { - fn read<T: Read>(s: &mut T, b: &mut [u8]) -> usize { + fn read<T: std::io::Read>(s: &mut T, b: &mut [u8]) -> Result<usize, ErrorKind> { use crate::protocol::primitive::deserialize::Deserialize; - s.read(&mut b[0..4]).unwrap(); - let (_, len) = i32::parse(&b[0..4]); + s.read(&mut b[0..4])?; + let (_, len) = i32::parse(&b[0..4])?; let mut pos: usize = 4; for _ in 0..len { - pos += String::read(s, &mut b[pos..]); + pos += String::read(s, &mut b[pos..])?; } - return pos; + return Ok(pos); } } diff --git a/src/protocol/primitive/mod.rs b/src/protocol/primitive/mod.rs index 2cdd20a..42f6aae 100644 --- a/src/protocol/primitive/mod.rs +++ b/src/protocol/primitive/mod.rs @@ -5,26 +5,33 @@ pub mod variant; pub use basic::*; pub use variant::*; + pub mod serialize { + use crate::protocol::error::ErrorKind; + pub trait Serialize { - fn serialize(&self) -> Vec<u8>; + fn serialize(&self) -> Result<Vec<u8>, ErrorKind>; } pub trait SerializeUTF8 { - fn serialize_utf8(&self) -> Vec<u8>; + fn serialize_utf8(&self) -> Result<Vec<u8>, ErrorKind>; } } pub mod deserialize { + use crate::protocol::error::ErrorKind; + pub trait Deserialize { - fn parse(b: &[u8]) -> (usize, Self); + fn parse(b: &[u8]) -> Result<(usize, Self), ErrorKind> where Self: std::marker::Sized ; } pub trait DeserializeUTF8 { - fn parse_utf8(b: &[u8]) -> (usize, Self); + fn parse_utf8(b: &[u8]) -> Result<(usize, Self), ErrorKind> where Self: std::marker::Sized ; } } pub mod qread { + use crate::protocol::error::ErrorKind; + pub trait QRead { - fn read<T: std::io::Read>(stream: &mut T, buf: &mut [u8]) -> usize; + fn read<T: std::io::Read>(stream: &mut T, buf: &mut [u8]) -> Result<usize, ErrorKind>; } } diff --git a/src/protocol/primitive/variant.rs b/src/protocol/primitive/variant.rs index fdf93ad..8c6173f 100644 --- a/src/protocol/primitive/variant.rs +++ b/src/protocol/primitive/variant.rs @@ -8,60 +8,61 @@ use crate::protocol::primitive::serialize::{Serialize, SerializeUTF8}; use crate::protocol::primitive::deserialize::{Deserialize, DeserializeUTF8}; use crate::protocol::primitive::qread::QRead; use crate::protocol::primitive::{String,StringList}; +use crate::protocol::error::ErrorKind; use crate::protocol::primitive; pub type VariantMap = HashMap<String, Variant>; impl Serialize for VariantMap { - fn serialize<'a>(&'a self) -> Vec<u8> { + fn serialize<'a>(&'a self) -> Result<Vec<u8>, ErrorKind> { let mut res: Vec<u8> = Vec::new(); for (k, v) in self { - res.extend(k.serialize()); - res.extend(v.serialize()); + res.extend(k.serialize()?); + res.extend(v.serialize()?); } - let len: i32 = self.len().try_into().unwrap(); + let len: i32 = self.len().try_into()?; util::insert_bytes(0, &mut res, &mut len.to_be_bytes()); - return res; + return Ok(res); } } impl Deserialize for VariantMap { - fn parse(b: &[u8]) -> (usize, Self) { - let (_, len) = i32::parse(&b[0..4]); + fn parse(b: &[u8]) -> Result<(usize, Self), ErrorKind> { + let (_, len) = i32::parse(&b[0..4])?; let mut pos = 4; let mut map = VariantMap::new(); for _ in 0..len { - let (nlen, name) = String::parse(&b[(pos)..]); + let (nlen, name) = String::parse(&b[(pos)..])?; pos += nlen; - let (vlen, value) = Variant::parse(&b[(pos)..]); + let (vlen, value) = Variant::parse(&b[(pos)..])?; pos += vlen; map.insert(name, value); } - return (pos, map); + return Ok((pos, map)); } } impl QRead for VariantMap { - fn read<T: Read>(s: &mut T, b: &mut [u8]) -> usize { - s.read(&mut b[0..4]).unwrap(); + fn read<T: Read>(s: &mut T, b: &mut [u8]) -> Result<usize, ErrorKind> { + s.read(&mut b[0..4])?; - let (_, len) = i32::parse(&b[0..4]); + let (_, len) = i32::parse(&b[0..4])?; let mut pos = 4; for _ in 0..len { - pos += String::read(s, &mut b[pos..]); - pos += Variant::read(s, &mut b[(pos+3..)]); + pos += String::read(s, &mut b[pos..])?; + pos += Variant::read(s, &mut b[(pos+3..)])?; } - return pos; + return Ok(pos); } } @@ -69,47 +70,47 @@ impl QRead for VariantMap { pub type VariantList = Vec<Variant>; impl Serialize for VariantList { - fn serialize(&self) -> Vec<u8> { - let len: i32 = self.len().try_into().unwrap(); + fn serialize(&self) -> Result<Vec<u8>, ErrorKind> { + let len: i32 = self.len().try_into()?; let mut res: Vec<u8> = Vec::new(); res.extend(len.to_be_bytes().iter()); for v in self { - res.extend(v.serialize().iter()); + res.extend(v.serialize()?.iter()); } - return res; + return Ok(res); } } impl Deserialize for VariantList { - fn parse(b: &[u8]) -> (usize, Self) { - let (_, len) = i32::parse(&b[0..4]); + fn parse(b: &[u8]) -> Result<(usize, Self), ErrorKind> { + let (_, len) = i32::parse(&b[0..4])?; let mut res: VariantList = VariantList::new(); let mut pos: usize = 4; for _ in 0..len { - let (vlen, val) = Variant::parse(&b[pos..]); + let (vlen, val) = Variant::parse(&b[pos..])?; res.push(val); pos += vlen; } - return (pos, res); + return Ok((pos, res)); } } impl QRead for VariantList { - fn read<T: Read>(s: &mut T, b: &mut [u8]) -> usize { - s.read(&mut b[0..4]).unwrap(); + fn read<T: Read>(s: &mut T, b: &mut [u8]) -> Result<usize, ErrorKind> { + s.read(&mut b[0..4])?; - let (_, len) = i32::parse(&b[0..4]); + let (_, len) = i32::parse(&b[0..4])?; let mut pos = 4; for _ in 0..len { - pos += Variant::read(s, &mut b[(pos+3..)]); + pos += Variant::read(s, &mut b[(pos+3..)])?; } - return pos; + return Ok(pos); } } @@ -135,38 +136,38 @@ pub enum Variant { } impl Serialize for Variant { - fn serialize(&self) -> Vec<u8> { + fn serialize(&self) -> Result<Vec<u8>, ErrorKind> { let unknown: u8 = 0x00; let mut res: Vec<u8> = Vec::new(); match self { Variant::Unknown => { - return res; + return Err(ErrorKind::UnknownVariant); }, Variant::VariantMap(v) => { res.extend(primitive::QVARIANTMAP.to_be_bytes().iter()); res.extend(unknown.to_be_bytes().iter()); - res.extend(v.serialize().iter()); + res.extend(v.serialize()?.iter()); }, Variant::VariantList(v) => { res.extend(primitive::QVARIANTLIST.to_be_bytes().iter()); res.extend(unknown.to_be_bytes().iter()); - res.extend(v.serialize().iter()); + res.extend(v.serialize()?.iter()); }, Variant::String(v) => { res.extend(primitive::QSTRING.to_be_bytes().iter()); res.extend(unknown.to_be_bytes().iter()); - res.extend(v.serialize().iter()); + res.extend(v.serialize()?.iter()); }, Variant::StringUTF8(v) => { res.extend(primitive::QBYTEARRAY.to_be_bytes().iter()); res.extend(unknown.to_be_bytes().iter()); - res.extend(v.serialize_utf8().iter()); + res.extend(v.serialize_utf8()?.iter()); }, Variant::StringList(v) => { res.extend(primitive::QSTRINGLIST.to_be_bytes().iter()); res.extend(unknown.to_be_bytes().iter()); - res.extend(v.serialize().iter()); + res.extend(v.serialize()?.iter()); }, Variant::bool(v) => { res.extend(primitive::BOOL.to_be_bytes().iter()); @@ -216,13 +217,13 @@ impl Serialize for Variant { }, } - return res + return Ok(res) } } impl Deserialize for Variant { - fn parse(b: &[u8]) -> (usize, Self) { - let (_, qtype) = i32::parse(&b[0..4]); + fn parse(b: &[u8]) -> Result<(usize, Self), ErrorKind> { + let (_, qtype) = i32::parse(&b[0..4])?; let qtype = qtype as u32; #[allow(unused_variables)] @@ -231,96 +232,96 @@ impl Deserialize for Variant { let len = 5; match qtype { primitive::QVARIANTMAP => { - let (vlen, value) = VariantMap::parse(&b[len..]); - return (len+vlen, Variant::VariantMap(value)); + let (vlen, value) = VariantMap::parse(&b[len..])?; + return Ok((len+vlen, Variant::VariantMap(value))); }, primitive::QVARIANTLIST => { - let (vlen, value) = VariantList::parse(&b[len..]); - return (len+vlen, Variant::VariantList(value)); + let (vlen, value) = VariantList::parse(&b[len..])?; + return Ok((len+vlen, Variant::VariantList(value))); }, primitive::QSTRING => { - let (vlen, value) = String::parse(&b[len..]); - return (len+vlen, Variant::String(value.clone())); + let (vlen, value) = String::parse(&b[len..])?; + return Ok((len+vlen, Variant::String(value.clone()))); }, primitive::QBYTEARRAY => { - let (vlen, value) = String::parse_utf8(&b[len..]); - return (len+vlen, Variant::StringUTF8(value.clone())); + let (vlen, value) = String::parse_utf8(&b[len..])?; + return Ok((len+vlen, Variant::StringUTF8(value.clone()))); }, primitive::QSTRINGLIST => { - let (vlen, value) = StringList::parse(&b[len..]); - return (len+vlen, Variant::StringList(value.clone())); + let (vlen, value) = StringList::parse(&b[len..])?; + return Ok((len+vlen, Variant::StringList(value.clone()))); }, primitive::BOOL => { - let (vlen, value) = bool::parse(&b[len..]); - return (len+vlen, Variant::bool(value)); + let (vlen, value) = bool::parse(&b[len..])?; + return Ok((len+vlen, Variant::bool(value))); }, primitive::ULONG => { - let (vlen, value) = u64::parse(&b[len..]); - return (len+vlen, Variant::u64(value)); + let (vlen, value) = u64::parse(&b[len..])?; + return Ok((len+vlen, Variant::u64(value))); }, primitive::UINT => { - let (vlen, value) = u32::parse(&b[len..]); - return (len+vlen, Variant::u32(value)); + let (vlen, value) = u32::parse(&b[len..])?; + return Ok((len+vlen, Variant::u32(value))); }, primitive::USHORT => { - let (vlen, value) = u16::parse(&b[len..]); - return (len+vlen, Variant::u16(value)); + let (vlen, value) = u16::parse(&b[len..])?; + return Ok((len+vlen, Variant::u16(value))); }, primitive::UCHAR => { - let (vlen, value) = u8::parse(&b[len..]); - return (len+vlen, Variant::u8(value)); + let (vlen, value) = u8::parse(&b[len..])?; + return Ok((len+vlen, Variant::u8(value))); }, primitive::LONG => { - let (vlen, value) = i64::parse(&b[len..]); - return (len+vlen, Variant::i64(value)); + let (vlen, value) = i64::parse(&b[len..])?; + return Ok((len+vlen, Variant::i64(value))); }, primitive::INT => { - let (vlen, value) = i32::parse(&b[len..]); - return (len+vlen, Variant::i32(value)); + let (vlen, value) = i32::parse(&b[len..])?; + return Ok((len+vlen, Variant::i32(value))); }, primitive::SHORT => { - let (vlen, value) = i16::parse(&b[len..]); - return (len+vlen, Variant::i16(value)); + let (vlen, value) = i16::parse(&b[len..])?; + return Ok((len+vlen, Variant::i16(value))); }, primitive::CHAR => { - let (vlen, value) = i8::parse(&b[len..]); - return (len+vlen, Variant::i8(value)); + let (vlen, value) = i8::parse(&b[len..])?; + return Ok((len+vlen, Variant::i8(value))); }, _ => { - return (0, Variant::Unknown); + return Err(ErrorKind::UnknownVariant); } } } } impl QRead for Variant { - fn read<T: Read>(s: &mut T, b: &mut [u8]) -> usize { + fn read<T: Read>(s: &mut T, b: &mut [u8]) -> Result<usize, ErrorKind> { - s.read(&mut b[0..4]).unwrap(); - let (_, qtype) = i32::parse(&b[0..4]); + s.read(&mut b[0..4])?; + let (_, qtype) = i32::parse(&b[0..4])?; let qtype = qtype as u32; - s.read(&mut [b[4]]).unwrap(); + s.read(&mut [b[4]])?; let mut len = 5; match qtype { - primitive::QVARIANTMAP => len += VariantMap::read(s, &mut b[len..]), - primitive::QVARIANTLIST => len += VariantList::read(s, &mut b[len..]), - primitive::QSTRING => len += String::read(s, &mut b[len..]), - primitive::QBYTEARRAY => len += String::read(s, &mut b[len..]), - primitive::QSTRINGLIST => len += StringList::read(s, &mut b[len..]), - primitive::BOOL => len += bool::read(s, &mut b[len..]), - primitive::ULONG => len += u64::read(s, &mut b[len..]), - primitive::UINT => len += u32::read(s, &mut b[len..]), - primitive::USHORT => len += u16::read(s, &mut b[len..]), - primitive::UCHAR => len += u8::read(s, &mut b[len..]), - primitive::LONG => len += i64::read(s, &mut b[len..]), - primitive::INT => len += i32::read(s, &mut b[len..]), - primitive::SHORT => len += i16::read(s, &mut b[len..]), - primitive::CHAR => len += i8::read(s, &mut b[len..]), - _ => return len + primitive::QVARIANTMAP => len += VariantMap::read(s, &mut b[len..])?, + primitive::QVARIANTLIST => len += VariantList::read(s, &mut b[len..])?, + primitive::QSTRING => len += String::read(s, &mut b[len..])?, + primitive::QBYTEARRAY => len += String::read(s, &mut b[len..])?, + primitive::QSTRINGLIST => len += StringList::read(s, &mut b[len..])?, + primitive::BOOL => len += bool::read(s, &mut b[len..])?, + primitive::ULONG => len += u64::read(s, &mut b[len..])?, + primitive::UINT => len += u32::read(s, &mut b[len..])?, + primitive::USHORT => len += u16::read(s, &mut b[len..])?, + primitive::UCHAR => len += u8::read(s, &mut b[len..])?, + primitive::LONG => len += i64::read(s, &mut b[len..])?, + primitive::INT => len += i32::read(s, &mut b[len..])?, + primitive::SHORT => len += i16::read(s, &mut b[len..])?, + primitive::CHAR => len += i8::read(s, &mut b[len..])?, + _ => return Err(ErrorKind::UnknownVariant) } - return len; + return Ok(len); } } diff --git a/src/tests/base_types.rs b/src/tests/base_types.rs index 99e6cd5..45f1fd3 100644 --- a/src/tests/base_types.rs +++ b/src/tests/base_types.rs @@ -8,14 +8,14 @@ use crate::protocol::primitive::*; pub fn serialize_string() { let test_string: String = String::from("Configured"); - assert_eq!(test_string.serialize(), [0, 0, 0, 20, 0, 67, 0, 111, 0, 110, 0, 102, 0, 105, 0, 103, 0, 117, 0, 114, 0, 101, 0, 100]); + assert_eq!(test_string.serialize().unwrap(), [0, 0, 0, 20, 0, 67, 0, 111, 0, 110, 0, 102, 0, 105, 0, 103, 0, 117, 0, 114, 0, 101, 0, 100]); } #[test] pub fn serialize_string_utf8() { let test_string: String = String::from("Configured"); - assert_eq!(test_string.serialize_utf8(), [0, 0, 0, 10, 67, 111, 110, 102, 105, 103, 117, 114, 101, 100]); + assert_eq!(test_string.serialize_utf8().unwrap(), [0, 0, 0, 10, 67, 111, 110, 102, 105, 103, 117, 114, 101, 100]); } #[test] @@ -25,7 +25,7 @@ pub fn read_string() { let test_bytes: Vec<u8> = vec![0, 0, 0, 20, 0, 67, 0, 111, 0, 110, 0, 102, 0, 105, 0, 103, 0, 117, 0, 114, 0, 101, 0, 100, 0, 0, 0, 1]; let mut buf: Vec<u8> = [0; 24].to_vec(); - let len = String::read(&mut Cursor::new(&test_bytes), &mut buf); + let len = String::read(&mut Cursor::new(&test_bytes), &mut buf).unwrap(); assert_eq!(len, 24); @@ -36,7 +36,7 @@ pub fn read_string() { #[test] pub fn deserialize_string() { let test_bytes: &[u8] = &[0, 0, 0, 20, 0, 67, 0, 111, 0, 110, 0, 102, 0, 105, 0, 103, 0, 117, 0, 114, 0, 101, 0, 100, 0, 0, 0, 1]; - let (len, res) = String::parse(test_bytes); + let (len, res) = String::parse(test_bytes).unwrap(); assert_eq!(res, "Configured"); assert_eq!(len, 24); } @@ -44,7 +44,7 @@ pub fn deserialize_string() { #[test] pub fn deserialize_string_utf8() { let test_bytes: &[u8] = &[0, 0, 0, 10, 67, 111, 110, 102, 105, 103, 117, 114, 101, 100, 0, 0, 0, 1]; - let (len, res) = String::parse_utf8(test_bytes); + let (len, res) = String::parse_utf8(test_bytes).unwrap(); assert_eq!(len, 14); assert_eq!(res, "Configured"); } @@ -54,7 +54,7 @@ pub fn serialize_string_list() { let mut test_list = StringList::new(); test_list.push("Configured".to_string()); assert_eq!( - test_list.serialize(), + test_list.serialize().unwrap(), [0, 0, 0, 1, 0, 0, 0, 20, 0, 67, 0, 111, 0, 110, 0, 102, 0, 105, 0, 103, 0, 117, 0, 114, 0, 101, 0, 100] ) } @@ -66,7 +66,7 @@ pub fn read_string_list() { let test_bytes: Vec<u8> = vec![0, 0, 0, 1, 0, 0, 0, 20, 0, 67, 0, 111, 0, 110, 0, 102, 0, 105, 0, 103, 0, 117, 0, 114, 0, 101, 0, 100, 0, 0, 0, 1]; let mut buf: Vec<u8> = [0; 28].to_vec(); - let len = StringList::read(&mut Cursor::new(&test_bytes), &mut buf); + let len = StringList::read(&mut Cursor::new(&test_bytes), &mut buf).unwrap(); assert_eq!(len, 28); @@ -80,7 +80,7 @@ pub fn deserialize_string_list() { let mut test_list = StringList::new(); test_list.push("Configured".to_string()); println!("aaaaa"); - let (len, res) = StringList::parse(test_bytes); + let (len, res) = StringList::parse(test_bytes).unwrap(); assert_eq!(len, 28); assert_eq!(test_list, res); } diff --git a/src/tests/handshake_types.rs b/src/tests/handshake_types.rs index dd3387f..a664128 100644 --- a/src/tests/handshake_types.rs +++ b/src/tests/handshake_types.rs @@ -9,7 +9,7 @@ pub fn serialize_variantmap() { 0, 0, 0, 20, 0, 67, 0, 111, 0, 110, 0, 102, 0, 105, 0, 103, 0, 117, 0, 114, 0, 101, 0, 100, 0, 0, 0, 1, 0, 1].to_vec(); assert_eq!( - test_variantmap.serialize(), + test_variantmap.serialize().unwrap(), bytes ); } @@ -23,7 +23,7 @@ pub fn read_variantmap() { 0, 0, 0, 1, 0, 1, 0, 0, 0, 1]; let mut buf: Vec<u8> = [0; 43].to_vec(); - let len = VariantMap::read(&mut Cursor::new(&test_bytes), &mut buf); + let len = VariantMap::read(&mut Cursor::new(&test_bytes), &mut buf).unwrap(); assert_eq!(len, 43); @@ -41,7 +41,7 @@ pub fn deserialize_variantmap() { let mut test_variantmap = VariantMap::new(); test_variantmap.insert("Configured".to_string(), Variant::bool(true)); - let (len, res) = VariantMap::parse(test_bytes); + let (len, res) = VariantMap::parse(test_bytes).unwrap(); assert_eq!(len, 43); assert_eq!(res, test_variantmap); @@ -55,7 +55,7 @@ pub fn deserialize_variantmap_utf8() { let mut test_variantmap = VariantMap::new(); test_variantmap.insert("Configured".to_string(), Variant::bool(true)); - let (len, res) = VariantMap::parse(test_bytes); + let (len, res) = VariantMap::parse(test_bytes).unwrap(); assert_eq!(len, 33); assert_eq!(res, test_variantmap); diff --git a/src/tests/variant_types.rs b/src/tests/variant_types.rs index 8c4dedc..6c49506 100644 --- a/src/tests/variant_types.rs +++ b/src/tests/variant_types.rs @@ -8,11 +8,11 @@ pub fn serialize_variant_bool() { let test_variant_true = Variant::bool(true); let test_variant_false = Variant::bool(false); assert_eq!( - test_variant_true.serialize(), + test_variant_true.serialize().unwrap(), [0, 0, 0, 1, 0, 1] ); assert_eq!( - test_variant_false.serialize(), + test_variant_false.serialize().unwrap(), [0, 0, 0, 1, 0, 0] ); } @@ -20,7 +20,7 @@ pub fn serialize_variant_bool() { #[test] pub fn deserialize_variant_bool() { let test_bytes: &[u8] = &[0, 0, 0, 1, 0, 1, 0, 0, 0, 1]; - let (len, res) = Variant::parse(test_bytes); + let (len, res) = Variant::parse(test_bytes).unwrap(); assert_eq!(len, 6); assert_eq!(res, Variant::bool(true)); } @@ -30,7 +30,7 @@ pub fn serialize_variantlist() { let mut test_variantlist = VariantList::new(); test_variantlist.push(Variant::bool(true)); assert_eq!( - test_variantlist.serialize(), + test_variantlist.serialize().unwrap(), [0, 0, 0, 1, 0, 0, 0, 1, 0, 1] ); } @@ -38,7 +38,7 @@ pub fn serialize_variantlist() { #[test] pub fn deserialize_variantlist() { let test_bytes: &[u8] = &[0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1]; - let (len, res) = VariantList::parse(test_bytes); + let (len, res) = VariantList::parse(test_bytes).unwrap(); let mut test_variantlist = VariantList::new(); test_variantlist.push(Variant::bool(true)); assert_eq!(len, 10); @@ -53,7 +53,7 @@ pub fn serialize_variantmap() { 0, 0, 0, 20, 0, 67, 0, 111, 0, 110, 0, 102, 0, 105, 0, 103, 0, 117, 0, 114, 0, 101, 0, 100, 0, 0, 0, 1, 0, 1].to_vec(); assert_eq!( - test_variantmap.serialize(), + test_variantmap.serialize().unwrap(), bytes ); } @@ -63,26 +63,9 @@ pub fn deserialize_variantmap() { let test_bytes: &[u8] = &[0, 0, 0, 1, 0, 0, 0, 20, 0, 67, 0, 111, 0, 110, 0, 102, 0, 105, 0, 103, 0, 117, 0, 114, 0, 101, 0, 100, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1]; - let (len, res) = VariantMap::parse(test_bytes); + let (len, res) = VariantMap::parse(test_bytes).unwrap(); let mut test_variantmap = VariantMap::new(); test_variantmap.insert("Configured".to_string(), Variant::bool(true)); assert_eq!(len, 34); assert_eq!(res, test_variantmap); } - -// -// 0000 00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00 ..............E. -// 0010 00 e2 36 3d 40 00 40 06 05 d7 7f 00 00 01 7f 00 ..6=@.@......... -// 0020 00 01 10 92 c0 dc e8 73 50 fe 2f 68 6d 9e 80 18 .......sP./hm... -// 0030 02 00 fe d6 00 00 01 01 08 0a 5f 0a 31 00 5f 0a .........._.1._. -// 0040 31 00 00 00 00 aa 00 00 00 0a 00 00 00 0c 00 00 1............... -// 0050 00 00 0a 43 6f 6e 66 69 67 75 72 65 64 00 00 00 ...Configured... -// 0060 01 00 01 00 00 00 0c 00 00 00 00 0c 43 6f 72 65 ............Core -// 0070 46 65 61 74 75 72 65 73 00 00 00 03 00 00 00 fe Features........ -// 0080 ff 00 00 00 0c 00 00 00 00 0c 4c 6f 67 69 6e 45 ..........LoginE -// 0090 6e 61 62 6c 65 64 00 00 00 01 00 01 00 00 00 0c nabled.......... -// 00a0 00 00 00 00 07 4d 73 67 54 79 70 65 00 00 00 0a .....MsgType.... -// 00b0 00 00 00 00 1a 00 43 00 6c 00 69 00 65 00 6e 00 ......C.l.i.e.n. -// 00c0 74 00 49 00 6e 00 69 00 74 00 41 00 63 00 6b 00 t.I.n.i.t.A.c.k. -// 00d0 00 00 0c 00 00 00 00 0f 53 74 6f 72 61 67 65 42 ........StorageB -// 00e0 61 63 6b 65 6e 64 73 00 00 00 09 00 00 00 00 00 ackends......... |
