From 5778bbc714af34e9cd59982b2a2d0be78207452c Mon Sep 17 00:00:00 2001 From: Denis Drakhnia Date: Wed, 1 Nov 2023 09:04:05 +0200 Subject: [PATCH] protocol: support old servers (protocol 48) --- master/src/master_server.rs | 6 +++--- protocol/src/filter.rs | 27 ++++++++++++++++++----- protocol/src/master.rs | 38 ++++++++++++++++++++++++-------- protocol/src/server.rs | 43 +++++++++++++++++++++++++++++-------- 4 files changed, 88 insertions(+), 26 deletions(-) diff --git a/master/src/master_server.rs b/master/src/master_server.rs index 84ca55a..41708d4 100644 --- a/master/src/master_server.rs +++ b/master/src/master_server.rs @@ -252,10 +252,10 @@ impl MasterServer { let p = server::GetServerInfoResponse { map: self.update_map.as_ref(), host: self.update_title.as_ref(), - protocol: 49, + protocol: 48, // XXX: how to detect what version client will accept? dm: true, maxcl: 32, - gamedir: "valve", + gamedir: "valve", // XXX: probably must be specific for client... ..Default::default() }; trace!("{}: send {:?}", from, p); @@ -334,7 +334,7 @@ impl MasterServer { } } } else { - debug!("invalid packet: \"{}\"", Str(src)); + debug!("{}: invalid packet: \"{}\"", from, Str(src)); } Ok(()) diff --git a/protocol/src/filter.rs b/protocol/src/filter.rs index 63db85d..5230b1b 100644 --- a/protocol/src/filter.rs +++ b/protocol/src/filter.rs @@ -87,23 +87,36 @@ impl From<&ServerAdd> for FilterFlags { pub struct Version { pub major: u8, pub minor: u8, + pub patch: u8, } impl Version { pub const fn new(major: u8, minor: u8) -> Self { - Self { major, minor } + Self::with_patch(major, minor, 0) + } + + pub const fn with_patch(major: u8, minor: u8, patch: u8) -> Self { + Self { + major, + minor, + patch, + } } } impl fmt::Debug for Version { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{}.{}", self.major, self.minor) + write!(fmt, "{}.{}", self.major, self.minor)?; + if self.patch != 0 { + write!(fmt, ".{}", self.patch)?; + } + Ok(()) } } impl fmt::Display for Version { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{}.{}", self.major, self.minor) + ::fmt(self, fmt) } } @@ -111,8 +124,12 @@ impl FromStr for Version { type Err = ParseIntError; fn from_str(s: &str) -> Result { - let (major, minor) = s.split_once('.').unwrap_or((s, "0")); - Ok(Self::new(major.parse()?, minor.parse()?)) + let (major, tail) = s.split_once('.').unwrap_or((s, "0")); + let (minor, patch) = tail.split_once('.').unwrap_or((tail, "0")); + let major = major.parse()?; + let minor = minor.parse()?; + let patch = patch.parse()?; + Ok(Self::with_patch(major, minor, patch)) } } diff --git a/protocol/src/master.rs b/protocol/src/master.rs index 4b61ddc..7a2ebe1 100644 --- a/protocol/src/master.rs +++ b/protocol/src/master.rs @@ -9,13 +9,13 @@ use super::Error; #[derive(Clone, Debug, PartialEq)] pub struct ChallengeResponse { pub master_challenge: u32, - pub server_challenge: u32, + pub server_challenge: Option, } impl ChallengeResponse { pub const HEADER: &'static [u8] = b"\xff\xff\xff\xffs\n"; - pub fn new(master_challenge: u32, server_challenge: u32) -> Self { + pub fn new(master_challenge: u32, server_challenge: Option) -> Self { Self { master_challenge, server_challenge, @@ -26,7 +26,11 @@ impl ChallengeResponse { let mut cur = Cursor::new(src); cur.expect(Self::HEADER)?; let master_challenge = cur.get_u32_le()?; - let server_challenge = cur.get_u32_le()?; + let server_challenge = if cur.remaining() == 4 { + Some(cur.get_u32_le()?) + } else { + None + }; cur.expect_empty()?; Ok(Self { master_challenge, @@ -35,11 +39,13 @@ impl ChallengeResponse { } pub fn encode(&self, buf: &mut [u8; N]) -> Result { - Ok(CursorMut::new(buf) - .put_bytes(Self::HEADER)? - .put_u32_le(self.master_challenge)? - .put_u32_le(self.server_challenge)? - .pos()) + let mut cur = CursorMut::new(buf); + cur.put_bytes(Self::HEADER)?; + cur.put_u32_le(self.master_challenge)?; + if let Some(server_challenge) = self.server_challenge { + cur.put_u32_le(server_challenge)?; + } + Ok(cur.pos()) } } @@ -222,7 +228,21 @@ mod tests { #[test] fn challenge_response() { - let p = ChallengeResponse::new(0x12345678, 0x87654321); + let p = ChallengeResponse::new(0x12345678, Some(0x87654321)); + let mut buf = [0; 512]; + let n = p.encode(&mut buf).unwrap(); + assert_eq!(ChallengeResponse::decode(&buf[..n]), Ok(p)); + } + + #[test] + fn challenge_response_old() { + let s = b"\xff\xff\xff\xffs\n\x78\x56\x34\x12"; + assert_eq!( + ChallengeResponse::decode(s), + Ok(ChallengeResponse::new(0x12345678, None)) + ); + + let p = ChallengeResponse::new(0x12345678, None); let mut buf = [0; 512]; let n = p.encode(&mut buf).unwrap(); assert_eq!(ChallengeResponse::decode(&buf[..n]), Ok(p)); diff --git a/protocol/src/server.rs b/protocol/src/server.rs index cf181ce..b2c43b6 100644 --- a/protocol/src/server.rs +++ b/protocol/src/server.rs @@ -13,29 +13,35 @@ use super::Error; #[derive(Clone, Debug, PartialEq)] pub struct Challenge { - pub server_challenge: u32, + pub server_challenge: Option, } impl Challenge { pub const HEADER: &'static [u8] = b"q\xff"; - pub fn new(server_challenge: u32) -> Self { + pub fn new(server_challenge: Option) -> Self { Self { server_challenge } } pub fn decode(src: &[u8]) -> Result { let mut cur = Cursor::new(src); cur.expect(Self::HEADER)?; - let server_challenge = cur.get_u32_le()?; + let server_challenge = if cur.remaining() == 4 { + Some(cur.get_u32_le()?) + } else { + None + }; cur.expect_empty()?; Ok(Self { server_challenge }) } pub fn encode(&self, buf: &mut [u8; N]) -> Result { - Ok(CursorMut::new(buf) - .put_bytes(Self::HEADER)? - .put_u32_le(self.server_challenge)? - .pos()) + let mut cur = CursorMut::new(buf); + cur.put_bytes(Self::HEADER)?; + if let Some(server_challenge) = self.server_challenge { + cur.put_u32_le(server_challenge)?; + } + Ok(cur.pos()) } } @@ -264,7 +270,15 @@ where b"map" => ret.map = cur.get_key_value()?, b"type" => ret.server_type = cur.get_key_value()?, b"os" => ret.os = cur.get_key_value()?, - b"version" => ret.version = cur.get_key_value()?, + b"version" => { + ret.version = cur + .get_key_value() + .map_err(|e| { + debug!("invalid server version"); + e + }) + .unwrap_or_default() + } b"region" => ret.region = cur.get_key_value()?, b"product" => ret.product = cur.get_key_value()?, b"bots" => ret.flags.set(ServerFlags::BOTS, cur.get_key_value()?), @@ -460,12 +474,23 @@ mod tests { #[test] fn challenge() { - let p = Challenge::new(0x12345678); + let p = Challenge::new(Some(0x12345678)); let mut buf = [0; 128]; let n = p.encode(&mut buf).unwrap(); assert_eq!(Challenge::decode(&buf[..n]), Ok(p)); } + #[test] + fn challenge_old() { + let s = b"q\xff"; + assert_eq!(Challenge::decode(s), Ok(Challenge::new(None))); + + let p = Challenge::new(None); + let mut buf = [0; 128]; + let n = p.encode(&mut buf).unwrap(); + assert_eq!(&buf[..n], b"q\xff"); + } + #[test] fn server_add() { let p = ServerAdd {