From 0407b0b1aef34047e9133776944298919f467cee Mon Sep 17 00:00:00 2001 From: Ferdinand Stehle Date: Thu, 23 Oct 2014 21:07:09 +0200 Subject: [PATCH 1/4] Enabling a session and replying ack-requests. --- wocky/Makefile.am | 2 + wocky/wocky-connector.c | 112 ++++++++++++++++++--- wocky/wocky-debug.c | 1 + wocky/wocky-debug.h | 1 + wocky/wocky-namespaces.h | 3 + wocky/wocky-sm.c | 219 ++++++++++++++++++++++++++++++++++++++++++ wocky/wocky-sm.h | 80 +++++++++++++++ wocky/wocky-stanza.c | 16 +++ wocky/wocky-stanza.h | 6 ++ wocky/wocky-xmpp-connection.c | 10 ++ wocky/wocky-xmpp-connection.h | 3 + wocky/wocky-xmpp-reader.c | 38 ++++++++ wocky/wocky-xmpp-reader.h | 2 + wocky/wocky.h | 1 + 14 files changed, 483 insertions(+), 11 deletions(-) create mode 100644 wocky/wocky-sm.c create mode 100644 wocky/wocky-sm.h diff --git a/wocky/Makefile.am b/wocky/Makefile.am index 1917a58..752c259 100644 --- a/wocky/Makefile.am +++ b/wocky/Makefile.am @@ -104,6 +104,7 @@ handwritten_headers = \ wocky-sasl-scram.h \ wocky-sasl-plain.h \ wocky-session.h \ + wocky-sm.h \ wocky-stanza.h \ wocky-tls.h \ wocky-tls-handler.h \ @@ -170,6 +171,7 @@ handwritten_sources = \ wocky-sasl-utils.c \ wocky-sasl-plain.c \ wocky-session.c \ + wocky-sm.c \ wocky-stanza.c \ wocky-utils.c \ wocky-tls-common.c \ diff --git a/wocky/wocky-connector.c b/wocky/wocky-connector.c index 89f4369..f2b2336 100644 --- a/wocky/wocky-connector.c +++ b/wocky/wocky-connector.c @@ -48,15 +48,15 @@ * │ ↓ * └→ maybe_old_ssl * ↓ - * xmpp_init ←─────────────────┬──┐ - * ↓ │ │ - * xmpp_init_sent_cb │ │ - * ↓ │ │ - * xmpp_init_recv_cb │ │ - * │ ↓ │ │ - * │ xmpp_features_cb │ │ - * │ │ │ ↓ │ │ - * │ │ │ tls_module_secure_cb ─┘ │ ① + * xmpp_init ←─────────────────┬────────────┐ + * ↓ │ │ + * xmpp_init_sent_cb │ │ + * ↓ │ │ + * xmpp_init_recv_cb │ │ + * │ ↓ │ │ + * │ xmpp_features_cb │ │ + * │ │ │ ↓ │ │ + * │ │ │ tls_module_secure_cb ─┘ │ ① * │ │ ↓ │ ↑ * │ │ sasl_request_auth │ jabber_auth_done * │ │ ↓ │ ↑ @@ -68,11 +68,17 @@ * │ ↓ │ * │ iq_bind_resource_recv_cb │ * │ ↓ │ - * │ ① │ + * │ ① │ * └──────────[old auth]────────────────────┘ * * ① * ↓ + * sm_enable + * ↓ + * sm_enable_sent_cb + * ↓ + * sm_enable_recv_cb + * ↓ * establish_session ─────────→ success * ↓ ↑ * establish_session_sent_cb │ @@ -187,6 +193,10 @@ static void iq_bind_resource_recv_cb (GObject *source, GAsyncResult *result, gpointer data); +static void sm_enable(WockyConnector *self); +static void sm_enable_sent_cb (GObject *source, GAsyncResult *result, gpointer data); +static void sm_enable_recv_cb (GObject *source, GAsyncResult *result, gpointer data); + void establish_session (WockyConnector *self); static void establish_session_sent_cb (GObject *source, GAsyncResult *result, @@ -1246,6 +1256,7 @@ xmpp_features_cb (GObject *source, WockyNode *node; gboolean can_encrypt = FALSE; gboolean can_bind = FALSE; + gboolean can_sm = FALSE; stanza = wocky_xmpp_connection_recv_stanza_finish (priv->conn, result, &error); @@ -1285,6 +1296,14 @@ xmpp_features_cb (GObject *source, wocky_node_get_child_ns (node, "starttls", WOCKY_XMPP_NS_TLS) != NULL; can_bind = wocky_node_get_child_ns (node, "bind", WOCKY_XMPP_NS_BIND) != NULL; + can_sm = + wocky_node_get_child_ns (node, "sm", WOCKY_NS_STREAM_MANAGEMENT) != NULL; + + + if (can_sm) + g_warning ("stream supports stream management!"); + else + g_warning ("stream does NOT support stream management!"); /* conditions: * not encrypted, not encryptable, require encryption → ABORT @@ -1902,6 +1921,69 @@ xep77_signup_recv (GObject *source, } /* ************************************************************************* */ +/* Stream Management calls */ +static void sm_enable(WockyConnector *self) +{ + + WockyConnectorPrivate *priv = self->priv; + WockyStanza *enable = wocky_stanza_new("enable", WOCKY_NS_STREAM_MANAGEMENT); + + DEBUG ("sending sm enable stanza"); + wocky_xmpp_connection_send_stanza_async (priv->conn, enable, priv->cancellable, + sm_enable_sent_cb, self); + +} + +static void +sm_enable_sent_cb (GObject *source, + GAsyncResult *result, + gpointer data) +{ + GError *error = NULL; + WockyConnector *self = WOCKY_CONNECTOR (data); + WockyConnectorPrivate *priv = self->priv; + + DEBUG ("sm_enable_sent_cb"); + + if (!wocky_xmpp_connection_send_stanza_finish (priv->conn, result, &error)) + { + abort_connect_error (self, &error, "Failed to enable sm!"); + g_error_free (error); + return; + } + + wocky_xmpp_connection_recv_stanza_async (priv->conn, priv->cancellable, + sm_enable_recv_cb, data); +} +static void +sm_enable_recv_cb (GObject *source, + GAsyncResult *result, + gpointer data) +{ + GError *error = NULL; + WockyConnector *self = WOCKY_CONNECTOR (data); + WockyConnectorPrivate *priv = self->priv; + WockyStanza *reply = NULL; + + + reply = wocky_xmpp_connection_recv_stanza_finish (priv->conn, result, &error); + + if (reply == NULL) + { + abort_connect_error (self, &error, "Failed to receive sm enable result"); + g_error_free (error); + return; + } + + wocky_xmpp_connection_set_stanza_recv_count(priv->conn, 0); + + DEBUG("sm_complete: now est_ session"); + establish_session (self); + + g_object_unref (reply); +} + +/* ************************************************************************* */ /* BIND calls */ static void iq_bind_resource (WockyConnector *self) @@ -2026,7 +2108,15 @@ iq_bind_resource_recv_cb (GObject *source, priv->identity = g_strdup (priv->jid); priv->state = WCON_XMPP_BOUND; - establish_session (self); + + node = wocky_stanza_get_top_node (priv->features); + + if (wocky_node_get_child_ns (node, "sm", WOCKY_NS_STREAM_MANAGEMENT) != NULL) + sm_enable (self); + else + establish_session (self); + + break; default: diff --git a/wocky/wocky-debug.c b/wocky/wocky-debug.c index f313dae..f2c134b 100644 --- a/wocky/wocky-debug.c +++ b/wocky/wocky-debug.c @@ -37,6 +37,7 @@ static GDebugKey keys[] = { { "presence", WOCKY_DEBUG_PRESENCE }, { "connection-factory",WOCKY_DEBUG_CONNECTION_FACTORY}, { "media", WOCKY_DEBUG_JINGLE }, + { "streammanagement", WOCKY_DEBUG_SM }, { 0, }, }; diff --git a/wocky/wocky-debug.h b/wocky/wocky-debug.h index e48fec3..28e0e77 100644 --- a/wocky/wocky-debug.h +++ b/wocky/wocky-debug.h @@ -32,6 +32,7 @@ typedef enum WOCKY_DEBUG_PRESENCE = 1 << 19, WOCKY_DEBUG_CONNECTION_FACTORY= 1 << 20, WOCKY_DEBUG_JINGLE = 1 << 21, + WOCKY_DEBUG_SM = 1 << 22, } WockyDebugFlags; #define WOCKY_DEBUG_XMPP (WOCKY_DEBUG_XMPP_READER | WOCKY_DEBUG_XMPP_WRITER) diff --git a/wocky/wocky-namespaces.h b/wocky/wocky-namespaces.h index 9896c4f..b65c15a 100644 --- a/wocky/wocky-namespaces.h +++ b/wocky/wocky-namespaces.h @@ -210,4 +210,7 @@ #define WOCKY_NS_VCARD_TEMP "vcard-temp" #define WOCKY_NS_VCARD_TEMP_UPDATE "vcard-temp:x:update" +/* XEP-0198 (Stream Management) */ +#define WOCKY_NS_STREAM_MANAGEMENT "urn:xmpp:sm:3" + #endif /* #ifndef __WOCKY_NAMESPACES_H__ */ diff --git a/wocky/wocky-sm.c b/wocky/wocky-sm.c new file mode 100644 index 0000000..156057e --- /dev/null +++ b/wocky/wocky-sm.c @@ -0,0 +1,219 @@ +/* + * wocky-sm.c - Source for WockySM + * Copyright (C) 2010 Collabora Ltd. + * @author Senko Rasic + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * SECTION: wocky-sm + * @title: WockySM + * @short_description: support for stream management stanza acking + * + * Support for XEP-0198 stream management. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "wocky-sm.h" + +#include "wocky-namespaces.h" +#include "wocky-stanza.h" + +#include + +#define WOCKY_DEBUG_FLAG WOCKY_DEBUG_SM +#include "wocky-debug-internal.h" + +G_DEFINE_TYPE (WockySM, wocky_sm, G_TYPE_OBJECT) + +/* properties */ +enum +{ + PROP_PORTER = 1, +}; + +/* private structure */ +struct _WockySMPrivate +{ + WockyC2SPorter *porter; + + gulong sm_iq_cb; + + gboolean dispose_has_run; +}; + +static gboolean sm_r_cb (WockyPorter *porter, WockyStanza *stanza, + gpointer data); + +static void +wocky_sm_init (WockySM *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, WOCKY_TYPE_SM, + WockySMPrivate); +} + +static void +wocky_sm_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + WockySM *self = WOCKY_SM (object); + WockySMPrivate *priv = self->priv; + + switch (property_id) + { + case PROP_PORTER: + priv->porter = g_value_dup_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +wocky_sm_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + WockySM *self = WOCKY_SM (object); + WockySMPrivate *priv = self->priv; + + switch (property_id) + { + case PROP_PORTER: + g_value_set_object (value, priv->porter); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +wocky_sm_constructed (GObject *object) +{ + WockySM *self = WOCKY_SM (object); + WockySMPrivate *priv = self->priv; + + g_assert (priv->porter != NULL); + + g_warning("Register SM R handler"); + priv->sm_iq_cb = wocky_porter_register_handler_from_anyone ( + WOCKY_PORTER (priv->porter), + WOCKY_STANZA_TYPE_SM_R, WOCKY_STANZA_SUB_TYPE_NONE, + WOCKY_PORTER_HANDLER_PRIORITY_NORMAL, sm_r_cb, self, NULL); +} + +static void +wocky_sm_dispose (GObject *object) +{ + WockySM *self = WOCKY_SM (object); + WockySMPrivate *priv = self->priv; + + if (priv->dispose_has_run) + return; + + priv->dispose_has_run = TRUE; + + if (priv->sm_iq_cb != 0) + { + wocky_porter_unregister_handler (WOCKY_PORTER (priv->porter), + priv->sm_iq_cb); + priv->sm_iq_cb = 0; + } + + g_object_unref (priv->porter); + priv->porter = NULL; + + if (G_OBJECT_CLASS (wocky_sm_parent_class)->dispose) + G_OBJECT_CLASS (wocky_sm_parent_class)->dispose (object); +} + +static void +wocky_sm_class_init (WockySMClass *wocky_sm_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (wocky_sm_class); + GParamSpec *spec; + + g_type_class_add_private (wocky_sm_class, + sizeof (WockySMPrivate)); + + object_class->constructed = wocky_sm_constructed; + object_class->set_property = wocky_sm_set_property; + object_class->get_property = wocky_sm_get_property; + object_class->dispose = wocky_sm_dispose; + + spec = g_param_spec_object ("porter", "Wocky C2S porter", + "the wocky porter to set up sm acks on", + WOCKY_TYPE_C2S_PORTER, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_PORTER, spec); +} + +WockySM * +wocky_sm_new (WockyC2SPorter *porter) +{ + g_return_val_if_fail (WOCKY_IS_C2S_PORTER (porter), NULL); + + return g_object_new (WOCKY_TYPE_SM, + "porter", porter, + NULL); +} + + +/** +* sm_r_cb +* @porter: WockyPorter object +* @stanza: The originally received stanza +* @data: unused user data +* +* Callback function handling stream management -stanzas by replying +* the number of received stanzas. +*/ +static gboolean +sm_r_cb (WockyPorter *porter, WockyStanza *stanza, gpointer data) +{ + //BUILD A stanza + WockyStanza *result = wocky_stanza_new("a", WOCKY_NS_STREAM_MANAGEMENT); + WockyNode* node = wocky_stanza_get_top_node(result); + + guint count = wocky_stanza_get_recv_count(stanza); + + char buffer[12]; + + sprintf(buffer, "%d", count); + + wocky_node_set_attribute (node, "h", buffer); + + //SEND stanza + if (result != NULL) + { + wocky_porter_send (porter, result); + g_object_unref (result); + } + + return TRUE; +} + + + diff --git a/wocky/wocky-sm.h b/wocky/wocky-sm.h new file mode 100644 index 0000000..a8d99b3 --- /dev/null +++ b/wocky/wocky-sm.h @@ -0,0 +1,80 @@ +/* + * wocky-sm.h - Header for WockySM (Stream Management) + * Copyright (C) 2010 Collabora Ltd. + * @author Senko Rasic + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#if !defined (WOCKY_H_INSIDE) && !defined (WOCKY_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __WOCKY_SM_H__ +#define __WOCKY_SM_H__ + +#include + +#include "wocky-types.h" +#include "wocky-c2s-porter.h" + +G_BEGIN_DECLS + +typedef struct _WockySM WockySM; + +/** + * WockySMClass: + * + * The class of a #WockySM. + */ +typedef struct _WockySMClass WockySMClass; +typedef struct _WockySMPrivate WockySMPrivate; + +GQuark wocky_sm_error_quark (void); + +struct _WockySMClass { + /**/ + GObjectClass parent_class; +}; + +struct _WockySM { + /**/ + GObject parent; + + WockySMPrivate *priv; +}; + +GType wocky_sm_get_type (void); + +#define WOCKY_TYPE_SM \ + (wocky_sm_get_type ()) +#define WOCKY_SM(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), WOCKY_TYPE_SM, \ + WockySM)) +#define WOCKY_SM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), WOCKY_TYPE_SM, \ + WockySMClass)) +#define WOCKY_IS_SM(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), WOCKY_TYPE_SM)) +#define WOCKY_IS_SM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), WOCKY_TYPE_SM)) +#define WOCKY_SM_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), WOCKY_TYPE_SM, \ + WockySMClass)) + +WockySM * wocky_sm_new (WockyC2SPorter *porter); + +G_END_DECLS + +#endif /* #ifndef __WOCKY_SM_H__ */ diff --git a/wocky/wocky-stanza.c b/wocky/wocky-stanza.c index a44fe6a..e722bc0 100644 --- a/wocky/wocky-stanza.c +++ b/wocky/wocky-stanza.c @@ -41,6 +41,7 @@ struct _WockyStanzaPrivate WockyContact *from_contact; WockyContact *to_contact; + guint recv_count; gboolean dispose_has_run; }; @@ -78,6 +79,10 @@ static StanzaTypeName type_names[NUM_WOCKY_STANZA_TYPE] = WOCKY_XMPP_NS_SASL_AUTH }, { WOCKY_STANZA_TYPE_STREAM_ERROR, "error", WOCKY_XMPP_NS_STREAM }, + { WOCKY_STANZA_TYPE_ENABLE, "enable", + WOCKY_NS_STREAM_MANAGEMENT }, + { WOCKY_STANZA_TYPE_SM_R, "r", + WOCKY_NS_STREAM_MANAGEMENT }, { WOCKY_STANZA_TYPE_UNKNOWN, NULL, NULL }, }; @@ -777,6 +782,17 @@ wocky_stanza_get_to (WockyStanza *self) return wocky_node_get_attribute (wocky_stanza_get_top_node (self), "to"); } +guint +wocky_stanza_get_recv_count (WockyStanza *self) +{ + return self->priv->recv_count; +} +void +wocky_stanza_set_recv_count (WockyStanza *self, guint count) +{ + self->priv->recv_count = count; +} + WockyContact * wocky_stanza_get_to_contact (WockyStanza *self) { diff --git a/wocky/wocky-stanza.h b/wocky/wocky-stanza.h index bcca670..0fb2d54 100644 --- a/wocky/wocky-stanza.h +++ b/wocky/wocky-stanza.h @@ -86,6 +86,7 @@ GType wocky_stanza_get_type (void); * @WOCKY_STANZA_TYPE_SUCCESS: <success/> stanza * @WOCKY_STANZA_TYPE_FAILURE: <failure/> stanza * @WOCKY_STANZA_TYPE_STREAM_ERROR: <stream:error/> stanza + * @WOCKY_STANZA_TYPE_ENABLE: <enable/> stanza * @WOCKY_STANZA_TYPE_UNKNOWN: unknown stanza type * * XMPP stanza types. @@ -104,6 +105,8 @@ typedef enum WOCKY_STANZA_TYPE_SUCCESS, WOCKY_STANZA_TYPE_FAILURE, WOCKY_STANZA_TYPE_STREAM_ERROR, + WOCKY_STANZA_TYPE_ENABLE, + WOCKY_STANZA_TYPE_SM_R, WOCKY_STANZA_TYPE_UNKNOWN, /*< private >*/ NUM_WOCKY_STANZA_TYPE @@ -175,6 +178,7 @@ gboolean wocky_stanza_has_type (WockyStanza *stanza, const gchar *wocky_stanza_get_from (WockyStanza *self); const gchar *wocky_stanza_get_to (WockyStanza *self); +guint wocky_stanza_get_recv_count (WockyStanza *self); WockyStanza * wocky_stanza_build_va (WockyStanzaType type, WockyStanzaSubType sub_type, @@ -210,6 +214,8 @@ void wocky_stanza_set_to_contact (WockyStanza *self, WockyContact *contact); void wocky_stanza_set_from_contact (WockyStanza *self, WockyContact *contact); +void wocky_stanza_set_recv_count (WockyStanza *self, + guint count); G_END_DECLS diff --git a/wocky/wocky-xmpp-connection.c b/wocky/wocky-xmpp-connection.c index 6097763..541f35a 100644 --- a/wocky/wocky-xmpp-connection.c +++ b/wocky/wocky-xmpp-connection.c @@ -1231,3 +1231,13 @@ wocky_xmpp_connection_force_close_finish ( return TRUE; } +guint +wocky_xmpp_connection_get_stanza_recv_count (WockyXmppConnection *connection) +{ + return wocky_xmpp_reader_get_recv_count (connection->priv->reader); +} +void +wocky_xmpp_connection_set_stanza_recv_count (WockyXmppConnection *connection, guint count) +{ + wocky_xmpp_reader_set_recv_count (connection->priv->reader, count); +} diff --git a/wocky/wocky-xmpp-connection.h b/wocky/wocky-xmpp-connection.h index edbd106..72cd588 100644 --- a/wocky/wocky-xmpp-connection.h +++ b/wocky/wocky-xmpp-connection.h @@ -190,6 +190,9 @@ void wocky_xmpp_connection_reset (WockyXmppConnection *connection); gchar * wocky_xmpp_connection_new_id (WockyXmppConnection *self); +guint wocky_xmpp_connection_get_stanza_recv_count (WockyXmppConnection *connection); +void wocky_xmpp_connection_set_stanza_recv_count (WockyXmppConnection *connection, guint count); + G_END_DECLS #endif /* #ifndef __WOCKY_XMPP_CONNECTION_H__*/ diff --git a/wocky/wocky-xmpp-reader.c b/wocky/wocky-xmpp-reader.c index f0eaa92..7a84086 100644 --- a/wocky/wocky-xmpp-reader.c +++ b/wocky/wocky-xmpp-reader.c @@ -128,6 +128,7 @@ struct _WockyXmppReaderPrivate gchar *default_namespace; GQueue *stanzas; WockyXmppReaderState state; + guint stanza_read_count; }; /** @@ -223,6 +224,7 @@ wocky_xmpp_reader_init (WockyXmppReader *self) priv->nodes = g_queue_new (); priv->stanzas = g_queue_new (); + priv->stanza_read_count = 0; } static void wocky_xmpp_reader_dispose (GObject *object); @@ -657,7 +659,18 @@ _end_element_ns (void *user_data, const xmlChar *localname, { g_assert (g_queue_get_length (priv->nodes) == 0); DEBUG_STANZA (priv->stanza, "Received stanza"); + + if(!wocky_stanza_has_type(priv->stanza, WOCKY_STANZA_TYPE_SM_R)) + priv->stanza_read_count ++; + + wocky_stanza_set_recv_count (priv->stanza, priv->stanza_read_count); + + char buffer[30]; + sprintf(buffer, "Increased_Stanza_Count:_%d", priv->stanza_read_count); + g_warning(buffer); + g_queue_push_tail (priv->stanzas, priv->stanza); + priv->stanza = NULL; priv->node = NULL; } @@ -828,3 +841,28 @@ wocky_xmpp_reader_reset (WockyXmppReader *reader) wocky_xmpp_reader_clear_parser_state (reader); wocky_init_xml_parser (reader); } +/** + * wocky_xmpp_reader_get_recv_count: + * @reader: a #WockyXmppReader + * + * Get the internal received stanza counter value. + * + */ +guint +wocky_xmpp_reader_get_recv_count (WockyXmppReader *reader) +{ + return reader->priv->stanza_read_count; +} +/** + * wocky_xmpp_reader_set_recv_count: + * @reader: a #WockyXmppReader + * @count: the new value of the counter value. + * + * Set the internal received stanza counter value. + * + */ +void +wocky_xmpp_reader_set_recv_count (WockyXmppReader *reader, guint count) +{ + reader->priv->stanza_read_count = count; +} diff --git a/wocky/wocky-xmpp-reader.h b/wocky/wocky-xmpp-reader.h index f8bc29f..dc491da 100644 --- a/wocky/wocky-xmpp-reader.h +++ b/wocky/wocky-xmpp-reader.h @@ -130,6 +130,8 @@ WockyStanza *wocky_xmpp_reader_peek_stanza (WockyXmppReader *reader); GError *wocky_xmpp_reader_get_error (WockyXmppReader *reader); void wocky_xmpp_reader_reset (WockyXmppReader *reader); +guint wocky_xmpp_reader_get_recv_count (WockyXmppReader *reader); +void wocky_xmpp_reader_set_recv_count (WockyXmppReader *reader, guint count); G_END_DECLS diff --git a/wocky/wocky.h b/wocky/wocky.h index f3449d6..a4b287a 100644 --- a/wocky/wocky.h +++ b/wocky/wocky.h @@ -76,6 +76,7 @@ #include "wocky-sasl-utils.h" #include "wocky-session.h" #include "wocky-stanza.h" +#include "wocky-sm.h" #include "wocky-tls-connector.h" #include "wocky-tls.h" #include "wocky-tls-handler.h" -- 2.1.2 From dcf3fa8bb5f6738cde1f7a0ba27e456f1dbfe634 Mon Sep 17 00:00:00 2001 From: Ferdinand Stehle Date: Sun, 26 Oct 2014 17:00:59 +0100 Subject: [PATCH 2/4] Let wocky-c2s-porter handle wocky-sm creation --- wocky/wocky-c2s-porter.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/wocky/wocky-c2s-porter.c b/wocky/wocky-c2s-porter.c index 02c46cd..3f06a63 100644 --- a/wocky/wocky-c2s-porter.c +++ b/wocky/wocky-c2s-porter.c @@ -48,6 +48,7 @@ #include "wocky-utils.h" #include "wocky-namespaces.h" #include "wocky-contact-factory.h" +#include "wocky-sm.h" #define WOCKY_DEBUG_FLAG WOCKY_DEBUG_PORTER #include "wocky-debug-internal.h" @@ -107,6 +108,8 @@ struct _WockyC2SPorterPrivate GQueue queueable_stanza_patterns; WockyXmppConnection *connection; + + WockySM *sm; }; typedef struct @@ -351,6 +354,8 @@ wocky_c2s_porter_init (WockyC2SPorter *self) priv->iq_reply_handlers = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) stanza_iq_handler_free); + + priv->sm = wocky_sm_new (WOCKY_C2S_PORTER (self)); } static void wocky_c2s_porter_dispose (GObject *object); @@ -557,6 +562,8 @@ wocky_c2s_porter_dispose (GObject *object) if (G_OBJECT_CLASS (wocky_c2s_porter_parent_class)->dispose) G_OBJECT_CLASS (wocky_c2s_porter_parent_class)->dispose (object); + + g_object_unref (priv->sm); } void -- 2.1.2 From 18f751302d084e19578d8e629d66ce0261666fc6 Mon Sep 17 00:00:00 2001 From: Ferdinand Stehle Date: Sun, 26 Oct 2014 17:03:18 +0100 Subject: [PATCH 3/4] request and handle acks for every sent stanza --- wocky/wocky-c2s-porter.c | 10 ++++ wocky/wocky-sm.c | 138 ++++++++++++++++++++++++++++++++++++++++------ wocky/wocky-sm.h | 4 ++ wocky/wocky-stanza.c | 2 + wocky/wocky-stanza.h | 1 + wocky/wocky-xmpp-reader.c | 20 +++---- 6 files changed, 147 insertions(+), 28 deletions(-) diff --git a/wocky/wocky-c2s-porter.c b/wocky/wocky-c2s-porter.c index 3f06a63..a6d3eb4 100644 --- a/wocky/wocky-c2s-porter.c +++ b/wocky/wocky-c2s-porter.c @@ -774,6 +774,10 @@ wocky_c2s_porter_send_async (WockyPorter *porter, elem->cancelled_sig_id = g_cancellable_connect (cancellable, G_CALLBACK (send_cancelled_cb), elem, NULL); } + + if((!wocky_stanza_has_type(stanza, WOCKY_STANZA_TYPE_SM_R)) + && (!wocky_stanza_has_type(stanza, WOCKY_STANZA_TYPE_SM_A))) + wocky_sm_request_for_stanza(priv->sm, stanza); } static gboolean @@ -1488,6 +1492,12 @@ wocky_c2s_porter_close_async (WockyPorter *porter, return; } + //deliberatly send one last ack stanza, even if not requested + wocky_sm_send_a (self, wocky_xmpp_connection_get_stanza_recv_count (priv->connection)); + + //check for unsent stanzas + wocky_sm_is_unacked_stanza (self->priv->sm); + priv->close_result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, wocky_c2s_porter_close_async); diff --git a/wocky/wocky-sm.c b/wocky/wocky-sm.c index 156057e..ac0473e 100644 --- a/wocky/wocky-sm.c +++ b/wocky/wocky-sm.c @@ -53,11 +53,17 @@ struct _WockySMPrivate { WockyC2SPorter *porter; - gulong sm_iq_cb; + gulong sm_r_cb; + gulong sm_a_cb; gboolean dispose_has_run; + + uint count_sent; + GQueue *stanzas; }; +static gboolean sm_a_cb (WockyPorter *porter, WockyStanza *stanza, + gpointer data); static gboolean sm_r_cb (WockyPorter *porter, WockyStanza *stanza, gpointer data); @@ -117,10 +123,19 @@ wocky_sm_constructed (GObject *object) g_assert (priv->porter != NULL); g_warning("Register SM R handler"); - priv->sm_iq_cb = wocky_porter_register_handler_from_anyone ( + priv->sm_r_cb = wocky_porter_register_handler_from_anyone ( WOCKY_PORTER (priv->porter), WOCKY_STANZA_TYPE_SM_R, WOCKY_STANZA_SUB_TYPE_NONE, WOCKY_PORTER_HANDLER_PRIORITY_NORMAL, sm_r_cb, self, NULL); + + priv->sm_a_cb = wocky_porter_register_handler_from_anyone ( + WOCKY_PORTER (priv->porter), + WOCKY_STANZA_TYPE_SM_A, WOCKY_STANZA_SUB_TYPE_NONE, + WOCKY_PORTER_HANDLER_PRIORITY_NORMAL, sm_a_cb, self, NULL); + + //Session stanza has been sent after sm-establishment + priv->count_sent = 1; + priv->stanzas = g_queue_new (); } static void @@ -134,11 +149,17 @@ wocky_sm_dispose (GObject *object) priv->dispose_has_run = TRUE; - if (priv->sm_iq_cb != 0) + if (priv->sm_a_cb != 0) { wocky_porter_unregister_handler (WOCKY_PORTER (priv->porter), - priv->sm_iq_cb); - priv->sm_iq_cb = 0; + priv->sm_a_cb); + priv->sm_a_cb = 0; + } + if (priv->sm_r_cb != 0) + { + wocky_porter_unregister_handler (WOCKY_PORTER (priv->porter), + priv->sm_r_cb); + priv->sm_r_cb = 0; } g_object_unref (priv->porter); @@ -180,7 +201,48 @@ wocky_sm_new (WockyC2SPorter *porter) NULL); } +/** wocky_sm_send_a + * @porter: WockyPorter object + * @recv_count: Number of received stanzas to write in the ack + * + * Builds and sends an ack-stanza. + */ +void wocky_sm_send_a(WockyPorter* porter, uint recv_count) +{ + WockyStanza *stanza_a = wocky_stanza_new("a", WOCKY_NS_STREAM_MANAGEMENT); + + if (stanza_a != NULL) + { + WockyNode* node = wocky_stanza_get_top_node(stanza_a); + char buffer[12]; + sprintf(buffer, "%d", recv_count); + wocky_node_set_attribute (node, "h", buffer); + + DEBUG("Sending sm-ack h=%d", recv_count); + + wocky_porter_send (porter, stanza_a); + g_object_unref (stanza_a); + } +} +/** wocky_sm_send_r + * @porter: WockyPorter object + * @recv_count: Number of received stanzas to write in the ack + * + * Builds and sends an ack-stanza. + */ +void wocky_sm_send_r(WockyPorter* porter, uint count_sent) +{ + WockyStanza *stanza_r = wocky_stanza_new("r", WOCKY_NS_STREAM_MANAGEMENT); + + if (stanza_r != NULL) + { + DEBUG("Sending sm-request, sent_count = %d", count_sent); + + wocky_porter_send (porter, stanza_r); + g_object_unref (stanza_r); + } +} /** * sm_r_cb * @porter: WockyPorter object @@ -193,27 +255,69 @@ wocky_sm_new (WockyC2SPorter *porter) static gboolean sm_r_cb (WockyPorter *porter, WockyStanza *stanza, gpointer data) { - //BUILD A stanza - WockyStanza *result = wocky_stanza_new("a", WOCKY_NS_STREAM_MANAGEMENT); - WockyNode* node = wocky_stanza_get_top_node(result); + DEBUG("Got sm-request"); + wocky_sm_send_a(porter, wocky_stanza_get_recv_count(stanza)); - guint count = wocky_stanza_get_recv_count(stanza); - - char buffer[12]; + return TRUE; +} - sprintf(buffer, "%d", count); +/** +* sm_a_cb +* @porter: WockyPorter object +* @stanza: The originally received stanza +* @data: unused user data +* +* Callback function handling stream management -stanzas +*/ +static gboolean +sm_a_cb (WockyPorter *porter, WockyStanza *stanza_a, gpointer data) +{ + WockySM *self = WOCKY_SM(data); + WockySMPrivate *priv = self->priv; - wocky_node_set_attribute (node, "h", buffer); + WockyNode* node = wocky_stanza_get_top_node(stanza_a); - //SEND stanza - if (result != NULL) + if (node != NULL) { - wocky_porter_send (porter, result); - g_object_unref (result); + gchar *val_h = wocky_node_get_attribute (node, "h"); + if (val_h != NULL) + { + WockyStanza *stanza = g_queue_pop_head (priv->stanzas); + + if (stanza != NULL) + { + DEBUG("Got sm-ack h=%s, shouldbe=%d", val_h, wocky_stanza_get_recv_count(stanza)); + g_object_unref(stanza); + } + else + DEBUG("Got sm-ack h=%s, QUEUE IS EMPTY"); + } + else + g_warning("Failed to get h-attribute"); } + else + g_warning("Failed to get_top_node"); return TRUE; } +void wocky_sm_request_for_stanza(WockySM *self, WockyStanza *stanza) +{ + WockySMPrivate *priv = self->priv; + + priv->count_sent ++; + + wocky_stanza_set_recv_count(stanza, priv->count_sent); + + g_queue_push_tail (priv->stanzas, g_object_ref (stanza)); + + wocky_sm_send_r(priv->porter, priv->count_sent); +} + +gboolean wocky_sm_is_unacked_stanza(WockySM *self) +{ + DEBUG ("unacked stanza count: %d", g_queue_get_length (self->priv->stanzas)); + return (g_queue_get_length (self->priv->stanzas) > 0); +} diff --git a/wocky/wocky-sm.h b/wocky/wocky-sm.h index a8d99b3..af3209b 100644 --- a/wocky/wocky-sm.h +++ b/wocky/wocky-sm.h @@ -74,6 +74,10 @@ GType wocky_sm_get_type (void); WockySMClass)) WockySM * wocky_sm_new (WockyC2SPorter *porter); +void wocky_sm_send_a(WockyPorter* porter, uint recv_count); +void wocky_sm_send_r(WockyPorter* porter, uint sent_count); +void wocky_sm_request_for_stanza(WockySM *self, WockyStanza *stanza); +gboolean wocky_sm_is_unacked_stanza(WockySM *self); G_END_DECLS diff --git a/wocky/wocky-stanza.c b/wocky/wocky-stanza.c index e722bc0..a0ad780 100644 --- a/wocky/wocky-stanza.c +++ b/wocky/wocky-stanza.c @@ -83,6 +83,8 @@ static StanzaTypeName type_names[NUM_WOCKY_STANZA_TYPE] = WOCKY_NS_STREAM_MANAGEMENT }, { WOCKY_STANZA_TYPE_SM_R, "r", WOCKY_NS_STREAM_MANAGEMENT }, + { WOCKY_STANZA_TYPE_SM_A, "a", + WOCKY_NS_STREAM_MANAGEMENT }, { WOCKY_STANZA_TYPE_UNKNOWN, NULL, NULL }, }; diff --git a/wocky/wocky-stanza.h b/wocky/wocky-stanza.h index 0fb2d54..ef21fba 100644 --- a/wocky/wocky-stanza.h +++ b/wocky/wocky-stanza.h @@ -107,6 +107,7 @@ typedef enum WOCKY_STANZA_TYPE_STREAM_ERROR, WOCKY_STANZA_TYPE_ENABLE, WOCKY_STANZA_TYPE_SM_R, + WOCKY_STANZA_TYPE_SM_A, WOCKY_STANZA_TYPE_UNKNOWN, /*< private >*/ NUM_WOCKY_STANZA_TYPE diff --git a/wocky/wocky-xmpp-reader.c b/wocky/wocky-xmpp-reader.c index 7a84086..d870af4 100644 --- a/wocky/wocky-xmpp-reader.c +++ b/wocky/wocky-xmpp-reader.c @@ -128,7 +128,7 @@ struct _WockyXmppReaderPrivate gchar *default_namespace; GQueue *stanzas; WockyXmppReaderState state; - guint stanza_read_count; + guint stanza_recv_count; }; /** @@ -224,7 +224,7 @@ wocky_xmpp_reader_init (WockyXmppReader *self) priv->nodes = g_queue_new (); priv->stanzas = g_queue_new (); - priv->stanza_read_count = 0; + priv->stanza_recv_count = 0; } static void wocky_xmpp_reader_dispose (GObject *object); @@ -657,17 +657,15 @@ _end_element_ns (void *user_data, const xmlChar *localname, } else if (priv->depth == (priv->stream_mode ? 1 : 0)) { + char buffer[30]; g_assert (g_queue_get_length (priv->nodes) == 0); DEBUG_STANZA (priv->stanza, "Received stanza"); - if(!wocky_stanza_has_type(priv->stanza, WOCKY_STANZA_TYPE_SM_R)) - priv->stanza_read_count ++; - - wocky_stanza_set_recv_count (priv->stanza, priv->stanza_read_count); + if((!wocky_stanza_has_type(priv->stanza, WOCKY_STANZA_TYPE_SM_R)) + && (!wocky_stanza_has_type(priv->stanza, WOCKY_STANZA_TYPE_SM_A))) + priv->stanza_recv_count ++; - char buffer[30]; - sprintf(buffer, "Increased_Stanza_Count:_%d", priv->stanza_read_count); - g_warning(buffer); + wocky_stanza_set_recv_count (priv->stanza, priv->stanza_recv_count); g_queue_push_tail (priv->stanzas, priv->stanza); @@ -851,7 +849,7 @@ wocky_xmpp_reader_reset (WockyXmppReader *reader) guint wocky_xmpp_reader_get_recv_count (WockyXmppReader *reader) { - return reader->priv->stanza_read_count; + return reader->priv->stanza_recv_count; } /** * wocky_xmpp_reader_set_recv_count: @@ -864,5 +862,5 @@ wocky_xmpp_reader_get_recv_count (WockyXmppReader *reader) void wocky_xmpp_reader_set_recv_count (WockyXmppReader *reader, guint count) { - reader->priv->stanza_read_count = count; + reader->priv->stanza_recv_count = count; } -- 2.1.2 From 74c62cce52d90447bb7199035814a317212792a7 Mon Sep 17 00:00:00 2001 From: Ferdinand Stehle Date: Sun, 26 Oct 2014 17:27:42 +0100 Subject: [PATCH 4/4] changed the author in the wocky-sm header files --- wocky/wocky-sm.c | 3 +-- wocky/wocky-sm.h | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/wocky/wocky-sm.c b/wocky/wocky-sm.c index ac0473e..9880be5 100644 --- a/wocky/wocky-sm.c +++ b/wocky/wocky-sm.c @@ -1,7 +1,6 @@ /* * wocky-sm.c - Source for WockySM - * Copyright (C) 2010 Collabora Ltd. - * @author Senko Rasic + * @author Ferdinand Stehle * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/wocky/wocky-sm.h b/wocky/wocky-sm.h index af3209b..e560f91 100644 --- a/wocky/wocky-sm.h +++ b/wocky/wocky-sm.h @@ -1,7 +1,6 @@ /* * wocky-sm.h - Header for WockySM (Stream Management) - * Copyright (C) 2010 Collabora Ltd. - * @author Senko Rasic + * @author Ferdinand Stehle * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public -- 2.1.2