return 0;
}
+#define NEW_SUBSCRIBE(notifier, endpoint, resource, rdata) notifier->new_subscribe_with_rdata ? notifier->new_subscribe_with_rdata(endpoint, resource, rdata) : notifier->new_subscribe(endpoint, resource)
+
/*!
* \brief Build child nodes for a given parent.
*
* \param visited The resources that have already been visited.
*/
static void build_node_children(struct ast_sip_endpoint *endpoint, const struct ast_sip_subscription_handler *handler,
- struct resource_list *list, struct tree_node *parent, struct resources *visited)
+ struct resource_list *list, struct tree_node *parent, struct resources *visited, pjsip_rx_data *rdata)
{
int i;
child_list = retrieve_resource_list(resource, list->event);
if (!child_list) {
- int resp = handler->notifier->new_subscribe(endpoint, resource);
+ int resp = NEW_SUBSCRIBE(handler->notifier, endpoint, resource, rdata);
if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
char display_name[AST_MAX_EXTENSION] = "";
if (list->resource_display_name && handler->notifier->get_resource_display_name) {
ast_debug(1, "Cannot build children of resource %s due to allocation failure\n", resource);
continue;
}
- build_node_children(endpoint, handler, child_list, current, visited);
+ build_node_children(endpoint, handler, child_list, current, visited, rdata);
if (AST_VECTOR_SIZE(¤t->children) > 0) {
ast_debug(1, "List %s had no successful children.\n", resource);
if (AST_VECTOR_APPEND(&parent->children, current)) {
* \retval 300-699 Failure to subscribe to requested resource.
*/
static int build_resource_tree(struct ast_sip_endpoint *endpoint, const struct ast_sip_subscription_handler *handler,
- const char *resource, struct resource_tree *tree, int has_eventlist_support)
+ const char *resource, struct resource_tree *tree, int has_eventlist_support, pjsip_rx_data *rdata)
{
RAII_VAR(struct resource_list *, list, NULL, ao2_cleanup);
struct resources visited;
- if (!has_eventlist_support || !(list = retrieve_resource_list(resource, handler->event_name))) {
+ int not_eventlist_but_needs_children = !strcmp(handler->body_type, AST_SIP_DEVICE_FEATURE_SYNC_DATA);
+
+ if ((!has_eventlist_support && !not_eventlist_but_needs_children) || !(list = retrieve_resource_list(resource, handler->event_name))) {
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, NULL);
if (!tree->root) {
return 500;
}
- return handler->notifier->new_subscribe(endpoint, resource);
+ return NEW_SUBSCRIBE(handler->notifier, endpoint, resource, rdata);
}
ast_debug(2, "Subscription '%s->%s' is a list\n",
tree->notification_batch_interval = list->notification_batch_interval;
- build_node_children(endpoint, handler, list, tree->root, &visited);
+ build_node_children(endpoint, handler, list, tree->root, &visited, rdata);
AST_VECTOR_FREE(&visited);
if (AST_VECTOR_SIZE(&tree->root->children) > 0) {
sub->handler->subscription_shutdown(sub);
}
}
+
static int subscription_unreference_dialog(void *obj)
{
struct sip_subscription_tree *sub_tree = obj;
memset(&tree, 0, sizeof(tree));
resp = build_resource_tree(endpoint, handler, resource, &tree,
- ast_sip_pubsub_has_eventlist_support(rdata));
+ ast_sip_pubsub_has_eventlist_support(rdata), rdata);
if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
pj_status_t dlg_status;
return require;
}
+static void set_state_terminated(struct ast_sip_subscription *sub)
+{
+ int i;
+
+ sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
+ for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
+ set_state_terminated(AST_VECTOR_GET(&sub->children, i));
+ }
+}
+
/*!
* \brief Send a NOTIFY request to a subscriber
*
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) require);
}
+ if (sub_tree->root->handler->notifier->notify_created) {
+ /* The module for this event wants a callback to the pjsip_tx_data,
+ * e.g. so it can add custom headers or do something custom to the response. */
+ sub_tree->root->handler->notifier->notify_created(sub_tree->root, tdata);
+ }
+
if (sip_subscription_send_request(sub_tree, tdata)) {
/* do not call pjsip_tx_data_dec_ref(tdata). The pjsip_dlg_send_request deletes the message on error */
return -1;
notify_data = sub->handler->notifier->get_notify_data(sub);
if (!notify_data) {
+ ast_debug(3, "No notify data, not generating any body content\n");
return -1;
}
memset(&tree, 0, sizeof(tree));
resp = build_resource_tree(endpoint, handler, resource, &tree,
- ast_sip_pubsub_has_eventlist_support(rdata));
+ ast_sip_pubsub_has_eventlist_support(rdata), rdata);
if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, resp, NULL, NULL, NULL);
resource_tree_destroy(&tree);
sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator, &tree, &dlg_status, NULL);
if (!sub_tree) {
if (dlg_status != PJ_EEXISTS) {
+ ast_debug(3, "No dialog exists, rejecting\n");
pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
}
} else {
publication->handler = handler;
if (publication->handler->publication_state_change(publication, rdata->msg_info.msg->body,
AST_SIP_PUBLISH_STATE_INITIALIZED)) {
+ ast_debug(3, "Publication state change failed\n");
pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
ao2_cleanup(publication);
return NULL;
return PJ_FALSE;
}
-static void set_state_terminated(struct ast_sip_subscription *sub)
-{
- int i;
-
- sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
- for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
- set_state_terminated(AST_VECTOR_GET(&sub->children, i));
- }
-}
-
/*!
* \brief Callback sequence for subscription terminate:
*
/* The code in this function was previously in pubsub_on_evsub_state. */
-static void clean_sub_tree(pjsip_evsub *evsub){
+static void clean_sub_tree(pjsip_evsub *evsub)
+{
struct sip_subscription_tree *sub_tree;
sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
return;
}
-
/* 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)
This was previously handled by pubsub_on_rx_refresh setting:
'sub_tree->state = SIP_SUB_TREE_TERMINATE_PENDING' */
if (event->body.tsx_state.type == PJSIP_EVENT_RX_MSG &&
- !pjsip_method_cmp(&event->body.tsx_state.tsx->method, &pjsip_subscribe_method) &&
- pjsip_evsub_get_expires(evsub) == 0) {
-
+ !pjsip_method_cmp(&event->body.tsx_state.tsx->method, &pjsip_subscribe_method) &&
+ pjsip_evsub_get_expires(evsub) == 0) {
ast_debug(3, "Subscription ending, do nothing.\n");
return;
}
int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
{
struct sip_subscription_tree *sub_tree;
+ RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
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->state = SIP_SUB_TREE_TERMINATE_PENDING;
}
+ endpoint = ast_pjsip_rdata_get_endpoint(rdata);
+
+ /* If the handler wants a callback on refresh, then do it (some protocols require this). */
+ if (sub_tree->state == SIP_SUB_TREE_NORMAL && sub_tree->root->handler->notifier->refresh_subscribe) {
+ if (!sub_tree->root->handler->notifier->refresh_subscribe(sub_tree->root, rdata)) {
+ return; /* If the callback handled it, we're done. */
+ }
+ }
+
if (sub_tree->state == SIP_SUB_TREE_NORMAL && sub_tree->is_list) {
/* update RLS */
const char *resource = sub_tree->root->resource;
struct ast_sip_subscription *old_root = sub_tree->root;
struct ast_sip_subscription *new_root = NULL;
- RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
- struct ast_sip_subscription_handler *handler = NULL;
+
struct ast_sip_pubsub_body_generator *generator = NULL;
- if ((endpoint = ast_pjsip_rdata_get_endpoint(rdata))
- && (handler = subscription_get_handler_from_rdata(rdata, ast_sorcery_object_get_id(endpoint)))
- && (generator = subscription_get_generator_from_rdata(rdata, handler))) {
+ if (endpoint && (generator = subscription_get_generator_from_rdata(rdata, sub_tree->root->handler))) {
struct resource_tree tree;
int resp;
memset(&tree, 0, sizeof(tree));
- resp = build_resource_tree(endpoint, handler, resource, &tree,
- ast_sip_pubsub_has_eventlist_support(rdata));
+ resp = build_resource_tree(endpoint, sub_tree->root->handler, resource, &tree,
+ ast_sip_pubsub_has_eventlist_support(rdata), rdata);
if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
- new_root = create_virtual_subscriptions(handler, resource, generator, sub_tree, tree.root);
+ new_root = create_virtual_subscriptions(sub_tree->root->handler, resource, generator, sub_tree, tree.root);
if (new_root) {
if (cmp_subscription_childrens(old_root, new_root)) {
ast_debug(1, "RLS '%s->%s' was modified, regenerate it\n", ast_sorcery_object_get_id(endpoint), old_root->resource);
}
tree = ast_calloc(1, sizeof(*tree));
- resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1);
+ resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1, NULL);
if (resp != 200) {
ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
return AST_TEST_FAIL;
}
tree = ast_calloc(1, sizeof(*tree));
- resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1);
+ resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1, NULL);
if (resp != 200) {
ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
return AST_TEST_FAIL;
}
tree = ast_calloc(1, sizeof(*tree));
- resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1);
+ resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1, NULL);
if (resp != 200) {
ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
return AST_TEST_FAIL;
}
tree = ast_calloc(1, sizeof(*tree));
- resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1);
+ resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1, NULL);
if (resp != 200) {
ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
return AST_TEST_FAIL;
}
tree = ast_calloc(1, sizeof(*tree));
- resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1);
+ resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1, NULL);
if (resp != 200) {
ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
return AST_TEST_FAIL;
}
tree = ast_calloc(1, sizeof(*tree));
- resp = build_resource_tree(NULL, &test_handler, "herp", tree, 1);
+ resp = build_resource_tree(NULL, &test_handler, "herp", tree, 1, NULL);
if (resp == 200) {
ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
return AST_TEST_FAIL;
/* Since the test_handler is for event "test", this should not build a list, but
* instead result in a single resource being created, called "foo"
*/
- resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1);
+ resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1, NULL);
if (resp != 200) {
ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
return AST_TEST_FAIL;