From 3a83588802224c2495db04d81dd0e20cb9c07d5c Mon Sep 17 00:00:00 2001 From: CosminPerRam Date: Sun, 16 Oct 2022 17:55:48 +0300 Subject: [PATCH] Much more readable code! --- src/protocols/valve.rs | 174 ++++++++++++++--------------------------- src/utils.rs | 46 +++++------ 2 files changed, 78 insertions(+), 142 deletions(-) diff --git a/src/protocols/valve.rs b/src/protocols/valve.rs index 028f2d9..e1e2486 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_first_string, get_u64_from_buf}; +use crate::utils::{buffer, complete_address, concat_u8}; #[derive(Debug)] pub enum Server { @@ -108,127 +108,73 @@ impl ValveProtocol { client.do_request(Request::A2sInfo(None), None); let mut buf = client.receive(DEFAULT_PACKET_SIZE); - let mut pos = 5; + let mut pos = 4; - if buf[4] == 0x41 { + if buffer::get_u8(&buf, &mut pos)? == 0x41 { client.do_request(Request::A2sInfo(Some([buf[pos], buf[pos + 1], buf[pos + 2], buf[pos + 3]])), None); buf = client.receive(DEFAULT_PACKET_SIZE); } - let protocol = buf[5]; pos = 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 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[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 the_ship = match has_the_ship { - false => None, - true => { - let ship = TheShip { - mode: buf[pos], - witnesses: buf[pos + 1], - duration: buf[pos + 2] - }; pos = pos + 3; - Some(ship) - } - }; - - 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 edf_port = match (value & 0x80) > 0 { - false => None, - true => { - let p = combine_two_u8(buf[pos + 1], buf[pos]); pos = pos + 2; - Some(p) + Ok(Response { + protocol: buffer::get_u8(&buf, &mut pos)?, + name: buffer::get_string(&buf, &mut pos), + map: buffer::get_string(&buf, &mut pos), + folder: buffer::get_string(&buf, &mut pos), + game: buffer::get_string(&buf, &mut pos), + id: buffer::get_u16(&buf, &mut pos), + players: buffer::get_u8(&buf, &mut pos)?, + max_players: buffer::get_u8(&buf, &mut pos)?, + bots: buffer::get_u8(&buf, &mut pos)?, + server_type: match buffer::get_u8(&buf, &mut pos)? as char { + 'd' => Server::Dedicated, + 'l' => Server::NonDedicated, + _ => Server::SourceTV + }, + environment_type: match buffer::get_u8(&buf, &mut pos)? as char { + 'l' => Environment::Linux, + 'w' => Environment::Windows, + _ => Environment::Mac + }, + has_password: buffer::get_u8(&buf, &mut pos)? == 1, + vac_secured: buffer::get_u8(&buf, &mut pos)? == 1, + the_ship: match has_the_ship { + false => None, + true => Some(TheShip { + mode: buffer::get_u8(&buf, &mut pos)?, + witnesses: buffer::get_u8(&buf, &mut pos)?, + duration: buffer::get_u8(&buf, &mut pos)? + }) + }, + version: buffer::get_string(&buf, &mut pos), + extra_data: match buffer::get_u8(&buf, &mut pos) { + Err(_) => None, + Ok(value) => Some(ExtraData { + port: match (value & 0x80) > 0 { + false => None, + true => Some(buffer::get_u16(&buf, &mut pos)) + }, + steam_id: match (value & 0x10) > 0 { + false => None, + true => Some(buffer::get_u64(&buf, &mut pos)) + }, + tv_port: match (value & 0x40) > 0 { + false => None, + true => Some(buffer::get_u16(&buf, &mut pos)) + }, + tv_name: match (value & 0x40) > 0 { + false => None, + true => Some(buffer::get_string(&buf, &mut pos)) + }, + keywords: match (value & 0x20) > 0 { + false => None, + true => Some(buffer::get_string(&buf, &mut pos)) + }, + game_id: match (value & 0x01) > 0 { + false => None, + true => Some(buffer::get_u64(&buf, &mut pos)) } - }; - - let steam_id = match (value & 0x10) > 0 { - false => None, - true => { - let p = get_u64_from_buf(&buf[pos..]); pos = pos + 8; - Some(p) - } - }; - - let (tv_port, tv_name) = match (value & 0x40) > 0 { - false => (None, None), - true => { - 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 keywords = find_first_string(&buf[pos..]); pos = pos + keywords.len() + 1; - Some(keywords) - } - }; - - let game_id = match (value & 0x01) > 0 { - false => None, - true => { - let game_id = get_u64_from_buf(&buf[pos..]); pos = pos + 8; - Some(game_id) - } - }; - - Some(ExtraData { - port: edf_port, - steam_id, - tv_port, - tv_name, - keywords, - game_id }) } - }; - - Ok(Response { - protocol, - name, - map, - folder, - game, - id, - players, - max_players, - bots, - server_type, - environment_type, - has_password, - vac_secured, - the_ship, - version, - extra_data }) } } diff --git a/src/utils.rs b/src/utils.rs index ca4a0d6..6e5ee2c 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,18 +1,12 @@ use std::ops::Add; +use crate::GDError; pub fn concat_u8(first: &[u8], second: &[u8]) -> Vec { [first, second].concat() } -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::() + std::str::from_utf8(&arr[..arr.iter().position(|&x| x == 0).unwrap()]).unwrap().to_string() } pub fn complete_address(address: &str, port: u16) -> String { @@ -30,29 +24,31 @@ pub fn combine_eight_u8(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8, g: u8, h: u8) pub mod buffer { use super::*; - pub fn get_u8(buf: &[u8], pos: usize) -> (u8, usize) { - (buf[pos], pos + 1) + pub fn get_u8(buf: &[u8], pos: &mut usize) -> Result { + let value = buf[*pos]; + *pos += 1; + Ok(value) } - pub fn get_u16(buf: &[u8], pos: usize) -> (u16, usize) { - (combine_two_u8(buf[pos + 1], buf[pos]), pos + 2) + pub fn get_u16(buf: &[u8], pos: &mut usize) -> u16 { + let value = combine_two_u8(buf[*pos + 1], buf[*pos]); + *pos += 2; + value } - 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_u64(buf: &[u8], pos: &mut usize) -> u64 { + let value = 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; + value } - 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_string(buf: &[u8], pos: &mut usize) -> String { + let value = find_first_string(&buf[*pos..]); + *pos += value.len() + 1; + value } } -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]) -} - #[cfg(test)] mod utils { use super::*; @@ -68,12 +64,6 @@ mod utils { assert_eq!(b[1], combined[3]); } - #[test] - fn find_null_in_array_test() { - let arr: [u8; 4] = [0x64, 0x32, 0x00, 0x20]; - assert_eq!(2, find_first_null(&arr)); - } - #[test] fn complete_address_test() { let address = "192.168.0.1";