diff --git a/Cargo.toml b/Cargo.toml index d620e32..bdae01c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,5 @@ tokio-stream = "0.1" serde = { version = "1.0", features = ["derive", "std"] } serde_json = "1.0" bytes = "1.1" +uuid = "0.8" lixcraft-derive = { path = "lixcraft-derive" } \ No newline at end of file diff --git a/src/frames.rs b/src/frames.rs new file mode 100644 index 0000000..b0e0e10 --- /dev/null +++ b/src/frames.rs @@ -0,0 +1,87 @@ +use std::io::ErrorKind; +use bytes::{Buf, BufMut, Bytes, BytesMut}; +use tokio::io::Error; +use tokio_util::codec::{Decoder, Encoder}; +use crate::VarInt; + +pub struct LengthPrefixedFrame { + pub max_length: usize +} + +enum VarIntReadError { + BytesMissing, + InvalidData +} + +impl LengthPrefixedFrame { + fn try_read_var_int(&self, src: &mut BytesMut) -> Result<(VarInt, usize), VarIntReadError> { + let src = src.chunk(); + let mut num_read = 0; + let mut result = 0; + loop { + if src.len() <= num_read { + return Err(VarIntReadError::BytesMissing) + } + let read = src[num_read]; + let value = i32::from(read & 0b0111_1111); + result |= value.overflowing_shl((7 * num_read) as u32).0; + + num_read += 1; + + if num_read > 5 { + return Err(VarIntReadError::InvalidData); + } + if read & 0b1000_0000 == 0 { + return if result as usize > self.max_length { + Err(VarIntReadError::InvalidData) + } else { + Ok((VarInt(result), num_read)) + } + } + } + } +} + +impl Decoder for LengthPrefixedFrame { + type Item = BytesMut; + type Error = tokio::io::Error; + + fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { + println!("!"); + match self.try_read_var_int(src) { //TODO: Packet length maximal 2097151 byte + Ok((length, prefix_length)) => { + let total_length = prefix_length + usize::from(length); + + if src.len() >= total_length { + src.advance(prefix_length); + Ok(Some(src.split_to(usize::from(length)))) + } else { + Ok(None) + } + }, + Err(VarIntReadError::BytesMissing) => Ok(None), + Err(VarIntReadError::InvalidData) => Err(Error::from(ErrorKind::InvalidData)) + } + } +} +impl Encoder for LengthPrefixedFrame { + type Error = tokio::io::Error; + + fn encode(&mut self, data: Bytes, dst: &mut BytesMut) -> Result<(), Self::Error> { + dst.reserve(5 + data.len()); + + let mut v = data.len(); + loop { + if v & 0x80 == 0 { + dst.put_u8(v as u8); + break; + } + + dst.put_u8((v as u8 & 0x7f) | 0x80); + v >>= 7; + } + + dst.put_slice(&data); + Ok(()) + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index c3553f4..b8ddc28 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,49 @@ extern crate core; pub mod serde; -mod packets; +pub mod packets; +pub mod frames; +use std::collections::HashMap; use std::error::Error; -use std::io::ErrorKind; use std::net::SocketAddr; -use bytes::{Buf, BufMut, Bytes, BytesMut}; +use std::sync::Arc; +use bytes::BytesMut; use tokio::net::{TcpListener, TcpStream}; use tokio_stream::StreamExt; -use tokio_util::codec::{Decoder, Encoder, Framed}; +use tokio_util::codec::Framed; +use crate::frames::LengthPrefixedFrame; use crate::packets::handshake::HandshakePacket; use crate::serde::{JavaSerializable, VarInt}; +pub struct Server { + listener: Arc //TODO: TcpListener not required from anybody +} + +pub struct RawConnection { + pub server: Arc, + pub remote_addr: SocketAddr +} + +impl Server { + pub async fn new(listen_addr: String) -> Result, Box> { + let server = Arc::new(Server { + listener : Arc::new(TcpListener::bind(listen_addr).await?) + }); + + let server_clone = server.clone(); + tokio::spawn(async move { + while let Ok((inbound, addr)) = server_clone.listener.accept().await { + tokio::spawn(async move {process_initial(inbound, addr)}.await); + } + }); + + Ok(server) + } +} + +//TODO: Shutdown construction! Yay + #[tokio::main] async fn main() -> Result<(), Box> { let listen_addr = String::from("127.0.0.1:25565"); @@ -28,8 +59,25 @@ async fn main() -> Result<(), Box> { Ok(()) } +enum Reason { + Disconnected, + ConnectionDrop, + ProtocolError +} + +struct Protocol { + packet_handlers: HashMap Reason>> +} + +fn handle_handshake(buf: BytesMut) -> Result, Reason> { + Err(Reason::Disconnected) +} async fn process_initial(stream: TcpStream, _addr: SocketAddr) { + /*let handshake_protocol = Protocol { + packet_handlers: HashMap::from([(VarInt(0), Box::new(handle_handshake) as Box Reason>)]), + };*/ + let mut framed = Framed::new(stream, LengthPrefixedFrame {max_length: 263}); match framed.next().await { Some(Ok(buf)) => { @@ -48,95 +96,4 @@ async fn process_initial(stream: TcpStream, _addr: SocketAddr) { Some(Err(e)) => println!("Error: {:?}", e), None => {} } -} - - -enum VarIntReadError { - BytesMissing, - InvalidData -} - -pub struct LengthPrefixedFrame { - pub max_length: usize -} - -impl LengthPrefixedFrame { - fn try_read_var_int(&self, src: &mut BytesMut) -> Result<(VarInt, usize), VarIntReadError> { - let src = src.chunk(); - let mut num_read = 0; - let mut result = 0; - loop { - if src.len() <= num_read { - return Err(VarIntReadError::BytesMissing) - } - let read = src[num_read]; - let value = i32::from(read & 0b0111_1111); - result |= value.overflowing_shl((7 * num_read) as u32).0; - - num_read += 1; - - if num_read > 5 { - return Err(VarIntReadError::InvalidData); - } - if read & 0b1000_0000 == 0 { - return if result as usize > self.max_length { - Err(VarIntReadError::InvalidData) - } else { - Ok((VarInt(result), num_read)) - } - } - } - } -} - -impl Decoder for LengthPrefixedFrame { - type Item = BytesMut; - type Error = tokio::io::Error; - - fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { - println!("!"); - match self.try_read_var_int(src) { - Ok((length, prefix_length)) => { - let total_length = prefix_length + usize::from(length); - - if src.len() >= total_length { - src.advance(prefix_length); - println!("a1"); - Ok(Some(src.split_to(usize::from(length)))) - } else { - println!("a2"); - Ok(None) - } - }, - Err(VarIntReadError::BytesMissing) => { - println!("b"); - Ok(None) - }, - Err(VarIntReadError::InvalidData) => { - println!("c"); - Err(tokio::io::Error::from(ErrorKind::InvalidData)) - } - } - } -} -impl Encoder for LengthPrefixedFrame { - type Error = tokio::io::Error; - - fn encode(&mut self, data: Bytes, dst: &mut BytesMut) -> Result<(), Self::Error> { - dst.reserve(5 + data.len()); - - let mut v = data.len(); - loop { - if v & 0x80 == 0 { - dst.put_u8(v as u8); - break; - } - - dst.put_u8((v as u8 & 0x7f) | 0x80); - v >>= 7; - } - - dst.put_slice(&data); - Ok(()) - } } \ No newline at end of file diff --git a/src/packets.rs b/src/packets.rs index 149a933..f5d63f4 100644 --- a/src/packets.rs +++ b/src/packets.rs @@ -1,10 +1,10 @@ pub mod handshake { - use crate::serde::{VarInt, JavaSerializable, NextState}; + use crate::serde::{VarInt, JavaSerializable, NextState, String255}; #[derive(JavaSerializable, Debug)] pub struct HandshakePacket { pub protocol_version: VarInt, - pub server_address: String, + pub server_address: String255, pub server_port: u16, pub next_state: NextState } @@ -28,8 +28,9 @@ pub mod status { } pub mod login { - use bytes::{BufMut, Bytes, BytesMut}; - use crate::serde::{VarInt, JavaSerializable, Chat, JavaDeserError}; + use bytes::{Bytes, BytesMut}; + use uuid::Uuid; + use crate::serde::{VarInt, JavaSerializable, Chat, JavaDeserError, String20, String16, Identifier, RemainingBytes}; #[derive(JavaSerializable, Debug)] pub struct DisconnectPacket{ @@ -38,15 +39,15 @@ pub mod login { #[derive(JavaSerializable, Debug)] pub struct EncryptionRequestPacket { - server_id: String, + server_id: String20, public_key: Vec::, verify_token: Vec:: } #[derive(JavaSerializable, Debug)] pub struct LoginSuccessPacket { - uuid: String, //TODO: UUID - username: String + uuid: Uuid, + username: String16 } #[derive(JavaSerializable, Debug)] @@ -57,13 +58,13 @@ pub mod login { #[derive(JavaSerializable, Debug)] pub struct PluginRequestPacket { message_id: VarInt, - channel: String, //TODO: Identifier - data: Vec:: //TODO: Length inferred by packet length + channel: Identifier, + data: RemainingBytes } #[derive(JavaSerializable, Debug)] pub struct LoginStartPacket { - name: String + name: String16 } #[derive(JavaSerializable, Debug)] @@ -74,7 +75,7 @@ pub mod login { #[derive(Debug)] pub enum PluginResponseSuccessful { - Successful(Vec), + Successful(RemainingBytes), Failed } impl JavaSerializable for PluginResponseSuccessful { @@ -89,7 +90,7 @@ pub mod login { match self { PluginResponseSuccessful::Successful(v) => { true.serialize(buf); - buf.put_slice(v.as_slice()) + v.serialize(buf); } PluginResponseSuccessful::Failed => false.serialize(buf) } @@ -97,7 +98,7 @@ pub mod login { fn deserialize(buf: &mut Bytes) -> Result { match bool::deserialize(buf)? { - true => Ok(PluginResponseSuccessful::Successful(buf.to_vec())), + true => Ok(PluginResponseSuccessful::Successful(RemainingBytes::deserialize(buf)?)), false => Ok(PluginResponseSuccessful::Failed) } } diff --git a/src/serde.rs b/src/serde.rs index 8d543b4..aa04ced 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -3,6 +3,7 @@ use bytes::{Buf, BufMut, Bytes, BytesMut}; use crate::serde::JavaDeserError::{InvalidValue, MissingBytes}; pub use lixcraft_derive::JavaSerializable; +use uuid::Uuid; #[derive(Debug)] pub enum JavaDeserError { @@ -105,7 +106,7 @@ macro_rules! impl_wrapper { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct VarInt(pub i32); impl_wrapper!(VarInt, i32, VarInt); @@ -211,22 +212,63 @@ impl JavaSerializable for VarLong { } } -impl JavaSerializable for String { +impl JavaSerializable for Uuid { fn size_in_bytes(&self) -> usize { - VarInt(self.len() as i32).size_in_bytes() + self.len() + 16 } fn serialize(&self, buf: &mut BytesMut) { - VarInt(self.len() as i32).serialize(buf); - buf.put_slice(self.as_bytes()) + buf.put_u128(self.as_u128()) } fn deserialize(buf: &mut Bytes) -> Result { - let len = VarInt::deserialize(buf)?; - Ok(String::from_utf8(buf.split_to(usize::from(len)).to_vec()).map_err(|_| InvalidValue)?) + Ok(Uuid::from_u128(save_get!(16, buf, get_u128)?)) } } +macro_rules! impl_string { + ($i:ident, $v:expr) => { + #[derive(Debug)] + pub struct $i(pub String); + impl_wrapper!($i, String, $i); + + impl JavaSerializable for $i { + fn size_in_bytes(&self) -> usize { + VarInt(self.len() as i32).size_in_bytes() + self.len() + } + + fn serialize(&self, buf: &mut BytesMut) { + VarInt(self.len() as i32).serialize(buf); + buf.put_slice(self.as_bytes()) + } + + fn deserialize(buf: &mut Bytes) -> Result { + let len = VarInt::deserialize(buf)?; + if usize::from(len) > $v * 4 { + Err(InvalidValue) + } else if buf.len() < usize::from(len) { + Err(MissingBytes) + } else { + let string = String::from_utf8(buf.split_to(usize::from(len)).to_vec()).map_err(|_| InvalidValue)?; + if string.chars().count() > $v { + Err(InvalidValue) + } else { + Ok($i(string)) + } + } + } + } + } +} + +impl_string!(String16, 16); +impl_string!(String20, 20); +impl_string!(String255, 255); +impl_string!(String32767, 32767); +impl_string!(String262144, 262144); + +impl_string!(Identifier, 32767); + impl JavaSerializable for Vec { fn size_in_bytes(&self) -> usize { VarInt(self.len() as i32).size_in_bytes() + self.len() @@ -249,6 +291,24 @@ impl JavaSerializable for Vec { } } +#[derive(Debug)] +pub struct RemainingBytes(pub Vec); +impl_wrapper!(RemainingBytes, Vec, RemainingBytes); + +impl JavaSerializable for RemainingBytes { + fn size_in_bytes(&self) -> usize { + self.len() + } + + fn serialize(&self, buf: &mut BytesMut) { + buf.put_slice(self.as_slice()); + } + + fn deserialize(buf: &mut Bytes) -> Result { + Ok(RemainingBytes(buf.to_vec())) + } +} + #[derive(Debug)] pub enum NextState { Status, @@ -301,18 +361,18 @@ pub struct StatusResponseDescription { } macro_rules! impl_json { - ($t:ty) => { + ($t:ty, $st:ident) => { impl JavaSerializable for $t { fn size_in_bytes(&self) -> usize { - serde_json::to_string(self).unwrap().size_in_bytes() + $st(serde_json::to_string(self).unwrap()).size_in_bytes() } fn serialize(&self, buf: &mut BytesMut) { - serde_json::to_string(self).unwrap().serialize(buf) + $st(serde_json::to_string(self).unwrap()).serialize(buf) } fn deserialize(buf: &mut Bytes) -> Result { - match serde_json::from_str(&String::deserialize(buf)?) { + match serde_json::from_str(&$st::deserialize(buf)?) { Ok(v) => Ok(v), Err(_) => Err(InvalidValue) } @@ -329,7 +389,7 @@ pub struct StatusResponse { #[serde(skip_serializing_if = "Option::is_none")] pub favicon: Option } -impl_json!(StatusResponse); +impl_json!(StatusResponse, String32767); #[derive(Debug, serde::Serialize, serde::Deserialize)] @@ -431,4 +491,4 @@ pub enum Chat { selector: String //TODO ominous } } -impl_json!(Chat); \ No newline at end of file +impl_json!(Chat, String262144); \ No newline at end of file