Finalize Handshake, Status and Login serde
Dieser Commit ist enthalten in:
Ursprung
4efe1aaf36
Commit
2989ac7938
@ -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" }
|
87
src/frames.rs
Normale Datei
87
src/frames.rs
Normale Datei
@ -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<Option<Self::Item>, 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<Bytes> 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(())
|
||||
}
|
||||
}
|
147
src/main.rs
147
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<TcpListener> //TODO: TcpListener not required from anybody
|
||||
}
|
||||
|
||||
pub struct RawConnection {
|
||||
pub server: Arc<Server>,
|
||||
pub remote_addr: SocketAddr
|
||||
}
|
||||
|
||||
impl Server {
|
||||
pub async fn new(listen_addr: String) -> Result<Arc<Server>, Box<dyn Error>> {
|
||||
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<dyn Error>> {
|
||||
let listen_addr = String::from("127.0.0.1:25565");
|
||||
@ -28,8 +59,25 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
enum Reason {
|
||||
Disconnected,
|
||||
ConnectionDrop,
|
||||
ProtocolError
|
||||
}
|
||||
|
||||
struct Protocol {
|
||||
packet_handlers: HashMap<VarInt, Box<dyn FnMut(BytesMut) -> Reason>>
|
||||
}
|
||||
|
||||
fn handle_handshake(buf: BytesMut) -> Result<Framed<TcpStream, LengthPrefixedFrame>, 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<dyn FnMut(BytesMut) -> Reason>)]),
|
||||
};*/
|
||||
|
||||
let mut framed = Framed::new(stream, LengthPrefixedFrame {max_length: 263});
|
||||
match framed.next().await {
|
||||
Some(Ok(buf)) => {
|
||||
@ -49,94 +97,3 @@ async fn process_initial(stream: TcpStream, _addr: SocketAddr) {
|
||||
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<Option<Self::Item>, 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<Bytes> 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(())
|
||||
}
|
||||
}
|
@ -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::<u8>,
|
||||
verify_token: Vec::<u8>
|
||||
}
|
||||
|
||||
#[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::<u8> //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<u8>),
|
||||
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<Self, JavaDeserError> {
|
||||
match bool::deserialize(buf)? {
|
||||
true => Ok(PluginResponseSuccessful::Successful(buf.to_vec())),
|
||||
true => Ok(PluginResponseSuccessful::Successful(RemainingBytes::deserialize(buf)?)),
|
||||
false => Ok(PluginResponseSuccessful::Failed)
|
||||
}
|
||||
}
|
||||
|
78
src/serde.rs
78
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,7 +212,27 @@ impl JavaSerializable for VarLong {
|
||||
}
|
||||
}
|
||||
|
||||
impl JavaSerializable for String {
|
||||
impl JavaSerializable for Uuid {
|
||||
fn size_in_bytes(&self) -> usize {
|
||||
16
|
||||
}
|
||||
|
||||
fn serialize(&self, buf: &mut BytesMut) {
|
||||
buf.put_u128(self.as_u128())
|
||||
}
|
||||
|
||||
fn deserialize(buf: &mut Bytes) -> Result<Self, JavaDeserError> {
|
||||
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()
|
||||
}
|
||||
@ -223,9 +244,30 @@ impl JavaSerializable for String {
|
||||
|
||||
fn deserialize(buf: &mut Bytes) -> Result<Self, JavaDeserError> {
|
||||
let len = VarInt::deserialize(buf)?;
|
||||
Ok(String::from_utf8(buf.split_to(usize::from(len)).to_vec()).map_err(|_| InvalidValue)?)
|
||||
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<T: JavaSerializable> JavaSerializable for Vec<T> {
|
||||
fn size_in_bytes(&self) -> usize {
|
||||
@ -249,6 +291,24 @@ impl<T: JavaSerializable> JavaSerializable for Vec<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RemainingBytes(pub Vec<u8>);
|
||||
impl_wrapper!(RemainingBytes, Vec<u8>, 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<Self, JavaDeserError> {
|
||||
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<Self, JavaDeserError> {
|
||||
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<String>
|
||||
}
|
||||
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);
|
||||
impl_json!(Chat, String262144);
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren