protocol: support old servers (protocol 48)

This commit is contained in:
Denis Drakhnia 2023-11-01 09:04:05 +02:00
parent 05b447a750
commit 5778bbc714
4 changed files with 88 additions and 26 deletions

View File

@ -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(())

View File

@ -87,23 +87,36 @@ impl<T> From<&ServerAdd<T>> 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)
<Self as fmt::Debug>::fmt(self, fmt)
}
}
@ -111,8 +124,12 @@ impl FromStr for Version {
type Err = ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
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))
}
}

View File

@ -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<u32>,
}
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<u32>) -> 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<const N: usize>(&self, buf: &mut [u8; N]) -> Result<usize, Error> {
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));

View File

@ -13,29 +13,35 @@ use super::Error;
#[derive(Clone, Debug, PartialEq)]
pub struct Challenge {
pub server_challenge: u32,
pub server_challenge: Option<u32>,
}
impl Challenge {
pub const HEADER: &'static [u8] = b"q\xff";
pub fn new(server_challenge: u32) -> Self {
pub fn new(server_challenge: Option<u32>) -> Self {
Self { server_challenge }
}
pub fn decode(src: &[u8]) -> Result<Self, Error> {
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<const N: usize>(&self, buf: &mut [u8; N]) -> Result<usize, Error> {
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 {