Pumpkin/pumpkin/src/client/mod.rs
2024-07-31 22:17:51 +02:00

254 lines
8.5 KiB
Rust

use std::{
collections::VecDeque,
io::{self, Write},
rc::Rc,
};
use crate::{
entity::player::{ChatMode, Hand, Player},
protocol::{
client::{config::CConfigDisconnect, login::CLoginDisconnect},
server::{
config::{SAcknowledgeFinishConfig, SClientInformation, SKnownPacks},
handshake::SHandShake,
login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart},
status::{SPingRequest, SStatusRequest},
},
ClientPacket, RawPacket,
},
server::Server,
};
use crate::protocol::ConnectionState;
use anyhow::Context;
use mio::{event::Event, net::TcpStream, Token};
use packet_decoder::PacketDecoder;
use packet_encoder::PacketEncoder;
use rsa::Pkcs1v15Encrypt;
use std::io::Read;
mod client_packet;
mod packet_decoder;
mod packet_encoder;
use client_packet::ClientPacketProcessor;
pub const MAX_PACKET_SIZE: i32 = 2097152;
pub struct PlayerConfig {
locale: String, // 16
view_distance: i8,
chat_mode: ChatMode,
chat_colors: bool,
skin_parts: u8,
main_hand: Hand,
text_filtering: bool,
server_listing: bool,
}
pub struct Client {
pub player: Option<Player>,
pub name: Option<String>,
pub uuid: Option<uuid::Uuid>,
pub config: Option<PlayerConfig>,
pub connection_state: ConnectionState,
pub encrytion: bool,
pub closed: bool,
pub token: Rc<Token>,
pub connection: TcpStream,
enc: PacketEncoder,
dec: PacketDecoder,
pub client_packets_queue: VecDeque<RawPacket>,
}
impl Client {
pub fn new(token: Rc<Token>, connection: TcpStream) -> Self {
Self {
name: None,
uuid: None,
config: None,
token,
player: None,
connection_state: ConnectionState::HandShake,
connection,
enc: PacketEncoder::default(),
dec: PacketDecoder::default(),
encrytion: true,
closed: false,
client_packets_queue: VecDeque::new(),
}
}
pub fn add_packet(&mut self, packet: RawPacket) {
self.client_packets_queue.push_back(packet);
}
pub fn enable_encryption(
&mut self,
server: &mut Server,
shared_secret: Vec<u8>,
) -> anyhow::Result<()> {
self.encrytion = true;
let shared_secret = server
.private_key
.decrypt(Pkcs1v15Encrypt, &shared_secret)
.context("failed to decrypt shared secret")?;
let crypt_key: [u8; 16] = shared_secret
.as_slice()
.try_into()
.context("shared secret has the wrong length")?;
self.dec.enable_encryption(&crypt_key);
self.enc.enable_encryption(&crypt_key);
Ok(())
}
pub fn send_packet<P: ClientPacket>(&mut self, packet: P) {
dbg!("sending packet");
self.enc.append_packet(packet).unwrap();
self.connection.write_all(&self.enc.take()).unwrap();
}
pub fn process_packets(&mut self, server: &mut Server) {
let mut i = 0;
while i < self.client_packets_queue.len() {
let mut packet = self.client_packets_queue.remove(i).unwrap();
self.handle_packet(server, &mut packet);
i += 1;
}
}
pub fn handle_packet(&mut self, server: &mut Server, packet: &mut RawPacket) {
dbg!("Handling packet");
let bytebuf = &mut packet.bytebuf;
match self.connection_state {
crate::protocol::ConnectionState::HandShake => match packet.id {
SHandShake::PACKET_ID => self.handle_handshake(server, SHandShake::read(bytebuf)),
_ => log::error!(
"Failed to handle packet id {} while in Handshake state",
packet.id
),
},
crate::protocol::ConnectionState::Status => match packet.id {
SStatusRequest::PACKET_ID => {
self.handle_status_request(server, SStatusRequest::read(bytebuf))
}
SPingRequest::PACKET_ID => {
self.handle_ping_request(server, SPingRequest::read(bytebuf))
}
_ => log::error!(
"Failed to handle packet id {} while in Status state",
packet.id
),
},
crate::protocol::ConnectionState::Login => match packet.id {
SLoginStart::PACKET_ID => {
self.handle_login_start(server, SLoginStart::read(bytebuf))
}
SEncryptionResponse::PACKET_ID => {
self.handle_encryption_response(server, SEncryptionResponse::read(bytebuf))
}
SLoginPluginResponse::PACKET_ID => {
self.handle_plugin_response(server, SLoginPluginResponse::read(bytebuf))
}
SLoginAcknowledged::PACKET_ID => {
self.handle_login_acknowledged(server, SLoginAcknowledged::read(bytebuf))
}
_ => log::error!(
"Failed to handle packet id {} while in Login state",
packet.id
),
},
crate::protocol::ConnectionState::Config => match packet.id {
SClientInformation::PACKET_ID => {
self.handle_client_information(server, SClientInformation::read(bytebuf))
}
SAcknowledgeFinishConfig::PACKET_ID => {
self.handle_config_acknowledged(server, SAcknowledgeFinishConfig::read(bytebuf))
}
SKnownPacks::PACKET_ID => {
self.handle_known_packs(server, SKnownPacks::read(bytebuf))
}
_ => log::error!(
"Failed to handle packet id {} while in Config state",
packet.id
),
},
_ => log::error!("Invalid Connection state {:?}", self.connection_state),
}
}
/// Returns `true` if the connection is done.
pub fn poll(&mut self, server: &mut Server, event: &Event) -> anyhow::Result<bool> {
if event.is_readable() {
let mut received_data = vec![0; 4096];
let mut bytes_read = 0;
// We can (maybe) read from the connection.
loop {
match self.connection.read(&mut received_data[bytes_read..]) {
Ok(0) => {
// Reading 0 bytes means the other side has closed the
// connection or is done writing, then so are we.
self.closed = true;
break;
}
Ok(n) => {
bytes_read += n;
if bytes_read == received_data.len() {
received_data.resize(received_data.len() + 1024, 0);
}
}
// Would block "errors" are the OS's way of saying that the
// connection is not actually ready to perform this I/O operation.
Err(ref err) if would_block(err) => break,
Err(ref err) if interrupted(err) => continue,
// Other errors we'll consider fatal.
Err(err) => return anyhow::bail!(err),
}
}
if bytes_read != 0 {
self.dec.reserve(4096);
self.dec.queue_slice(&received_data[..bytes_read]);
if let Some(packet) = self.dec.decode()? {
self.add_packet(packet);
self.process_packets(server);
}
self.dec.clear();
}
}
Ok(self.closed)
}
pub fn kick(&mut self, reason: &str) {
// Todo
match self.connection_state {
ConnectionState::Login => {
self.send_packet(CLoginDisconnect::new(reason));
}
ConnectionState::Config => {
self.send_packet(CConfigDisconnect::new(reason));
}
_ => {
log::warn!("Cant't kick in {:?} State", self.connection_state)
}
}
self.close()
}
// Kick before when needed
pub fn close(&mut self) {
self.closed = true;
}
}
fn would_block(err: &io::Error) -> bool {
err.kind() == io::ErrorKind::WouldBlock
}
pub fn interrupted(err: &io::Error) -> bool {
err.kind() == io::ErrorKind::Interrupted
}