Massive net refactoring, protocol now defined via macros!

* Fixed cli.yml, which was blatently broken previously.

* Split PacketData into PacketReadable and PacketWritable,
  which allows implementing PacketWritable for un-owned types
  (for example, &str and &[u8]).

* Added impl_packet_data_for_num! and impl_varnum!
  which makes defining packet serialization
  for the numbers very concise.

* Added define_packet! macro which
  makes defining packets easy and much less tedious.

* Added ProtocolState macro which encapsulates
  packet enums and packet ids into a single unit.

* Added define_packet! macro which makes
  defining protocol states trivial
  (it's just a simple id/packet mapping).

* Made packet serialization/deserialization part of PacketFormat,
  which massively simplifies the API.

It took a while to get the hang of this all,
but the more I use Rust, the more I love it.
master
James T. Martin 2020-07-24 22:13:23 -07:00
parent 0b5d3c026f
commit cfc7bd6f46
Signed by: james
GPG Key ID: 4B7F3DA9351E577C
9 changed files with 431 additions and 406 deletions

View File

@ -4,6 +4,10 @@ author: James Martin
about: A Minecraft protocol-compatible server written in Rust.
args:
- host:
long: host
help: The IP address the server will use to listen for connections. Defaults to any address (`::`).
takes_value: true
- port:
help: The port the server will accept connections from. Defaults to 25565.
long: port
help: The port the server will accept connections from. Defaults to 25565.
takes_value: true

View File

@ -5,7 +5,6 @@ mod net;
use crate::net::{Reader, Writer};
use crate::net::chat::Chat;
use crate::net::format::{PacketFormat, DefaultPacketFormat};
use crate::net::serialize::VecPacketDeserializer;
use tokio::io::{BufReader, BufWriter};
use tokio::net::{TcpListener, TcpStream};
use std::io;
@ -13,8 +12,10 @@ use std::net::IpAddr;
#[tokio::main]
async fn main() -> io::Result<()> {
let yaml = clap::load_yaml!("cli.yml");
let args = clap::App::from_yaml(yaml).get_matches();
use clap::{App, load_yaml};
let yaml = load_yaml!("cli.yml");
let args = App::from_yaml(yaml).get_matches();
let host: IpAddr = args.value_of("host").unwrap_or("::").parse()
.expect("Invalid host IP address.");
let port: u16 = args.value_of("port").unwrap_or("25565").parse()
@ -56,64 +57,52 @@ async fn accept_connection(mut socket: TcpStream) {
async fn interact_handshake<'a>(source: &mut Reader<'a>, dest: &mut Writer<'a>) -> io::Result<()> {
use crate::net::packet::handshake::*;
use PacketHandshakeServerbound::*;
let (id, data) = DefaultPacketFormat.recieve(source).await?;
let mut deser = VecPacketDeserializer::new(&data);
let pkt = DefaultPacketFormat.recieve::<HandshakeServerbound>(source).await?;
match read_packet_handshake(id, &mut deser)
.map_err(|err| io::Error::new(io::ErrorKind::Other, err)) {
Ok(pkt) => match pkt {
Handshake(pkt) => {
if pkt.next_state == HandshakeNextState::Status {
interact_status(source, dest).await
} else {
Err(io::Error::new(io::ErrorKind::Other, "We do not support client log-in yet.".to_string()))
}
match pkt {
HandshakeServerbound::Handshake(handshake) => {
if handshake.next_state == HandshakeNextState::Status {
interact_status(source, dest).await
} else {
Err(io::Error::new(io::ErrorKind::Other, "We do not support client log-in yet.".to_string()))
}
},
Err(err) => Err(io::Error::new(io::ErrorKind::Other, err))
}
}
}
async fn interact_status<'a>(source: &mut Reader<'a>, dest: &mut Writer<'a>) -> io::Result<()> {
use crate::net::packet::status::*;
use PacketStatusClientbound::*;
use PacketStatusServerbound::*;
loop {
let (id, data) = DefaultPacketFormat.recieve(source).await?;
let mut deser = VecPacketDeserializer::new(&data);
let pkt = DefaultPacketFormat.recieve::<StatusServerbound>(source).await?;
match read_packet_status(id, &mut deser)
.map_err(|err| io::Error::new(io::ErrorKind::Other, err)) {
Ok(pkt) => match pkt {
Request => {
let mut buf = Vec::new();
let id = write_packet_status(&mut buf, Response(PacketResponse {
version: PacketResponseVersion {
match pkt {
StatusServerbound::Request(Request {}) => {
DefaultPacketFormat.send(dest, &StatusClientbound::Response(Response {
data: ResponseData {
version: ResponseVersion {
name: "1.16.1".to_string(),
protocol: 736,
},
players: PacketResponsePlayers {
players: ResponsePlayers {
max: 255,
online: 0,
sample: Vec::new(),
},
description: Chat { text: "Hello, world!".to_string() },
favicon: None,
}));
DefaultPacketFormat.send(dest, id, buf.as_slice()).await?;
},
Ping(payload) => {
let mut buf = Vec::new();
let id = write_packet_status(&mut buf, Pong(payload));
DefaultPacketFormat.send(dest, id, buf.as_slice()).await?;
return Ok(());
}
}
})).await?;
},
StatusServerbound::Ping(ping) => {
DefaultPacketFormat.send(dest, &StatusClientbound::Pong(Pong {
payload: ping.payload
})).await?;
// The status ping is now over so the server ends the connection.
return Ok(());
},
Err(err) => return Err(io::Error::new(io::ErrorKind::Other, err))
}
}
}

View File

@ -1,13 +1,14 @@
use async_trait::async_trait;
use crate::net::{Reader, Writer};
use crate::net::state::ProtocolState;
use std::boxed::Box;
use std::io;
use tokio::io::AsyncReadExt;
#[async_trait]
pub trait PacketFormat {
async fn send<'wr, 'w>(&self, dest: &'wr mut Writer<'w>, packet_id: i32, data: &[u8]) -> io::Result<()>;
async fn recieve<'rr, 'r>(&self, src: &'rr mut Reader<'r>) -> io::Result<(i32, Box<[u8]>)>;
async fn send<'wr, 'w, P: ProtocolState + Sync>(&self, dest: &'wr mut Writer<'w>, pkt: &P) -> io::Result<()>;
async fn recieve<'rr, 'r, P: ProtocolState>(&self, src: &'rr mut Reader<'r>) -> io::Result<P>;
}
pub const MAX_CLIENT_PACKET_SIZE: usize = 32767;
@ -34,9 +35,13 @@ async fn read_varint<'rr, 'r>(src: &'rr mut Reader<'r>) -> io::Result<(usize, i3
#[async_trait]
impl PacketFormat for DefaultPacketFormat {
async fn send<'wr, 'w>(&self, dest: &'wr mut Writer<'w>, packet_id: i32, data: &[u8]) -> io::Result<()> {
async fn send<'wr, 'w, P: ProtocolState + Sync>(&self, dest: &'wr mut Writer<'w>, pkt: &P) -> io::Result<()> {
use crate::net::serialize::{PacketSerializer, VarInt};
let packet_id = pkt.id();
let mut data = Vec::new();
pkt.write(&mut data);
let mut packet_id_buf = Vec::with_capacity(5);
packet_id_buf.write(VarInt(packet_id));
@ -49,14 +54,16 @@ impl PacketFormat for DefaultPacketFormat {
dest.write(packet_length_buf.as_slice()).await?;
dest.write(packet_id_buf.as_slice()).await?;
dest.write(data).await?;
dest.write(data.as_slice()).await?;
dest.flush().await?;
}
Ok(())
}
async fn recieve<'rr, 'r>(&self, src: &'rr mut Reader<'r>) -> io::Result<(i32, Box<[u8]>)> {
async fn recieve<'rr, 'r, P: ProtocolState>(&self, src: &'rr mut Reader<'r>) -> io::Result<P> {
use crate::net::serialize::VecPacketDeserializer;
let (_, length) = read_varint(src).await?;
if length > MAX_CLIENT_PACKET_SIZE as i32 {
return Err(io::Error::new(io::ErrorKind::Other, "Packet was too long."));
@ -69,6 +76,7 @@ impl PacketFormat for DefaultPacketFormat {
buf.resize(length - id_length, 0);
src.read_exact(buf.as_mut_slice()).await?;
Ok((id, buf.into_boxed_slice()))
P::read(id, &mut VecPacketDeserializer::new(&buf))
.map_err(|err| io::Error::new(io::ErrorKind::Other, err))
}
}

View File

@ -2,6 +2,7 @@ pub mod chat;
pub mod format;
pub mod packet;
pub mod serialize;
pub mod state;
use tokio::io::{BufReader, BufWriter};
use tokio::net::tcp::{ReadHalf, WriteHalf};

View File

@ -1,2 +1,38 @@
pub mod handshake;
pub mod status;
#[macro_export]
macro_rules! define_packets {
{ $( packet $name:ident { $( $field:ident : $type:ty ),* } )+ } => {
$(
pub struct $name {
$(
pub $field: $type,
)*
}
impl crate::net::serialize::PacketReadable for $name {
fn read(deser: &mut impl crate::net::serialize::PacketDeserializer) -> Result<Self, String> {
$(
let $field = deser.read::<$type>()?;
)*
deser.read_eof()?;
Ok($name {
$(
$field: $field,
)*
})
}
}
impl crate::net::serialize::PacketWritable for &$name {
fn write(self, ser: &mut impl crate::net::serialize::PacketSerializer) {
$(
self.$field.write(ser);
)*
ser.write_eof();
}
}
)*
}
}

View File

@ -1,56 +1,48 @@
use crate::net::serialize::{PacketData, PacketDeserializer, PacketSerializer, VarInt};
use crate::{define_packets, define_states};
use crate::net::serialize::{PacketReadable, PacketWritable, PacketDeserializer, PacketSerializer, VarInt};
#[derive(Debug, PartialEq, Eq)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum HandshakeNextState {
Status,
Login,
}
#[derive(Debug)]
pub struct PacketHandshake {
pub protocol_version: i32,
pub server_address: String,
pub server_port: u16,
pub next_state: HandshakeNextState,
}
impl PacketData for PacketHandshake {
impl PacketReadable for HandshakeNextState {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
let protocol_version = deser.read::<VarInt>()?.into();
let server_address = deser.read::<String>()?;
let server_port = deser.read::<u16>()?;
let next_state = match deser.read::<VarInt>()?.into() {
1 => HandshakeNextState::Status,
2 => HandshakeNextState::Login,
use HandshakeNextState::*;
Ok(match deser.read::<VarInt>()?.into() {
1 => Status,
2 => Login,
n => return Err(format!("Invalid next protocol state in handshake: {}", n))
};
deser.read_eof()?;
Ok(PacketHandshake {
protocol_version: protocol_version,
server_address: server_address,
server_port: server_port,
next_state: next_state,
})
}
}
fn write(&self, ser: &mut impl PacketSerializer) {
ser.write(self.protocol_version);
ser.write(self.server_address.clone());
ser.write(self.server_port);
impl PacketWritable for &HandshakeNextState {
fn write(self, ser: &mut impl PacketSerializer) {
use HandshakeNextState::*;
ser.write(VarInt(match self {
Status => 1,
Login => 2,
}));
}
}
#[derive(Debug)]
pub enum PacketHandshakeServerbound {
Handshake(PacketHandshake),
}
pub fn read_packet_handshake(id: i32, deser: &mut impl PacketDeserializer)
-> Result<PacketHandshakeServerbound, String> {
use PacketHandshakeServerbound::*;
match id {
0x00 => deser.read().map(Handshake),
id => Err(format!("Invalid handshake packet id: {}", id))
define_packets! {
packet Handshake {
protocol_version: VarInt,
server_address: String,
server_port: u16,
next_state: HandshakeNextState
}
}
define_states! {
state HandshakeClientbound { }
state HandshakeServerbound {
0x00 => Handshake
}
}

View File

@ -1,81 +1,69 @@
use crate::{define_packets, define_states};
use crate::net::chat::Chat;
use crate::net::serialize::{PacketDeserializer, PacketSerializer, PacketJson};
use crate::net::serialize::{PacketJson};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[derive(Clone, Deserialize, Serialize)]
pub struct PacketResponseVersion {
pub struct ResponseVersion {
pub name: String,
pub protocol: u32,
}
impl PacketJson for PacketResponseVersion {}
impl PacketJson for ResponseVersion {}
#[derive(Clone, Deserialize, Serialize)]
pub struct PacketResponsePlayersSample {
pub struct ResponsePlayersSample {
pub name: String,
pub id: Uuid,
}
impl PacketJson for PacketResponsePlayersSample {}
impl PacketJson for ResponsePlayersSample {}
#[derive(Clone, Deserialize, Serialize)]
pub struct PacketResponsePlayers {
pub struct ResponsePlayers {
pub max: u32,
pub online: u32,
pub sample: Vec<PacketResponsePlayersSample>
pub sample: Vec<ResponsePlayersSample>
}
impl PacketJson for PacketResponsePlayers {}
impl PacketJson for ResponsePlayers {}
#[derive(Clone, Deserialize, Serialize)]
pub struct PacketResponse {
pub version: PacketResponseVersion,
pub players: PacketResponsePlayers,
pub struct ResponseData {
pub version: ResponseVersion,
pub players: ResponsePlayers,
pub description: Chat,
#[serde(skip_serializing_if = "Option::is_none")]
pub favicon: Option<String>,
}
impl PacketJson for PacketResponse {}
impl PacketJson for ResponseData {}
pub enum PacketStatusClientbound {
Response(PacketResponse),
Pong([u8; 8]),
}
define_packets! {
// Clientbound
#[derive(Debug)]
pub enum PacketStatusServerbound {
Request,
Ping([u8; 8]),
}
packet Response {
data: ResponseData
}
pub fn read_packet_status(id: i32, deser: &mut impl PacketDeserializer)
-> Result<PacketStatusServerbound, String> {
use PacketStatusServerbound::*;
packet Pong {
payload: [u8; 8]
}
match id {
0 => {
deser.read_eof()?;
Ok(Request)
},
1 => {
let payload = deser.read::<[u8; 8]>()?;
deser.read_eof()?;
Ok(Ping(payload))
}
id => Err(format!("Invalid status packet id: {}", id))
// Serverbound
packet Request { }
packet Ping {
payload: [u8; 8]
}
}
pub fn write_packet_status(ser: &mut impl PacketSerializer, packet: PacketStatusClientbound)
-> i32 {
use PacketStatusClientbound::*;
define_states! {
state StatusClientbound {
0x00 => Response,
0x01 => Pong
}
match packet {
Response(response) => {
ser.write(response);
0x00
},
Pong(payload) => {
ser.write(payload);
0x01
}
state StatusServerbound {
0x00 => Request,
0x01 => Ping
}
}

View File

@ -1,283 +1,15 @@
use crate::net::format::MAX_CLIENT_PACKET_SIZE;
use serde::Serialize;
use serde::de::DeserializeOwned;
use std::borrow::Borrow;
use std::convert::{From, Into};
pub trait PacketData: Sized {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String>
where Self: std::marker::Sized;
fn write(&self, ser: &mut impl PacketSerializer);
}
impl<const N: usize> PacketData for [u8; N] {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
use std::convert::TryInto;
let mut buf = [0; N];
deser.read_exact(&mut buf)?;
Ok(buf.try_into().unwrap())
}
fn write(&self, ser: &mut impl PacketSerializer) {
ser.write_exact(self);
}
}
impl PacketData for bool {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
let value = deser.read::<u8>()?;
match value {
0x00 => Ok(false),
0x01 => Ok(true),
n => Err(format!("{:0X} is not a valid boolean.", n))
}
}
fn write(&self, ser: &mut impl PacketSerializer) {
ser.write(*self as u8);
}
}
impl PacketData for u8 {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
deser.read::<[u8; 1]>().map(u8::from_be_bytes)
}
fn write(&self, ser: &mut impl PacketSerializer) {
ser.write(self.to_be_bytes())
}
}
impl PacketData for i8 {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
deser.read::<[u8; 1]>().map(i8::from_be_bytes)
}
fn write(&self, ser: &mut impl PacketSerializer) {
ser.write(self.to_be_bytes())
}
}
impl PacketData for u16 {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
deser.read::<[u8; 2]>().map(u16::from_be_bytes)
}
fn write(&self, ser: &mut impl PacketSerializer) {
ser.write(self.to_be_bytes());
}
}
impl PacketData for i16 {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
deser.read::<[u8; 2]>().map(i16::from_be_bytes)
}
fn write(&self, ser: &mut impl PacketSerializer) {
ser.write(self.to_be_bytes());
}
}
impl PacketData for i32 {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
deser.read::<[u8; 4]>().map(i32::from_be_bytes)
}
fn write(&self, ser: &mut impl PacketSerializer) {
ser.write(self.to_be_bytes());
}
}
impl PacketData for i64 {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
deser.read::<[u8; 8]>().map(i64::from_be_bytes)
}
fn write(&self, ser: &mut impl PacketSerializer) {
ser.write(self.to_be_bytes());
}
}
impl PacketData for f32 {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
deser.read::<[u8; 4]>().map(f32::from_be_bytes)
}
fn write(&self, ser: &mut impl PacketSerializer) {
ser.write(self.to_be_bytes());
}
}
impl PacketData for f64 {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
deser.read::<[u8; 8]>().map(f64::from_be_bytes)
}
fn write(&self, ser: &mut impl PacketSerializer) {
ser.write(self.to_be_bytes());
}
}
pub struct VarInt(pub i32);
impl From<i32> for VarInt {
fn from(x: i32) -> Self { VarInt(x) }
}
impl Into<i32> for VarInt {
fn into(self) -> i32 { self.0 }
}
impl PacketData for VarInt {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
let mut length = 1;
let mut acc = 0;
// VarInts must not be longer than 5 bytes.
while length <= 5 {
// If the highest bit is set, there are further bytes to be read from this VarInt;
// the rest of the bits are the actual data in the VarInt.
let read = deser.read::<u8>()?;
acc |= (read & 0b01111111) as i32;
// There are no more bytes.
if (read & 0b10000000) == 0 {
return Ok(VarInt(acc));
}
// Make space for the rest of the bits.
acc = acc << 7;
length += 1;
}
// The VarInt was too long!
Err("VarInt was more than 5 bytes.".to_string())
}
fn write(&self, ser: &mut impl PacketSerializer) {
let mut value = self.0;
loop {
let mut temp = (value & 0b01111111) as u8;
value = value >> 7;
if value != 0 {
temp |= 0b10000000;
}
ser.write(temp);
if value == 0 {
break;
}
}
}
}
pub struct VarLong(pub i64);
impl From<i64> for VarLong {
fn from(x: i64) -> Self { VarLong(x) }
}
impl Into<i64> for VarLong {
fn into(self) -> i64 { self.0 }
}
impl PacketData for VarLong {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
let mut length = 1;
let mut acc = 0;
// VarLongs must not be longer than 5 bytes.
while length <= 10 {
// If the highest bit is set, there are further bytes to be read from this VarLong;
// the rest of the bits are the actual data in the VarLong.
let read = deser.read::<u8>()?;
acc |= (read & 0b01111111) as i64;
// There are no more bytes.
if (read & 0b10000000) == 0 {
return Ok(VarLong(acc));
}
// Make space for the rest of the bits.
acc = acc << 7;
length += 1;
}
// The VarLong was too long!
Err("VarLong was more than 10 bytes.".to_string())
}
fn write(&self, ser: &mut impl PacketSerializer) {
let mut value = self.0;
loop {
let mut temp = (value & 0b01111111) as u8;
value = value >> 7;
if value != 0 {
temp |= 0b10000000;
}
ser.write(temp);
if value == 0 {
break;
}
}
}
}
impl PacketData for Vec<u8> {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
let length: i32 = deser.read::<VarInt>()?.into();
if length < 0 {
return Err("String length cannot be negative.".to_string());
}
let length = length as usize;
if length > MAX_CLIENT_PACKET_SIZE {
return Err("Byte array was too long.".to_string());
}
let mut it = Vec::with_capacity(length);
it.resize(length, 0);
deser.read_exact(it.as_mut_slice())?;
Ok(it)
}
fn write(&self, ser: &mut impl PacketSerializer) {
ser.write(VarInt(self.len() as i32));
ser.write_exact(self.as_slice());
}
}
impl PacketData for String {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
let bytes = deser.read()?;
String::from_utf8(bytes).map_err(|_| "String contained invalid UTF-8.".to_string())
}
fn write(&self, ser: &mut impl PacketSerializer) {
ser.write(self.clone().into_bytes());
}
}
pub trait PacketJson: DeserializeOwned + Serialize + Sized { }
impl PacketJson for crate::net::chat::Chat { }
impl<S: PacketJson> PacketData for S {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
let bytes = deser.read::<Vec<u8>>()?;
serde_json::from_slice(&bytes).map_err(|_| "Bad JSON syntax".to_string())
}
fn write(&self, ser: &mut impl PacketSerializer) {
ser.write(serde_json::to_vec(self).unwrap());
}
}
pub trait PacketSerializer: Sized {
/// Write a slice of bytes directly, without a length prefix.
fn write_exact(&mut self, value: &[u8]);
fn write_eof(&mut self);
fn write<D: PacketData>(&mut self, value: D) {
fn write<D: PacketWritable>(&mut self, value: D) {
value.write(self)
}
}
@ -286,13 +18,15 @@ impl PacketSerializer for Vec<u8> {
fn write_exact(&mut self, value: &[u8]) {
self.extend_from_slice(value);
}
fn write_eof(&mut self) {}
}
pub trait PacketDeserializer: Sized {
fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), String>;
fn read_eof(&mut self) -> Result<(), String>;
fn read<D: PacketData>(&mut self) -> Result<D, String> {
fn read<D: PacketReadable>(&mut self) -> Result<D, String> {
D::read(self)
}
}
@ -332,3 +66,232 @@ impl PacketDeserializer for VecPacketDeserializer<'_> {
Ok(())
}
}
pub trait PacketReadable: Sized {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String>;
}
pub trait PacketWritable {
fn write(self, ser: &mut impl PacketSerializer);
}
pub trait PacketData: PacketReadable + PacketWritable {}
impl<T: PacketReadable + PacketWritable> PacketData for T {}
impl PacketReadable for bool {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
let value = deser.read::<u8>()?;
match value {
0x00 => Ok(false),
0x01 => Ok(true),
n => Err(format!("{:0X} is not a valid boolean.", n))
}
}
}
impl PacketWritable for bool {
fn write(self, ser: &mut impl PacketSerializer) {
ser.write(self as u8);
}
}
macro_rules! impl_packet_data_for_num {
( $( $num:ty, $len:expr );+ ) => {
$(
impl PacketReadable for $num {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
deser.read::<[u8; $len]>().map(Self::from_be_bytes)
}
}
impl PacketWritable for $num {
fn write(self, ser: &mut impl PacketSerializer) {
ser.write(self.to_be_bytes())
}
}
)*
}
}
impl_packet_data_for_num!(u8, 1; i8, 1; u16, 2; i16, 2; u32, 4; i32, 4; u64, 8; i64, 8;
f32, 4; f64, 8);
// HACK: There is probably a better solution to this than a macro.
// Same goes for the above, but to a lesser degree.
macro_rules! impl_varnum {
( $( $name:ident, $wraps:ty, $length:expr);+ ) => {
$(
#[derive(Copy, Clone, Debug)]
pub struct $name(pub $wraps);
impl From<$wraps> for $name {
fn from(x: $wraps) -> Self { $name(x) }
}
impl Into<$wraps> for $name {
fn into(self) -> $wraps { self.0 }
}
impl PacketReadable for $name {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
let mut length = 1;
let mut acc = 0;
while length <= $length {
// If the highest bit is set, there are further bytes to be read;
// the rest of the bits are the actual bits of the number.
let read = deser.read::<u8>()?;
acc |= (read & 0b01111111) as $wraps;
if (read & 0b10000000) == 0 {
// There are no more bytes.
return Ok($name(acc));
}
// Make space for the rest of the bits.
acc = acc << 7;
length += 1;
}
Err(format!("VarNum was more than {} bytes.", $length))
}
}
impl PacketWritable for $name {
fn write(self, ser: &mut impl PacketSerializer) {
let mut value = self.0;
loop {
let mut temp = (value & 0b01111111) as u8;
value = value >> 7;
if value != 0 {
temp |= 0b10000000;
}
ser.write(temp);
if value == 0 {
break;
}
}
}
}
)*
}
}
impl_varnum!(VarInt, i32, 5; VarLong, i64, 10);
impl PacketWritable for &[u8] {
fn write(self, ser: &mut impl PacketSerializer) {
ser.write(VarInt(self.len() as i32));
ser.write_exact(self);
}
}
impl PacketReadable for Vec<u8> {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
let length: i32 = deser.read::<VarInt>()?.into();
if length < 0 {
return Err("String length cannot be negative.".to_string());
}
let length = length as usize;
if length > MAX_CLIENT_PACKET_SIZE {
return Err("Byte array was too long.".to_string());
}
let mut it = Vec::with_capacity(length);
it.resize(length, 0);
deser.read_exact(it.as_mut_slice())?;
Ok(it)
}
}
impl PacketWritable for &Vec<u8> {
fn write(self, ser: &mut impl PacketSerializer) {
ser.write(self.as_slice());
}
}
impl PacketReadable for Box<[u8]> {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
deser.read::<Vec<u8>>().map(|x| x.into_boxed_slice())
}
}
impl PacketWritable for &Box<[u8]> {
fn write(self, ser: &mut impl PacketSerializer) {
ser.write::<&[u8]>(self.borrow());
}
}
impl PacketWritable for &str {
fn write(self, ser: &mut impl PacketSerializer) {
ser.write(self.as_bytes());
}
}
impl PacketReadable for String {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
let bytes = deser.read()?;
String::from_utf8(bytes).map_err(|_| "String contained invalid UTF-8.".to_string())
}
}
impl PacketWritable for &String {
fn write(self, ser: &mut impl PacketSerializer) {
ser.write::<&str>(self.borrow());
}
}
impl PacketReadable for Box<str> {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
deser.read::<String>().map(|x| x.into_boxed_str())
}
}
impl PacketWritable for &Box<str> {
fn write(self, ser: &mut impl PacketSerializer) {
ser.write::<&str>(self.borrow());
}
}
/// A marker trait indicating that a JSON-serialiable type should be serialized as JSON in packets.
/// Most primitive types are already serializable as JSON,
/// but we explicitly *don't* want to serialize them as JSON in packets.
pub trait PacketJson { }
impl PacketJson for crate::net::chat::Chat { }
impl<S: DeserializeOwned + PacketJson + Sized> PacketReadable for S {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
let bytes = deser.read::<Vec<u8>>()?;
serde_json::from_slice(&bytes).map_err(|_| "Bad JSON syntax".to_string())
}
}
impl<S: PacketJson + Serialize> PacketWritable for &S {
fn write(self, ser: &mut impl PacketSerializer) {
ser.write(&serde_json::to_vec(self).unwrap())
}
}
// Although according to my organizational scheme, this should go first,
// it goes last anyway because constant generics break Atom's syntax highlighting
// for all code below it.
impl<const N: usize> PacketReadable for [u8; N] {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
use std::convert::TryInto;
let mut buf = [0; N];
deser.read_exact(&mut buf)?;
Ok(buf.try_into().unwrap())
}
}
impl<const N: usize> PacketWritable for [u8; N] {
fn write(self, ser: &mut impl PacketSerializer) {
ser.write_exact(&self);
}
}

