From d73087734d0ee0444fb045bf74a4f02e3b822796 Mon Sep 17 00:00:00 2001 From: MeexReay Date: Mon, 13 May 2024 13:42:45 +0300 Subject: [PATCH] more writing and reading primary types --- examples/recv_motd.rs | 49 ++++++++++++++++++++ examples/status_server.rs | 97 +++++++++++++++++++++++++++++++++++++++ src/lib.rs | 83 +++++++++++++++++++++++++++++++-- src/main.rs | 50 +++++++++----------- 4 files changed, 245 insertions(+), 34 deletions(-) create mode 100644 examples/recv_motd.rs create mode 100644 examples/status_server.rs diff --git a/examples/recv_motd.rs b/examples/recv_motd.rs new file mode 100644 index 0000000..379a33b --- /dev/null +++ b/examples/recv_motd.rs @@ -0,0 +1,49 @@ +use rust_mc_proto::{Packet, ProtocolError, MCConnTcp, DataBufferReader, DataBufferWriter}; + +/* + + Example of receiving motd from the server + Sends handshake, status request and receiving one + +*/ + +fn send_handshake(conn: &mut MCConnTcp, + protocol_version: u16, + server_address: &str, + server_port: u16, + next_state: u8) -> Result<(), ProtocolError> { + let mut packet = Packet::empty(0x00); + + packet.write_u16_varint(protocol_version)?; + packet.write_string(server_address)?; + packet.write_unsigned_short(server_port)?; + packet.write_u8_varint(next_state)?; + + conn.write_packet(&packet)?; + + Ok(()) +} + +fn send_status_request(conn: &mut MCConnTcp) -> Result<(), ProtocolError> { + let packet = Packet::empty(0x00); + conn.write_packet(&packet)?; + + Ok(()) +} + +fn read_status_response(conn: &mut MCConnTcp) -> Result { + let mut packet = conn.read_packet()?; + + packet.read_string() +} + +fn main() { + let mut conn = MCConnTcp::connect("localhost:25565").unwrap(); + + send_handshake(&mut conn, 765, "localhost", 25565, 1).unwrap(); + send_status_request(&mut conn).unwrap(); + + let motd = read_status_response(&mut conn).unwrap(); + + println!("Motd: {}", motd); +} diff --git a/examples/status_server.rs b/examples/status_server.rs new file mode 100644 index 0000000..aab7050 --- /dev/null +++ b/examples/status_server.rs @@ -0,0 +1,97 @@ +use std::{net::TcpListener, sync::{Arc, Mutex}, thread}; + +use rust_mc_proto::{DataBufferReader, DataBufferWriter, MCConn, MCConnTcp, MinecraftConnection, Packet, ProtocolError}; + +/* + + Example of simple server that sends motd + to client like an vanilla minecraft server + +*/ + +struct MinecraftServer { + server_ip: String, + server_port: u16, + protocol_version: u16, + motd: String +} + +impl MinecraftServer { + fn new(server_ip: &str, + server_port: u16, + protocol_version: u16, + motd: &str) -> Self { + MinecraftServer { + server_ip: server_ip.to_string(), + server_port, + protocol_version, + motd: motd.to_string() + } + } +} + +fn accept_client(mut conn: MCConnTcp, server: Arc>) -> Result<(), ProtocolError> { + let mut handshake = false; + + loop { + let mut packet = match conn.read_packet() { + Ok(i) => i, + Err(_) => { break; }, + }; + + if handshake { + if packet.id == 0x00 { + let mut status = Packet::empty(0x00); + status.write_string(&server.lock().unwrap().motd)?; + conn.write_packet(&status)?; + } else if packet.id == 0x01 { + let mut status = Packet::empty(0x01); + status.write_long(packet.read_long()?)?; + conn.write_packet(&status)?; + } + } else if packet.id == 0x00 { + let protocol_version = packet.read_u16_varint()?; + let server_address = packet.read_string()?; + let server_port = packet.read_unsigned_short()?; + let next_state = packet.read_u8_varint()?; + + if next_state != 1 { break; } + + println!("Client handshake info:"); + println!(" IP: {}", conn.stream.peer_addr().unwrap()); + println!(" Protocol version: {}", protocol_version); + println!(" Server address: {}", server_address); + println!(" Server port: {}", server_port); + + handshake = true; + } else { + break; + } + } + + conn.close(); + + Ok(()) +} + +fn main() { + let server = MinecraftServer::new( + "localhost", + 25565, + 765, + "{}" + ); + + let addr = server.server_ip.clone() + ":" + &server.server_port.to_string(); + let listener = TcpListener::bind(addr).unwrap(); + let server = Arc::new(Mutex::new(server)); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + let local_server = server.clone(); + + thread::spawn(move || { + accept_client(MinecraftConnection::new(stream), local_server).unwrap(); + }); + } +} diff --git a/src/lib.rs b/src/lib.rs index 50c6fd4..f0d7dcf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -100,11 +100,44 @@ pub trait DataBufferReader { Err(_) => Err(ProtocolError::StringParseError) } } - fn read_unsigned_short(&mut self) -> Result { - let bytes = self.read_bytes(2)?; - let bytes = [bytes[0], bytes[1]]; - Ok(u16::from_be_bytes(bytes)) + match self.read_bytes(2)?.try_into() { + Ok(i) => Ok(u16::from_be_bytes(i)), + Err(_) => Err(ProtocolError::ReadError), + } + } + fn read_boolean(&mut self) -> Result { + Ok(self.read_byte()? == 0x01) + } + fn read_short(&mut self) -> Result { + match self.read_bytes(2)?.try_into() { + Ok(i) => Ok(i16::from_be_bytes(i)), + Err(_) => Err(ProtocolError::ReadError), + } + } + fn read_long(&mut self) -> Result { + match self.read_bytes(8)?.try_into() { + Ok(i) => Ok(i64::from_be_bytes(i)), + Err(_) => Err(ProtocolError::ReadError), + } + } + fn read_float(&mut self) -> Result { + match self.read_bytes(4)?.try_into() { + Ok(i) => Ok(f32::from_be_bytes(i)), + Err(_) => Err(ProtocolError::ReadError), + } + } + fn read_double(&mut self) -> Result { + match self.read_bytes(8)?.try_into() { + Ok(i) => Ok(f64::from_be_bytes(i)), + Err(_) => Err(ProtocolError::ReadError), + } + } + fn read_int(&mut self) -> Result { + match self.read_bytes(4)?.try_into() { + Ok(i) => Ok(i32::from_be_bytes(i)), + Err(_) => Err(ProtocolError::ReadError), + } } fn read_usize_varint(&mut self) -> Result { read_varint!(usize, self) } @@ -127,7 +160,7 @@ pub trait DataBufferWriter { fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), ProtocolError>; fn write_byte(&mut self, byte: u8) -> Result<(), ProtocolError>; - fn write_string(&mut self, val: String) -> Result<(), ProtocolError> { + fn write_string(&mut self, val: &str) -> Result<(), ProtocolError> { let bytes = val.as_bytes(); self.write_usize_varint(bytes.len())?; @@ -139,6 +172,42 @@ pub trait DataBufferWriter { Err(_) => Err(ProtocolError::UnsignedShortError), } } + fn write_boolean(&mut self, val: bool) -> Result<(), ProtocolError> { + match self.write_byte(if val { 0x01 } else { 0x00 }) { + Ok(_) => Ok(()), + Err(_) => Err(ProtocolError::UnsignedShortError), + } + } + fn write_short(&mut self, val: i16) -> Result<(), ProtocolError> { + match self.write_bytes(&val.to_be_bytes()) { + Ok(_) => Ok(()), + Err(_) => Err(ProtocolError::UnsignedShortError), + } + } + fn write_long(&mut self, val: i64) -> Result<(), ProtocolError> { + match self.write_bytes(&val.to_be_bytes()) { + Ok(_) => Ok(()), + Err(_) => Err(ProtocolError::UnsignedShortError), + } + } + fn write_float(&mut self, val: f32) -> Result<(), ProtocolError> { + match self.write_bytes(&val.to_be_bytes()) { + Ok(_) => Ok(()), + Err(_) => Err(ProtocolError::UnsignedShortError), + } + } + fn write_double(&mut self, val: f64) -> Result<(), ProtocolError> { + match self.write_bytes(&val.to_be_bytes()) { + Ok(_) => Ok(()), + Err(_) => Err(ProtocolError::UnsignedShortError), + } + } + fn write_int(&mut self, val: i32) -> Result<(), ProtocolError> { + match self.write_bytes(&val.to_be_bytes()) { + Ok(_) => Ok(()), + Err(_) => Err(ProtocolError::UnsignedShortError), + } + } fn write_usize_varint(&mut self, val: usize) -> Result<(), ProtocolError> { write_varint!(usize, self, val) } fn write_u8_varint(&mut self, val: u8) -> Result<(), ProtocolError> { write_varint!(u8, self, val) } @@ -275,6 +344,10 @@ impl MinecraftConnection { compress_threashold: 0 }) } + + pub fn close(&mut self) { + let _ = self.stream.shutdown(std::net::Shutdown::Both); + } } impl DataBufferReader for MinecraftConnection { diff --git a/src/main.rs b/src/main.rs index f8f6430..48b7699 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,42 +1,34 @@ -use rust_mc_proto::{Packet, ProtocolError, MCConnTcp, DataBufferReader, DataBufferWriter}; +use std::{net::TcpListener, sync::Arc, thread}; -fn send_handshake(conn: &mut MCConnTcp, - protocol_version: u16, - server_address: &str, - server_port: u16, - next_state: u8) -> Result<(), ProtocolError> { - let mut packet = Packet::empty(0x00); +use rust_mc_proto::{DataBufferReader, DataBufferWriter, MCConn, MCConnTcp, MinecraftConnection, Packet, ProtocolError}; - packet.write_u16_varint(protocol_version)?; - packet.write_string(server_address.to_string())?; - packet.write_unsigned_short(server_port)?; - packet.write_u8_varint(next_state)?; +/* - conn.write_packet(&packet)?; + Example of simple server that sends motd + to client like an vanilla minecraft server - Ok(()) -} +*/ -fn send_status_request(conn: &mut MCConnTcp) -> Result<(), ProtocolError> { - let packet = Packet::empty(0x00); - conn.write_packet(&packet)?; +fn accept_client(mut conn: MCConnTcp) { + loop { + let packet = match conn.read_packet() { + Ok(p) => p, + Err(_) => { break }, + }; - Ok(()) -} - -fn read_status_response(conn: &mut MCConnTcp) -> Result { - let mut packet = conn.read_packet()?; - - packet.read_string() + dbg!(packet); + } } fn main() { - let mut conn = MCConnTcp::connect("localhost:25566").unwrap(); + let listener = TcpListener::bind("localhost:25565").unwrap(); - send_handshake(&mut conn, 765, "localhost", 25565, 1).unwrap(); - send_status_request(&mut conn).unwrap(); + for stream in listener.incoming() { + let stream = stream.unwrap(); - let motd = read_status_response(&mut conn).unwrap(); - println!("Motd: {}", motd); + thread::spawn(move || { + accept_client(MinecraftConnection::new(stream)); + }); + } }