gamedig / rust-gamedig

Game Server Query Library.
https://crates.io/crates/gamedig
MIT License
39 stars 12 forks source link

Bi-directional packet parsing #104

Open Douile opened 1 year ago

Douile commented 1 year ago

I'm not sure this fits the goals for the project but I will put it here for comments.

What is this feature about? Long term I think it would be nice to both serialize and de-serialize packets. As it currently stands we serialize requests in plain functions with no input data (in most cases), and de-serialize responses to a struct but in a standalone function. I imagine a nice abstraction would be like the serde Serialize, and Deserialize traits where both requests and responses can be created from Vec<u8> and serialized into Vec<u8>.

Use cases This would enable people to use the library to create pseudo-game servers (I'm not suggesting we implement any of the server logic here). But this could be useful for testing: we could implement a pseudo-server and query ourselves using node-gamedig and rust-gamedig and compare outputs.

Douile commented 10 months ago

I was implementing wireshark dissectors for game queries and I found this library: wsdf

It has a proc macro that allows parsing raw binary data:

#[derive(PacketField)]
struct ValveQuery {
  header: [u8; 4],
  kind: u8,
  challenge: Vec<u8>,
}

It then uses field annotations for more advanced decoding:

A decode function parses the data-type you specified into a different data type

#[wsdf(decode_with = "name_of_decode_function")]
kind: u8,

A consume function can consume an arbitrary amount of bytes from the buffer.

#[wsdf(consume_with = "consume_function")]
challenge: Vec<u8>,

There's also a neat attribute that allows you to chose the variant of an enum based on part of the previously parsed packet.

#[wsdf(dispatch_with = "kind")]
payload: PayloadEnum,

I think a similar design could definitely be used for gamedig, and it could make writing new protocols simpler.

It would definitely be a lot of work though especially with us needing to encode as well as decode types. And I'm not sure if there would be a performance detriment that makes this not worth it.

CosminPerRam commented 10 months ago

Woah, that indeed looks great. But sometimes when we decode a packet there are other conditional steps (e.g. additional data, stuff that needs to be mutated, decoding in another order etc) so I don't think we could apply something like this for all of our use cases (some yes but not all) but for sure it's something that might be worth to look into.