From b4ee03d7c7b11ce4069b8c5d653a255ba67fa779 Mon Sep 17 00:00:00 2001 From: Stefan Becker Date: Fri, 19 Jul 2013 22:29:59 +0300 Subject: [PATCH] groupchat: handle Session-Expires At least on Lync 2013 the group chat session comes with a Session-Expires: header and the server sends a BYE if the chat session is idle for that long. The session gets invalidated by this and the next group chat message then can crash, because dialog is NULL. Honor the Session-Expires: by sending an UPDATE message before the timeout. --- src/core/sip-transport.c | 6 ++++++ src/core/sip-transport.h | 4 +++- src/core/sipe-groupchat.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-- src/core/sipe-groupchat.h | 6 ++++-- src/core/sipe-im.c | 4 ++-- 5 files changed, 59 insertions(+), 7 deletions(-) diff --git a/src/core/sip-transport.c b/src/core/sip-transport.c index eac93eac..e47867ef 100644 --- a/src/core/sip-transport.c +++ b/src/core/sip-transport.c @@ -872,6 +872,12 @@ void sip_transport_subscribe(struct sipe_core_private *sipe_private, callback); } +void sip_transport_update(struct sipe_core_private *sipe_private, + struct sip_dialog *dialog) +{ + sip_transport_simple_request(sipe_private, "UPDATE", dialog); +} + static const gchar *get_auth_header(struct sipe_core_private *sipe_private, struct sip_auth *auth, struct sipmsg *msg) diff --git a/src/core/sip-transport.h b/src/core/sip-transport.h index 503e0c67..99645436 100644 --- a/src/core/sip-transport.h +++ b/src/core/sip-transport.h @@ -3,7 +3,7 @@ * * pidgin-sipe * - * Copyright (C) 2010-11 SIPE Project + * Copyright (C) 2010-2013 SIPE Project * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -105,6 +105,8 @@ void sip_transport_subscribe(struct sipe_core_private *sipe_private, const gchar *body, struct sip_dialog *dialog, TransCallback callback); +void sip_transport_update(struct sipe_core_private *sipe_private, + struct sip_dialog *dialog); /* Misc. SIP transport stuff */ guint sip_transport_port(struct sipe_core_private *sipe_private); diff --git a/src/core/sipe-groupchat.c b/src/core/sipe-groupchat.c index e49f49a5..cd87c486 100644 --- a/src/core/sipe-groupchat.c +++ b/src/core/sipe-groupchat.c @@ -33,6 +33,8 @@ * * Microsoft DevNet: [MS-XCCOSIP] Extensible Chat Control Over SIP * + * RFC 4028: Session Timers in the Session Initiation Protocol (SIP) + * * * * @TODO: @@ -163,6 +165,7 @@ struct sipe_groupchat { GHashTable *uri_to_chat_session; GHashTable *msgs; guint envid; + guint expires; gboolean connected; }; @@ -303,7 +306,7 @@ static void groupchat_init_retry(struct sipe_core_private *sipe_private) groupchat->connected = FALSE; sipe_schedule_seconds(sipe_private, - "<+grouchat-retry>", + "<+groupchat-retry>", NULL, GROUPCHAT_RETRY_TIMEOUT, groupchat_init_retry_cb, @@ -368,11 +371,29 @@ static gchar *generate_chanid_node(const gchar *uri, guint key) return chanid; } +/* sipe_schedule_action */ +static void groupchat_update_cb(struct sipe_core_private *sipe_private, + SIPE_UNUSED_PARAMETER gpointer data) +{ + struct sipe_groupchat *groupchat = sipe_private->groupchat; + struct sip_dialog *dialog = sipe_dialog_find(groupchat->session, + groupchat->session->with); + + sip_transport_update(sipe_private, dialog); + sipe_schedule_seconds(sipe_private, + "<+groupchat-expires>", + NULL, + groupchat->expires, + groupchat_update_cb, + NULL); +} + static struct sipe_groupchat_msg *chatserver_command(struct sipe_core_private *sipe_private, const gchar *cmd); void sipe_groupchat_invite_response(struct sipe_core_private *sipe_private, - struct sip_dialog *dialog) + struct sip_dialog *dialog, + struct sipmsg *response) { struct sipe_groupchat *groupchat = sipe_private->groupchat; @@ -382,6 +403,9 @@ void sipe_groupchat_invite_response(struct sipe_core_private *sipe_private, /* response to initial invite */ struct sipe_groupchat_msg *msg = generate_xccos_message(groupchat, ""); + const gchar *session_expires = sipmsg_find_header(response, + "Session-Expires"); + sip_transport_info(sipe_private, "Content-Type: text/plain\r\n", msg->xccos, @@ -389,6 +413,24 @@ void sipe_groupchat_invite_response(struct sipe_core_private *sipe_private, NULL); sipe_groupchat_msg_remove(msg); + if (session_expires) { + groupchat->expires = strtoul(session_expires, NULL, 10); + + if (groupchat->expires) { + SIPE_DEBUG_INFO("sipe_groupchat_invite_response: session expires in %d seconds", + groupchat->expires); + + if (groupchat->expires > 10) + groupchat->expires -= 10; + sipe_schedule_seconds(sipe_private, + "<+groupchat-expires>", + NULL, + groupchat->expires, + groupchat_update_cb, + NULL); + } + } + } else { /* response to group chat server invite */ gchar *invcmd; diff --git a/src/core/sipe-groupchat.h b/src/core/sipe-groupchat.h index f1d2a07b..230f4d28 100644 --- a/src/core/sipe-groupchat.h +++ b/src/core/sipe-groupchat.h @@ -3,7 +3,7 @@ * * pidgin-sipe * - * Copyright (C) 2010 SIPE Project + * Copyright (C) 2010-2013 SIPE Project * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,6 +21,7 @@ */ /* Forward declarations */ +struct sipmsg; struct sip_dialog; struct sip_session; struct sipe_chat_session; @@ -31,7 +32,8 @@ void sipe_groupchat_init(struct sipe_core_private *sipe_private); void sipe_groupchat_invite_failed(struct sipe_core_private *sipe_private, struct sip_session *session); void sipe_groupchat_invite_response(struct sipe_core_private *sipe_private, - struct sip_dialog *dialog); + struct sip_dialog *dialog, + struct sipmsg *response); void process_incoming_info_groupchat(struct sipe_core_private *sipe_private, struct sipmsg *msg, struct sip_session *session); diff --git a/src/core/sipe-im.c b/src/core/sipe-im.c index 34e3df01..86acea57 100644 --- a/src/core/sipe-im.c +++ b/src/core/sipe-im.c @@ -3,7 +3,7 @@ * * pidgin-sipe * - * Copyright (C) 2011-12 SIPE Project + * Copyright (C) 2011-2013 SIPE Project * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -236,7 +236,7 @@ static gboolean process_invite_response(struct sipe_core_private *sipe_private, } if (session->is_groupchat) { - sipe_groupchat_invite_response(sipe_private, dialog); + sipe_groupchat_invite_response(sipe_private, dialog, msg); } if(g_slist_find_custom(dialog->supported, "ms-text-format", (GCompareFunc)g_ascii_strcasecmp)) { -- 2.11.4.GIT