44
src/net/state.rs Normal file
View File

@ -0,0 +1,44 @@
use crate::net::serialize::{PacketDeserializer, PacketSerializer};
pub trait ProtocolState: Sized {
/// Get a packet's id.
fn id(&self) -> i32;
/// Read a packet from the deserializer.
fn read(id: i32, deser: &mut impl PacketDeserializer) -> Result<Self, String>;
/// Write this packet's data to the serializer.
fn write(&self, ser: &mut impl PacketSerializer);
}
#[macro_export]
macro_rules! define_states {
{ $( state $name:ident { $( $id:expr => $packet:ident ),* } )+ } => {
$(
pub enum $name {
$( $packet($packet) ),*
}
impl crate::net::state::ProtocolState for $name {
fn id(&self) -> i32 {
match *self {
$( $name::$packet(_) => $id ),*
}
}
#[allow(unused_variables)]
fn read(id: i32, deser: &mut impl crate::net::serialize::PacketDeserializer) -> Result<Self, String> {
match id {
$( $id => deser.read::<$packet>().map($name::$packet), )*
id => Err(format!("Invalid packet id: {}", id))
}
}
#[allow(unused_variables)]
fn write(&self, ser: &mut impl crate::net::serialize::PacketSerializer) {
match *self {
$( $name::$packet(ref pkt) => ser.write(pkt) ),*
}
}
}
)*
}
}