improve error handling
- replace anyhow with thiserror - implement own error types - Security: Begin to haarding Server, Prevent Crashes when Fail to receive/send Client Packet
This commit is contained in:
parent
a8d595f53f
commit
c421a402fe
24
Cargo.lock
generated
24
Cargo.lock
generated
@ -19,12 +19,6 @@ dependencies = [
|
|||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "anyhow"
|
|
||||||
version = "1.0.86"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
@ -290,9 +284,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.2.6"
|
version = "2.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
|
checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
@ -529,7 +523,6 @@ name = "pumpkin"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
"anyhow",
|
|
||||||
"base64",
|
"base64",
|
||||||
"bytes",
|
"bytes",
|
||||||
"cfb8",
|
"cfb8",
|
||||||
@ -546,6 +539,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"simple_logger",
|
"simple_logger",
|
||||||
|
"thiserror",
|
||||||
"toml",
|
"toml",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
@ -808,9 +802,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.8.17"
|
version = "0.8.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a44eede9b727419af8095cb2d72fab15487a541f54647ad4414b34096ee4631"
|
checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
@ -829,9 +823,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
version = "0.22.18"
|
version = "0.22.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1490595c74d930da779e944f5ba2ecdf538af67df1a9848cbd156af43c1b7cf0"
|
checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"serde",
|
"serde",
|
||||||
@ -1011,9 +1005,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.6.16"
|
version = "0.6.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b480ae9340fc261e6be3e95a1ba86d54ae3f9171132a73ce8d4bbaf68339507c"
|
checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -24,5 +24,8 @@ A Minecraft server written in pure Rust
|
|||||||
- [ ] Compression
|
- [ ] Compression
|
||||||
- [x] Configuration
|
- [x] Configuration
|
||||||
|
|
||||||
|
## Contributions
|
||||||
|
Contributions are welcome!. Feel free to open an issue or pull request.
|
||||||
|
|
||||||
### Thanks
|
### Thanks
|
||||||
A big thank you to https://wiki.vg/ for providing valuable information used in the development of this project.
|
A big thank you to https://wiki.vg/ for providing valuable information used in the development of this project.
|
||||||
|
|||||||
@ -18,7 +18,7 @@ cfb8 = "0.8.1"
|
|||||||
flate2 = "1.0.30"
|
flate2 = "1.0.30"
|
||||||
bytes = "1.7"
|
bytes = "1.7"
|
||||||
|
|
||||||
anyhow = "1.0.86"
|
thiserror = "1.0.63"
|
||||||
|
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
image = { version = "0.25", default-features = false, features = ["png"]}
|
image = { version = "0.25", default-features = false, features = ["png"]}
|
||||||
|
|||||||
@ -18,6 +18,8 @@ use crate::{
|
|||||||
|
|
||||||
use super::{Client, PlayerConfig};
|
use super::{Client, PlayerConfig};
|
||||||
|
|
||||||
|
/// Processes incoming Packets from the Client to the Server
|
||||||
|
/// Implements the `Client` Packets, So everything before the Play state, then will use the `PlayerPacketProcessor`
|
||||||
pub trait ClientPacketProcessor {
|
pub trait ClientPacketProcessor {
|
||||||
// Handshake
|
// Handshake
|
||||||
fn handle_handshake(&mut self, server: &mut Server, handshake: SHandShake);
|
fn handle_handshake(&mut self, server: &mut Server, handshake: SHandShake);
|
||||||
@ -65,14 +67,18 @@ impl ClientPacketProcessor for Client {
|
|||||||
fn handle_status_request(&mut self, server: &mut Server, _status_request: SStatusRequest) {
|
fn handle_status_request(&mut self, server: &mut Server, _status_request: SStatusRequest) {
|
||||||
dbg!("sending status");
|
dbg!("sending status");
|
||||||
|
|
||||||
let response = serde_json::to_string(&server.status_response).unwrap();
|
if let Ok(response) = serde_json::to_string(&server.status_response) {
|
||||||
|
self.send_packet(CStatusResponse::new(response))
|
||||||
self.send_packet(CStatusResponse::new(response));
|
.unwrap_or_else(|e| self.kick(&e.to_string()));
|
||||||
|
} else {
|
||||||
|
log::error!("Failed to parse Status response to JSON")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_ping_request(&mut self, _server: &mut Server, ping_request: SPingRequest) {
|
fn handle_ping_request(&mut self, _server: &mut Server, ping_request: SPingRequest) {
|
||||||
dbg!("ping");
|
dbg!("ping");
|
||||||
self.send_packet(CPingResponse::new(ping_request.payload));
|
self.send_packet(CPingResponse::new(ping_request.payload))
|
||||||
|
.unwrap_or_else(|e| self.kick(&e.to_string()));
|
||||||
self.close();
|
self.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +94,8 @@ impl ClientPacketProcessor for Client {
|
|||||||
&verify_token,
|
&verify_token,
|
||||||
false, // TODO
|
false, // TODO
|
||||||
);
|
);
|
||||||
self.send_packet(packet);
|
self.send_packet(packet)
|
||||||
|
.unwrap_or_else(|e| self.kick(&e.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_encryption_response(
|
fn handle_encryption_response(
|
||||||
@ -97,16 +104,20 @@ impl ClientPacketProcessor for Client {
|
|||||||
encryption_response: SEncryptionResponse,
|
encryption_response: SEncryptionResponse,
|
||||||
) {
|
) {
|
||||||
dbg!("encryption response");
|
dbg!("encryption response");
|
||||||
// should be impossible
|
|
||||||
if self.uuid.is_none() || self.name.is_none() {
|
|
||||||
self.kick("UUID or Name is none");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.enable_encryption(server, encryption_response.shared_secret)
|
self.enable_encryption(server, encryption_response.shared_secret)
|
||||||
.unwrap();
|
.unwrap_or_else(|e| self.kick(&e.to_string()));
|
||||||
|
|
||||||
let packet = CLoginSuccess::new(self.uuid.unwrap(), self.name.clone().unwrap(), 0, false);
|
if let Some(uuid) = self.uuid {
|
||||||
self.send_packet(packet);
|
if let Some(name) = &self.name {
|
||||||
|
let packet = CLoginSuccess::new(uuid, name.clone(), 0, false);
|
||||||
|
self.send_packet(packet)
|
||||||
|
.unwrap_or_else(|e| self.kick(&e.to_string()));
|
||||||
|
} else {
|
||||||
|
self.kick("Name is none");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.kick("UUID is none");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_plugin_response(
|
fn handle_plugin_response(
|
||||||
@ -122,13 +133,14 @@ impl ClientPacketProcessor for Client {
|
|||||||
_login_acknowledged: SLoginAcknowledged,
|
_login_acknowledged: SLoginAcknowledged,
|
||||||
) {
|
) {
|
||||||
self.connection_state = ConnectionState::Config;
|
self.connection_state = ConnectionState::Config;
|
||||||
Server::send_brand(self);
|
Server::send_brand(self).unwrap_or_else(|e| self.kick(&e.to_string()));
|
||||||
// known data packs
|
// known data packs
|
||||||
self.send_packet(CKnownPacks::new(&[KnownPack {
|
self.send_packet(CKnownPacks::new(&[KnownPack {
|
||||||
namespace: "minecraft",
|
namespace: "minecraft",
|
||||||
id: "core",
|
id: "core",
|
||||||
version: "1.21",
|
version: "1.21",
|
||||||
}]));
|
}]))
|
||||||
|
.unwrap_or_else(|e| self.kick(&e.to_string()));
|
||||||
dbg!("login achnowlaged");
|
dbg!("login achnowlaged");
|
||||||
}
|
}
|
||||||
fn handle_client_information(
|
fn handle_client_information(
|
||||||
@ -169,11 +181,13 @@ impl ClientPacketProcessor for Client {
|
|||||||
has_data: true,
|
has_data: true,
|
||||||
}, */
|
}, */
|
||||||
],
|
],
|
||||||
));
|
))
|
||||||
|
.unwrap_or_else(|e| self.kick(&e.to_string()));
|
||||||
|
|
||||||
// We are done with configuring
|
// We are done with configuring
|
||||||
dbg!("finish config");
|
dbg!("finish config");
|
||||||
self.send_packet(CFinishConfig::new());
|
self.send_packet(CFinishConfig::new())
|
||||||
|
.unwrap_or_else(|e| self.kick(&e.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_config_acknowledged(
|
fn handle_config_acknowledged(
|
||||||
|
|||||||
@ -20,14 +20,15 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::protocol::ConnectionState;
|
use crate::protocol::ConnectionState;
|
||||||
use anyhow::Context;
|
|
||||||
use mio::{event::Event, net::TcpStream, Token};
|
use mio::{event::Event, net::TcpStream, Token};
|
||||||
use packet_decoder::PacketDecoder;
|
use packet_decoder::PacketDecoder;
|
||||||
use packet_encoder::PacketEncoder;
|
use packet_encoder::PacketEncoder;
|
||||||
use rsa::Pkcs1v15Encrypt;
|
use rsa::Pkcs1v15Encrypt;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
mod client_packet;
|
mod client_packet;
|
||||||
|
mod player_packet;
|
||||||
|
|
||||||
mod packet_decoder;
|
mod packet_decoder;
|
||||||
mod packet_encoder;
|
mod packet_encoder;
|
||||||
@ -90,25 +91,30 @@ impl Client {
|
|||||||
&mut self,
|
&mut self,
|
||||||
server: &mut Server,
|
server: &mut Server,
|
||||||
shared_secret: Vec<u8>,
|
shared_secret: Vec<u8>,
|
||||||
) -> anyhow::Result<()> {
|
) -> Result<(), EncryptionError> {
|
||||||
self.encrytion = true;
|
self.encrytion = true;
|
||||||
let shared_secret = server
|
let shared_secret = server
|
||||||
.private_key
|
.private_key
|
||||||
.decrypt(Pkcs1v15Encrypt, &shared_secret)
|
.decrypt(Pkcs1v15Encrypt, &shared_secret)
|
||||||
.context("failed to decrypt shared secret")?;
|
.map_err(|_| EncryptionError::FailedDecrypt)?;
|
||||||
let crypt_key: [u8; 16] = shared_secret
|
let crypt_key: [u8; 16] = shared_secret
|
||||||
.as_slice()
|
.as_slice()
|
||||||
.try_into()
|
.try_into()
|
||||||
.context("shared secret has the wrong length")?;
|
.map_err(|_| EncryptionError::SharedWrongLength)?;
|
||||||
self.dec.enable_encryption(&crypt_key);
|
self.dec.enable_encryption(&crypt_key);
|
||||||
self.enc.enable_encryption(&crypt_key);
|
self.enc.enable_encryption(&crypt_key);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_packet<P: ClientPacket>(&mut self, packet: P) {
|
/// Im many cases we want to kick the Client when an Packet Error occours, But especially in the Client state we will not try to kick when not important packets
|
||||||
|
/// e.g Postion, Rotation... has not been send
|
||||||
|
pub fn send_packet<P: ClientPacket>(&mut self, packet: P) -> Result<(), PacketError> {
|
||||||
dbg!("sending packet");
|
dbg!("sending packet");
|
||||||
self.enc.append_packet(packet).unwrap();
|
self.enc.append_packet(packet)?;
|
||||||
self.connection.write_all(&self.enc.take()).unwrap();
|
self.connection
|
||||||
|
.write_all(&self.enc.take())
|
||||||
|
.map_err(|_| PacketError::ConnectionWrite)?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_packets(&mut self, server: &mut Server) {
|
pub fn process_packets(&mut self, server: &mut Server) {
|
||||||
@ -180,8 +186,8 @@ impl Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the connection is done.
|
/// Returns `true` if the connection is closed.
|
||||||
pub fn poll(&mut self, server: &mut Server, event: &Event) -> anyhow::Result<bool> {
|
pub fn poll(&mut self, server: &mut Server, event: &Event) -> Result<bool, io::Error> {
|
||||||
if event.is_readable() {
|
if event.is_readable() {
|
||||||
let mut received_data = vec![0; 4096];
|
let mut received_data = vec![0; 4096];
|
||||||
let mut bytes_read = 0;
|
let mut bytes_read = 0;
|
||||||
@ -205,16 +211,21 @@ impl Client {
|
|||||||
Err(ref err) if would_block(err) => break,
|
Err(ref err) if would_block(err) => break,
|
||||||
Err(ref err) if interrupted(err) => continue,
|
Err(ref err) if interrupted(err) => continue,
|
||||||
// Other errors we'll consider fatal.
|
// Other errors we'll consider fatal.
|
||||||
Err(err) => return anyhow::bail!(err),
|
Err(err) => return Err(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if bytes_read != 0 {
|
if bytes_read != 0 {
|
||||||
self.dec.reserve(4096);
|
self.dec.reserve(4096);
|
||||||
self.dec.queue_slice(&received_data[..bytes_read]);
|
self.dec.queue_slice(&received_data[..bytes_read]);
|
||||||
if let Some(packet) = self.dec.decode()? {
|
match self.dec.decode() {
|
||||||
self.add_packet(packet);
|
Ok(packet) => {
|
||||||
self.process_packets(server);
|
if let Some(packet) = packet {
|
||||||
|
self.add_packet(packet);
|
||||||
|
self.process_packets(server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => self.kick(&err.to_string()),
|
||||||
}
|
}
|
||||||
self.dec.clear();
|
self.dec.clear();
|
||||||
}
|
}
|
||||||
@ -226,10 +237,12 @@ impl Client {
|
|||||||
// Todo
|
// Todo
|
||||||
match self.connection_state {
|
match self.connection_state {
|
||||||
ConnectionState::Login => {
|
ConnectionState::Login => {
|
||||||
self.send_packet(CLoginDisconnect::new(reason));
|
self.send_packet(CLoginDisconnect::new(reason))
|
||||||
|
.unwrap_or_else(|_| self.close());
|
||||||
}
|
}
|
||||||
ConnectionState::Config => {
|
ConnectionState::Config => {
|
||||||
self.send_packet(CConfigDisconnect::new(reason));
|
self.send_packet(CConfigDisconnect::new(reason))
|
||||||
|
.unwrap_or_else(|_| self.close());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
log::warn!("Cant't kick in {:?} State", self.connection_state)
|
log::warn!("Cant't kick in {:?} State", self.connection_state)
|
||||||
@ -244,6 +257,32 @@ impl Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum EncryptionError {
|
||||||
|
#[error("failed to decrypt shared secret")]
|
||||||
|
FailedDecrypt,
|
||||||
|
#[error("shared secret has the wrong length")]
|
||||||
|
SharedWrongLength,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum PacketError {
|
||||||
|
#[error("failed to decode packet ID")]
|
||||||
|
DecodeID,
|
||||||
|
#[error("failed to encode packet ID")]
|
||||||
|
EncodeID,
|
||||||
|
#[error("failed to write encoded packet")]
|
||||||
|
EncodeFailedWrite,
|
||||||
|
#[error("failed to write encoded packet to connection")]
|
||||||
|
ConnectionWrite,
|
||||||
|
#[error("packet exceeds maximum length")]
|
||||||
|
TooLong,
|
||||||
|
#[error("packet length is out of bounds")]
|
||||||
|
OutOfBounds,
|
||||||
|
#[error("malformed packet length VarInt")]
|
||||||
|
MailformedLength,
|
||||||
|
}
|
||||||
|
|
||||||
fn would_block(err: &io::Error) -> bool {
|
fn would_block(err: &io::Error) -> bool {
|
||||||
err.kind() == io::ErrorKind::WouldBlock
|
err.kind() == io::ErrorKind::WouldBlock
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
use aes::cipher::{generic_array::GenericArray, BlockDecryptMut, BlockSizeUser, KeyIvInit};
|
use aes::cipher::{generic_array::GenericArray, BlockDecryptMut, BlockSizeUser, KeyIvInit};
|
||||||
use anyhow::{bail, ensure, Context};
|
|
||||||
use bytes::{Buf, BytesMut};
|
use bytes::{Buf, BytesMut};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
client::MAX_PACKET_SIZE,
|
client::{PacketError, MAX_PACKET_SIZE},
|
||||||
protocol::{bytebuf::ByteBuffer, RawPacket, VarInt32, VarIntDecodeError},
|
protocol::{bytebuf::ByteBuffer, RawPacket, VarInt32, VarIntDecodeError},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -18,19 +17,18 @@ pub struct PacketDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PacketDecoder {
|
impl PacketDecoder {
|
||||||
pub fn decode(&mut self) -> anyhow::Result<Option<RawPacket>> {
|
pub fn decode(&mut self) -> Result<Option<RawPacket>, PacketError> {
|
||||||
let mut r = &self.buf[..];
|
let mut r = &self.buf[..];
|
||||||
|
|
||||||
let packet_len = match VarInt32::decode_partial(&mut r) {
|
let packet_len = match VarInt32::decode_partial(&mut r) {
|
||||||
Ok(len) => len,
|
Ok(len) => len,
|
||||||
Err(VarIntDecodeError::Incomplete) => return Ok(None),
|
Err(VarIntDecodeError::Incomplete) => return Ok(None),
|
||||||
Err(VarIntDecodeError::TooLarge) => bail!("malformed packet length VarInt"),
|
Err(VarIntDecodeError::TooLarge) => Err(PacketError::MailformedLength)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
ensure!(
|
if !(0..=MAX_PACKET_SIZE).contains(&packet_len) {
|
||||||
(0..=MAX_PACKET_SIZE).contains(&packet_len),
|
Err(PacketError::OutOfBounds)?
|
||||||
"packet length of {packet_len} is out of bounds"
|
}
|
||||||
);
|
|
||||||
|
|
||||||
if r.len() < packet_len as usize {
|
if r.len() < packet_len as usize {
|
||||||
// Not enough data arrived yet.
|
// Not enough data arrived yet.
|
||||||
@ -48,7 +46,7 @@ impl PacketDecoder {
|
|||||||
|
|
||||||
r = &data[..];
|
r = &data[..];
|
||||||
let packet_id = VarInt32::decode(&mut r)
|
let packet_id = VarInt32::decode(&mut r)
|
||||||
.context("failed to decode packet ID")?
|
.map_err(|_| PacketError::DecodeID)?
|
||||||
.0;
|
.0;
|
||||||
|
|
||||||
data.advance(data.len() - r.len());
|
data.advance(data.len() - r.len());
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use aes::cipher::{generic_array::GenericArray, BlockEncryptMut, BlockSizeUser, KeyIvInit};
|
use aes::cipher::{generic_array::GenericArray, BlockEncryptMut, BlockSizeUser, KeyIvInit};
|
||||||
use anyhow::{ensure, Context};
|
|
||||||
use bytes::{BufMut, BytesMut};
|
use bytes::{BufMut, BytesMut};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -9,6 +8,8 @@ use crate::{
|
|||||||
protocol::{bytebuf::ByteBuffer, ClientPacket, VarInt32},
|
protocol::{bytebuf::ByteBuffer, ClientPacket, VarInt32},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::PacketError;
|
||||||
|
|
||||||
type Cipher = cfb8::Encryptor<aes::Aes128>;
|
type Cipher = cfb8::Encryptor<aes::Aes128>;
|
||||||
|
|
||||||
// Encoder: Server -> Client
|
// Encoder: Server -> Client
|
||||||
@ -20,7 +21,7 @@ pub struct PacketEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PacketEncoder {
|
impl PacketEncoder {
|
||||||
pub fn append_packet<P: ClientPacket>(&mut self, packet: P) -> anyhow::Result<()> {
|
pub fn append_packet<P: ClientPacket>(&mut self, packet: P) -> Result<(), PacketError> {
|
||||||
let start_len = self.buf.len();
|
let start_len = self.buf.len();
|
||||||
|
|
||||||
let mut writer = (&mut self.buf).writer();
|
let mut writer = (&mut self.buf).writer();
|
||||||
@ -28,10 +29,12 @@ impl PacketEncoder {
|
|||||||
let mut packet_buf = ByteBuffer::empty();
|
let mut packet_buf = ByteBuffer::empty();
|
||||||
VarInt32(P::PACKET_ID)
|
VarInt32(P::PACKET_ID)
|
||||||
.encode(&mut writer)
|
.encode(&mut writer)
|
||||||
.context("failed to encode packet ID")?;
|
.map_err(|_| PacketError::EncodeID)?;
|
||||||
packet.write(&mut packet_buf);
|
packet.write(&mut packet_buf);
|
||||||
|
|
||||||
writer.write(packet_buf.buf()).unwrap();
|
writer
|
||||||
|
.write(packet_buf.buf())
|
||||||
|
.map_err(|_| PacketError::EncodeFailedWrite)?;
|
||||||
|
|
||||||
let data_len = self.buf.len() - start_len;
|
let data_len = self.buf.len() - start_len;
|
||||||
|
|
||||||
@ -39,10 +42,9 @@ impl PacketEncoder {
|
|||||||
}
|
}
|
||||||
let packet_len = data_len;
|
let packet_len = data_len;
|
||||||
|
|
||||||
ensure!(
|
if packet_len >= MAX_PACKET_SIZE as usize {
|
||||||
packet_len <= MAX_PACKET_SIZE as usize,
|
Err(PacketError::TooLong)?
|
||||||
"packet exceeds maximum length"
|
}
|
||||||
);
|
|
||||||
|
|
||||||
let packet_len_size = VarInt32(packet_len as i32).written_size();
|
let packet_len_size = VarInt32(packet_len as i32).written_size();
|
||||||
|
|
||||||
@ -51,7 +53,9 @@ impl PacketEncoder {
|
|||||||
.copy_within(start_len..start_len + data_len, start_len + packet_len_size);
|
.copy_within(start_len..start_len + data_len, start_len + packet_len_size);
|
||||||
|
|
||||||
let front = &mut self.buf[start_len..];
|
let front = &mut self.buf[start_len..];
|
||||||
VarInt32(packet_len as i32).encode(front)?;
|
VarInt32(packet_len as i32)
|
||||||
|
.encode(front)
|
||||||
|
.map_err(|_| PacketError::EncodeID)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,2 @@
|
|||||||
|
// implement player packets
|
||||||
|
pub trait PlayerPacketProcessor {}
|
||||||
@ -1,9 +1,9 @@
|
|||||||
use std::io::{Read, Write};
|
use std::io::{self, Write};
|
||||||
|
|
||||||
use anyhow::bail;
|
|
||||||
use bytebuf::ByteBuffer;
|
use bytebuf::ByteBuffer;
|
||||||
use bytes::{Buf, BytesMut};
|
use bytes::Buf;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::Serialize;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
pub mod bytebuf;
|
pub mod bytebuf;
|
||||||
mod registry;
|
mod registry;
|
||||||
@ -42,7 +42,7 @@ impl VarInt32 {
|
|||||||
Err(VarIntDecodeError::TooLarge)
|
Err(VarIntDecodeError::TooLarge)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encode(&self, mut w: impl Write) -> anyhow::Result<()> {
|
pub fn encode(&self, mut w: impl Write) -> Result<(), io::Error> {
|
||||||
let x = self.0 as u64;
|
let x = self.0 as u64;
|
||||||
let stage1 = (x & 0x000000000000007f)
|
let stage1 = (x & 0x000000000000007f)
|
||||||
| ((x & 0x0000000000003f80) << 1)
|
| ((x & 0x0000000000003f80) << 1)
|
||||||
@ -63,11 +63,10 @@ impl VarInt32 {
|
|||||||
let bytes = merged.to_le_bytes();
|
let bytes = merged.to_le_bytes();
|
||||||
|
|
||||||
w.write_all(unsafe { bytes.get_unchecked(..bytes_needed as usize) })?;
|
w.write_all(unsafe { bytes.get_unchecked(..bytes_needed as usize) })?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode(r: &mut &[u8]) -> anyhow::Result<Self> {
|
pub fn decode(r: &mut &[u8]) -> Result<Self, VarIntDecodeError> {
|
||||||
let mut val = 0;
|
let mut val = 0;
|
||||||
for i in 0..Self::MAX_SIZE {
|
for i in 0..Self::MAX_SIZE {
|
||||||
let byte = r.get_u8();
|
let byte = r.get_u8();
|
||||||
@ -76,13 +75,15 @@ impl VarInt32 {
|
|||||||
return Ok(VarInt32(val));
|
return Ok(VarInt32(val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bail!("VarInt is too large")
|
Err(VarIntDecodeError::TooLarge)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, Error)]
|
||||||
pub enum VarIntDecodeError {
|
pub enum VarIntDecodeError {
|
||||||
|
#[error("incomplete VarInt decode")]
|
||||||
Incomplete,
|
Incomplete,
|
||||||
|
#[error("VarInt is too large")]
|
||||||
TooLarge,
|
TooLarge,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use std::{
|
use std::{
|
||||||
io::Cursor,
|
io::{self, Cursor},
|
||||||
sync::atomic::{AtomicI32, Ordering},
|
sync::atomic::{AtomicI32, Ordering},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -9,7 +9,7 @@ use rsa::{rand_core::OsRng, traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey}
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
client::Client,
|
client::{Client, PacketError},
|
||||||
configuration::{AdvancedConfiguration, BasicConfiguration},
|
configuration::{AdvancedConfiguration, BasicConfiguration},
|
||||||
entity::{
|
entity::{
|
||||||
player::{GameMode, Player},
|
player::{GameMode, Player},
|
||||||
@ -77,10 +77,9 @@ impl Server {
|
|||||||
pub fn poll(
|
pub fn poll(
|
||||||
&mut self,
|
&mut self,
|
||||||
client: &mut Client,
|
client: &mut Client,
|
||||||
poll: &Poll,
|
_poll: &Poll,
|
||||||
event: &Event,
|
event: &Event,
|
||||||
) -> anyhow::Result<bool> {
|
) -> Result<bool, io::Error> {
|
||||||
let _ = poll;
|
|
||||||
// todo, Poll players in every world
|
// todo, Poll players in every world
|
||||||
client.poll(self, event)
|
client.poll(self, event)
|
||||||
}
|
}
|
||||||
@ -92,30 +91,32 @@ impl Server {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
client.send_packet(CLogin::new(
|
client
|
||||||
player.entity_id(),
|
.send_packet(CLogin::new(
|
||||||
self.difficulty == Difficulty::Hard,
|
player.entity_id(),
|
||||||
1,
|
self.difficulty == Difficulty::Hard,
|
||||||
vec!["minecraft:overworld".into()],
|
1,
|
||||||
self.max_players as VarInt,
|
vec!["minecraft:overworld".into()],
|
||||||
8, // view distance todo
|
self.max_players as VarInt,
|
||||||
8, // sim view dinstance todo
|
8, // view distance todo
|
||||||
false,
|
8, // sim view dinstance todo
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
1,
|
false,
|
||||||
"minecraft:overworld".into(),
|
1,
|
||||||
0, // seed
|
"minecraft:overworld".into(),
|
||||||
GameMode::Survival,
|
0, // seed
|
||||||
GameMode::Undefined,
|
GameMode::Survival,
|
||||||
false,
|
GameMode::Undefined,
|
||||||
false,
|
false,
|
||||||
false, // deth loc
|
false,
|
||||||
None,
|
false, // deth loc
|
||||||
None,
|
None,
|
||||||
0,
|
None,
|
||||||
false,
|
0,
|
||||||
));
|
false,
|
||||||
|
))
|
||||||
|
.unwrap_or_else(|e| client.kick(&e.to_string()));
|
||||||
|
|
||||||
client.player = Some(player);
|
client.player = Some(player);
|
||||||
}
|
}
|
||||||
@ -125,7 +126,7 @@ impl Server {
|
|||||||
self.entity_id.fetch_add(1, Ordering::SeqCst)
|
self.entity_id.fetch_add(1, Ordering::SeqCst)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_brand(client: &mut Client) {
|
pub fn send_brand(client: &mut Client) -> Result<(), PacketError> {
|
||||||
// send server brand
|
// send server brand
|
||||||
let brand = "pumpkin";
|
let brand = "pumpkin";
|
||||||
let mut buf = vec![];
|
let mut buf = vec![];
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user