aboutsummaryrefslogtreecommitdiff
path: root/xmpp-vala/src/module/xep/0198_stream_management.vala
diff options
context:
space:
mode:
authorfiaxh <git@lightrise.org>2026-04-24 11:09:10 +0200
committerfiaxh <git@lightrise.org>2026-04-24 11:17:43 +0200
commit9abf8f6869bc35c76bdfa86416012d4e7f0dda78 (patch)
tree3c3f7628d7fdc5410113a8efc6b96a4372c6d80b /xmpp-vala/src/module/xep/0198_stream_management.vala
parentc5ba4275ae68dd558108ce273dafa1bf890259e8 (diff)
Add support for Sasl2 + Bind2
Diffstat (limited to 'xmpp-vala/src/module/xep/0198_stream_management.vala')
-rw-r--r--xmpp-vala/src/module/xep/0198_stream_management.vala157
1 files changed, 116 insertions, 41 deletions
diff --git a/xmpp-vala/src/module/xep/0198_stream_management.vala b/xmpp-vala/src/module/xep/0198_stream_management.vala
index 68eee8ae..6b0d5162 100644
--- a/xmpp-vala/src/module/xep/0198_stream_management.vala
+++ b/xmpp-vala/src/module/xep/0198_stream_management.vala
@@ -128,20 +128,23 @@ public class Module : XmppStreamNegotiationModule, WriteNodeFunc {
}
private void check_resume(XmppStream stream) {
- if (stream_has_sm_feature(stream) && session_id != null) {
+ if (stream_has_sm_feature(stream) && session_id != null && !Flag.get_add_flag(stream).finished) {
StanzaNode node = new StanzaNode.build("resume", NS_URI).add_self_xmlns()
.put_attribute("h", h_inbound.to_string())
.put_attribute("previd", session_id);
write_node.begin(stream, node);
- stream.add_flag(new Flag());
+
+ Flag.get_add_flag(stream);
}
}
private void check_enable(XmppStream stream) {
- if (stream_has_sm_feature(stream) && session_id == null) {
+ if (stream_has_sm_feature(stream) && session_id == null && !Flag.get_add_flag(stream).finished) {
StanzaNode node = new StanzaNode.build("enable", NS_URI).add_self_xmlns().put_attribute("resume", "true");
write_node.begin(stream, node);
- stream.add_flag(new Flag());
+
+ Flag.get_add_flag(stream);
+
h_outbound = 0;
}
}
@@ -153,46 +156,64 @@ public class Module : XmppStreamNegotiationModule, WriteNodeFunc {
} else if (node.name == "a") {
handle_ack(stream, node);
} else if (node.name in new string[]{"enabled", "resumed", "failed"}) {
- stream.get_flag(Flag.IDENTITY).finished = true;
-
if (node.name == "enabled") {
- h_inbound = 0;
- session_id = node.get_attribute("id", NS_URI);
- flags = stream.flags;
- ((IoXmppStream)stream).write_obj = this;
+ on_enabled(stream, node);
} else if (node.name == "resumed") {
- stream.get_flag(Flag.IDENTITY).resumed = true;
-
- foreach (XmppStreamFlag flag in flags) {
- stream.add_flag(flag);
- }
-
- h_outbound = int.parse(node.get_attribute("h", NS_URI));
- handle_incoming_h(stream, h_outbound);
- foreach (var id in in_flight_stanzas.keys) {
- node_queue.add(in_flight_stanzas[id]);
- }
- in_flight_stanzas.clear();
- check_queue(stream);
- ((IoXmppStream)stream).write_obj = this;
+ on_resumed(stream, node);
} else if (node.name == "failed") {
- session_id = null;
- string? h_acked = node.get_attribute("h", NS_URI);
- if (h_acked != null) {
- h_outbound = int.parse(h_acked);
- handle_incoming_h(stream, h_outbound);
- }
- foreach (var id in in_flight_stanzas.keys) {
- in_flight_stanzas[id].promise.set_exception(new IOError.FAILED("Stanza not acked and session not resumed"));
- }
- in_flight_stanzas.clear();
- check_queue(stream);
- stream.received_features_node(stream);
+ on_resume_failed(stream, node);
}
}
}
}
+ public void on_resumed(XmppStream stream, StanzaNode resumed_node) {
+ var flag = stream.get_flag(Flag.IDENTITY);
+ flag.resumed = true;
+ flag.finished = true;
+
+ foreach (XmppStreamFlag f in flags) {
+ stream.add_flag(f);
+ }
+
+ h_outbound = int.parse(resumed_node.get_attribute("h", NS_URI));
+ handle_incoming_h(stream, h_outbound);
+ foreach (var id in in_flight_stanzas.keys) {
+ node_queue.add(in_flight_stanzas[id]);
+ }
+ in_flight_stanzas.clear();
+ check_queue(stream);
+ ((IoXmppStream)stream).write_obj = this;
+
+ stream.get_flag(Flag.IDENTITY).finished = true;
+ }
+
+ public void on_resume_failed(XmppStream stream, StanzaNode failed_node) {
+ session_id = null;
+ string? h_acked = failed_node.get_attribute("h", NS_URI);
+ if (h_acked != null) {
+ h_outbound = int.parse(h_acked);
+ handle_incoming_h(stream, h_outbound);
+ }
+ foreach (var id in in_flight_stanzas.keys) {
+ in_flight_stanzas[id].promise.set_exception(new IOError.FAILED("Stanza not acked and session not resumed"));
+ }
+ in_flight_stanzas.clear();
+ check_queue(stream);
+ stream.received_features_node(stream);
+
+ stream.get_flag(Flag.IDENTITY).finished = true;
+ }
+
+ public void on_enabled(XmppStream stream, StanzaNode enabled_node) {
+ h_inbound = 0;
+ session_id = enabled_node.get_attribute("id", NS_URI);
+ flags = stream.flags;
+ ((IoXmppStream)stream).write_obj = this;
+
+ stream.get_flag(Flag.IDENTITY).finished = true;
+ }
+
private void send_ack(XmppStream stream) {
StanzaNode node = new StanzaNode.build("a", NS_URI).add_self_xmlns().put_attribute("h", h_inbound.to_string());
write_node.begin(stream, node);
@@ -217,19 +238,73 @@ public class Module : XmppStreamNegotiationModule, WriteNodeFunc {
in_flight_stanzas.unset(nr);
}
}
-
- private bool stream_has_sm_feature(XmppStream stream) {
- return stream.features.get_subnode("sm", NS_URI) != null;
- }
}
public class Flag : XmppStreamFlag {
public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, "stream_management");
- public bool finished = false;
+ public bool finished { get; set; default=false; }
public bool resumed = false;
public override string get_ns() { return NS_URI; }
public override string get_id() { return IDENTITY.id; }
+
+ public static Flag get_add_flag(XmppStream stream) {
+ Flag? flag = stream.get_flag(IDENTITY);
+ if (flag == null) {
+ flag = new Flag();
+ stream.add_flag(flag);
+ }
+ return flag;
+ }
}
+ public class Bind2Activation : Bind2.Bind2InlineActivation {
+ public override StanzaNode? get_activation_node(XmppStream stream) {
+ // Always insert an enable node, even if we also try to resume in Sasl2. Because if resumption fails, enable will be used.
+ Flag.get_add_flag(stream);
+
+ stream.get_module(Module.IDENTITY).h_outbound = 0;
+
+ return new StanzaNode.build("enable", NS_URI).add_self_xmlns().put_attribute("resume", "true");
+ }
+
+ public override void on_bound(XmppStream stream, StanzaNode bound_node) {
+ StanzaNode? enabled_node = bound_node.get_subnode("enabled", NS_URI);
+ if (enabled_node != null) {
+ stream.get_module(Module.IDENTITY).on_enabled(stream, enabled_node);
+ }
+ }
+ }
+
+ public class Sasl2Activation : ExtensibleSaslProfile.Sasl2InlineActivation {
+ public override StanzaNode? get_activation_node(XmppStream stream, StanzaNode node) {
+ if (stream.get_module(Module.IDENTITY).session_id != null) {
+ Flag.get_add_flag(stream);
+
+ var sm_module = stream.get_module(Module.IDENTITY);
+
+ StanzaNode resume_node = new StanzaNode.build("resume", NS_URI).add_self_xmlns()
+ .put_attribute("h", sm_module.h_inbound.to_string())
+ .put_attribute("previd", sm_module.session_id);
+ return resume_node;
+ }
+ return null;
+ }
+
+ public override void on_bound(XmppStream stream, Jid authorization_identifier, StanzaNode success_node) {
+ StanzaNode? resumed_node = success_node.get_subnode("resumed", NS_URI);
+ if (resumed_node != null) {
+ stream.get_module(Module.IDENTITY).on_resumed(stream, resumed_node);
+ }
+
+ StanzaNode? failed_node = success_node.get_subnode("failed", NS_URI);
+ if (failed_node != null) {
+ stream.get_module(Module.IDENTITY).on_resume_failed(stream, failed_node);
+ }
+ }
+ }
+
+ private bool stream_has_sm_feature(XmppStream stream) {
+ return stream.features.get_subnode("sm", NS_URI) != null;
+ }
}