From aec7afd06af37767abdd7a6bedb7bafba41bb886 Mon Sep 17 00:00:00 2001 From: James Booth Date: Sun, 30 Nov 2014 00:37:36 +0000 Subject: Added caching of legacy capabilities --- src/xmpp/iq.c | 202 ++++++++++++++++++++++++++++++++++++++++++++-------- src/xmpp/presence.c | 14 ++-- src/xmpp/xmpp.h | 2 + 3 files changed, 185 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index 1138620d..2292e9c4 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -96,6 +96,10 @@ static int _ping_timed_handler(xmpp_conn_t * const conn, void * const userdata); static int _caps_response_handler(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _caps_response_handler_for_jid(xmpp_conn_t *const conn, + xmpp_stanza_t * const stanza, void * const userdata); +static int _caps_response_handler_legacy(xmpp_conn_t *const conn, + xmpp_stanza_t * const stanza, void * const userdata); void iq_add_handlers(void) @@ -201,7 +205,7 @@ _iq_send_caps_request_for_jid(const char * const to, const char * const id, xmpp_stanza_t *iq = stanza_create_disco_info_iq(ctx, id, to, node_str->str); g_string_free(node_str, TRUE); - xmpp_id_handler_add(conn, _caps_response_handler, id, strdup(to)); + xmpp_id_handler_add(conn, _caps_response_handler_for_jid, id, strdup(to)); xmpp_send(conn, iq); xmpp_stanza_release(iq); @@ -234,6 +238,33 @@ _iq_send_caps_request(const char * const to, const char * const id, xmpp_stanza_release(iq); } +static void +_iq_send_caps_request_legacy(const char * const to, const char * const id, + const char * const node, const char * const ver) +{ + xmpp_conn_t * const conn = connection_get_conn(); + xmpp_ctx_t * const ctx = connection_get_ctx(); + + if (!node) { + log_error("Could not create caps request, no node"); + return; + } + if (!ver) { + log_error("Could not create caps request, no ver"); + return; + } + + GString *node_str = g_string_new(""); + g_string_printf(node_str, "%s#%s", node, ver); + xmpp_stanza_t *iq = stanza_create_disco_info_iq(ctx, id, to, node_str->str); + + xmpp_id_handler_add(conn, _caps_response_handler_legacy, id, node_str->str); + g_string_free(node_str, FALSE); + + xmpp_send(conn, iq); + xmpp_stanza_release(iq); +} + static void _iq_disco_items_request(gchar *jid) { @@ -521,40 +552,154 @@ _caps_response_handler(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, return 0; } - if (userdata) { - char *jid = (char *)userdata; - log_info("Associating capabilities with: %s", jid); - Capabilities *capabilities = caps_create(query); - caps_add_by_jid(jid, capabilities); + // validate sha1 + gchar **split = g_strsplit(node, "#", -1); + char *given_sha1 = split[1]; + char *generated_sha1 = caps_create_sha1_str(query); + + if (g_strcmp0(given_sha1, generated_sha1) != 0) { + log_warning("Generated sha-1 does not match given:"); + log_warning("Generated : %s", generated_sha1); + log_warning("Given : %s", given_sha1); } else { - // validate sha1 - gchar **split = g_strsplit(node, "#", -1); - char *given_sha1 = split[1]; - char *generated_sha1 = caps_create_sha1_str(query); - - if (g_strcmp0(given_sha1, generated_sha1) != 0) { - log_warning("Generated sha-1 does not match given:"); - log_warning("Generated : %s", generated_sha1); - log_warning("Given : %s", given_sha1); + log_info("Valid SHA-1 hash found: %s", given_sha1); + + if (caps_contains(given_sha1)) { + log_info("Capabilties already cached: %s", given_sha1); } else { - log_info("Valid SHA-1 hash found: %s", given_sha1); - - if (caps_contains(given_sha1)) { - log_info("Capabilties already cached: %s", given_sha1); - } else { - log_info("Capabilities not cached: %s, storing", given_sha1); - Capabilities *capabilities = caps_create(query); - caps_add_by_ver(given_sha1, capabilities); - caps_destroy(capabilities); - } + log_info("Capabilities not cached: %s, storing", given_sha1); + Capabilities *capabilities = caps_create(query); + caps_add_by_ver(given_sha1, capabilities); + caps_destroy(capabilities); + } + + caps_map_jid_to_ver(from, given_sha1); + } - caps_map_jid_to_ver(from, given_sha1); + g_free(generated_sha1); + g_strfreev(split); + + return 0; +} + +static int +_caps_response_handler_for_jid(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, + void * const userdata) +{ + const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); + xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); + + char *type = xmpp_stanza_get_type(stanza); + // ignore non result + if ((g_strcmp0(type, "get") == 0) || (g_strcmp0(type, "set") == 0)) { + return 1; + } + + if (id) { + log_info("Capabilities response handler fired for id %s", id); + } else { + log_info("Capabilities response handler fired"); + } + + const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); + if (!from) { + log_info("No from attribute"); + return 0; + } + + // handle error responses + if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { + char *error_message = stanza_get_error_message(stanza); + log_warning("Error received for capabilities response from %s: ", from, error_message); + free(error_message); + return 0; + } + + if (query == NULL) { + log_warning("No query element found."); + return 0; + } + + char *node = xmpp_stanza_get_attribute(query, STANZA_ATTR_NODE); + if (node == NULL) { + log_warning("No node attribute found"); + return 0; + } + + char *jid = (char *)userdata; + log_info("Associating capabilities with: %s", jid); + Capabilities *capabilities = caps_create(query); + caps_add_by_jid(jid, capabilities); + + return 0; +} + +static int +_caps_response_handler_legacy(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, + void * const userdata) +{ + const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); + xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); + + char *type = xmpp_stanza_get_type(stanza); + // ignore non result + if ((g_strcmp0(type, "get") == 0) || (g_strcmp0(type, "set") == 0)) { + return 1; + } + + if (id) { + log_info("Capabilities response handler fired for id %s", id); + } else { + log_info("Capabilities response handler fired"); + } + + const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); + if (!from) { + log_info("No from attribute"); + return 0; + } + + // handle error responses + if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { + char *error_message = stanza_get_error_message(stanza); + log_warning("Error received for capabilities response from %s: ", from, error_message); + free(error_message); + return 0; + } + + if (query == NULL) { + log_warning("No query element found."); + return 0; + } + + char *node = xmpp_stanza_get_attribute(query, STANZA_ATTR_NODE); + if (node == NULL) { + log_warning("No node attribute found"); + return 0; + } + + char *expected_node = (char *)userdata; + + // nodes match + if (g_strcmp0(expected_node, node) == 0) { + log_info("Legacy capabilities, nodes match %s", node); + if (caps_contains(node)) { + log_info("Capabilties already cached: %s", node); + } else { + log_info("Capabilities not cached: %s, storing", node); + Capabilities *capabilities = caps_create(query); + caps_add_by_ver(node, capabilities); + caps_destroy(capabilities); } - g_free(generated_sha1); - g_strfreev(split); + caps_map_jid_to_ver(from, node); + + // node match fail + } else { + log_info("Legacy Capabilities nodes do not match, expeceted %s, given %s.", expected_node, node); } + free(expected_node); return 0; } @@ -1295,6 +1440,7 @@ iq_init_module(void) iq_submit_room_config = _iq_submit_room_config; iq_send_caps_request = _iq_send_caps_request; iq_send_caps_request_for_jid = _iq_send_caps_request_for_jid; + iq_send_caps_request_legacy = _iq_send_caps_request_legacy; iq_room_info_request = _iq_room_info_request; iq_room_affiliation_set = _iq_room_affiliation_set; iq_room_affiliation_list = _iq_room_affiliation_list; diff --git a/src/xmpp/presence.c b/src/xmpp/presence.c index 5acec9da..9e24c7ac 100644 --- a/src/xmpp/presence.c +++ b/src/xmpp/presence.c @@ -502,7 +502,7 @@ _unavailable_handler(xmpp_conn_t * const conn, static void _handle_caps(char *jid, XMPPCaps *caps) { - // hash supported xep-0115 + // hash supported, xep-0115, cache against ver if (g_strcmp0(caps->hash, "sha-1") == 0) { log_info("Hash %s supported", caps->hash); if (caps->ver) { @@ -517,17 +517,21 @@ _handle_caps(char *jid, XMPPCaps *caps) } } - // unsupported hash + // unsupported hash, xep-0115, assoiciate with JID, no cache } else if (caps->hash) { log_info("Hash %s not supported: %s, sending service discovery request", caps->hash, jid); char *id = create_unique_id("caps"); iq_send_caps_request_for_jid(jid, id, caps->node, caps->ver); free(id); - // no hash + // no hash, legacy caps, cache against node#ver + } else if (caps->node && caps->ver) { + log_info("No hash specified: %s, legacy request made for %s#%s", jid, caps->node, caps->ver); + char *id = create_unique_id("caps"); + iq_send_caps_request_legacy(jid, id, caps->node, caps->ver); + free(id); } else { - log_info("No hash specified: %s, not sending service discovery request", jid); - // do legacy + log_info("No hash specified: %s, could not create ver string, not sending service disovery request.", jid); } } diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index 349f8638..f300e84f 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -194,6 +194,8 @@ void (*iq_send_caps_request)(const char * const to, const char * const id, const char * const node, const char * const ver); void (*iq_send_caps_request_for_jid)(const char * const to, const char * const id, const char * const node, const char * const ver); +void (*iq_send_caps_request_legacy)(const char * const to, const char * const id, + const char * const node, const char * const ver); void (*iq_room_info_request)(gchar *room); void (*iq_room_affiliation_list)(const char * const room, char *affiliation); void (*iq_room_affiliation_set)(const char * const room, const char * const jid, char *affiliation, -- cgit 1.4.1-2-gfad0