implement caps to avoid a panic
The previous disco#info was missing the required disco#info feature and an identity, and the ecaps2 was computed from an empty disco#info instead of the one we advertise. In our case caps is a tiny optimisation which lets other participants cache our disco#info to avoid querying us every time. A future improvement will be to reply to ecaps2 queries as well.
This commit is contained in:
parent
c793d08bb6
commit
66cfaa4da5
|
@ -14,9 +14,10 @@ use tracing::{debug, error, info, trace, warn};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
pub use xmpp_parsers::disco::Feature;
|
pub use xmpp_parsers::disco::Feature;
|
||||||
use xmpp_parsers::{
|
use xmpp_parsers::{
|
||||||
disco::{DiscoInfoQuery, DiscoInfoResult},
|
disco::{DiscoInfoQuery, DiscoInfoResult, Identity},
|
||||||
|
caps::{self, Caps},
|
||||||
ecaps2::{self, ECaps2},
|
ecaps2::{self, ECaps2},
|
||||||
hashes::Algo,
|
hashes::{Algo, Hash},
|
||||||
iq::{Iq, IqType},
|
iq::{Iq, IqType},
|
||||||
jingle::{Action, Jingle},
|
jingle::{Action, Jingle},
|
||||||
message::{Message, MessageType},
|
message::{Message, MessageType},
|
||||||
|
@ -24,6 +25,7 @@ use xmpp_parsers::{
|
||||||
nick::Nick,
|
nick::Nick,
|
||||||
ns,
|
ns,
|
||||||
presence::{self, Presence},
|
presence::{self, Presence},
|
||||||
|
stanza_error::{DefinedCondition, ErrorType, StanzaError},
|
||||||
BareJid, Element, FullJid, Jid,
|
BareJid, Element, FullJid, Jid,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,8 +38,11 @@ use crate::{
|
||||||
xmpp::{self, connection::Connection},
|
xmpp::{self, connection::Connection},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const DISCO_NODE: &str = "https://github.com/avstack/gst-meet";
|
||||||
|
|
||||||
static DISCO_INFO: Lazy<DiscoInfoResult> = Lazy::new(|| {
|
static DISCO_INFO: Lazy<DiscoInfoResult> = Lazy::new(|| {
|
||||||
let mut features = vec![
|
let mut features = vec![
|
||||||
|
Feature::new(ns::DISCO_INFO),
|
||||||
Feature::new(ns::JINGLE_RTP_AUDIO),
|
Feature::new(ns::JINGLE_RTP_AUDIO),
|
||||||
Feature::new(ns::JINGLE_RTP_VIDEO),
|
Feature::new(ns::JINGLE_RTP_VIDEO),
|
||||||
Feature::new(ns::JINGLE_ICE_UDP),
|
Feature::new(ns::JINGLE_ICE_UDP),
|
||||||
|
@ -54,16 +59,23 @@ static DISCO_INFO: Lazy<DiscoInfoResult> = Lazy::new(|| {
|
||||||
else {
|
else {
|
||||||
warn!("Upgrade GStreamer to 1.19 or later to enable RTP header extensions");
|
warn!("Upgrade GStreamer to 1.19 or later to enable RTP header extensions");
|
||||||
}
|
}
|
||||||
|
let identities = vec![
|
||||||
|
Identity::new("client", "bot", "en", "gst-meet"),
|
||||||
|
];
|
||||||
// Not supported yet:
|
// Not supported yet:
|
||||||
// Feature::new("http://jitsi.org/opus-red")
|
// Feature::new("http://jitsi.org/opus-red")
|
||||||
DiscoInfoResult {
|
DiscoInfoResult {
|
||||||
node: None,
|
node: None,
|
||||||
identities: vec![],
|
identities,
|
||||||
features,
|
features,
|
||||||
extensions: vec![],
|
extensions: vec![],
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
static COMPUTED_CAPS_HASH: Lazy<Hash> = Lazy::new(|| {
|
||||||
|
caps::hash_caps(&caps::compute_disco(&DISCO_INFO), Algo::Sha_1).unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum JitsiConferenceState {
|
enum JitsiConferenceState {
|
||||||
Discovering,
|
Discovering,
|
||||||
|
@ -437,18 +449,12 @@ impl StanzaFilter for JitsiConference {
|
||||||
bail!("focus IQ failed");
|
bail!("focus IQ failed");
|
||||||
};
|
};
|
||||||
|
|
||||||
let jitsi_disco_info = DiscoInfoResult {
|
let ecaps2_hash =
|
||||||
node: Some("http://jitsi.org/jitsimeet".to_string()),
|
ecaps2::hash_ecaps2(&ecaps2::compute_disco(&DISCO_INFO)?, Algo::Sha_256)?;
|
||||||
identities: vec![],
|
|
||||||
features: vec![],
|
|
||||||
extensions: vec![],
|
|
||||||
};
|
|
||||||
|
|
||||||
let jitsi_disco_hash =
|
|
||||||
ecaps2::hash_ecaps2(&ecaps2::compute_disco(&jitsi_disco_info)?, Algo::Sha_256)?;
|
|
||||||
let mut presence = vec![
|
let mut presence = vec![
|
||||||
Muc::new().into(),
|
Muc::new().into(),
|
||||||
ECaps2::new(vec![jitsi_disco_hash]).into(),
|
Caps::new(DISCO_NODE, COMPUTED_CAPS_HASH.clone()).into(),
|
||||||
|
ECaps2::new(vec![ecaps2_hash]).into(),
|
||||||
Element::builder("stats-id", ns::DEFAULT_NS).append("gst-meet").build(),
|
Element::builder("stats-id", ns::DEFAULT_NS).append("gst-meet").build(),
|
||||||
Element::builder("jitsi_participant_codecType", ns::DEFAULT_NS)
|
Element::builder("jitsi_participant_codecType", ns::DEFAULT_NS)
|
||||||
.append(self.config.video_codec.as_str())
|
.append(self.config.video_codec.as_str())
|
||||||
|
@ -501,15 +507,34 @@ impl StanzaFilter for JitsiConference {
|
||||||
iq.from.as_ref().unwrap(),
|
iq.from.as_ref().unwrap(),
|
||||||
query.node
|
query.node
|
||||||
);
|
);
|
||||||
if query.node.is_none() {
|
if let Some(node) = query.node {
|
||||||
|
match node.splitn(2, '#').collect::<Vec<_>>().as_slice() {
|
||||||
|
// TODO: also support ecaps2, as we send it in our presence.
|
||||||
|
[uri, hash] if *uri == DISCO_NODE && *hash == COMPUTED_CAPS_HASH.to_base64() => {
|
||||||
|
let mut disco_info = DISCO_INFO.clone();
|
||||||
|
disco_info.node = Some(node);
|
||||||
|
let iq = Iq::from_result(iq.id, Some(disco_info))
|
||||||
|
.with_from(Jid::Full(self.jid.clone()))
|
||||||
|
.with_to(iq.from.unwrap());
|
||||||
|
self.xmpp_tx.send(iq.into()).await?;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let error = StanzaError::new(
|
||||||
|
ErrorType::Cancel, DefinedCondition::ItemNotFound,
|
||||||
|
"en", format!("Unknown disco#info node: {}", node));
|
||||||
|
let iq = Iq::from_error(iq.id, error)
|
||||||
|
.with_from(Jid::Full(self.jid.clone()))
|
||||||
|
.with_to(iq.from.unwrap());
|
||||||
|
self.xmpp_tx.send(iq.into()).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
let iq = Iq::from_result(iq.id, Some(DISCO_INFO.clone()))
|
let iq = Iq::from_result(iq.id, Some(DISCO_INFO.clone()))
|
||||||
.with_from(Jid::Full(self.jid.clone()))
|
.with_from(Jid::Full(self.jid.clone()))
|
||||||
.with_to(iq.from.unwrap());
|
.with_to(iq.from.unwrap());
|
||||||
self.xmpp_tx.send(iq.into()).await?;
|
self.xmpp_tx.send(iq.into()).await?;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
panic!("don't know how to handle disco info node: {:?}", query.node);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
IqType::Set(element) => {
|
IqType::Set(element) => {
|
||||||
|
|
Loading…
Reference in New Issue