From c2742fbcf0d7c842db2d620f318f588b00428960 Mon Sep 17 00:00:00 2001 From: CosminPerRam Date: Sun, 16 Oct 2022 16:14:10 +0300 Subject: [PATCH] More readable code --- src/protocols/valve.rs | 98 ++++++++++++++++++++++-------------------- src/utils.rs | 30 ++++++++++++- 2 files changed, 79 insertions(+), 49 deletions(-) diff --git a/src/protocols/valve.rs b/src/protocols/valve.rs index 0d684eb..028f2d9 100644 --- a/src/protocols/valve.rs +++ b/src/protocols/valve.rs @@ -1,6 +1,6 @@ use std::net::UdpSocket; use crate::errors::GDError; -use crate::utils::{combine_two_u8, complete_address, concat_u8, find_null_in_array, get_u64_from_buf}; +use crate::utils::{combine_two_u8, complete_address, concat_u8, find_first_string, get_u64_from_buf}; #[derive(Debug)] pub enum Server { @@ -108,55 +108,62 @@ impl ValveProtocol { client.do_request(Request::A2sInfo(None), None); let mut buf = client.receive(DEFAULT_PACKET_SIZE); + let mut pos = 5; if buf[4] == 0x41 { - client.do_request(Request::A2sInfo(Some([buf[5], buf[6], buf[7], buf[8]])), None); + client.do_request(Request::A2sInfo(Some([buf[pos], buf[pos + 1], buf[pos + 2], buf[pos + 3]])), None); buf = client.receive(DEFAULT_PACKET_SIZE); } - println!("{:x?}", &buf); + let protocol = buf[5]; pos = pos + 1; - let name_null_pos = find_null_in_array(&mut buf); - let map_null_pos = name_null_pos + 1 + find_null_in_array(&mut buf[name_null_pos + 1..]); - let folder_null_pos = map_null_pos + 1 + find_null_in_array(&mut buf[map_null_pos + 1..]); - let game_null_pos = folder_null_pos + 1 + find_null_in_array(&mut buf[folder_null_pos + 1..]); + let name = find_first_string(&buf[pos..]); pos = pos + name.len() + 1; + let map = find_first_string(&buf[pos..]); pos = pos + map.len() + 1; + let folder = find_first_string(&buf[pos..]); pos = pos + folder.len() + 1; + let game = find_first_string(&buf[pos..]); pos = pos + game.len() + 1; - let server_type = match buf[game_null_pos + 6] as char { + let id = combine_two_u8(buf[pos + 1], buf[pos]); pos = pos + 2; + let players = buf[pos]; pos = pos + 1; + let max_players = buf[pos]; pos = pos + 1; + let bots = buf[pos]; pos = pos + 1; + + let server_type = match buf[pos] as char { 'd' => Server::Dedicated, 'l' => Server::NonDedicated, _ => Server::SourceTV - }; + }; pos = pos + 1; - let environment_type = match buf[game_null_pos + 7] as char { + let environment_type = match buf[pos] as char { 'l' => Environment::Linux, 'w' => Environment::Windows, _ => Environment::Mac - }; + }; pos = pos + 1; + + let has_password = buf[pos] == 1; pos = pos + 1; + let vac_secured = buf[pos] == 1; pos = pos + 1; - let mut the_ship_index = game_null_pos + 10; let the_ship = match has_the_ship { false => None, true => { let ship = TheShip { - mode: buf[the_ship_index], - witnesses: buf[the_ship_index + 1], - duration: buf[the_ship_index + 2] - }; - the_ship_index = the_ship_index + 3; + mode: buf[pos], + witnesses: buf[pos + 1], + duration: buf[pos + 2] + }; pos = pos + 3; Some(ship) } }; - let version_null_pos = the_ship_index + find_null_in_array(&mut buf[the_ship_index..]); - let extra_data = match buf.get(version_null_pos + 1) { + let version = find_first_string(&buf[pos..]); pos = pos + version.len() + 1; + + pos = pos + 1; //look ahead + let extra_data = match buf.get(pos - 1) { None => None, Some(value) => { - let mut last_edf_position = version_null_pos + 2; let edf_port = match (value & 0x80) > 0 { false => None, true => { - let p = combine_two_u8(buf[last_edf_position + 1], buf[last_edf_position]); - last_edf_position = last_edf_position + 2; + let p = combine_two_u8(buf[pos + 1], buf[pos]); pos = pos + 2; Some(p) } }; @@ -164,8 +171,7 @@ impl ValveProtocol { let steam_id = match (value & 0x10) > 0 { false => None, true => { - let p = get_u64_from_buf(&buf[last_edf_position..]); - last_edf_position = last_edf_position + 8; + let p = get_u64_from_buf(&buf[pos..]); pos = pos + 8; Some(p) } }; @@ -173,28 +179,26 @@ impl ValveProtocol { let (tv_port, tv_name) = match (value & 0x40) > 0 { false => (None, None), true => { - let port = combine_two_u8(buf[last_edf_position + 1], buf[last_edf_position]); - last_edf_position = last_edf_position + 2; - let tv_name_null_pos = last_edf_position + find_null_in_array(&buf[last_edf_position..]); - let tv_name = String::from_utf8(Vec::from(&buf[last_edf_position..tv_name_null_pos])).expect("cacat"); - last_edf_position = tv_name_null_pos + 1; - (Some(port), Some(tv_name)) + let tv_port = combine_two_u8(buf[pos + 1], buf[pos]); pos = pos + 2; + let tv_name = find_first_string(&buf[pos..]); pos = pos + tv_name.len() + 1; + (Some(tv_port), Some(tv_name)) } }; let keywords = match (value & 0x20) > 0 { false => None, true => { - let kws_null_pos = last_edf_position + find_null_in_array(&buf[last_edf_position..]); - let kws = String::from_utf8(Vec::from(&buf[last_edf_position..kws_null_pos])).expect("cacat"); - last_edf_position = kws_null_pos + 1; - Some(kws) + let keywords = find_first_string(&buf[pos..]); pos = pos + keywords.len() + 1; + Some(keywords) } }; let game_id = match (value & 0x01) > 0 { false => None, - true => Some(get_u64_from_buf(&buf[last_edf_position..])) + true => { + let game_id = get_u64_from_buf(&buf[pos..]); pos = pos + 8; + Some(game_id) + } }; Some(ExtraData { @@ -209,21 +213,21 @@ impl ValveProtocol { }; Ok(Response { - protocol: buf[5], - name: String::from_utf8(Vec::from(&mut buf[6..name_null_pos])).expect("cacat"), - map: String::from_utf8(Vec::from(&mut buf[name_null_pos + 1..map_null_pos])).expect("cacat"), - folder: String::from_utf8(Vec::from(&mut buf[map_null_pos + 1..folder_null_pos])).expect("cacat"), - game: String::from_utf8(Vec::from(&mut buf[folder_null_pos + 1..game_null_pos])).expect("cacat"), - id: combine_two_u8(buf[game_null_pos + 2], buf[game_null_pos + 1]), - players: buf[game_null_pos + 3], - max_players: buf[game_null_pos + 4], - bots: buf[game_null_pos + 5], + protocol, + name, + map, + folder, + game, + id, + players, + max_players, + bots, server_type, environment_type, - has_password: buf[game_null_pos + 8] == 1, - vac_secured: buf[game_null_pos + 9] != 0, + has_password, + vac_secured, the_ship, - version: String::from_utf8(Vec::from(&mut buf[the_ship_index..version_null_pos])).expect("cacat"), + version, extra_data }) } diff --git a/src/utils.rs b/src/utils.rs index 496a23d..ca4a0d6 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -4,13 +4,17 @@ pub fn concat_u8(first: &[u8], second: &[u8]) -> Vec { [first, second].concat() } -pub fn find_null_in_array(arr: &[u8]) -> usize { +pub fn find_first_null(arr: &[u8]) -> usize { match arr.iter().position(|&x| x == 0) { None => arr.len(), Some(position) => position } } +pub fn find_first_string(arr: &[u8]) -> String { + arr.iter().take_while(|&&b| b != 0).map(|&e| e as char).collect::() +} + pub fn complete_address(address: &str, port: u16) -> String { String::from(address.to_owned() + ":").add(&*port.to_string()) } @@ -23,6 +27,28 @@ pub fn combine_eight_u8(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8, g: u8, h: u8) u64::from_be_bytes([a, b, c, d, e, f, g, h]) } +pub mod buffer { + use super::*; + + pub fn get_u8(buf: &[u8], pos: usize) -> (u8, usize) { + (buf[pos], pos + 1) + } + + pub fn get_u16(buf: &[u8], pos: usize) -> (u16, usize) { + (combine_two_u8(buf[pos + 1], buf[pos]), pos + 2) + } + + pub fn get_u64(buf: &[u8], pos: usize) -> (u64, usize) { + (combine_eight_u8(buf[pos + 7], buf[pos + 6], buf[pos + 5], buf[pos + 4], buf[pos + 3], buf[pos + 2], buf[pos + 1], buf[pos]), pos + 8) + } + + pub fn get_string(buf: &[u8], pos: usize) -> (String, usize) { + let string = find_first_string(&buf[pos..]); + let string_size = string.len(); + (string, pos + string_size + 1) + } +} + pub fn get_u64_from_buf(buf: &[u8]) -> u64 { combine_eight_u8(buf[7], buf[6], buf[5], buf[4], buf[3], buf[2], buf[1], buf[0]) } @@ -45,7 +71,7 @@ mod utils { #[test] fn find_null_in_array_test() { let arr: [u8; 4] = [0x64, 0x32, 0x00, 0x20]; - assert_eq!(2, find_null_in_array(&arr)); + assert_eq!(2, find_first_null(&arr)); } #[test]