valve_server_query/
lib.rs

1//! Access Valve's Server Query using this package.
2//!
3//! # Game Server Info
4//!
5//! ```no_run
6//! use valve_server_query::Server;
7//!
8//! let server = Server::new("127.0.0.1:12345").expect("Connect to dedicated server running Valve game");
9//!
10//! let info = server.info().expect("Get general server information");
11//! let players = server.players().expect("Get server player information");
12//! let rules = server.rules().expect("Get server rules");
13//! ```
14
15pub use models::info::Info;
16pub use models::info::Platform;
17pub use models::info::ServerType;
18pub use models::info::Vac;
19pub use models::info::Visibility;
20pub use models::Player;
21pub use server::Rules;
22pub use server::Server;
23
24#[allow(dead_code)]
25const ENCODING: &str = "utf-8";
26const PACKET_SIZE: usize = 1400;
27/// Packet is not split.
28const SIMPLE_RESPONSE_HEADER: [u8; 4] = [0xFF, 0xFF, 0xFF, 0xFF];
29/// Packet is split.
30const MULTI_PACKET_RESPONSE_HEADER: [u8; 4] = [0xFF, 0xFF, 0xFF, 0xFE];
31
32/// All types are little endian
33pub mod types {
34
35    // All types are little endian
36    pub type Byte = u8;
37    pub type Short = i16;
38    pub type Long = i32;
39    pub type Float = f32;
40    pub type LongLong = u64;
41    pub type CString = std::ffi::CString;
42
43    /// All types are little endian,
44    pub enum DataType {
45        // Name   Description
46        //
47        // byte   8 bit character or unsigned integer
48        // short  16 bit signed integer
49        // long   32 bit signed integer
50        // float  32 bit floating point
51        // long   long 64 bit unsigned integer
52        // string variable-length byte field, encoded in UTF-8, terminated by null byte (0x00)
53        Byte(Byte),
54        Short(Short),
55        Long(i32),
56        Float(f32),
57        LongLong(u64),
58        // UTF-8 Encoded
59        // Null-Terminated
60        String(CString),
61    }
62
63    pub fn get_byte<'a, I>(bytes: &mut I) -> Byte
64    where
65        I: Iterator<Item = &'a u8>,
66    {
67        bytes.next().expect("the next byte exists").to_owned()
68    }
69    pub fn get_short<'a, I>(bytes: &mut I) -> Short
70    where
71        I: Iterator<Item = &'a u8>,
72    {
73        Short::from_le_bytes([
74            *bytes.next().expect("next byte exists"),
75            *bytes.next().expect("next byte exists"),
76        ])
77    }
78    pub fn get_long<'a, I>(bytes: &mut I) -> Long
79    where
80        I: Iterator<Item = &'a u8>,
81    {
82        Long::from_le_bytes([
83            *bytes.next().expect("next byte exists"),
84            *bytes.next().expect("next byte exists"),
85            *bytes.next().expect("next byte exists"),
86            *bytes.next().expect("next byte exists"),
87        ])
88    }
89    pub fn get_float<'a, I>(bytes: &mut I) -> Float
90    where
91        I: Iterator<Item = &'a u8>,
92    {
93        Float::from_le_bytes([
94            *bytes.next().expect("next byte exists"),
95            *bytes.next().expect("next byte exists"),
96            *bytes.next().expect("next byte exists"),
97            *bytes.next().expect("next byte exists"),
98        ])
99    }
100    pub fn get_longlong<'a, I>(bytes: &mut I) -> LongLong
101    where
102        I: Iterator<Item = &'a u8>,
103    {
104        LongLong::from_le_bytes([
105            *bytes.next().expect("next byte exists"),
106            *bytes.next().expect("next byte exists"),
107            *bytes.next().expect("next byte exists"),
108            *bytes.next().expect("next byte exists"),
109            *bytes.next().expect("next byte exists"),
110            *bytes.next().expect("next byte exists"),
111            *bytes.next().expect("next byte exists"),
112            *bytes.next().expect("next byte exists"),
113        ])
114    }
115    pub fn get_string<'a, I>(bytes: &mut I) -> String
116    where
117        I: Iterator<Item = &'a u8>,
118    {
119        let mut string = String::new();
120        loop {
121            let byte = bytes.next().expect("next byte exists");
122            if *byte == 0 {
123                break;
124            } else {
125                string.push(*byte as char);
126            }
127        }
128        string
129    }
130}
131
132pub mod models {
133
134    use crate::types::{get_byte, get_float, get_long, get_string, Byte, Float, Long};
135
136    #[derive(Debug, PartialEq, Clone)]
137    pub struct Player {
138        index: Byte,
139        name: String,
140        score: Long,
141        duration: Float,
142    }
143
144    impl Default for Player {
145        fn default() -> Self {
146            Self {
147                index: 0,
148                name: "".to_string(),
149                score: 0,
150                duration: 0.0,
151            }
152        }
153    }
154
155    /// Getters (Immutable)
156    impl Player {
157        pub fn name(&self) -> &str {
158            &self.name
159        }
160        pub fn score(&self) -> Long {
161            self.score
162        }
163        pub fn duration(&self) -> Float {
164            self.duration
165        }
166    }
167
168    impl Player {
169        pub fn get_players(bytes: &[u8]) -> Vec<Self> {
170            let mut it = bytes.iter();
171            let mut players: Vec<Self> = Vec::new();
172
173            while it.len()
174                > (
175                    // There's a String too, but that has a varialble size.
176                    std::mem::size_of::<Byte>()
177                        + std::mem::size_of::<Long>()
178                        + std::mem::size_of::<Float>()
179                )
180            {
181                let player = Self::from_iter_bytes(&mut it);
182
183                players.push(player);
184            }
185
186            players
187        }
188
189        pub fn from_iter_bytes<'a, I>(iter_bytes: &mut I) -> Self
190        where
191            I: Iterator<Item = &'a u8>,
192        {
193            let index = get_byte(iter_bytes);
194            let name = get_string(iter_bytes);
195            let score = get_long(iter_bytes);
196            let duration = get_float(iter_bytes);
197
198            Self {
199                index,
200                name,
201                score,
202                duration,
203            }
204        }
205
206        pub fn from_bytes(bytes: &[u8]) -> Self {
207            let mut it = bytes.iter();
208
209            let index = get_byte(&mut it);
210            let name = get_string(&mut it);
211            let score = get_long(&mut it);
212            let duration = get_float(&mut it);
213
214            Self {
215                index,
216                name,
217                score,
218                duration,
219            }
220        }
221    }
222
223    pub mod info {
224
225        use crate::types::{Byte, LongLong, Short};
226
227        /// Represents a steam game server.
228        ///
229        /// Ref: <https://developer.valvesoftware.com/wiki/Server_queries#A2S_INFO>
230        ///
231        /// ```compile_fail
232        /// let server_name = info.name();
233        /// let loaded_map = info.map();
234        /// let max_players = info.player_max();
235        /// let players_online = info.player_count();
236        /// ```
237        #[derive(Debug, PartialEq, Clone)]
238        pub struct Info {
239            /// Response header. Always equal to 'I' (0x49).
240            header: Byte,
241            /// Protocol version used by the server.
242            protocol: Byte,
243            /// Name of the server.
244            name: String,
245            /// Map the server has currently loaded.
246            map: String,
247            /// Name of the folder containing the game files.
248            folder: String,
249            /// Full name of the game.
250            game: String,
251            /// Steam Application ID of game.
252            id: Short,
253            /// Number of players on the server.
254            players: Byte,
255            /// Maximum number of players the server reports it can hold.
256            max_players: Byte,
257            /// Number of bots on the server.
258            bots: Byte,
259            /// Indicates the type of server:
260            /// 'd' for a dedicated server
261            /// 'l' for a non-dedicated server
262            /// 'p' for a SourceTV relay (proxy)
263            server_type: ServerType,
264            /// Indicates the operating system of the server:
265            /// 'l' for Linux
266            /// 'w' for Windows
267            /// 'm' or 'o' for Mac (the code changed after L4D1)
268            environment: Platform,
269            /// Indicates whether the server requires a password:
270            /// 0 for public
271            /// 1 for private
272            visibility: Visibility,
273            /// Specifies whether the server uses VAC:
274            /// 0 for unsecured
275            /// 1 for secured
276            vac: Vac,
277            /// Version of the game installed on the server.
278            game_version: String,
279            /// Flag for Extra Features
280            extra_data_flag: Option<Byte>,
281            /// The server's game port number.
282            port: Option<Short>,
283            /// Server's SteamID.
284            steam_id: Option<LongLong>,
285            /// Spectator port number for SourceTV.
286            spectator_port: Option<Short>,
287            /// Name of the spectator server for SourceTV.
288            spectator_name: Option<String>,
289            /// Tags that describe the game according to the server (for future use.)
290            keywords: Option<String>,
291            /// The server's 64-bit GameID. If this is present, a more accurate AppID is present in the
292            /// low 24 bits. The earlier AppID could have been truncated as it was forced into 16-bit
293            /// storage.
294            game_id: Option<LongLong>,
295            /// Trailing bytes for Self::from_bytes
296            trailing_bytes: Option<Vec<Byte>>,
297        }
298
299        impl Info {
300            pub fn from_bytes(bytes: &[u8]) -> Self {
301                use crate::types::get_byte;
302                use crate::types::get_longlong;
303                use crate::types::get_short;
304                use crate::types::get_string;
305                use crate::utils::compress_trailing_null_bytes;
306
307                let mut it = bytes.iter();
308
309                let header = get_byte(&mut it);
310                let protocol = get_byte(&mut it);
311                let name = get_string(&mut it);
312                let map = get_string(&mut it);
313                let folder = get_string(&mut it);
314                let game = get_string(&mut it);
315                let id = get_short(&mut it);
316                let players = get_byte(&mut it);
317                let max_players = get_byte(&mut it);
318                let bots = get_byte(&mut it);
319                let server_type = ServerType::from_byte(&get_byte(&mut it));
320                let environment = Platform::from_byte(&get_byte(&mut it));
321                let visibility = Visibility::from_byte(&get_byte(&mut it));
322                let vac = Vac::from_byte(&get_byte(&mut it));
323                let game_version = get_string(&mut it);
324
325                let extra_data_flag: Option<u8>;
326                if let Some(u) = it.next() {
327                    extra_data_flag = Some(*u);
328                } else {
329                    extra_data_flag = None;
330                }
331
332                let port: Option<Short>;
333                if extra_data_flag.is_some() && (extra_data_flag.expect("data exists") & 0x80) != 0
334                {
335                    port = Some(get_short(&mut it));
336                } else {
337                    port = None;
338                }
339
340                let steam_id: Option<LongLong>;
341                if extra_data_flag.is_some() && (extra_data_flag.expect("data exists") & 0x10) != 0
342                {
343                    steam_id = Some(get_longlong(&mut it));
344                } else {
345                    steam_id = None;
346                }
347
348                let spectator_port: Option<Short>;
349                let spectator_name: Option<String>;
350                if extra_data_flag.is_some() && (extra_data_flag.expect("data exists") & 0x40) != 0
351                {
352                    spectator_port = Some(get_short(&mut it));
353                    spectator_name = Some(get_string(&mut it));
354                } else {
355                    spectator_port = None;
356                    spectator_name = None;
357                }
358
359                let keywords: Option<String>;
360                if extra_data_flag.is_some() && (extra_data_flag.expect("data exists") & 0x20) != 0
361                {
362                    keywords = Some(get_string(&mut it));
363                } else {
364                    keywords = None;
365                }
366
367                let game_id: Option<LongLong>;
368                if extra_data_flag.is_some() && (extra_data_flag.expect("data exists") & 0x01) != 0
369                {
370                    game_id = Some(get_longlong(&mut it));
371                } else {
372                    game_id = None;
373                }
374
375                // These are hanging bytes that were not parsed
376                let trailing_bytes: Option<Vec<u8>> = if it.len() > 0 {
377                    // Remove trailing null bytes (and leave one if there are any)
378                    let mut min_bytes: Vec<u8> = it.into_iter().map(|x| *x).collect();
379                    compress_trailing_null_bytes(&mut min_bytes);
380
381                    // Just a [0]
382                    if min_bytes.len() == 1 && *min_bytes.last().expect("last byte exists") == 0 {
383                        None
384                    } else {
385                        Some(min_bytes.into_iter().collect::<Vec<u8>>())
386                    }
387                } else {
388                    None
389                };
390
391                Self {
392                    header,
393                    game_id,
394                    trailing_bytes,
395                    keywords,
396                    spectator_port,
397                    spectator_name,
398                    extra_data_flag,
399                    steam_id,
400                    protocol,
401                    name,
402                    map,
403                    folder,
404                    game,
405                    id,
406                    players,
407                    max_players,
408                    bots,
409                    server_type,
410                    environment,
411                    visibility,
412                    vac,
413                    game_version,
414                    port,
415                }
416            }
417        }
418
419        /// Getters (Immutable)
420        impl Info {
421            /// Name of the server.
422            pub fn name(&self) -> &str {
423                &self.name
424            }
425            /// Map the server has currently loaded.
426            pub fn map(&self) -> &str {
427                &self.map
428            }
429            /// Name of the folder containing the game files.
430            pub fn folder(&self) -> &str {
431                &self.folder
432            }
433            /// Tags that describe the game according to the server (for future use)
434            // TODO: Current server has CSV format. Is this consistent?
435            pub fn keywords(&self) -> &Option<String> {
436                &self.keywords
437            }
438
439            /// Full name of the game.
440            pub fn game(&self) -> &str {
441                &self.game
442            }
443            /// The server's 64-bit GameID. If this is present, a more accurate AppID is present in the
444            /// low 24 bits. The earlier AppID could have been truncated as it was forced into 16-bit
445            /// storage.
446            pub fn game_id(&self) -> &Option<LongLong> {
447                &self.game_id
448            }
449            /// Version of the game installed on the server.
450            pub fn game_version(&self) -> &str {
451                &self.game_version
452            }
453            /// Steam Application ID of game
454            pub fn steam_app_id(&self) -> &Short {
455                &self.id
456            }
457            /// Server's SteamID.
458            pub fn steam_id(&self) -> &Option<LongLong> {
459                &self.steam_id
460            }
461
462            /// Number of players on the server.
463            pub fn player_count(&self) -> &Byte {
464                &self.players
465            }
466            /// Maximum number of players the server reports it can hold.
467            pub fn player_max(&self) -> &Byte {
468                &self.max_players
469            }
470            /// Number of bots on the server.
471            pub fn bot_count(&self) -> &Byte {
472                &self.bots
473            }
474
475            /// Indicates the type of server
476            pub fn server_type(&self) -> &ServerType {
477                &self.server_type
478            }
479            /// Indicates the operating system of the server
480            pub fn platform(&self) -> &Platform {
481                &self.environment
482            }
483
484            /// Indicates whether the server requires a password
485            pub fn visibility(&self) -> &Visibility {
486                &self.visibility
487            }
488            /// Specifies whether the server uses VAC
489            pub fn vac(&self) -> &Vac {
490                &self.vac
491            }
492
493            /// The server's game port number
494            pub fn port(&self) -> &Option<Short> {
495                &self.port
496            }
497            /// Name of the spectator server for SourceTV.
498            pub fn spectator_name(&self) -> &Option<String> {
499                &self.spectator_name
500            }
501            /// Spectator port number for SourceTV.
502            pub fn spectator_port(&self) -> &Option<Short> {
503                &self.spectator_port
504            }
505        }
506
507        #[derive(Debug, Eq, PartialEq, Clone)]
508        pub enum ServerType {
509            Dedicated,
510            NonDedicated,
511            SourceTvRelay,
512        }
513
514        impl ServerType {
515            fn from_byte(byte: &u8) -> Self {
516                use self::ServerType::{Dedicated, NonDedicated, SourceTvRelay};
517
518                match *byte as char {
519                    'd' => Dedicated,
520                    'l' => NonDedicated,
521                    'p' => SourceTvRelay,
522                    _ => panic!("Unrecognized Server Type: <{byte}>."),
523                }
524            }
525        }
526
527        #[derive(Debug, Eq, PartialEq, Clone)]
528        pub enum Platform {
529            Linux,
530            Windows,
531            Mac,
532        }
533
534        impl Platform {
535            fn from_byte(byte: &u8) -> Self {
536                use self::Platform::{Linux, Mac, Windows};
537
538                match *byte as char {
539                    'l' => Linux,
540                    'w' => Windows,
541                    'm' => Mac,
542                    'o' => Mac,
543                    _ => panic!("Unrecognized Environment: <{byte}>."),
544                }
545            }
546        }
547
548        #[derive(Debug, Eq, PartialEq, Clone)]
549        pub enum Visibility {
550            Public,
551            Private,
552        }
553
554        impl Visibility {
555            fn from_byte(byte: &u8) -> Self {
556                use self::Visibility::{Private, Public};
557
558                match *byte {
559                    0x00 => Public,
560                    0x01 => Private,
561                    _ => panic!("Unrecognized Visibility Byte: <{byte}>."),
562                }
563            }
564        }
565
566        #[derive(Debug, Eq, PartialEq, Clone)]
567        /// Specifies if a server uses VAC.
568        pub enum Vac {
569            Unsecured,
570            Secured,
571        }
572
573        impl Vac {
574            fn from_byte(byte: &u8) -> Self {
575                use self::Vac::{Secured, Unsecured};
576
577                match *byte {
578                    0x00 => Unsecured,
579                    0x01 => Secured,
580                    _ => panic!("Unrecognized Vac Byte: <{byte}>."),
581                }
582            }
583        }
584
585        #[cfg(test)]
586        mod tests {
587            use super::*;
588            #[test]
589            fn test_servertype_from_byte() {
590                assert_eq!(ServerType::Dedicated, ServerType::from_byte(&('d' as u8)));
591            }
592            #[test]
593            fn test_environment_from_byte() {
594                assert_eq!(Platform::Linux, Platform::from_byte(&('l' as u8)));
595            }
596            #[test]
597            fn test_visibility_from_byte() {
598                assert_eq!(Visibility::Public, Visibility::from_byte(&(0x00)));
599            }
600            #[test]
601            fn test_vac_from_byte() {
602                assert_eq!(Vac::Secured, Vac::from_byte(&(0x01)));
603            }
604        }
605    }
606}
607
608pub mod server {
609
610    use crate::{MULTI_PACKET_RESPONSE_HEADER, PACKET_SIZE, SIMPLE_RESPONSE_HEADER};
611    use std::collections::HashMap;
612    use std::error::Error;
613    use std::io;
614    use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
615    use std::time::Duration;
616
617    use crate::models::info::Info;
618    use crate::models::Player;
619    use crate::types::Byte;
620    use crate::utils::get_multipacket_data;
621
622    pub type Rules = HashMap<String, String>;
623
624    /// Represents a game server running a Steam game.
625    ///
626    /// ```compile_fail
627    /// let server = Server::new("127.0.0.1:12345").expect("Connect to dedicated server running Valve game");
628    ///
629    /// let info = server.info().expect("Get general server information");
630    /// let players = server.players().expect("Get server player information");
631    /// let rules = server.rules().expect("Get server rules");
632    /// ```
633    #[derive(Debug)]
634    pub struct Server {
635        socket: UdpSocket,
636        addr: SocketAddr,
637    }
638
639    impl Server {
640        pub fn new(url: &str) -> Result<Self, Box<dyn Error>> {
641            // Init
642            let addr: SocketAddr;
643            let socket: UdpSocket;
644
645            // Handle Errors
646            let result: Result<SocketAddr, _> = url.parse();
647            if let Ok(a) = result {
648                addr = a;
649            } else {
650                if let Err(e) = result {
651                    return Err(Box::new(e));
652                } else {
653                    unreachable!();
654                }
655            }
656
657            let result: Result<UdpSocket, _> =
658                UdpSocket::bind((IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0));
659            if let Ok(s) = result {
660                socket = s;
661            } else {
662                if let Err(e) = result {
663                    return Err(Box::new(e));
664                } else {
665                    unreachable!();
666                }
667            }
668
669            // Socket Settings
670            socket.set_read_timeout(Some(Duration::from_secs(1)))?;
671            socket.set_write_timeout(Some(Duration::from_secs(1)))?;
672
673            // Return Successfully
674            Ok(Self { addr, socket })
675        }
676    }
677
678    /// Socket Settings
679    impl Server {
680        pub fn set_read_timeout(
681            &mut self,
682            duration: Option<Duration>,
683        ) -> Result<(), Box<dyn Error>> {
684            self.socket.set_read_timeout(duration)?;
685            Ok(())
686        }
687        pub fn set_write_timeout(
688            &mut self,
689            duration: Option<Duration>,
690        ) -> Result<(), Box<dyn Error>> {
691            self.socket.set_write_timeout(duration)?;
692            Ok(())
693        }
694    }
695
696    // A2S_INFO Implementation
697    impl Server {
698        pub fn info(&self) -> Result<Info, io::Error> {
699            let mut request: Vec<u8> = vec![
700                255, 255, 255, 255, 84, 83, 111, 117, 114, 99, 101, 32, 69, 110, 103, 105, 110,
701                101, 32, 81, 117, 101, 114, 121, 0,
702            ];
703
704            self.socket.send_to(&request, &self.addr)?;
705
706            let mut buffer = [0; PACKET_SIZE];
707            let mut bytes_returned = self.socket.recv(&mut buffer)?;
708
709            if bytes_returned == 9 {
710                // Challenge Received
711
712                // Last 5 bytes of the response
713                let challenge = buffer
714                    .into_iter()
715                    .rev()
716                    .skip_while(|&i| i == 0)
717                    .collect::<Vec<u8>>()
718                    .to_owned()
719                    .into_iter()
720                    .rev()
721                    .collect::<Vec<u8>>()[5..]
722                    .to_vec();
723
724                request.extend(challenge);
725
726                self.socket.send_to(&request, &self.addr)?;
727                buffer = [0; PACKET_SIZE];
728                bytes_returned = self.socket.recv(&mut buffer)?;
729            }
730
731            let packet_header = &buffer[..4];
732            let payload: Vec<u8>;
733
734            if packet_header == SIMPLE_RESPONSE_HEADER {
735                payload = buffer[4..bytes_returned + 1].to_vec();
736            } else if packet_header == MULTI_PACKET_RESPONSE_HEADER {
737                // id starts at 0
738                // tcp means they don't have to be in order
739                let (_answer_id, total, packet_id) = get_multipacket_data(&buffer);
740                let mut packet_map: HashMap<Byte, Vec<u8>> = HashMap::with_capacity(total as usize);
741
742                let current_payload = buffer[(4 + 4 + 1 + 1)..bytes_returned + 1].to_vec();
743                packet_map.insert(packet_id, current_payload);
744
745                // Get the remaining packet data.
746                while total > packet_map.len() as u8 {
747                    buffer = [0; PACKET_SIZE]; // Clear buffer
748                    bytes_returned = self.socket.recv(&mut buffer)?;
749
750                    let (_answer_id, _total, packet_id) = get_multipacket_data(&buffer);
751                    let current_payload = buffer[(4 + 4 + 1 + 1)..bytes_returned + 1].to_vec();
752                    packet_map.insert(packet_id, current_payload);
753                }
754
755                // Sort and Collect all packet data
756                let mut v: Vec<(u8, Vec<u8>)> = packet_map.into_iter().collect();
757                v.sort_by_key(|i| i.0);
758                payload = v
759                    .into_iter()
760                    .map(|(_, bytes)| bytes)
761                    .flatten()
762                    .collect::<Vec<u8>>();
763            } else {
764                panic!("An unknown packet header was received.");
765            }
766
767            let info = Info::from_bytes(&payload);
768            Ok(info)
769        }
770    }
771
772    // A2S_PLAYER Implementation
773    impl Server {
774        pub fn players(&self) -> Result<Vec<Player>, io::Error> {
775            let request = [
776                0xFF, 0xFF, 0xFF, 0xFF, // Simple Header
777                0x55, // Header
778                0xFF, 0xFF, 0xFF, 0xFF, // Request Challenge
779            ];
780
781            self.socket.send_to(&request, &self.addr)?;
782
783            let mut buffer = [0; PACKET_SIZE];
784            let _bytes_returned = self.socket.recv(&mut buffer)?;
785
786            //  Get Challenge
787            let challenge = buffer
788                .into_iter()
789                .rev()
790                .skip_while(|&i| i == 0)
791                .collect::<Vec<u8>>()
792                .to_owned()
793                .into_iter()
794                .rev()
795                .collect::<Vec<u8>>()[5..]
796                .to_vec();
797
798            // Resend Request
799            let mut request = vec![
800                0xFF, 0xFF, 0xFF, 0xFF, // Simple Header
801                0x55, // Header
802            ];
803            request.extend(challenge);
804
805            // Get Data
806            self.socket.send_to(&request, &self.addr)?;
807            buffer = [0; PACKET_SIZE];
808            let mut bytes_returned = self.socket.recv(&mut buffer)?;
809
810            // Parse Data
811            let packet_header = &buffer[..=3];
812
813            let payload: Vec<u8>;
814            if packet_header == SIMPLE_RESPONSE_HEADER {
815                payload = buffer[4..].to_vec();
816            } else if packet_header == MULTI_PACKET_RESPONSE_HEADER {
817                // id starts at 0
818                // tcp means they don't have to be in order
819                let (_answer_id, total, packet_id) = get_multipacket_data(&buffer);
820                let mut packet_map: HashMap<Byte, Vec<u8>> = HashMap::with_capacity(total as usize);
821
822                let current_payload = buffer[(4 + 4 + 1 + 1)..bytes_returned + 1].to_vec();
823                packet_map.insert(packet_id, current_payload);
824
825                // Get the remaining packet data.
826                while total > packet_map.len() as u8 {
827                    buffer = [0; PACKET_SIZE]; // Clear buffer
828                    bytes_returned = self.socket.recv(&mut buffer)?;
829
830                    let (_answer_id, _total, packet_id) = get_multipacket_data(&buffer);
831                    let current_payload = buffer[(4 + 4 + 1 + 1)..bytes_returned + 1].to_vec();
832                    packet_map.insert(packet_id, current_payload);
833                }
834
835                // Sort and Collect all packet data
836                let mut v: Vec<(u8, Vec<u8>)> = packet_map.into_iter().collect();
837                v.sort_by_key(|i| i.0);
838                payload = v
839                    .into_iter()
840                    .map(|(_, bytes)| bytes)
841                    .flatten()
842                    .collect::<Vec<u8>>();
843            } else {
844                panic!("An unknown packet header was received.");
845            }
846
847            let _header: &Byte = &payload[0];
848            let player_count: Byte = payload[1].clone();
849
850            let mut it = payload[2..].iter();
851            let mut players: Vec<Player> = Vec::new();
852            for _ in 0..player_count {
853                let player = Player::from_iter_bytes(&mut it);
854                players.push(player);
855            }
856
857            Ok(players)
858        }
859    }
860
861    /// A2S_RULES Implementation
862    impl Server {
863        pub fn rules(&self) -> Result<Rules, io::Error> {
864            use crate::utils::compress_trailing_null_bytes;
865
866            let request = [
867                0xFF, 0xFF, 0xFF, 0xFF, // Simple Header
868                0x56, // Header
869                0xFF, 0xFF, 0xFF, 0xFF, // Request Challenge
870            ];
871
872            self.socket.send_to(&request, &self.addr)?;
873
874            let mut buffer = [0; PACKET_SIZE];
875            let _bytes_returned = self.socket.recv(&mut buffer)?;
876
877            //  Get Challenge
878            let challenge = buffer
879                .into_iter()
880                .rev()
881                .skip_while(|&i| i == 0)
882                .collect::<Vec<u8>>()
883                .to_owned()
884                .into_iter()
885                .rev()
886                .collect::<Vec<u8>>()[5..]
887                .to_vec();
888
889            // Resend Request
890            let mut request = vec![
891                0xFF, 0xFF, 0xFF, 0xFF, // Simple Header
892                0x56, // Header
893            ];
894            request.extend(challenge);
895
896            // Get Data
897            self.socket.send_to(&request, &self.addr)?;
898            buffer = [0; PACKET_SIZE];
899            let mut bytes_returned = self.socket.recv(&mut buffer)?;
900
901            // Parse Data
902            let packet_header = &buffer[..=3];
903            let _header: &Byte = &buffer[4];
904
905            let mut payload: Vec<u8>;
906            if packet_header == SIMPLE_RESPONSE_HEADER {
907                let _rule_count: Byte = buffer[5].clone();
908                let _ = buffer[6]; // Null Byte
909                payload = buffer[7..].to_vec();
910                compress_trailing_null_bytes(&mut payload);
911            } else if packet_header == MULTI_PACKET_RESPONSE_HEADER {
912                // id starts at 0
913                // tcp means they don't have to be in order
914                let (_answer_id, total, packet_id) = get_multipacket_data(&buffer);
915                let mut packet_map: HashMap<Byte, Vec<u8>> = HashMap::with_capacity(total as usize);
916
917                let current_payload = buffer[(4 + 4 + 1 + 1)..bytes_returned + 1].to_vec();
918                packet_map.insert(packet_id, current_payload);
919
920                // Get the remaining packet data.
921                while total > packet_map.len() as u8 {
922                    buffer = [0; PACKET_SIZE]; // Clear buffer
923                    bytes_returned = self.socket.recv(&mut buffer)?;
924
925                    let (_answer_id, _total, packet_id) = get_multipacket_data(&buffer);
926                    let current_payload = buffer[(4 + 4 + 1 + 1)..bytes_returned + 1].to_vec();
927                    packet_map.insert(packet_id, current_payload);
928                }
929
930                // Sort and Collect all packet data
931                let mut v: Vec<(u8, Vec<u8>)> = packet_map.into_iter().collect();
932                v.sort_by_key(|i| i.0);
933                payload = v
934                    .into_iter()
935                    .map(|(_, bytes)| bytes)
936                    .flatten()
937                    .collect::<Vec<u8>>();
938            } else {
939                panic!("An unknown packet header was received.");
940            }
941
942            let rules: Rules = Self::get_rules(&payload);
943
944            Ok(rules)
945        }
946
947        pub fn get_rules(bytes: &[u8]) -> Rules {
948            use crate::types::get_string;
949
950            let mut it = bytes.iter();
951            let mut rules = HashMap::new();
952
953            while it.len() > 0 {
954                let name = get_string(&mut it);
955                let value = get_string(&mut it);
956
957                rules.insert(name, value);
958            }
959
960            rules
961        }
962    }
963
964    #[cfg(test)]
965    mod tests {
966
967        use super::*;
968
969        #[test]
970        fn test_client_init() {
971            let server: Result<_, _> = Server::new("");
972            if let Err(_) = server {
973            } else {
974                assert!(false, "Server was successfully contructed when it should have failed when parsing URL.")
975            }
976        }
977
978        #[test]
979        #[ignore]
980        fn test_client_init_live() {
981            // Live server I own
982            let server: Result<_, _> = Server::new("54.186.150.6:9879");
983            if let Ok(_) = server {
984            } else {
985                assert!(
986                    false,
987                    "Server failed to be contructed when it should have succeeded (LIVE TEST)."
988                )
989            }
990        }
991
992        #[test]
993        fn test_client_info() {
994            // Dummy
995            let server = Server::new("127.0.0.1:12345").unwrap();
996            let info: Result<Info, _> = server.info();
997            if let Err(_) = info {
998            } else {
999                assert!(
1000                    false,
1001                    "Target URL is not real, but we got back an Ok response for A2S_INFO."
1002                )
1003            }
1004        }
1005
1006        #[test]
1007        #[ignore]
1008        fn test_client_info_live() {
1009            // Live server I own
1010            let server = Server::new("54.186.150.6:9879").unwrap();
1011            let info: Result<Info, _> = server.info();
1012            if let Ok(_) = info {
1013            } else {
1014                assert!(
1015                    false,
1016                    "Target URL is real and live, but we got back an Err response for A2S_INFO."
1017                )
1018            }
1019        }
1020        #[test]
1021        #[ignore]
1022        fn test_client_players_live() {
1023            // Live server I own
1024            let server = Server::new("54.186.150.6:9879").unwrap();
1025            let players: Result<Vec<Player>, _> = server.players();
1026            if let Ok(_) = players {
1027            } else {
1028                assert!(
1029                    false,
1030                    "Target URL is real and live, but we got back an Err response for A2S_PLAYER."
1031                )
1032            }
1033        }
1034        #[test]
1035        #[ignore]
1036        fn test_client_rules_live() {
1037            // Live server I own
1038            let server = Server::new("54.186.150.6:9879").unwrap();
1039            let rules: Result<Rules, _> = server.rules();
1040            if let Ok(_) = rules {
1041            } else {
1042                assert!(
1043                    false,
1044                    "Target URL is real and live, but we got back an Err response for A2S_RULES."
1045                )
1046            }
1047        }
1048    }
1049}
1050
1051pub mod utils {
1052    use crate::types::{get_byte, get_long, Byte, Long};
1053
1054    pub fn get_multipacket_data(buffer: &[u8]) -> (Long, Byte, Byte) {
1055        let v = buffer.to_vec();
1056        let mut buffer_mut = v.iter();
1057
1058        let _header = get_long(&mut buffer_mut);
1059        let answer_id = get_long(&mut buffer_mut);
1060        let total = get_byte(&mut buffer_mut);
1061        let packet_id = get_byte(&mut buffer_mut);
1062
1063        (answer_id, total, packet_id)
1064    }
1065
1066    pub fn compress_trailing_null_bytes(bytes: &mut Vec<u8>) {
1067        // No Size
1068        if bytes.len() == 0 || bytes.len() == 1 {
1069            return;
1070        }
1071        // No trailing null bytes
1072        if bytes.last().expect("a last byte exists") != &0 {
1073            return;
1074        }
1075
1076        // Remove trailing null bytes, then add one null byte
1077        let mut last = bytes.pop().expect("the next byte exists");
1078        while last == 0 && bytes.len() > 0 {
1079            last = bytes.pop().expect("the next byte exists");
1080        }
1081        bytes.push(last);
1082        bytes.push(0x00);
1083    }
1084
1085    #[cfg(test)]
1086    mod tests {
1087
1088        use super::*;
1089
1090        #[test]
1091        fn test_compress_null_bytes_basic() {
1092            let mut bytes: Vec<u8> = vec![1, 2, 3, 0, 0, 0, 0];
1093            compress_trailing_null_bytes(&mut bytes);
1094
1095            let result = bytes;
1096            let expected: Vec<u8> = vec![1, 2, 3, 0];
1097
1098            assert_eq!(result, expected);
1099        }
1100        #[test]
1101        fn test_compress_null_bytes_with_no_trailing_zeroes() {
1102            let mut bytes: Vec<u8> = vec![1, 2, 3];
1103            compress_trailing_null_bytes(&mut bytes);
1104
1105            let result = bytes;
1106            let expected: Vec<u8> = vec![1, 2, 3];
1107
1108            assert_eq!(result, expected);
1109        }
1110        #[test]
1111        fn test_compress_null_bytes_with_one_trailing_zeroes() {
1112            let mut bytes: Vec<u8> = vec![1, 2, 3, 0];
1113            compress_trailing_null_bytes(&mut bytes);
1114
1115            let result = bytes;
1116            let expected: Vec<u8> = vec![1, 2, 3, 0];
1117
1118            assert_eq!(result, expected);
1119        }
1120        #[test]
1121        fn test_compress_null_bytes_with_empty_vector() {
1122            let mut bytes: Vec<u8> = vec![];
1123            compress_trailing_null_bytes(&mut bytes);
1124
1125            let result = bytes;
1126            let expected: Vec<u8> = vec![];
1127
1128            assert_eq!(result, expected);
1129        }
1130        #[test]
1131        fn test_compress_null_bytes_with_one_zero_as_vector() {
1132            let mut bytes: Vec<u8> = vec![0];
1133            compress_trailing_null_bytes(&mut bytes);
1134
1135            let result = bytes;
1136            let expected: Vec<u8> = vec![0];
1137
1138            assert_eq!(result, expected);
1139        }
1140    }
1141}