POPT_DIR
POPT_INCLUDE
POPT_LIB
+PBX_PJSIP_EVSUB_SET_UAS_TIMEOUT
+PJSIP_EVSUB_SET_UAS_TIMEOUT_DIR
+PJSIP_EVSUB_SET_UAS_TIMEOUT_INCLUDE
+PJSIP_EVSUB_SET_UAS_TIMEOUT_LIB
PBX_PJSIP_AUTH_CLT_DEINIT
PJSIP_AUTH_CLT_DEINIT_DIR
PJSIP_AUTH_CLT_DEINIT_INCLUDE
$as_echo "#define HAVE_PJSIP_AUTH_CLT_DEINIT 1" >>confdefs.h
+$as_echo "#define HAVE_PJSIP_EVSUB_SET_UAS_TIMEOUT 1" >>confdefs.h
+
+
+
+PJSIP_EVSUB_SET_UAS_TIMEOUT_DESCRIP="PJSIP EVSUB Set UAS Timeout support"
+PJSIP_EVSUB_SET_UAS_TIMEOUT_OPTION=pjsip
+PJSIP_EVSUB_SET_UAS_TIMEOUT_DIR=${PJPROJECT_DIR}
+
+PBX_PJSIP_EVSUB_SET_UAS_TIMEOUT=0
+
+
+
+
+
+
fi
fi
+
+if test "x${PBX_PJSIP_EVSUB_SET_UAS_TIMEOUT}" != "x1" -a "${USE_PJSIP_EVSUB_SET_UAS_TIMEOUT}" != "no"; then
+ pbxlibdir=""
+ # if --with-PJSIP_EVSUB_SET_UAS_TIMEOUT=DIR has been specified, use it.
+ if test "x${PJSIP_EVSUB_SET_UAS_TIMEOUT_DIR}" != "x"; then
+ if test -d ${PJSIP_EVSUB_SET_UAS_TIMEOUT_DIR}/lib; then
+ pbxlibdir="-L${PJSIP_EVSUB_SET_UAS_TIMEOUT_DIR}/lib"
+ else
+ pbxlibdir="-L${PJSIP_EVSUB_SET_UAS_TIMEOUT_DIR}"
+ fi
+ fi
+ pbxfuncname="pjsip_evsub_set_uas_timeout"
+ if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers
+ AST_PJSIP_EVSUB_SET_UAS_TIMEOUT_FOUND=yes
+ else
+ ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
+ CFLAGS="${CFLAGS} $PJPROJECT_CFLAGS"
+ as_ac_Lib=`$as_echo "ac_cv_lib_pjsip_${pbxfuncname}" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpjsip" >&5
+$as_echo_n "checking for ${pbxfuncname} in -lpjsip... " >&6; }
+if eval \${$as_ac_Lib+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpjsip ${pbxlibdir} $PJPROJECT_LIB $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ${pbxfuncname} ();
+int
+main ()
+{
+return ${pbxfuncname} ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$as_ac_Lib=yes"
+else
+ eval "$as_ac_Lib=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+eval ac_res=\$$as_ac_Lib
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+ AST_PJSIP_EVSUB_SET_UAS_TIMEOUT_FOUND=yes
+else
+ AST_PJSIP_EVSUB_SET_UAS_TIMEOUT_FOUND=no
+fi
+
+ CFLAGS="${ast_ext_lib_check_save_CFLAGS}"
+ fi
+
+ # now check for the header.
+ if test "${AST_PJSIP_EVSUB_SET_UAS_TIMEOUT_FOUND}" = "yes"; then
+ PJSIP_EVSUB_SET_UAS_TIMEOUT_LIB="${pbxlibdir} -lpjsip $PJPROJECT_LIB"
+ # if --with-PJSIP_EVSUB_SET_UAS_TIMEOUT=DIR has been specified, use it.
+ if test "x${PJSIP_EVSUB_SET_UAS_TIMEOUT_DIR}" != "x"; then
+ PJSIP_EVSUB_SET_UAS_TIMEOUT_INCLUDE="-I${PJSIP_EVSUB_SET_UAS_TIMEOUT_DIR}/include"
+ fi
+ PJSIP_EVSUB_SET_UAS_TIMEOUT_INCLUDE="${PJSIP_EVSUB_SET_UAS_TIMEOUT_INCLUDE} $PJPROJECT_CFLAGS"
+ if test "xpjsip.h" = "x" ; then # no header, assume found
+ PJSIP_EVSUB_SET_UAS_TIMEOUT_HEADER_FOUND="1"
+ else # check for the header
+ ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
+ CPPFLAGS="${CPPFLAGS} ${PJSIP_EVSUB_SET_UAS_TIMEOUT_INCLUDE}"
+ ac_fn_c_check_header_mongrel "$LINENO" "pjsip.h" "ac_cv_header_pjsip_h" "$ac_includes_default"
+if test "x$ac_cv_header_pjsip_h" = xyes; then :
+ PJSIP_EVSUB_SET_UAS_TIMEOUT_HEADER_FOUND=1
+else
+ PJSIP_EVSUB_SET_UAS_TIMEOUT_HEADER_FOUND=0
+fi
+
+
+ CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
+ fi
+ if test "x${PJSIP_EVSUB_SET_UAS_TIMEOUT_HEADER_FOUND}" = "x0" ; then
+ PJSIP_EVSUB_SET_UAS_TIMEOUT_LIB=""
+ PJSIP_EVSUB_SET_UAS_TIMEOUT_INCLUDE=""
+ else
+ if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library
+ PJSIP_EVSUB_SET_UAS_TIMEOUT_LIB=""
+ fi
+ PBX_PJSIP_EVSUB_SET_UAS_TIMEOUT=1
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_PJSIP_EVSUB_SET_UAS_TIMEOUT 1
+_ACEOF
+
+ fi
+ fi
+fi
+
+
fi
fi
SIP_SUB_TREE_TERMINATED,
};
+static char *sub_tree_state_description[] = {
+ "Normal",
+ "TerminatePending",
+ "TerminateInProgress",
+ "Terminated"
+};
+
/*!
* \brief A tree of SIP subscriptions
*
AST_LIST_ENTRY(sip_subscription_tree) next;
/*! Subscription tree state */
enum sip_subscription_tree_state state;
+ /*! On asterisk restart, this is the task data used
+ * to restart the expiration timer if pjproject isn't
+ * capable of restarting the timer.
+ */
+ struct ast_sip_sched_task *expiration_task;
};
/*!
[AST_SIP_NOTIFIER] = "Notifier"
};
+enum sip_persistence_update_type {
+ /*! Called from send request */
+ SUBSCRIPTION_PERSISTENCE_SEND_REQUEST = 0,
+ /*! Subscription created from initial client request */
+ SUBSCRIPTION_PERSISTENCE_CREATED,
+ /*! Subscription recreated by asterisk on startup */
+ SUBSCRIPTION_PERSISTENCE_RECREATED,
+ /*! Subscription created from client refresh */
+ SUBSCRIPTION_PERSISTENCE_REFRESHED,
+};
+
AST_RWLIST_HEAD_STATIC(subscriptions, sip_subscription_tree);
AST_RWLIST_HEAD_STATIC(body_generators, ast_sip_pubsub_body_generator);
/*! \brief Function which updates persistence information of a subscription in sorcery */
static void subscription_persistence_update(struct sip_subscription_tree *sub_tree,
- pjsip_rx_data *rdata)
+ pjsip_rx_data *rdata, enum sip_persistence_update_type type)
{
pjsip_dialog *dlg;
return;
}
+ ast_debug(3, "Updating persistence for '%s->%s'\n",
+ ast_sorcery_object_get_id(sub_tree->endpoint), sub_tree->root->resource);
+
dlg = sub_tree->dlg;
sub_tree->persistence->cseq = dlg->local.cseq;
* persistence that is pulled from persistent storage, though, the rdata->pkt_info.packet will
* only ever have a single SIP message on it, and so we base persistence on that.
*/
- if (rdata->msg_info.msg_buf) {
- ast_copy_string(sub_tree->persistence->packet, rdata->msg_info.msg_buf,
- MIN(sizeof(sub_tree->persistence->packet), rdata->msg_info.len));
- } else {
- ast_copy_string(sub_tree->persistence->packet, rdata->pkt_info.packet,
- sizeof(sub_tree->persistence->packet));
+ if (type == SUBSCRIPTION_PERSISTENCE_CREATED
+ || type == SUBSCRIPTION_PERSISTENCE_RECREATED) {
+ if (rdata->msg_info.msg_buf) {
+ ast_copy_string(sub_tree->persistence->packet, rdata->msg_info.msg_buf,
+ MIN(sizeof(sub_tree->persistence->packet), rdata->msg_info.len));
+ } else {
+ ast_copy_string(sub_tree->persistence->packet, rdata->pkt_info.packet,
+ sizeof(sub_tree->persistence->packet));
+ }
}
ast_copy_string(sub_tree->persistence->src_name, rdata->pkt_info.src_name,
sizeof(sub_tree->persistence->src_name));
struct resources visited;
if (!has_eventlist_support || !(list = retrieve_resource_list(resource, handler->event_name))) {
- ast_debug(2, "Subscription to resource %s is not to a list\n", resource);
+ ast_debug(2, "Subscription '%s->%s' is not to a list\n",
+ ast_sorcery_object_get_id(endpoint), resource);
tree->root = tree_node_alloc(resource, NULL, 0);
if (!tree->root) {
return 500;
return handler->notifier->new_subscribe(endpoint, resource);
}
- ast_debug(2, "Subscription to resource %s is a list\n", resource);
+ ast_debug(2, "Subscription '%s->%s' is a list\n",
+ ast_sorcery_object_get_id(endpoint), resource);
if (AST_VECTOR_INIT(&visited, AST_VECTOR_SIZE(&list->items))) {
return 500;
}
if (i == obj) {
AST_RWLIST_REMOVE_CURRENT(next);
if (i->root) {
- ast_debug(2, "Removing subscription to resource %s from list of subscriptions\n",
- ast_sip_subscription_get_resource_name(i->root));
+ ast_debug(2, "Removing subscription '%s->%s' from list of subscriptions\n",
+ ast_sorcery_object_get_id(i->endpoint), ast_sip_subscription_get_resource_name(i->root));
}
break;
}
static void destroy_subscription(struct ast_sip_subscription *sub)
{
- ast_debug(3, "Destroying SIP subscription to resource %s\n", sub->resource);
+ ast_debug(3, "Destroying SIP subscription from '%s->%s'\n",
+ ast_sorcery_object_get_id(sub->tree->endpoint), sub->resource);
ast_free(sub->body_text);
AST_VECTOR_FREE(&sub->children);
{
struct sip_subscription_tree *sub_tree = obj;
- ast_debug(3, "Destroying subscription tree %p\n", sub_tree);
+ ast_debug(3, "Destroying subscription tree %p '%s->%s'\n",
+ sub_tree,
+ sub_tree->endpoint ? ast_sorcery_object_get_id(sub_tree->endpoint) : "Unknown",
+ sub_tree->root ? sub_tree->root->resource : "Unknown");
ao2_cleanup(sub_tree->endpoint);
void ast_sip_subscription_destroy(struct ast_sip_subscription *sub)
{
- ast_debug(3, "Removing subscription %p reference to subscription tree %p\n", sub, sub->tree);
+ ast_debug(3, "Removing subscription %p '%s->%s' reference to subscription tree %p\n",
+ sub, ast_sorcery_object_get_id(sub->tree->endpoint), sub->resource, sub->tree);
ao2_cleanup(sub->tree);
}
dlg->local.tag_hval = pj_hash_calc_tolower(0, NULL, &dlg->local.info->tag);
pjsip_ua_register_dlg(pjsip_ua_instance(), dlg);
dlg->local.cseq = persistence->cseq;
- dlg->remote.cseq = persistence->cseq;
}
pjsip_evsub_create_uas(dlg, &pubsub_cb, rdata, 0, &sub_tree->evsub);
return sub_tree;
}
+/*! Wrapper structure for initial_notify_task */
+struct initial_notify_data {
+ struct sip_subscription_tree *sub_tree;
+ int expires;
+};
+
static int initial_notify_task(void *obj);
static int send_notify(struct sip_subscription_tree *sub_tree, unsigned int force_full_state);
}
pjsip_msg_add_hdr(rdata->msg_info.msg, (pjsip_hdr *) expires_header);
}
+
expires_header->ivalue = (ast_tvdiff_ms(persistence->expires, ast_tvnow()) / 1000);
if (expires_header->ivalue <= 0) {
/* The subscription expired since we started recreating the subscription. */
+ ast_debug(3, "Expired subscription retrived from persistent store '%s' %s\n",
+ persistence->endpoint, persistence->tag);
ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
ao2_ref(endpoint, -1);
return 0;
ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
}
} else {
+ struct initial_notify_data *ind = ast_malloc(sizeof(*ind));
+
+ if (!ind) {
+ pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
+ goto error;
+ }
+
+ ind->sub_tree = ao2_bump(sub_tree);
+ ind->expires = expires_header->ivalue;
+
sub_tree->persistence = ao2_bump(persistence);
- subscription_persistence_update(sub_tree, rdata);
- if (ast_sip_push_task(sub_tree->serializer, initial_notify_task,
- ao2_bump(sub_tree))) {
+ subscription_persistence_update(sub_tree, rdata, SUBSCRIPTION_PERSISTENCE_RECREATED);
+ if (ast_sip_push_task(sub_tree->serializer, initial_notify_task, ind)) {
/* Could not send initial subscribe NOTIFY */
pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
ao2_ref(sub_tree, -1);
+ ast_free(ind);
}
}
} else {
ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
}
+
+error:
resource_tree_destroy(&tree);
ao2_ref(endpoint, -1);
/* If this subscription has already expired remove it */
if (ast_tvdiff_ms(persistence->expires, ast_tvnow()) <= 0) {
+ ast_debug(3, "Expired subscription retrived from persistent store '%s' %s\n",
+ persistence->endpoint, persistence->tag);
ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
return 0;
}
res = internal_pjsip_evsub_send_request(sub_tree, tdata);
- subscription_persistence_update(sub_tree, NULL);
+ subscription_persistence_update(sub_tree, NULL, SUBSCRIPTION_PERSISTENCE_SEND_REQUEST);
ast_test_suite_event_notify("SUBSCRIPTION_STATE_SET",
"StateText: %s\r\n"
return res;
}
+static int pubsub_on_refresh_timeout(void *userdata);
+
static int initial_notify_task(void * obj)
{
- struct sip_subscription_tree *sub_tree;
+ struct initial_notify_data *ind = obj;
- sub_tree = obj;
- if (generate_initial_notify(sub_tree->root)) {
- pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
+ if (generate_initial_notify(ind->sub_tree->root)) {
+ pjsip_evsub_terminate(ind->sub_tree->evsub, PJ_TRUE);
} else {
- send_notify(sub_tree, 1);
+ send_notify(ind->sub_tree, 1);
ast_test_suite_event_notify("SUBSCRIPTION_ESTABLISHED",
"Resource: %s",
- sub_tree->root->resource);
+ ind->sub_tree->root->resource);
+ }
+
+ if (ind->expires > -1) {
+ char *name = ast_alloca(strlen("->/ ") +
+ strlen(ind->sub_tree->persistence->endpoint) +
+ strlen(ind->sub_tree->root->resource) +
+ strlen(ind->sub_tree->root->handler->event_name) +
+ ind->sub_tree->dlg->call_id->id.slen + 1);
+
+ sprintf(name, "%s->%s/%s %.*s", ind->sub_tree->persistence->endpoint,
+ ind->sub_tree->root->resource, ind->sub_tree->root->handler->event_name,
+ (int)ind->sub_tree->dlg->call_id->id.slen, ind->sub_tree->dlg->call_id->id.ptr);
+
+ ast_debug(3, "Scheduling timer: %s\n", name);
+ ind->sub_tree->expiration_task = ast_sip_schedule_task(ind->sub_tree->serializer,
+ ind->expires * 1000, pubsub_on_refresh_timeout, name,
+ ind->sub_tree, AST_SIP_SCHED_TASK_FIXED | AST_SIP_SCHED_TASK_DATA_AO2);
+ if (!ind->sub_tree->expiration_task) {
+ ast_log(LOG_ERROR, "Unable to create expiration timer of %d seconds for %s\n",
+ ind->expires, name);
+ }
}
- ao2_ref(sub_tree, -1);
+ ao2_ref(ind->sub_tree, -1);
+ ast_free(ind);
+
return 0;
}
pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
}
} else {
+ struct initial_notify_data *ind = ast_malloc(sizeof(*ind));
+
+ if (!ind) {
+ pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
+ resource_tree_destroy(&tree);
+ return PJ_TRUE;
+ }
+
+ ind->sub_tree = ao2_bump(sub_tree);
+ /* Since this is a normal subscribe, pjproject takes care of the timer */
+ ind->expires = -1;
+
sub_tree->persistence = subscription_persistence_create(sub_tree);
- subscription_persistence_update(sub_tree, rdata);
+ subscription_persistence_update(sub_tree, rdata, SUBSCRIPTION_PERSISTENCE_CREATED);
sip_subscription_accept(sub_tree, rdata, resp);
- if (ast_sip_push_task(sub_tree->serializer, initial_notify_task, ao2_bump(sub_tree))) {
+ if (ast_sip_push_task(sub_tree->serializer, initial_notify_task, ind)) {
pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
ao2_ref(sub_tree, -1);
+ ast_free(ind);
}
}
* send_notify ultimately calls pjsip_evsub_send_request
* pjsip_evsub_send_request calls evsub's set_state
* set_state calls pubsub_evsub_set_state
- * pubsub_evsub_set_state checks state == TERMINATE_IN_PROGRESS
+ * pubsub_on_evsub_state checks state == TERMINATE_IN_PROGRESS
* removes the subscriptions
* cleans up references to evsub
* sets state = TERMINATED
* serialized_pubsub_on_refresh_timeout starts
* See (1) Above
*
+ * * Transmission failure sending NOTIFY or error response from client
+ * pjproject transaction timer expires or non OK response
+ * pjproject locks dialog
+ * calls pubsub_on_evsub_state with event TSX_STATE
+ * pubsub_on_evsub_state checks event == TSX_STATE
+ * removes the subscriptions
+ * cleans up references to evsub
+ * sets state = TERMINATED
+ * pjproject unlocks dialog
*
* * ast_sip_subscription_notify is called
* checks state == NORMAL
*
* Although this function is called for every state change, we only care
* about the TERMINATED state, and only when we're actually processing the final
- * notify (SIP_SUB_TREE_TERMINATE_IN_PROGRESS). In this case, we do all
- * the subscription tree cleanup tasks and decrement the evsub reference.
+ * notify (SIP_SUB_TREE_TERMINATE_IN_PROGRESS) OR when a transmission failure
+ * occurs (PJSIP_EVENT_TSX_STATE). In this case, we do all the subscription tree
+ * cleanup tasks and decrement the evsub reference.
*/
static void pubsub_on_evsub_state(pjsip_evsub *evsub, pjsip_event *event)
{
- struct sip_subscription_tree *sub_tree;
+ struct sip_subscription_tree *sub_tree =
+ pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
- ast_debug(3, "on_evsub_state called with state %s\n", pjsip_evsub_get_state_name(evsub));
+ ast_debug(3, "evsub %p state %s event %s sub_tree %p sub_tree state %s\n", evsub,
+ pjsip_evsub_get_state_name(evsub), pjsip_event_str(event->type), sub_tree,
+ (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
- if (pjsip_evsub_get_state(evsub) != PJSIP_EVSUB_STATE_TERMINATED) {
+ if (!sub_tree || pjsip_evsub_get_state(evsub) != PJSIP_EVSUB_STATE_TERMINATED) {
return;
}
- sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
- if (!sub_tree || sub_tree->state != SIP_SUB_TREE_TERMINATE_IN_PROGRESS) {
- ast_debug(1, "Possible terminate race prevented %p\n", sub_tree);
+ /* It's easier to write this as what we WANT to process, then negate it. */
+ if (!(sub_tree->state == SIP_SUB_TREE_TERMINATE_IN_PROGRESS
+ || (event->type == PJSIP_EVENT_TSX_STATE && sub_tree->state == SIP_SUB_TREE_NORMAL)
+ )) {
+ ast_debug(3, "Do nothing.\n");
return;
}
+ if (sub_tree->expiration_task) {
+ char task_name[256];
+
+ ast_sip_sched_task_get_name(sub_tree->expiration_task, task_name, sizeof(task_name));
+ ast_debug(3, "Cancelling timer: %s\n", task_name);
+ ast_sip_sched_task_cancel(sub_tree->expiration_task);
+ ao2_cleanup(sub_tree->expiration_task);
+ sub_tree->expiration_task = NULL;
+ }
+
remove_subscription(sub_tree);
pjsip_evsub_set_mod_data(evsub, pubsub_module.id, NULL);
ao2_ref(sub_tree, -1);
}
-static int serialized_pubsub_on_refresh_timeout(void *userdata)
+static int pubsub_on_refresh_timeout(void *userdata)
{
struct sip_subscription_tree *sub_tree = userdata;
pjsip_dialog *dlg = sub_tree->dlg;
+ ast_debug(3, "sub_tree %p sub_tree state %s\n", sub_tree,
+ (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
+
pjsip_dlg_inc_lock(dlg);
if (sub_tree->state >= SIP_SUB_TREE_TERMINATE_IN_PROGRESS) {
- ast_debug(1, "Possible terminate race prevented %p %d\n", sub_tree->evsub, sub_tree->state);
pjsip_dlg_dec_lock(dlg);
- ao2_cleanup(sub_tree);
return 0;
}
"Resource: %s", sub_tree->root->resource);
pjsip_dlg_dec_lock(dlg);
+
+ return 0;
+}
+
+static int serialized_pubsub_on_refresh_timeout(void *userdata)
+{
+ struct sip_subscription_tree *sub_tree = userdata;
+
+ ast_debug(3, "sub_tree %p sub_tree state %s\n", sub_tree,
+ (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
+
+ pubsub_on_refresh_timeout(userdata);
ao2_cleanup(sub_tree);
+
return 0;
}
struct sip_subscription_tree *sub_tree;
sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
+ ast_debug(3, "evsub %p sub_tree %p sub_tree state %s\n", evsub, sub_tree,
+ (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
+
if (!sub_tree || sub_tree->state != SIP_SUB_TREE_NORMAL) {
- ast_debug(1, "Possible terminate race prevented %p %d\n", sub_tree, sub_tree ? sub_tree->state : -1 );
return;
}
+ if (sub_tree->expiration_task) {
+ char task_name[256];
+
+ ast_sip_sched_task_get_name(sub_tree->expiration_task, task_name, sizeof(task_name));
+ ast_debug(3, "Cancelling timer: %s\n", task_name);
+ ast_sip_sched_task_cancel(sub_tree->expiration_task);
+ ao2_cleanup(sub_tree->expiration_task);
+ sub_tree->expiration_task = NULL;
+ }
+
/* PJSIP will set the evsub's state to terminated before calling into this function
* if the Expires value of the incoming SUBSCRIBE is 0.
*/
sub_tree->state = SIP_SUB_TREE_TERMINATE_PENDING;
}
+ subscription_persistence_update(sub_tree, rdata, SUBSCRIPTION_PERSISTENCE_REFRESHED);
+
if (ast_sip_push_task(sub_tree->serializer, serialized_pubsub_on_refresh_timeout, ao2_bump(sub_tree))) {
/* If we can't push the NOTIFY refreshing task...we'll just go with it. */
ast_log(LOG_ERROR, "Failed to push task to send NOTIFY.\n");
sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
if (!sub_tree || sub_tree->state != SIP_SUB_TREE_NORMAL) {
- ast_debug(1, "Possible terminate race prevented %p %d\n", sub_tree, sub_tree ? sub_tree->state : -1 );
return;
}