WIP XEP-0198: implement stream management

Stream management is enabled when server supports it. There is no option
to disable it.
This commit is contained in:
Dmitry Podgorny
2017-07-15 21:11:03 +03:00
committed by Steffen Jaeckel
parent 3600756723
commit 57bc4bbb75
4 changed files with 92 additions and 5 deletions

View File

@@ -92,6 +92,9 @@ static int
_handle_session(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata);
static int _handle_missing_session(xmpp_conn_t *conn, void *userdata);
static int _handle_missing_handshake(xmpp_conn_t *conn, void *userdata);
static int _handle_sm(xmpp_conn_t *const conn,
xmpp_stanza_t *const stanza,
void *const userdata);
/* stream:error handler */
static int
@@ -908,6 +911,12 @@ _handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
ns != NULL && strcmp(ns, XMPP_NS_SESSION) == 0;
}
opt = xmpp_stanza_get_child_by_ns(stanza, XMPP_NS_SM);
if (opt && strcmp(xmpp_stanza_get_name(opt), "sm") == 0) {
/* stream management supported */
conn->sm_support = 1;
}
/* if bind is required, go ahead and start it */
if (conn->bind_required) {
/* bind resource */
@@ -997,7 +1006,7 @@ static int
_handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
const char *type;
xmpp_stanza_t *iq, *session;
xmpp_stanza_t *iq, *enable, *session, *binding, *jid_stanza;
UNUSED(userdata);
@@ -1010,12 +1019,11 @@ _handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
strophe_error(conn->ctx, "xmpp", "Binding failed.");
xmpp_disconnect(conn);
} else if (type && strcmp(type, "result") == 0) {
xmpp_stanza_t *binding = xmpp_stanza_get_child_by_name(stanza, "bind");
binding = xmpp_stanza_get_child_by_name(stanza, "bind");
strophe_debug(conn->ctx, "xmpp", "Bind successful.");
if (binding) {
xmpp_stanza_t *jid_stanza =
xmpp_stanza_get_child_by_name(binding, "jid");
jid_stanza = xmpp_stanza_get_child_by_name(binding, "jid");
if (jid_stanza) {
conn->bound_jid = xmpp_stanza_get_text(jid_stanza);
}
@@ -1051,7 +1059,23 @@ _handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
/* send session establishment request */
xmpp_send(conn, iq);
xmpp_stanza_release(iq);
} else {
}
if (conn->sm_support) {
enable = xmpp_stanza_new(conn->ctx);
if (!enable) {
disconnect_mem_error(conn);
return 0;
}
xmpp_stanza_set_name(enable, "enable");
xmpp_stanza_set_ns(enable, XMPP_NS_SM);
handler_add(conn, _handle_sm, XMPP_NS_SM, NULL, NULL, NULL);
xmpp_send(conn, enable);
xmpp_stanza_release(enable);
conn->sm_sent_nr = 0;
}
if (!conn->session_required) {
_auth_success(conn);
}
} else {
@@ -1120,6 +1144,23 @@ static int _handle_missing_legacy(xmpp_conn_t *conn, void *userdata)
return 0;
}
static int _handle_sm(xmpp_conn_t *const conn,
xmpp_stanza_t *const stanza,
void *const userdata)
{
const char *name;
name = xmpp_stanza_get_name(stanza);
if (name && strcmp(name, "enabled") == 0) {
conn->sm_enabled = 1;
conn->sm_handled_nr = 0;
} else {
conn->sm_enabled = 0;
strophe_warn(conn->ctx, "auth", "Stream management failed.");
}
return 0;
}
static int
_handle_legacy(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{

View File

@@ -204,6 +204,10 @@ struct _xmpp_conn_t {
/* if server returns <bind/> or <session/> we must do them */
int bind_required;
int session_required;
int sm_support;
int sm_enabled;
uint32_t sm_handled_nr;
uint32_t sm_sent_nr;
char *lang;
char *domain;

View File

@@ -94,6 +94,8 @@ static void _conn_attributes_destroy(xmpp_conn_t *conn,
static void _handle_stream_start(char *name, char **attrs, void *userdata);
static void _handle_stream_end(char *name, void *userdata);
static void _handle_stream_stanza(xmpp_stanza_t *stanza, void *userdata);
static void _conn_sm_handle_stanza(xmpp_conn_t *const conn,
xmpp_stanza_t *stanza);
static unsigned short _conn_default_port(xmpp_conn_t *conn,
xmpp_conn_type_t type);
static void _conn_reset(xmpp_conn_t *conn);
@@ -189,6 +191,10 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx)
conn->bind_required = 0;
conn->session_required = 0;
conn->sm_support = 0;
conn->sm_enabled = 0;
conn->sm_handled_nr = 0;
conn->sm_sent_nr = 0;
conn->parser =
parser_new(conn->ctx, _handle_stream_start, _handle_stream_end,
@@ -1486,6 +1492,36 @@ static void _handle_stream_stanza(xmpp_stanza_t *stanza, void *userdata)
}
handler_fire_stanza(conn, stanza);
if (conn->sm_enabled)
_conn_sm_handle_stanza(conn, stanza);
}
/* XEP-0198 stream management */
static void _conn_sm_handle_stanza(xmpp_conn_t *const conn,
xmpp_stanza_t *stanza)
{
xmpp_stanza_t *a;
const char *name;
const char *ns;
char h[11];
ns = xmpp_stanza_get_ns(stanza);
if (ns && strcmp(ns, XMPP_NS_SM) != 0)
++conn->sm_handled_nr;
else {
name = xmpp_stanza_get_name(stanza);
if (name && strcmp(name, "r") == 0) {
a = xmpp_stanza_new(conn->ctx);
if (!a)
return; /* XXX */
xmpp_stanza_set_name(a, "a");
xmpp_stanza_set_ns(a, XMPP_NS_SM);
strophe_snprintf(h, sizeof(h), "%u", conn->sm_handled_nr);
xmpp_stanza_set_attribute(a, "h", h);
xmpp_send(conn, a);
xmpp_stanza_release(a);
}
}
}
static unsigned short _conn_default_port(xmpp_conn_t *conn,
@@ -1547,6 +1583,8 @@ static void _conn_reset(xmpp_conn_t *conn)
conn->error = 0;
conn->tls_support = 0;
conn->sm_support = 0;
conn->sm_enabled = 0;
conn->bind_required = 0;
conn->session_required = 0;

View File

@@ -79,6 +79,10 @@ extern "C" {
* Namespace definition for 'jabber:iq:register'.
*/
#define XMPP_NS_REGISTER "jabber:iq:register"
/** @def XMPP_NS_SM
* Namespace definition for Stream Management.
*/
#define XMPP_NS_SM "urn:xmpp:sm:3"
/* error defines */
/** @def XMPP_EOK