s2s: timestamp arbitration for fjoin (lower TS wins — strip or wipe losing status), fmode and ftopic (drop changes stamped newer than ours)
This commit is contained in:
parent
7908fe50b0
commit
1ab643c870
2 changed files with 49 additions and 1 deletions
|
|
@ -118,6 +118,16 @@ impl Member {
|
||||||
|
|
||||||
/// Set/clear a prefix mode by its letter — built-in booleans or, for a
|
/// Set/clear a prefix mode by its letter — built-in booleans or, for a
|
||||||
/// config-defined letter, the custom-prefix set (used by the S2S mode applier).
|
/// config-defined letter, the custom-prefix set (used by the S2S mode applier).
|
||||||
|
/// Drop the standard status modes (q/a/o/h/v) — used when this side loses a
|
||||||
|
/// channel-timestamp war and every member must be de-statused.
|
||||||
|
pub fn clear_status(&mut self) {
|
||||||
|
self.owner = false;
|
||||||
|
self.admin = false;
|
||||||
|
self.op = false;
|
||||||
|
self.halfop = false;
|
||||||
|
self.voice = false;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_prefix(&mut self, letter: char, on: bool) {
|
pub fn set_prefix(&mut self, letter: char, on: bool) {
|
||||||
match letter {
|
match letter {
|
||||||
'y' => self.oprefix = on,
|
'y' => self.oprefix = on,
|
||||||
|
|
|
||||||
40
src/link.rs
40
src/link.rs
|
|
@ -20,7 +20,7 @@ use std::net::{SocketAddr, TcpStream};
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use crate::channels::{glob_match, Ban, Channel, Member, Topic};
|
use crate::channels::{glob_match, Ban, ChanModes, Channel, Member, Topic};
|
||||||
use crate::message::Message;
|
use crate::message::Message;
|
||||||
use crate::server::{now, Server};
|
use crate::server::{now, Server};
|
||||||
use crate::socketengine::OutSink;
|
use crate::socketengine::OutSink;
|
||||||
|
|
@ -2104,6 +2104,44 @@ mod tests {
|
||||||
|
|
||||||
// A server is a service iff its NAME matches the sasl_server or a `uline` config
|
// A server is a service iff its NAME matches the sasl_server or a `uline` config
|
||||||
// entry (case-insensitive); `silent` is honoured.
|
// entry (case-insensitive); `silent` is honoured.
|
||||||
|
// FJOIN timestamp arbitration: the lower channel TS wins. A member bursted with
|
||||||
|
// a NEWER TS than ours joins stripped of status; an OLDER TS wipes our side.
|
||||||
|
#[test]
|
||||||
|
fn fjoin_ts_arbitration_strips_losing_status() {
|
||||||
|
use crate::config::Config;
|
||||||
|
use std::sync::atomic::AtomicU64;
|
||||||
|
use std::sync::{mpsc, Arc};
|
||||||
|
let (tx, _rx) = mpsc::channel();
|
||||||
|
let mut s = Server::new(Config::default(), tx, Arc::new(AtomicU64::new(1)));
|
||||||
|
s.remote_users.insert(
|
||||||
|
"42SAAAAAA".to_string(),
|
||||||
|
RemoteUser {
|
||||||
|
uuid: "42SAAAAAA".to_string(),
|
||||||
|
nick: "bob".into(),
|
||||||
|
ident: "b".into(),
|
||||||
|
host: "h".into(),
|
||||||
|
realname: "b".into(),
|
||||||
|
account: None,
|
||||||
|
ip: String::new(),
|
||||||
|
modes: String::new(),
|
||||||
|
sid: "42S".into(),
|
||||||
|
via: 1,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
// we already hold #c at an OLD (winning) TS
|
||||||
|
s.channels.insert("#c".into(), {
|
||||||
|
let mut c = Channel::new("#c");
|
||||||
|
c.created = 1000;
|
||||||
|
c
|
||||||
|
});
|
||||||
|
// a peer bursts #c with a NEWER TS, opping bob — bob must join WITHOUT +o
|
||||||
|
let m = crate::message::parse(":42S FJOIN #c 2000 +nt :o,42SAAAAAA").unwrap();
|
||||||
|
s.link_fjoin_recv(1, &m);
|
||||||
|
let opped = s.channels["#c"].rmembers["42SAAAAAA"].op;
|
||||||
|
assert!(!opped, "a member bursted with a newer (losing) TS must be de-statused");
|
||||||
|
assert_eq!(s.channels["#c"].created, 1000, "our older TS is kept");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn uline_recognises_services_server() {
|
fn uline_recognises_services_server() {
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue