|
|
@ -90,7 +90,7 @@ pub struct Version { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl Version { |
|
|
|
impl Version { |
|
|
|
pub fn new(major: u8, minor: u8) -> Self { |
|
|
|
pub const fn new(major: u8, minor: u8) -> Self { |
|
|
|
Self { major, minor } |
|
|
|
Self { major, minor } |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -136,11 +136,11 @@ impl PutKeyValue for Version { |
|
|
|
#[derive(Clone, Debug, Default, PartialEq, Eq)] |
|
|
|
#[derive(Clone, Debug, Default, PartialEq, Eq)] |
|
|
|
pub struct Filter<'a> { |
|
|
|
pub struct Filter<'a> { |
|
|
|
/// Servers running the specified modification (ex. cstrike)
|
|
|
|
/// Servers running the specified modification (ex. cstrike)
|
|
|
|
pub gamedir: &'a [u8], |
|
|
|
pub gamedir: Option<&'a [u8]>, |
|
|
|
/// Servers running the specified map (ex. cs_italy)
|
|
|
|
/// Servers running the specified map (ex. cs_italy)
|
|
|
|
pub map: &'a [u8], |
|
|
|
pub map: Option<&'a [u8]>, |
|
|
|
/// Client version.
|
|
|
|
/// Client version.
|
|
|
|
pub clver: Version, |
|
|
|
pub clver: Option<Version>, |
|
|
|
|
|
|
|
|
|
|
|
pub flags: FilterFlags, |
|
|
|
pub flags: FilterFlags, |
|
|
|
pub flags_mask: FilterFlags, |
|
|
|
pub flags_mask: FilterFlags, |
|
|
@ -154,13 +154,15 @@ impl Filter<'_> { |
|
|
|
|
|
|
|
|
|
|
|
pub fn matches(&self, _addr: SocketAddrV4, info: &ServerInfo) -> bool { |
|
|
|
pub fn matches(&self, _addr: SocketAddrV4, info: &ServerInfo) -> bool { |
|
|
|
!((info.flags & self.flags_mask) != self.flags |
|
|
|
!((info.flags & self.flags_mask) != self.flags |
|
|
|
|| (!self.gamedir.is_empty() && self.gamedir != &*info.gamedir) |
|
|
|
|| self.gamedir.map_or(false, |s| s != &*info.gamedir) |
|
|
|
|| (!self.map.is_empty() && self.map != &*info.map)) |
|
|
|
|| self.map.map_or(false, |s| s != &*info.map)) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl<'a> Filter<'a> { |
|
|
|
impl<'a> TryFrom<&'a [u8]> for Filter<'a> { |
|
|
|
pub fn from_bytes(src: &'a [u8]) -> Result<Self, Error> { |
|
|
|
type Error = Error; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn try_from(src: &'a [u8]) -> Result<Self, Self::Error> { |
|
|
|
let mut cur = Cursor::new(src); |
|
|
|
let mut cur = Cursor::new(src); |
|
|
|
let mut filter = Self::default(); |
|
|
|
let mut filter = Self::default(); |
|
|
|
|
|
|
|
|
|
|
@ -174,17 +176,18 @@ impl<'a> Filter<'a> { |
|
|
|
match *key { |
|
|
|
match *key { |
|
|
|
b"dedicated" => filter.insert_flag(FilterFlags::DEDICATED, cur.get_key_value()?), |
|
|
|
b"dedicated" => filter.insert_flag(FilterFlags::DEDICATED, cur.get_key_value()?), |
|
|
|
b"secure" => filter.insert_flag(FilterFlags::SECURE, cur.get_key_value()?), |
|
|
|
b"secure" => filter.insert_flag(FilterFlags::SECURE, cur.get_key_value()?), |
|
|
|
b"gamedir" => filter.gamedir = cur.get_key_value()?, |
|
|
|
b"gamedir" => filter.gamedir = Some(cur.get_key_value()?), |
|
|
|
b"map" => filter.map = cur.get_key_value()?, |
|
|
|
b"map" => filter.map = Some(cur.get_key_value()?), |
|
|
|
b"empty" => filter.insert_flag(FilterFlags::NOT_EMPTY, cur.get_key_value()?), |
|
|
|
b"empty" => filter.insert_flag(FilterFlags::NOT_EMPTY, cur.get_key_value()?), |
|
|
|
b"full" => filter.insert_flag(FilterFlags::FULL, cur.get_key_value()?), |
|
|
|
b"full" => filter.insert_flag(FilterFlags::FULL, cur.get_key_value()?), |
|
|
|
b"password" => filter.insert_flag(FilterFlags::PASSWORD, cur.get_key_value()?), |
|
|
|
b"password" => filter.insert_flag(FilterFlags::PASSWORD, cur.get_key_value()?), |
|
|
|
b"noplayers" => filter.insert_flag(FilterFlags::NOPLAYERS, cur.get_key_value()?), |
|
|
|
b"noplayers" => filter.insert_flag(FilterFlags::NOPLAYERS, cur.get_key_value()?), |
|
|
|
b"clver" => { |
|
|
|
b"clver" => { |
|
|
|
filter.clver = cur |
|
|
|
filter.clver = Some( |
|
|
|
.get_key_value::<&str>()? |
|
|
|
cur.get_key_value::<&str>()? |
|
|
|
.parse() |
|
|
|
.parse() |
|
|
|
.map_err(|_| Error::InvalidPacket)? |
|
|
|
.map_err(|_| Error::InvalidPacket)?, |
|
|
|
|
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
b"nat" => filter.insert_flag(FilterFlags::NAT, cur.get_key_value()?), |
|
|
|
b"nat" => filter.insert_flag(FilterFlags::NAT, cur.get_key_value()?), |
|
|
|
b"lan" => filter.insert_flag(FilterFlags::LAN, cur.get_key_value()?), |
|
|
|
b"lan" => filter.insert_flag(FilterFlags::LAN, cur.get_key_value()?), |
|
|
@ -214,18 +217,20 @@ impl fmt::Display for &Filter<'_> { |
|
|
|
|
|
|
|
|
|
|
|
display_flag!("dedicated", FilterFlags::DEDICATED); |
|
|
|
display_flag!("dedicated", FilterFlags::DEDICATED); |
|
|
|
display_flag!("secure", FilterFlags::SECURE); |
|
|
|
display_flag!("secure", FilterFlags::SECURE); |
|
|
|
if !self.gamedir.is_empty() { |
|
|
|
if let Some(s) = self.gamedir { |
|
|
|
write!(fmt, "\\gamedir\\{}", Str(self.gamedir))?; |
|
|
|
write!(fmt, "\\gamedir\\{}", Str(s))?; |
|
|
|
} |
|
|
|
} |
|
|
|
display_flag!("secure", FilterFlags::SECURE); |
|
|
|
display_flag!("secure", FilterFlags::SECURE); |
|
|
|
if !self.map.is_empty() { |
|
|
|
if let Some(s) = self.map { |
|
|
|
write!(fmt, "\\map\\{}", Str(self.map))?; |
|
|
|
write!(fmt, "\\map\\{}", Str(s))?; |
|
|
|
} |
|
|
|
} |
|
|
|
display_flag!("empty", FilterFlags::NOT_EMPTY); |
|
|
|
display_flag!("empty", FilterFlags::NOT_EMPTY); |
|
|
|
display_flag!("full", FilterFlags::FULL); |
|
|
|
display_flag!("full", FilterFlags::FULL); |
|
|
|
display_flag!("password", FilterFlags::PASSWORD); |
|
|
|
display_flag!("password", FilterFlags::PASSWORD); |
|
|
|
display_flag!("noplayers", FilterFlags::NOPLAYERS); |
|
|
|
display_flag!("noplayers", FilterFlags::NOPLAYERS); |
|
|
|
write!(fmt, "\\clver\\{}", self.clver)?; |
|
|
|
if let Some(v) = self.clver { |
|
|
|
|
|
|
|
write!(fmt, "\\clver\\{}", v)?; |
|
|
|
|
|
|
|
} |
|
|
|
display_flag!("nat", FilterFlags::NAT); |
|
|
|
display_flag!("nat", FilterFlags::NAT); |
|
|
|
display_flag!("lan", FilterFlags::LAN); |
|
|
|
display_flag!("lan", FilterFlags::LAN); |
|
|
|
display_flag!("bots", FilterFlags::BOTS); |
|
|
|
display_flag!("bots", FilterFlags::BOTS); |
|
|
@ -253,7 +258,7 @@ mod tests { |
|
|
|
.. Filter::default() |
|
|
|
.. Filter::default() |
|
|
|
}; |
|
|
|
}; |
|
|
|
$(assert_eq!( |
|
|
|
$(assert_eq!( |
|
|
|
Filter::from_bytes($src), |
|
|
|
Filter::try_from($src as &[u8]), |
|
|
|
Ok(Filter { |
|
|
|
Ok(Filter { |
|
|
|
$($field: $value,)* |
|
|
|
$($field: $value,)* |
|
|
|
..predefined |
|
|
|
..predefined |
|
|
@ -266,17 +271,17 @@ mod tests { |
|
|
|
tests! { |
|
|
|
tests! { |
|
|
|
parse_gamedir { |
|
|
|
parse_gamedir { |
|
|
|
b"\\gamedir\\valve" => { |
|
|
|
b"\\gamedir\\valve" => { |
|
|
|
gamedir: &b"valve"[..], |
|
|
|
gamedir: Some(&b"valve"[..]), |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
parse_map { |
|
|
|
parse_map { |
|
|
|
b"\\map\\crossfire" => { |
|
|
|
b"\\map\\crossfire" => { |
|
|
|
map: &b"crossfire"[..], |
|
|
|
map: Some(&b"crossfire"[..]), |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
parse_clver { |
|
|
|
parse_clver { |
|
|
|
b"\\clver\\0.20" => { |
|
|
|
b"\\clver\\0.20" => { |
|
|
|
clver: Version::new(0, 20), |
|
|
|
clver: Some(Version::new(0, 20)), |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
parse_dedicated(flags_mask: FilterFlags::DEDICATED) { |
|
|
|
parse_dedicated(flags_mask: FilterFlags::DEDICATED) { |
|
|
@ -349,9 +354,9 @@ mod tests { |
|
|
|
\\password\\1\ |
|
|
|
\\password\\1\ |
|
|
|
\\secure\\1\ |
|
|
|
\\secure\\1\ |
|
|
|
" => { |
|
|
|
" => { |
|
|
|
gamedir: &b"valve"[..], |
|
|
|
gamedir: Some(&b"valve"[..]), |
|
|
|
map: &b"crossfire"[..], |
|
|
|
map: Some(&b"crossfire"[..]), |
|
|
|
clver: Version::new(0, 20), |
|
|
|
clver: Some(Version::new(0, 20)), |
|
|
|
flags: FilterFlags::all(), |
|
|
|
flags: FilterFlags::all(), |
|
|
|
flags_mask: FilterFlags::all(), |
|
|
|
flags_mask: FilterFlags::all(), |
|
|
|
} |
|
|
|
} |
|
|
@ -383,7 +388,7 @@ mod tests { |
|
|
|
macro_rules! matches { |
|
|
|
macro_rules! matches { |
|
|
|
($servers:expr, $filter:expr$(, $expected:expr)*) => ( |
|
|
|
($servers:expr, $filter:expr$(, $expected:expr)*) => ( |
|
|
|
let servers = &$servers; |
|
|
|
let servers = &$servers; |
|
|
|
let filter = Filter::from_bytes($filter).unwrap(); |
|
|
|
let filter = Filter::try_from($filter as &[u8]).unwrap(); |
|
|
|
let iter = servers |
|
|
|
let iter = servers |
|
|
|
.iter() |
|
|
|
.iter() |
|
|
|
.enumerate() |
|
|
|
.enumerate() |
|
|
|