Add a timeout to the AckHandlers.
--- a/jingle/jingle.c Sun Aug 15 22:12:04 2010 +0200
+++ b/jingle/jingle.c Mon Aug 16 02:04:50 2010 +0200
@@ -49,6 +49,7 @@
static LmMessageHandler* jingle_iq_handler = NULL;
static GSList *ack_handlers = NULL;
+static guint ack_timeout_checker = 0;
static guint connect_hid = 0;
static guint disconn_hid = 0;
@@ -144,27 +145,56 @@
LmConnection *connection,
LmMessage *message, gpointer user_data)
{
- ack_handlers = g_slist_remove(ack_handlers, handler);
- lm_message_handler_unref(handler);
-
// TODO: check subtype
if (user_data != NULL) {
JingleAckHandle *ah = user_data;
if(ah->callback != NULL)
- ah->callback(message, ah->user_data);
+ ah->callback(JINGLE_ACK_RESPONSE, message, ah->user_data);
- g_free(ah);
+ jingle_ack_handler_free(ah);
}
return LM_HANDLER_RESULT_REMOVE_MESSAGE;
}
+gboolean jingle_ack_timeout_checker(gpointer user_data)
+{
+ GSList *el;
+ time_t now = time(NULL);
+ JingleAckHandle *ah;
+
+ for (el = ack_handlers; el; el = g_slist_next(el)) {
+ JingleAckHandle *ah = el->data;
+
+ if (ah->timeout == 0 || ah->_inserted + ah->timeout > now)
+ continue;
+
+ if(ah->callback != NULL)
+ ah->callback(JINGLE_ACK_TIMEOUT, NULL, ah->user_data);
+
+ lm_message_handler_unref(ah->_handler);
+ jingle_ack_handler_free(ah);
+ }
+ return TRUE;
+}
+
LmMessageHandler *jingle_new_ack_handler(JingleAckHandle *ah)
{
- LmMessageHandler *h = lm_message_handler_new(jingle_handle_ack_iq,
- (gpointer) ah, NULL);
- ack_handlers = g_slist_append(ack_handlers, h);
- return h;
+ if(ack_timeout_checker == 0)
+ ack_timeout_checker = g_timeout_add_seconds(3, jingle_ack_timeout_checker, NULL);
+
+ ah->_inserted = time(NULL);
+ ah->_handler = lm_message_handler_new(jingle_handle_ack_iq,
+ (gpointer) ah, NULL);
+ ack_handlers = g_slist_append(ack_handlers, ah);
+ return ah->_handler;
+}
+
+void jingle_ack_handler_free(JingleAckHandle *ah)
+{
+ lm_message_handler_unref(ah->_handler);
+ ack_handlers = g_slist_remove(ack_handlers, ah);
+ g_free(ah);
}
/**
@@ -382,6 +412,11 @@
lm_message_handler_invalidate(jingle_iq_handler);
lm_message_handler_unref(jingle_iq_handler);
+
+ if (ack_timeout_checker != 0) {
+ GSource *s = g_main_context_find_source_by_id(NULL, ack_timeout_checker);
+ g_source_destroy(s);
+ }
}
void handle_trans_data(const gchar *xmlns, gconstpointer data, const gchar *data2, guint len)
--- a/jingle/jingle.h Sun Aug 15 22:12:04 2010 +0200
+++ b/jingle/jingle.h Mon Aug 16 02:04:50 2010 +0200
@@ -108,11 +108,31 @@
void (*handler)(JingleNode *);
};
-typedef void (*JingleAckCallback) (LmMessage *, gpointer);
+typedef enum {
+ JINGLE_ACK_RESPONSE,
+ JINGLE_ACK_TIMEOUT
+} JingleAckType;
+
+typedef void (*JingleAckCallback) (JingleAckType type, LmMessage *, gpointer);
typedef struct {
+ /* function to be called when we receive a response to the IQ */
JingleAckCallback callback;
+
+ /* additional data to pass to callback */
gpointer *user_data;
+
+ /* if no response was received after timeout seconds, callback
+ * will be called with JINGLE_ACK_TIMEOUT as type */
+ guint timeout;
+
+ /* (private) date at which the handler was inserted using
+ * jingle_new_ack_handler */
+ time_t _inserted;
+
+ /* (private) a pointer to the LmMessageHandler created
+ * using jingle_new_ack_handler */
+ LmMessageHandler *_handler;
} JingleAckHandle;
typedef struct {
@@ -125,6 +145,7 @@
LmConnection *connection,
LmMessage *message, gpointer user_data);
LmMessageHandler *jingle_new_ack_handler(JingleAckHandle *ri);
+void jingle_ack_handler_free(JingleAckHandle *ah);
LmMessage *jingle_new_iq_error(LmMessage *m, const gchar *errtype,
const gchar *cond, const gchar *jinglecond);
--- a/jingle/send.c Sun Aug 15 22:12:04 2010 +0200
+++ b/jingle/send.c Mon Aug 16 02:04:50 2010 +0200
@@ -60,18 +60,26 @@
lm_message_unref(r);
}
-static void jingle_handle_ack_iq_sa(LmMessage *mess, gpointer data)
+static void jingle_handle_ack_iq_sa(JingleAckType acktype, LmMessage *mess,
+ gpointer data)
{
LmMessageNode *node;
const gchar *type, *cause;
GSList *child = NULL;
JingleSession *sess = (JingleSession*)data;
SessionContent *sc;
-
+
+ if (acktype == JINGLE_ACK_TIMEOUT) {
+ // TODO: handle ack timeout...
+ scr_LogPrint(LPRINT_LOGNORM, "Jingle: session-accept %s: %s", type, cause);
+ session_delete(sess);
+ return;
+ }
+
if(lm_message_get_sub_type(mess) == LM_MESSAGE_SUB_TYPE_RESULT) {
return;
}
-
+
if(lm_message_get_sub_type(mess) == LM_MESSAGE_SUB_TYPE_ERROR) {
node = lm_message_get_node(mess);
node = lm_message_node_get_child(node,"error");
@@ -97,22 +105,30 @@
ackhandle = g_new0(JingleAckHandle, 1);
ackhandle->callback = jingle_handle_ack_iq_sa;
ackhandle->user_data = (gpointer)js;
- scr_log_print(LPRINT_DEBUG,
- "%s", lm_message_node_to_string(mess->node));lm_connection_send_with_reply(lconnection, mess,
+ ackhandle->timeout = 60;
+ lm_connection_send_with_reply(lconnection, mess,
jingle_new_ack_handler(ackhandle), NULL);
lm_message_unref(mess);
}
}
-static void jingle_handle_ack_iq_si(LmMessage *mess, gpointer data)
+static void jingle_handle_ack_iq_si(JingleAckType acktype, LmMessage *mess,
+ gpointer data)
{
LmMessageNode *node;
const gchar *type, *cause;
JingleSession *sess = (JingleSession*)data;
-
- if(lm_message_get_sub_type(mess) == LM_MESSAGE_SUB_TYPE_RESULT)
+
+ if (acktype == JINGLE_ACK_TIMEOUT) {
+ // TODO: handle ack timeout...
+ scr_LogPrint(LPRINT_LOGNORM, "Jingle: did not receive the ack in time, aborting");
+ session_delete(sess);
return;
- if(lm_message_get_sub_type(mess) == LM_MESSAGE_SUB_TYPE_ERROR) {
+ }
+
+ if (lm_message_get_sub_type(mess) == LM_MESSAGE_SUB_TYPE_RESULT)
+ return;
+ if (lm_message_get_sub_type(mess) == LM_MESSAGE_SUB_TYPE_ERROR) {
node = lm_message_get_node(mess);
node = lm_message_node_get_child(node,"error");
type = lm_message_node_get_attribute(node, "type");
@@ -128,7 +144,7 @@
{
JingleAckHandle *ackhandle;
GSList *listentry;
- GError *err;
+ GError *err = NULL;
gboolean status;
LmMessage *mess = lm_message_from_jinglesession(js, JINGLE_SESSION_INITIATE);
@@ -139,8 +155,7 @@
ackhandle = g_new0(JingleAckHandle, 1);
ackhandle->callback = jingle_handle_ack_iq_si;
ackhandle->user_data = (gpointer)js;
- scr_log_print(LPRINT_DEBUG,
- "%s", lm_message_node_to_string(mess->node));
+ ackhandle->timeout = 60;
status = lm_connection_send_with_reply(lconnection, mess,
jingle_new_ack_handler(ackhandle), &err);
// TODO: delete the ack_handler