From 348f101ce80ce75ff7c2f3bf9b2ca4577a0f8c80 Mon Sep 17 00:00:00 2001 From: lcdr Date: Sat, 20 Jun 2020 12:41:11 +0200 Subject: [PATCH] Generalize derive macro for arbitrary padding --- lu_packets_derive/src/lib.rs | 27 ++++++- lu_packets_derive/src/service_message_d.rs | 18 +++-- lu_packets_derive/src/service_message_s.rs | 18 +++-- src/auth/client.rs | 2 +- src/auth/server.rs | 1 + src/chat/server.rs | 84 +++++----------------- src/general/client.rs | 2 +- src/general/server.rs | 1 + src/world/client/mod.rs | 1 + src/world/server/mod.rs | 1 + 10 files changed, 77 insertions(+), 78 deletions(-) diff --git a/lu_packets_derive/src/lib.rs b/lu_packets_derive/src/lib.rs index 35538b6..f164c5a 100644 --- a/lu_packets_derive/src/lib.rs +++ b/lu_packets_derive/src/lib.rs @@ -5,6 +5,7 @@ mod service_message_d; mod service_message_s; use proc_macro::TokenStream; +use syn::{DeriveInput, Lit, LitInt, Meta}; #[proc_macro_derive(FromVariants)] pub fn derive_from_variants(input: TokenStream) -> TokenStream { @@ -21,12 +22,34 @@ pub fn derive_gm_type(input: TokenStream) -> TokenStream { gm_type::derive(input) } -#[proc_macro_derive(ServiceMessageD)] +#[proc_macro_derive(ServiceMessageD, attributes(disc_padding))] pub fn derive_service_message_d(input: TokenStream) -> TokenStream { service_message_d::derive(input) } -#[proc_macro_derive(ServiceMessageS)] +#[proc_macro_derive(ServiceMessageS, attributes(disc_padding))] pub fn derive_service_message_s(input: TokenStream) -> TokenStream { service_message_s::derive(input) } + +fn get_disc_padding(input: &DeriveInput) -> Option { + for attr in &input.attrs { + if !attr.path.is_ident("disc_padding") { + continue; + } + let meta = match attr.parse_meta() { + Err(_) => panic!("encountered unparseable disc_padding attribute"), + Ok(x) => x, + }; + let lit = match meta { + Meta::NameValue(x) => x.lit, + _ => panic!("disc_padding needs to be name=value"), + }; + let int_lit = match lit { + Lit::Int(x) => x, + _ => panic!("disc_padding needs to be an integer"), + }; + return Some(int_lit); + } + None +} diff --git a/lu_packets_derive/src/service_message_d.rs b/lu_packets_derive/src/service_message_d.rs index 32c602e..ad97f2b 100644 --- a/lu_packets_derive/src/service_message_d.rs +++ b/lu_packets_derive/src/service_message_d.rs @@ -1,6 +1,8 @@ use proc_macro2::{Ident, TokenStream}; use quote::quote; -use syn::{parse_macro_input, parse_quote, Data, DataEnum, DeriveInput, Fields}; +use syn::{parse_macro_input, parse_quote, Data, DataEnum, DeriveInput, Fields, LitInt}; + +use crate::get_disc_padding; pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = parse_macro_input!(input as DeriveInput); @@ -10,7 +12,8 @@ pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { }; let name = &input.ident; - let deser_code = gen_deser_code_enum(data, &name); + let disc_padding = get_disc_padding(&input); + let deser_code = gen_deser_code_enum(data, &name, disc_padding); let deser_impl = &mut input.generics.clone(); deser_impl.params.push(parse_quote!(__READER: ::std::io::Read)); let (deser_impl, _, _) = deser_impl.split_for_impl(); @@ -42,7 +45,7 @@ fn gen_deser_code_fields(fields: &Fields) -> TokenStream { } } -fn gen_deser_code_enum(data: &DataEnum, name: &Ident) -> TokenStream { +fn gen_deser_code_enum(data: &DataEnum, name: &Ident, padding: Option) -> TokenStream { let last_disc: syn::ExprLit = parse_quote! { 0 }; let mut last_disc = &last_disc.into(); let mut disc_offset = 0; @@ -58,9 +61,16 @@ fn gen_deser_code_enum(data: &DataEnum, name: &Ident) -> TokenStream { disc_offset += 1; arms.push(arm); } + let read_padding = match padding { + Some(x) => quote! { + let mut padding = [0; #x]; + ::std::io::Read::read_exact(reader, &mut padding)?; + }, + None => quote! { }, + }; quote! { let disc: u32 = ::endio::LERead::read(reader)?; - let _padding: u8 = ::endio::LERead::read(reader)?; + #read_padding Ok(match disc { #(#arms)* _ => return ::std::result::Result::Err(::std::io::Error::new(::std::io::ErrorKind::InvalidData, format!("invalid discriminant value for {}: {}", stringify!(#name), disc))) diff --git a/lu_packets_derive/src/service_message_s.rs b/lu_packets_derive/src/service_message_s.rs index 0ebe27b..f1046b5 100644 --- a/lu_packets_derive/src/service_message_s.rs +++ b/lu_packets_derive/src/service_message_s.rs @@ -1,6 +1,8 @@ use proc_macro2::{Ident, Span, TokenStream}; use quote::quote; -use syn::{parse_macro_input, parse_quote, Data, DataEnum, DeriveInput, Fields, Generics}; +use syn::{parse_macro_input, parse_quote, Data, DataEnum, DeriveInput, Fields, LitInt, Generics}; + +use crate::get_disc_padding; pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = parse_macro_input!(input as DeriveInput); @@ -10,7 +12,8 @@ pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { }; let name = &input.ident; - let ser_code = gen_ser_code_enum(data, &name, &input.generics); + let disc_padding = get_disc_padding(&input); + let ser_code = gen_ser_code_enum(data, &name, disc_padding, &input.generics); let ser_impl = &mut input.generics.clone(); ser_impl.params.push(parse_quote!('__LIFETIME)); ser_impl.params.push(parse_quote!(__WRITER: ::std::io::Write)); @@ -48,7 +51,7 @@ fn gen_ser_code_fields(fields: &Fields) -> TokenStream { } } -fn gen_ser_code_enum(data: &DataEnum, name: &Ident, generics: &Generics) -> TokenStream { +fn gen_ser_code_enum(data: &DataEnum, name: &Ident, padding: Option, generics: &Generics) -> TokenStream { let mut arms = vec![]; for f in &data.variants { let ident = &f.ident; @@ -56,10 +59,17 @@ fn gen_ser_code_enum(data: &DataEnum, name: &Ident, generics: &Generics) -> Toke let expanded = quote! { #name::#ident #ser_fields }; arms.push(expanded); } + let write_padding = match padding { + Some(x) => quote! { + let mut padding = [0; #x]; + ::std::io::Write::write_all(writer, &padding)?; + }, + None => quote! { }, + }; quote! { let disc = unsafe { *(self as *const #name #generics as *const u32) }; ::endio::LEWrite::write(writer, disc)?; - ::endio::LEWrite::write(writer, 0u8)?; + #write_padding match self { #(#arms)* } diff --git a/src/auth/client.rs b/src/auth/client.rs index db04a74..63a544c 100644 --- a/src/auth/client.rs +++ b/src/auth/client.rs @@ -16,7 +16,7 @@ impl From for Message { } #[derive(Debug, FromVariants, ServiceMessageS)] -#[non_exhaustive] +#[disc_padding=1] #[repr(u32)] pub enum ClientMessage { LoginResponse(LoginResponse), diff --git a/src/auth/server.rs b/src/auth/server.rs index 75dd640..4674d39 100644 --- a/src/auth/server.rs +++ b/src/auth/server.rs @@ -16,6 +16,7 @@ pub enum LuMessage { } #[derive(Debug, ServiceMessageD)] +#[disc_padding=1] #[repr(u32)] pub enum AuthMessage { LoginRequest(LoginRequest) diff --git a/src/chat/server.rs b/src/chat/server.rs index 7f39786..2be52d5 100644 --- a/src/chat/server.rs +++ b/src/chat/server.rs @@ -3,77 +3,24 @@ use std::io::Result as Res; use endio::{Deserialize, LERead}; use endio::LittleEndian as LE; +use lu_packets_derive::ServiceMessageD; -use crate::common::{err, LuWStr33, ObjId}; +use crate::common::{LuWStr33, ObjId}; -enum ChatId { - GeneralChatMessage = 1, - PrivateChatMessage = 2, - AddFriendResponse = 8, +#[derive(Debug, ServiceMessageD)] +#[disc_padding=9] +#[repr(u32)] +pub enum ChatMessage { + GeneralChatMessage(GeneralChatMessage) = 1, + PrivateChatMessage(PrivateChatMessage) = 2, + AddFriendResponse(AddFriendResponse) = 8, GetFriendsList = 10, GetIgnoreList = 13, - TeamInviteResponse = 16, - TeamLeave = 18, + TeamInviteResponse(TeamInviteResponse) = 16, + TeamLeave(TeamLeave) = 18, TeamGetStatus = 21, - RequestMinimumChatMode = 50, - RequestMinimumChatModePrivate = 51, -} - -#[derive(Debug)] -pub enum ChatMessage { - GeneralChatMessage(GeneralChatMessage), - PrivateChatMessage(PrivateChatMessage), - AddFriendResponse(AddFriendResponse), - GetFriendsList, - GetIgnoreList, - TeamInviteResponse(TeamInviteResponse), - TeamLeave, - TeamGetStatus, - RequestMinimumChatMode(RequestMinimumChatMode), - RequestMinimumChatModePrivate(RequestMinimumChatModePrivate), -} - -impl Deserialize for ChatMessage - where u8: Deserialize, - u32: Deserialize, - u64: Deserialize, - GeneralChatMessage: Deserialize, - PrivateChatMessage: Deserialize, - AddFriendResponse: Deserialize, - TeamInviteResponse: Deserialize, - RequestMinimumChatMode: Deserialize, - RequestMinimumChatModePrivate: Deserialize { - fn deserialize(reader: &mut R) -> Res { - let packet_id: u32 = LERead::read(reader)?; - let _padding: u8 = LERead::read(reader)?; - let routed_obj_id: u64 = LERead::read(reader)?; - assert_eq!(routed_obj_id, 0); - Ok(if packet_id == ChatId::GeneralChatMessage as u32 { - Self::GeneralChatMessage(LERead::read(reader)?) - } else if packet_id == ChatId::PrivateChatMessage as u32 { - Self::PrivateChatMessage(LERead::read(reader)?) - } else if packet_id == ChatId::AddFriendResponse as u32 { - Self::AddFriendResponse(LERead::read(reader)?) - } else if packet_id == ChatId::GetFriendsList as u32 { - Self::GetFriendsList - } else if packet_id == ChatId::GetIgnoreList as u32 { - Self::GetIgnoreList - } else if packet_id == ChatId::TeamGetStatus as u32 { - Self::TeamGetStatus - } else if packet_id == ChatId::TeamInviteResponse as u32 { - Self::TeamInviteResponse(LERead::read(reader)?) - } else if packet_id == ChatId::TeamLeave as u32 { - let mut unused = [0; 66]; - Read::read(reader, &mut unused)?; - Self::TeamLeave - } else if packet_id == ChatId::RequestMinimumChatMode as u32 { - Self::RequestMinimumChatMode(LERead::read(reader)?) - } else if packet_id == ChatId::RequestMinimumChatModePrivate as u32 { - Self::RequestMinimumChatModePrivate(LERead::read(reader)?) - } else { - return err("chat id", packet_id); - }) - } + RequestMinimumChatMode(RequestMinimumChatMode) = 50, + RequestMinimumChatModePrivate(RequestMinimumChatModePrivate) = 51, } #[derive(Debug)] @@ -189,6 +136,11 @@ pub struct TeamInviteResponse { pub sender: ObjId, } +#[derive(Debug, Deserialize)] +pub struct TeamLeave { + pub unused: LuWStr33, +} + #[derive(Debug, Deserialize)] pub struct RequestMinimumChatMode { pub chat_channel: u8, // todo: separate type? diff --git a/src/general/client.rs b/src/general/client.rs index 478b7fc..dc29767 100644 --- a/src/general/client.rs +++ b/src/general/client.rs @@ -28,7 +28,7 @@ impl From for Message { } #[derive(Debug, ServiceMessageS)] -#[non_exhaustive] +#[disc_padding=1] #[repr(u32)] pub enum GeneralMessage { Handshake(Handshake), diff --git a/src/general/server.rs b/src/general/server.rs index 2f36688..492580c 100644 --- a/src/general/server.rs +++ b/src/general/server.rs @@ -7,6 +7,7 @@ use lu_packets_derive::ServiceMessageD; use crate::common::ServiceId; #[derive(Debug, ServiceMessageD)] +#[disc_padding=1] #[repr(u32)] pub enum GeneralMessage { Handshake(Handshake) diff --git a/src/world/client/mod.rs b/src/world/client/mod.rs index 27b27f1..e9886c3 100644 --- a/src/world/client/mod.rs +++ b/src/world/client/mod.rs @@ -18,6 +18,7 @@ impl From for Message { #[derive(Debug, FromVariants, ServiceMessageS)] #[non_exhaustive] +#[disc_padding=1] #[repr(u32)] pub enum ClientMessage { CharacterListResponse(CharacterListResponse) = 6, diff --git a/src/world/server/mod.rs b/src/world/server/mod.rs index f974999..8f5c266 100644 --- a/src/world/server/mod.rs +++ b/src/world/server/mod.rs @@ -26,6 +26,7 @@ pub enum LuMessage { } #[derive(Debug, ServiceMessageD)] +#[disc_padding=1] #[repr(u32)] pub enum WorldMessage { ClientValidation(ClientValidation) = 1,