Add login server bound packets
This commit is contained in:
parent
acc098bc4e
commit
3d6dd8ed87
84
src/lib.rs
84
src/lib.rs
@ -1,6 +1,7 @@
|
|||||||
//! This crate implements Minecraft protocol.
|
//! This crate implements Minecraft protocol.
|
||||||
//!
|
//!
|
||||||
//! Information about protocol can be found at https://wiki.vg/Protocol.
|
//! Information about protocol can be found at https://wiki.vg/Protocol.
|
||||||
|
use byteorder::{ReadBytesExt, WriteBytesExt};
|
||||||
use io::Error as IoError;
|
use io::Error as IoError;
|
||||||
use mc_varint::{VarIntRead, VarIntWrite};
|
use mc_varint::{VarIntRead, VarIntWrite};
|
||||||
use serde_json::error::Error as JsonError;
|
use serde_json::error::Error as JsonError;
|
||||||
@ -9,17 +10,23 @@ use std::io::{Read, Write};
|
|||||||
use std::string::FromUtf8Error;
|
use std::string::FromUtf8Error;
|
||||||
|
|
||||||
pub mod chat;
|
pub mod chat;
|
||||||
|
pub mod login;
|
||||||
pub mod status;
|
pub mod status;
|
||||||
|
|
||||||
/// Current supported protocol version.
|
/// Current supported protocol version.
|
||||||
pub const PROTOCOL_VERSION: usize = 498;
|
pub const PROTOCOL_VERSION: usize = 498;
|
||||||
/// String maximum length.
|
/// String maximum length.
|
||||||
const MAX_STRING_LENGTH: usize = 32_768;
|
const STRING_MAX_LENGTH: u32 = 32_768;
|
||||||
|
|
||||||
/// Possible errors while encoding packet.
|
/// Possible errors while encoding packet.
|
||||||
pub enum EncodeError {
|
pub enum EncodeError {
|
||||||
/// String length can't be more than `MAX_STRING_LENGTH` value.
|
/// String length can't be more than provided value.
|
||||||
StringTooLong,
|
StringTooLong {
|
||||||
|
/// String length.
|
||||||
|
length: usize,
|
||||||
|
/// Max string length.
|
||||||
|
max_length: u32,
|
||||||
|
},
|
||||||
IOError {
|
IOError {
|
||||||
io_error: IoError,
|
io_error: IoError,
|
||||||
},
|
},
|
||||||
@ -46,8 +53,13 @@ pub enum DecodeError {
|
|||||||
UnknownPacketType {
|
UnknownPacketType {
|
||||||
type_id: u8,
|
type_id: u8,
|
||||||
},
|
},
|
||||||
/// String length can't be more than `MAX_STRING_LENGTH` value.
|
/// String length can't be more than provided value.
|
||||||
StringTooLong,
|
StringTooLong {
|
||||||
|
/// String length.
|
||||||
|
length: u32,
|
||||||
|
/// Max string length.
|
||||||
|
max_length: u32,
|
||||||
|
},
|
||||||
IOError {
|
IOError {
|
||||||
io_error: IoError,
|
io_error: IoError,
|
||||||
},
|
},
|
||||||
@ -58,6 +70,8 @@ pub enum DecodeError {
|
|||||||
Utf8Error {
|
Utf8Error {
|
||||||
utf8_error: FromUtf8Error,
|
utf8_error: FromUtf8Error,
|
||||||
},
|
},
|
||||||
|
/// Boolean are parsed from byte. Valid byte value are 0 or 1.
|
||||||
|
NonBoolValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<IoError> for DecodeError {
|
impl From<IoError> for DecodeError {
|
||||||
@ -88,20 +102,36 @@ trait Packet {
|
|||||||
|
|
||||||
/// Trait adds additional helper methods for `Read` to read protocol data.
|
/// Trait adds additional helper methods for `Read` to read protocol data.
|
||||||
trait PacketRead {
|
trait PacketRead {
|
||||||
fn read_string(&mut self) -> Result<String, DecodeError>;
|
fn read_bool(&mut self) -> Result<bool, DecodeError>;
|
||||||
|
|
||||||
|
fn read_string(&mut self, max_length: u32) -> Result<String, DecodeError>;
|
||||||
|
|
||||||
|
fn read_byte_array(&mut self) -> Result<Vec<u8>, DecodeError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait adds additional helper methods for `Write` to write protocol data.
|
/// Trait adds additional helper methods for `Write` to write protocol data.
|
||||||
trait PacketWrite {
|
trait PacketWrite {
|
||||||
fn write_string(&mut self, value: &str) -> Result<(), EncodeError>;
|
fn write_bool(&mut self, value: bool) -> Result<(), EncodeError>;
|
||||||
|
|
||||||
|
fn write_string(&mut self, value: &str, max_length: u32) -> Result<(), EncodeError>;
|
||||||
|
|
||||||
|
fn write_byte_array(&mut self, value: &[u8]) -> Result<(), EncodeError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Read> PacketRead for R {
|
impl<R: Read> PacketRead for R {
|
||||||
fn read_string(&mut self) -> Result<String, DecodeError> {
|
fn read_bool(&mut self) -> Result<bool, DecodeError> {
|
||||||
|
match self.read_u8()? {
|
||||||
|
0 => Ok(false),
|
||||||
|
1 => Ok(true),
|
||||||
|
_ => Err(DecodeError::NonBoolValue),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_string(&mut self, max_length: u32) -> Result<String, DecodeError> {
|
||||||
let length = self.read_var_u32()?;
|
let length = self.read_var_u32()?;
|
||||||
|
|
||||||
if length > MAX_STRING_LENGTH as u32 {
|
if length > max_length as u32 {
|
||||||
return Err(DecodeError::StringTooLong);
|
return Err(DecodeError::StringTooLong { length, max_length });
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut buf = vec![0; length as usize];
|
let mut buf = vec![0; length as usize];
|
||||||
@ -109,12 +139,33 @@ impl<R: Read> PacketRead for R {
|
|||||||
|
|
||||||
Ok(String::from_utf8(buf)?)
|
Ok(String::from_utf8(buf)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_byte_array(&mut self) -> Result<Vec<u8>, DecodeError> {
|
||||||
|
let length = self.read_var_u32()?;
|
||||||
|
|
||||||
|
let mut buf = vec![0; length as usize];
|
||||||
|
self.read_exact(&mut buf)?;
|
||||||
|
|
||||||
|
Ok(buf)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: Write> PacketWrite for W {
|
impl<W: Write> PacketWrite for W {
|
||||||
fn write_string(&mut self, value: &str) -> Result<(), EncodeError> {
|
fn write_bool(&mut self, value: bool) -> Result<(), EncodeError> {
|
||||||
if value.len() > MAX_STRING_LENGTH {
|
if value {
|
||||||
return Err(EncodeError::StringTooLong);
|
self.write_u8(1)?;
|
||||||
|
} else {
|
||||||
|
self.write_u8(0)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_string(&mut self, value: &str, max_length: u32) -> Result<(), EncodeError> {
|
||||||
|
let length = value.len();
|
||||||
|
|
||||||
|
if length > max_length as usize {
|
||||||
|
return Err(EncodeError::StringTooLong { length, max_length });
|
||||||
}
|
}
|
||||||
|
|
||||||
self.write_var_u32(value.len() as u32)?;
|
self.write_var_u32(value.len() as u32)?;
|
||||||
@ -122,4 +173,11 @@ impl<W: Write> PacketWrite for W {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_byte_array(&mut self, value: &[u8]) -> Result<(), EncodeError> {
|
||||||
|
self.write_var_u32(value.len() as u32)?;
|
||||||
|
self.write_all(value)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
162
src/login.rs
Normal file
162
src/login.rs
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
use crate::{DecodeError, EncodeError, Packet, PacketRead, PacketWrite};
|
||||||
|
use mc_varint::{VarIntRead, VarIntWrite};
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
|
/// Login maximum length.
|
||||||
|
const LOGIN_MAX_LENGTH: u32 = 16;
|
||||||
|
|
||||||
|
pub enum LoginServerBoundPacket {
|
||||||
|
LoginStart(LoginStart),
|
||||||
|
EncryptionResponse(EncryptionResponse),
|
||||||
|
LoginPluginResponse(LoginPluginResponse),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum LoginClientBoundPacket {
|
||||||
|
Disconnect,
|
||||||
|
EncryptionRequest,
|
||||||
|
LoginSuccess,
|
||||||
|
SetCompression,
|
||||||
|
LoginPluginRequest,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LoginServerBoundPacket {
|
||||||
|
pub fn get_type_id(&self) -> u8 {
|
||||||
|
match self {
|
||||||
|
LoginServerBoundPacket::LoginStart(_) => 0x00,
|
||||||
|
LoginServerBoundPacket::EncryptionResponse(_) => 0x01,
|
||||||
|
LoginServerBoundPacket::LoginPluginResponse(_) => 0x02,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode<R: Read>(type_id: u8, reader: &mut R) -> Result<Self, DecodeError> {
|
||||||
|
match type_id {
|
||||||
|
0x00 => {
|
||||||
|
let login_start = LoginStart::decode(reader)?;
|
||||||
|
|
||||||
|
Ok(LoginServerBoundPacket::LoginStart(login_start))
|
||||||
|
}
|
||||||
|
0x01 => {
|
||||||
|
let encryption_response = EncryptionResponse::decode(reader)?;
|
||||||
|
|
||||||
|
Ok(LoginServerBoundPacket::EncryptionResponse(
|
||||||
|
encryption_response,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
0x02 => {
|
||||||
|
let login_plugin_response = LoginPluginResponse::decode(reader)?;
|
||||||
|
|
||||||
|
Ok(LoginServerBoundPacket::LoginPluginResponse(
|
||||||
|
login_plugin_response,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
_ => Err(DecodeError::UnknownPacketType { type_id }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LoginStart {
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LoginStart {
|
||||||
|
pub fn new(name: String) -> LoginServerBoundPacket {
|
||||||
|
let login_start = LoginStart { name };
|
||||||
|
|
||||||
|
LoginServerBoundPacket::LoginStart(login_start)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Packet for LoginStart {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
|
||||||
|
writer.write_string(&self.name, LOGIN_MAX_LENGTH)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
|
||||||
|
let name = reader.read_string(LOGIN_MAX_LENGTH)?;
|
||||||
|
|
||||||
|
Ok(LoginStart { name })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EncryptionResponse {
|
||||||
|
pub shared_secret: Vec<u8>,
|
||||||
|
pub verify_token: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EncryptionResponse {
|
||||||
|
pub fn new(shared_secret: Vec<u8>, verify_token: Vec<u8>) -> LoginServerBoundPacket {
|
||||||
|
let encryption_response = EncryptionResponse {
|
||||||
|
shared_secret,
|
||||||
|
verify_token,
|
||||||
|
};
|
||||||
|
|
||||||
|
LoginServerBoundPacket::EncryptionResponse(encryption_response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Packet for EncryptionResponse {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
|
||||||
|
writer.write_byte_array(&self.shared_secret)?;
|
||||||
|
writer.write_byte_array(&self.verify_token)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
|
||||||
|
let shared_secret = reader.read_byte_array()?;
|
||||||
|
let verify_token = reader.read_byte_array()?;
|
||||||
|
|
||||||
|
Ok(EncryptionResponse {
|
||||||
|
shared_secret,
|
||||||
|
verify_token,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LoginPluginResponse {
|
||||||
|
pub message_id: i32,
|
||||||
|
pub successful: bool,
|
||||||
|
pub data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LoginPluginResponse {
|
||||||
|
pub fn new(message_id: i32, successful: bool, data: Vec<u8>) -> LoginServerBoundPacket {
|
||||||
|
let login_plugin_response = LoginPluginResponse {
|
||||||
|
message_id,
|
||||||
|
successful,
|
||||||
|
data,
|
||||||
|
};
|
||||||
|
|
||||||
|
LoginServerBoundPacket::LoginPluginResponse(login_plugin_response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Packet for LoginPluginResponse {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
|
||||||
|
writer.write_var_i32(self.message_id)?;
|
||||||
|
writer.write_bool(self.successful)?;
|
||||||
|
writer.write_all(&self.data)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
|
||||||
|
let message_id = reader.read_var_i32()?;
|
||||||
|
let successful = reader.read_bool()?;
|
||||||
|
|
||||||
|
let mut data = Vec::new();
|
||||||
|
reader.read_to_end(data.as_mut())?;
|
||||||
|
|
||||||
|
Ok(LoginPluginResponse {
|
||||||
|
message_id,
|
||||||
|
successful,
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
use crate::{DecodeError, EncodeError, Packet, PacketWrite};
|
use crate::{DecodeError, EncodeError, Packet, PacketWrite, STRING_MAX_LENGTH};
|
||||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
@ -143,7 +143,7 @@ impl Packet for StatusResponse {
|
|||||||
|
|
||||||
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
|
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
|
||||||
let json = serde_json::to_string(&self.server_status)?;
|
let json = serde_json::to_string(&self.server_status)?;
|
||||||
writer.write_string(&json)?;
|
writer.write_string(&json, STRING_MAX_LENGTH)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user