# HG changeset patch # User Nicolas Cornu # Date 1281917090 -7200 # Node ID 2d5c3efda92af360524dd6624e9bd45d03a552e1 # Parent cded9f40039eefbcb99ca746030ba6d947d4398a Add a timeout to the AckHandlers. diff -r cded9f40039e -r 2d5c3efda92a jingle/jingle.c --- 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) diff -r cded9f40039e -r 2d5c3efda92a jingle/jingle.h --- 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); diff -r cded9f40039e -r 2d5c3efda92a jingle/send.c --- 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