stasis: Segment channel snapshot to reduce creation cost.
authorJoshua Colp <jcolp@digium.com>
Wed, 7 Nov 2018 17:18:34 +0000 (13:18 -0400)
committerJoshua Colp <jcolp@digium.com>
Mon, 26 Nov 2018 18:56:24 +0000 (12:56 -0600)
When a channel snapshot was created it used to be done
from scratch, copying all data (many strings). This incurs
a cost when doing so.

This change segments the channel snapshot into different
components which can be reused if unchanged from the
previous snapshot creation, reducing the cost. In normal
cases this results in some pointers being copied with
reference count being bumped, some integers being set,
and a string or two copied. The other benefit is that it
is now possible to determine if a channel snapshot update
is redundant and thus stop it before a message is published
to stasis.

The specific segments in the channel snapshot were split up
based on whether they are changed together, how often they
are changed, and their general grouping. In practice only
1 (or 0) of the segments actually get changed in normal
operation.

Invalidation is done by setting a flag on the channel when
the segment source is changed, forcing creation of a new
segment when the channel snapshot is created.

ASTERISK-28119

Change-Id: I5d7ef3df963a88ac47bc187d73c5225c315f8423

32 files changed:
apps/app_queue.c
channels/chan_pjsip.c
channels/pjsip/cli_commands.c
configs/samples/ari.conf.sample
configs/samples/manager.conf.sample
include/asterisk/channel.h
include/asterisk/stasis_channels.h
main/bridge.c
main/cdr.c
main/cel.c
main/channel.c
main/channel_internal_api.c
main/cli.c
main/core_local.c
main/endpoints.c
main/manager.c
main/manager_bridges.c
main/manager_channels.c
main/stasis_bridges.c
main/stasis_channels.c
pbx/pbx_realtime.c
res/ari/resource_bridges.c
res/ari/resource_channels.c
res/parking/parking_applications.c
res/parking/parking_bridge_features.c
res/res_chan_stats.c
res/res_pjsip/pjsip_configuration.c
res/res_pjsip_refer.c
res/res_stasis.c
res/stasis/app.c
tests/test_cel.c
tests/test_stasis_channels.c

index 17e35f9..2e59bf6 100644 (file)
@@ -5890,13 +5890,13 @@ static void queue_agent_cb(void *userdata, struct stasis_subscription *sub,
        agent_blob = stasis_message_data(msg);
 
        if (ast_channel_agent_login_type() == stasis_message_type(msg)) {
-               ast_queue_log("NONE", agent_blob->snapshot->uniqueid,
+               ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
                        ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
-                       "AGENTLOGIN", "%s", agent_blob->snapshot->name);
+                       "AGENTLOGIN", "%s", agent_blob->snapshot->base->name);
        } else if (ast_channel_agent_logoff_type() == stasis_message_type(msg)) {
-               ast_queue_log("NONE", agent_blob->snapshot->uniqueid,
+               ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
                        ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
-                       "AGENTLOGOFF", "%s|%ld", agent_blob->snapshot->name,
+                       "AGENTLOGOFF", "%s|%ld", agent_blob->snapshot->base->name,
                        (long) ast_json_integer_get(ast_json_object_get(agent_blob->blob, "logintime")));
        }
 }
@@ -6088,8 +6088,8 @@ static void log_attended_transfer(struct queue_stasis_data *queue_data, struct a
                ast_str_set(&transfer_str, 0, "APP|%s", atxfer_msg->dest.app);
                break;
        case AST_ATTENDED_TRANSFER_DEST_LINK:
-               ast_str_set(&transfer_str, 0, "LINK|%s|%s", atxfer_msg->dest.links[0]->name,
-                               atxfer_msg->dest.links[1]->name);
+               ast_str_set(&transfer_str, 0, "LINK|%s|%s", atxfer_msg->dest.links[0]->base->name,
+                               atxfer_msg->dest.links[1]->base->name);
                break;
        case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
        case AST_ATTENDED_TRANSFER_DEST_FAIL:
@@ -6098,7 +6098,7 @@ static void log_attended_transfer(struct queue_stasis_data *queue_data, struct a
                return;
        }
 
-       ast_queue_log(queue_data->queue->name, caller->uniqueid, queue_data->member->membername, "ATTENDEDTRANSFER", "%s|%ld|%ld|%d",
+       ast_queue_log(queue_data->queue->name, caller->base->uniqueid, queue_data->member->membername, "ATTENDEDTRANSFER", "%s|%ld|%ld|%d",
                        ast_str_buffer(transfer_str),
                        (long) (queue_data->starttime - queue_data->holdstart),
                        (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
@@ -6131,11 +6131,11 @@ static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub,
                return;
        }
 
-       if (!strcmp(enter_blob->channel->uniqueid, queue_data->caller_uniqueid)) {
+       if (!strcmp(enter_blob->channel->base->uniqueid, queue_data->caller_uniqueid)) {
                ast_string_field_set(queue_data, bridge_uniqueid,
                                enter_blob->bridge->uniqueid);
                ast_debug(3, "Detected entry of caller channel %s into bridge %s\n",
-                               enter_blob->channel->name, queue_data->bridge_uniqueid);
+                               enter_blob->channel->base->name, queue_data->bridge_uniqueid);
        }
 }
 
@@ -6186,7 +6186,7 @@ static void handle_blind_transfer(void *userdata, struct stasis_subscription *su
        context = transfer_msg->context;
 
        ast_debug(3, "Detected blind transfer in queue %s\n", queue_data->queue->name);
-       ast_queue_log(queue_data->queue->name, caller_snapshot->uniqueid, queue_data->member->membername,
+       ast_queue_log(queue_data->queue->name, caller_snapshot->base->uniqueid, queue_data->member->membername,
                        "BLINDTRANSFER", "%s|%s|%ld|%ld|%d",
                        exten, context,
                        (long) (queue_data->starttime - queue_data->holdstart),
@@ -6302,9 +6302,9 @@ static void handle_local_optimization_begin(void *userdata, struct stasis_subscr
                return;
        }
 
-       if (!strcmp(local_one->uniqueid, queue_data->member_uniqueid)) {
+       if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
                optimization = &queue_data->member_optimize;
-       } else if (!strcmp(local_two->uniqueid, queue_data->caller_uniqueid)) {
+       } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
                optimization = &queue_data->caller_optimize;
        } else {
                return;
@@ -6313,9 +6313,9 @@ static void handle_local_optimization_begin(void *userdata, struct stasis_subscr
        /* We only allow move-swap optimizations, so there had BETTER be a source */
        ast_assert(source != NULL);
 
-       optimization->source_chan_uniqueid = ast_strdup(source->uniqueid);
+       optimization->source_chan_uniqueid = ast_strdup(source->base->uniqueid);
        if (!optimization->source_chan_uniqueid) {
-               ast_log(LOG_ERROR, "Unable to track local channel optimization for channel %s. Expect further errors\n", local_one->name);
+               ast_log(LOG_ERROR, "Unable to track local channel optimization for channel %s. Expect further errors\n", local_one->base->name);
                return;
        }
        id = ast_json_integer_get(ast_json_object_get(ast_multi_channel_blob_get_json(optimization_blob), "id"));
@@ -6354,10 +6354,10 @@ static void handle_local_optimization_end(void *userdata, struct stasis_subscrip
                return;
        }
 
-       if (!strcmp(local_one->uniqueid, queue_data->member_uniqueid)) {
+       if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
                optimization = &queue_data->member_optimize;
                is_caller = 0;
-       } else if (!strcmp(local_two->uniqueid, queue_data->caller_uniqueid)) {
+       } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
                optimization = &queue_data->caller_optimize;
                is_caller = 1;
        } else {
@@ -6420,16 +6420,16 @@ static void handle_hangup(void *userdata, struct stasis_subscription *sub,
                return;
        }
 
-       if (!strcmp(channel_blob->snapshot->uniqueid, queue_data->caller_uniqueid)) {
+       if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
                reason = CALLER;
-       } else if (!strcmp(channel_blob->snapshot->uniqueid, queue_data->member_uniqueid)) {
+       } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
                reason = AGENT;
        } else {
                ao2_unlock(queue_data);
                return;
        }
 
-       chan = ast_channel_get_by_name(channel_blob->snapshot->name);
+       chan = ast_channel_get_by_name(channel_blob->snapshot->base->name);
        if (chan && (ast_channel_has_role(chan, AST_TRANSFERER_ROLE_NAME) ||
                     !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "ATTENDEDTRANSFER")) ||
                     !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER")))) {
@@ -6446,9 +6446,9 @@ static void handle_hangup(void *userdata, struct stasis_subscription *sub,
        ao2_unlock(queue_data);
 
        ast_debug(3, "Detected hangup of queue %s channel %s\n", reason == CALLER ? "caller" : "member",
-                       channel_blob->snapshot->name);
+                       channel_blob->snapshot->base->name);
 
-       ast_queue_log(queue_data->queue->name, caller_snapshot->uniqueid, queue_data->member->membername,
+       ast_queue_log(queue_data->queue->name, caller_snapshot->base->uniqueid, queue_data->member->membername,
                        reason == CALLER ? "COMPLETECALLER" : "COMPLETEAGENT", "%ld|%ld|%d",
                (long) (queue_data->starttime - queue_data->holdstart),
                (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
index d0a74cd..e44f328 100644 (file)
@@ -1169,7 +1169,7 @@ static int chan_pjsip_devicestate(const char *data)
                        continue;
                }
 
-               if (chan_pjsip_get_hold(snapshot->uniqueid)) {
+               if (chan_pjsip_get_hold(snapshot->base->uniqueid)) {
                        ast_devstate_aggregate_add(&aggregate, AST_DEVICE_ONHOLD);
                } else {
                        ast_devstate_aggregate_add(&aggregate, ast_state_chan2dev(snapshot->state));
index 9a8dc29..2ce2369 100644 (file)
@@ -61,13 +61,13 @@ static int cli_channel_sort(const void *obj, const void *arg, int flags)
 
        switch (flags & OBJ_SEARCH_MASK) {
        case OBJ_SEARCH_OBJECT:
-               right_key = right_obj->name;
+               right_key = right_obj->base->name;
                /* Fall through */
        case OBJ_SEARCH_KEY:
-               cmp = strcmp(left_obj->name, right_key);
+               cmp = strcmp(left_obj->base->name, right_key);
                break;
        case OBJ_SEARCH_PARTIAL_KEY:
-               cmp = strncmp(left_obj->name, right_key, strlen(right_key));
+               cmp = strncmp(left_obj->base->name, right_key, strlen(right_key));
                break;
        default:
                cmp = 0;
@@ -86,17 +86,17 @@ static int cli_channelstats_sort(const void *obj, const void *arg, int flags)
 
        switch (flags & OBJ_SEARCH_MASK) {
        case OBJ_SEARCH_OBJECT:
-               cmp = strcmp(left_obj->bridgeid, right_obj->bridgeid);
+               cmp = strcmp(left_obj->bridge->id, right_obj->bridge->id);
                if (cmp) {
                        return cmp;
                }
-               right_key = right_obj->name;
+               right_key = right_obj->base->name;
                /* Fall through */
        case OBJ_SEARCH_KEY:
-               cmp = strcmp(left_obj->name, right_key);
+               cmp = strcmp(left_obj->base->name, right_key);
                break;
        case OBJ_SEARCH_PARTIAL_KEY:
-               cmp = strncmp(left_obj->name, right_key, strlen(right_key));
+               cmp = strncmp(left_obj->base->name, right_key, strlen(right_key));
                break;
        default:
                cmp = 0;
@@ -115,15 +115,15 @@ static int cli_channel_compare(void *obj, void *arg, int flags)
 
        switch (flags & OBJ_SEARCH_MASK) {
        case OBJ_SEARCH_OBJECT:
-               right_key = right_obj->name;
+               right_key = right_obj->base->name;
                /* Fall through */
        case OBJ_SEARCH_KEY:
-               if (strcmp(left_obj->name, right_key) == 0) {
+               if (strcmp(left_obj->base->name, right_key) == 0) {
                        cmp = CMP_MATCH | CMP_STOP;
                }
                break;
        case OBJ_SEARCH_PARTIAL_KEY:
-               if (strncmp(left_obj->name, right_key, strlen(right_key)) == 0) {
+               if (strncmp(left_obj->base->name, right_key, strlen(right_key)) == 0) {
                        cmp = CMP_MATCH;
                }
                break;
@@ -144,18 +144,18 @@ static int cli_channelstats_compare(void *obj, void *arg, int flags)
 
        switch (flags & OBJ_SEARCH_MASK) {
        case OBJ_SEARCH_OBJECT:
-               if (strcmp(left_obj->bridgeid, right_obj->bridgeid) == 0
-                       && strcmp(left_obj->name, right_obj->name) == 0) {
+               if (strcmp(left_obj->bridge->id, right_obj->bridge->id) == 0
+                       && strcmp(left_obj->base->name, right_obj->base->name) == 0) {
                        return CMP_MATCH | CMP_STOP;
                }
                break;
        case OBJ_SEARCH_KEY:
-               if (strcmp(left_obj->name, right_key) == 0) {
+               if (strcmp(left_obj->base->name, right_key) == 0) {
                        cmp = CMP_MATCH | CMP_STOP;
                }
                break;
        case OBJ_SEARCH_PARTIAL_KEY:
-               if (strncmp(left_obj->name, right_key, strlen(right_key)) == 0) {
+               if (strncmp(left_obj->base->name, right_key, strlen(right_key)) == 0) {
                        cmp = CMP_MATCH;
                }
                break;
@@ -172,7 +172,7 @@ static int cli_message_to_snapshot(void *obj, void *arg, int flags)
        struct ast_channel_snapshot *snapshot = obj;
        struct ao2_container *snapshots = arg;
 
-       if (!strcmp(snapshot->type, "PJSIP")) {
+       if (!strcmp(snapshot->base->type, "PJSIP")) {
                ao2_link(snapshots, snapshot);
                return CMP_MATCH;
        }
@@ -185,8 +185,8 @@ static int cli_filter_channels(void *obj, void *arg, int flags)
        struct ast_channel_snapshot *channel = obj;
        regex_t *regexbuf = arg;
 
-       if (!regexec(regexbuf, channel->name, 0, NULL, 0)
-               || !regexec(regexbuf, channel->appl, 0, NULL, 0)) {
+       if (!regexec(regexbuf, channel->base->name, 0, NULL, 0)
+               || !regexec(regexbuf, channel->dialplan->appl, 0, NULL, 0)) {
                return 0;
        }
 
@@ -236,7 +236,7 @@ static const char *cli_channel_get_id(const void *obj)
 {
        const struct ast_channel_snapshot *snapshot = obj;
 
-       return snapshot->name;
+       return snapshot->base->name;
 }
 
 static void *cli_channel_retrieve_by_id(const char *id)
@@ -280,16 +280,16 @@ static int cli_channel_print_body(void *obj, void *arg, int flags)
 
        ast_assert(context->output_buffer != NULL);
 
-       print_name_len = strlen(snapshot->name) + strlen(snapshot->appl) + 2;
+       print_name_len = strlen(snapshot->base->name) + strlen(snapshot->dialplan->appl) + 2;
        print_name = alloca(print_name_len);
 
        /* Append the application */
-       snprintf(print_name, print_name_len, "%s/%s", snapshot->name, snapshot->appl);
+       snprintf(print_name, print_name_len, "%s/%s", snapshot->base->name, snapshot->dialplan->appl);
 
        indent = CLI_INDENT_TO_SPACES(context->indent_level);
        flexwidth = CLI_LAST_TABSTOP - indent;
 
-       ast_format_duration_hh_mm_ss(ast_tvnow().tv_sec - snapshot->creationtime.tv_sec, print_time, 32);
+       ast_format_duration_hh_mm_ss(ast_tvnow().tv_sec - snapshot->base->creationtime.tv_sec, print_time, 32);
 
        ast_str_append(&context->output_buffer, 0, "%*s: %-*.*s %-12.12s  %-11.11s\n",
                CLI_INDENT_TO_SPACES(context->indent_level), "Channel",
@@ -307,9 +307,9 @@ static int cli_channel_print_body(void *obj, void *arg, int flags)
                        "%*s: %-*.*s  CLCID: \"%s\" <%s>\n",
                        indent, "Exten",
                        flexwidth, flexwidth,
-                       snapshot->exten,
-                       snapshot->connected_name,
-                       snapshot->connected_number
+                       snapshot->dialplan->exten,
+                       snapshot->connected->name,
+                       snapshot->connected->number
                        );
                context->indent_level--;
                if (context->indent_level == 0) {
@@ -338,7 +338,7 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags)
 {
        struct ast_sip_cli_context *context = arg;
        const struct ast_channel_snapshot *snapshot = obj;
-       struct ast_channel *channel = ast_channel_get_by_name(snapshot->name);
+       struct ast_channel *channel = ast_channel_get_by_name(snapshot->base->name);
        struct ast_sip_channel_pvt *cpvt = channel ? ast_channel_tech_pvt(channel) : NULL;
        struct ast_sip_session *session;
        struct ast_sip_session_media *media;
@@ -351,7 +351,7 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags)
        ast_assert(context->output_buffer != NULL);
 
        if (!channel) {
-               ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name);
+               ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->base->name);
                return -1;
        }
 
@@ -359,7 +359,7 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags)
 
        session = cpvt->session;
        if (!session) {
-               ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name);
+               ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->base->name);
                ast_channel_unlock(channel);
                ao2_cleanup(channel);
                return -1;
@@ -367,7 +367,7 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags)
 
        media = session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];
        if (!media || !media->rtp) {
-               ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name);
+               ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->base->name);
                ast_channel_unlock(channel);
                ao2_cleanup(channel);
                return -1;
@@ -383,18 +383,18 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags)
 
        ast_channel_unlock(channel);
 
-       print_name = ast_strdupa(snapshot->name);
+       print_name = ast_strdupa(snapshot->base->name);
        /* Skip the PJSIP/.  We know what channel type it is and we need the space. */
        print_name += 6;
 
-       ast_format_duration_hh_mm_ss(ast_tvnow().tv_sec - snapshot->creationtime.tv_sec, print_time, 32);
+       ast_format_duration_hh_mm_ss(ast_tvnow().tv_sec - snapshot->base->creationtime.tv_sec, print_time, 32);
 
        if (ast_rtp_instance_get_stats(rtp, &stats, AST_RTP_INSTANCE_STAT_ALL)) {
-               ast_str_append(&context->output_buffer, 0, "%s direct media\n", snapshot->name);
+               ast_str_append(&context->output_buffer, 0, "%s direct media\n", snapshot->base->name);
        } else {
                ast_str_append(&context->output_buffer, 0,
                        " %8.8s %-18.18s %-8.8s %-6.6s %6u%s %6u%s %3u %7.3f %6u%s %6u%s %3u %7.3f %7.3f\n",
-                       snapshot->bridgeid,
+                       snapshot->bridge->id,
                        print_name,
                        print_time,
                        codec_in_use,
index 8729b1e..5ce3166 100644 (file)
@@ -17,6 +17,8 @@ enabled = yes       ; When set to no, ARI support is disabled.
 ; Display certain channel variables every time a channel-oriented
 ; event is emitted:
 ;
+; Note that this does incur a performance penalty and should be avoided if possible.
+;
 ;channelvars = var1,var2,var3
 
 ;[username]
index 989441a..405e0d3 100644 (file)
@@ -55,6 +55,8 @@ bindaddr = 0.0.0.0
 ; Display certain channel variables every time a channel-oriented
 ; event is emitted:
 ;
+; Note that this does incur a performance penalty and should be avoided if possible.
+;
 ;channelvars = var1,var2,var3
 
 ; debug = on   ; enable some debugging info in AMI messages (default off).
index 9627ae2..58a4879 100644 (file)
@@ -4258,6 +4258,7 @@ enum ast_channel_state ast_channel_state(const struct ast_channel *chan);
 ast_callid ast_channel_callid(const struct ast_channel *chan);
 struct ast_channel_snapshot *ast_channel_snapshot(const struct ast_channel *chan);
 void ast_channel_snapshot_set(struct ast_channel *chan, struct ast_channel_snapshot *snapshot);
+struct ast_flags *ast_channel_snapshot_segment_flags(struct ast_channel *chan);
 
 /*!
  * \pre chan is locked
index 2aeff6f..c90470a 100644 (file)
  */
 
 /*!
+ * \since 17
+ * \brief Channel snapshot invalidation flags, used to force generation of segments
+ */
+enum ast_channel_snapshot_segment_invalidation {
+       /*! Invalidate the bridge segment */
+       AST_CHANNEL_SNAPSHOT_INVALIDATE_BRIDGE = (1 << 1),
+       /*! Invalidate the dialplan segment */
+       AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN = (1 << 2),
+       /*! Invalidate the connected segment */
+       AST_CHANNEL_SNAPSHOT_INVALIDATE_CONNECTED = (1 << 3),
+       /*! Invalidate the caller segment */
+       AST_CHANNEL_SNAPSHOT_INVALIDATE_CALLER = (1 << 4),
+       /*! Invalidate the hangup segment */
+       AST_CHANNEL_SNAPSHOT_INVALIDATE_HANGUP = (1 << 5),
+       /*! Invalidate the peer segment */
+       AST_CHANNEL_SNAPSHOT_INVALIDATE_PEER = (1 << 6),
+       /*! Invalidate the base segment */
+       AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE = (1 << 7),
+};
+
+/*!
+ * \since 17
+ * \brief Structure containing bridge information for a channel snapshot.
+ */
+struct ast_channel_snapshot_bridge {
+       char id[0]; /*!< Unique Bridge Identifier */
+};
+
+/*!
+ * \since 17
+ * \brief Structure containing dialplan information for a channel snapshot.
+ */
+struct ast_channel_snapshot_dialplan {
+       AST_DECLARE_STRING_FIELDS(
+               AST_STRING_FIELD(appl);             /*!< Current application */
+               AST_STRING_FIELD(data);             /*!< Data passed to current application */
+               AST_STRING_FIELD(context);          /*!< Current extension context */
+               AST_STRING_FIELD(exten);            /*!< Current extension number */
+       );
+       int priority; /*!< Current extension priority */
+};
+
+/*!
+ * \since 17
+ * \brief Structure containing caller information for a channel snapshot.
+ */
+struct ast_channel_snapshot_caller {
+       AST_DECLARE_STRING_FIELDS(
+               AST_STRING_FIELD(name);           /*!< Caller ID Name */
+               AST_STRING_FIELD(number);         /*!< Caller ID Number */
+               AST_STRING_FIELD(dnid);           /*!< Dialed ID Number */
+               AST_STRING_FIELD(dialed_subaddr); /*!< Dialed subaddress */
+               AST_STRING_FIELD(ani);            /*!< Caller ID ANI Number */
+               AST_STRING_FIELD(rdnis);          /*!< Caller ID RDNIS Number */
+               AST_STRING_FIELD(subaddr);        /*!< Caller subaddress */
+       );
+       int pres; /*!< Caller ID presentation. */
+};
+
+/*!
+ * \since 17
+ * \brief Structure containing connected information for a channel snapshot.
+ */
+struct ast_channel_snapshot_connected {
+       char *number; /*!< Connected Line Number */
+       char name[0]; /*!< Connected Line Name */
+};
+
+/*!
+ * \since 17
+ * \brief Structure containing base information for a channel snapshot.
+ */
+struct ast_channel_snapshot_base {
+       AST_DECLARE_STRING_FIELDS(
+               AST_STRING_FIELD(name);        /*!< ASCII unique channel name */
+               AST_STRING_FIELD(uniqueid);    /*!< Unique Channel Identifier */
+               AST_STRING_FIELD(accountcode); /*!< Account code for billing */
+               AST_STRING_FIELD(userfield);   /*!< Userfield for CEL billing */
+               AST_STRING_FIELD(language);    /*!< The default spoken language for the channel */
+               AST_STRING_FIELD(type);        /*!< Type of channel technology */
+       );
+       struct timeval creationtime; /*!< The time of channel creation */
+       int tech_properties;         /*!< Properties of the channel's technology */
+};
+
+/*!
+ * \since 17
+ * \brief Structure containing peer information for a channel snapshot.
+ */
+struct ast_channel_snapshot_peer {
+       char *linkedid;   /*!< Linked Channel Identifier -- gets propagated by linkage */
+       char account[0]; /*!< Peer account code for billing */
+};
+
+/*!
+ * \since 17
+ * \brief Structure containing hangup information for a channel snapshot.
+ */
+struct ast_channel_snapshot_hangup {
+       int cause;      /*!< Why is the channel hanged up. See causes.h */
+       char source[0]; /*!< Who is responsible for hanging up this channel */
+};
+
+/*!
  * \since 12
  * \brief Structure representing a snapshot of channel state.
  *
  * While not enforced programmatically, this object is shared across multiple
  * threads, and should be treated as an immutable object.
+ *
+ * It is guaranteed that the segments of this snapshot will always exist
+ * when accessing the snapshot.
  */
 struct ast_channel_snapshot {
-       AST_DECLARE_STRING_FIELDS(
-               AST_STRING_FIELD(name);             /*!< ASCII unique channel name */
-               AST_STRING_FIELD(uniqueid);         /*!< Unique Channel Identifier */
-               AST_STRING_FIELD(linkedid);         /*!< Linked Channel Identifier -- gets propagated by linkage */
-               AST_STRING_FIELD(appl);             /*!< Current application */
-               AST_STRING_FIELD(data);             /*!< Data passed to current application */
-               AST_STRING_FIELD(context);          /*!< Dialplan: Current extension context */
-               AST_STRING_FIELD(exten);            /*!< Dialplan: Current extension number */
-               AST_STRING_FIELD(accountcode);      /*!< Account code for billing */
-               AST_STRING_FIELD(peeraccount);      /*!< Peer account code for billing */
-               AST_STRING_FIELD(userfield);        /*!< Userfield for CEL billing */
-               AST_STRING_FIELD(hangupsource);     /*!< Who is responsible for hanging up this channel */
-               AST_STRING_FIELD(caller_name);      /*!< Caller ID Name */
-               AST_STRING_FIELD(caller_number);    /*!< Caller ID Number */
-               AST_STRING_FIELD(caller_dnid);      /*!< Dialed ID Number */
-               AST_STRING_FIELD(caller_ani);       /*!< Caller ID ANI Number */
-               AST_STRING_FIELD(caller_rdnis);     /*!< Caller ID RDNIS Number */
-               AST_STRING_FIELD(caller_subaddr);   /*!< Caller subaddress */
-               AST_STRING_FIELD(dialed_subaddr);   /*!< Dialed subaddress */
-               AST_STRING_FIELD(connected_name);   /*!< Connected Line Name */
-               AST_STRING_FIELD(connected_number); /*!< Connected Line Number */
-               AST_STRING_FIELD(language);         /*!< The default spoken language for the channel */
-               AST_STRING_FIELD(bridgeid);         /*!< Unique Bridge Identifier */
-               AST_STRING_FIELD(type);             /*!< Type of channel technology */
-       );
-
-       struct timeval creationtime;            /*!< The time of channel creation */
-       enum ast_channel_state state;           /*!< State of line */
-       int priority;                           /*!< Dialplan: Current extension priority */
-       int amaflags;                           /*!< AMA flags for billing */
-       int hangupcause;                        /*!< Why is the channel hanged up. See causes.h */
-       int caller_pres;                        /*!< Caller ID presentation. */
-       struct ast_flags flags;                 /*!< channel flags of AST_FLAG_ type */
-       struct ast_flags softhangup_flags;      /*!< softhangup channel flags */
-       struct varshead *manager_vars;          /*!< Variables to be appended to manager events */
-       int tech_properties;                    /*!< Properties of the channel's technology */
-       struct varshead *ari_vars;              /*!< Variables to be appended to ARI events */
+       struct ast_channel_snapshot_base *base;           /*!< Base information about the channel */
+       struct ast_channel_snapshot_peer *peer;           /*!< Peer information */
+       struct ast_channel_snapshot_caller *caller;       /*!< Information about the caller */
+       struct ast_channel_snapshot_connected *connected; /*!< Information about who this channel is connected to */
+       struct ast_channel_snapshot_bridge *bridge;       /*!< Information about the bridge */
+       struct ast_channel_snapshot_dialplan *dialplan;   /*!< Information about the dialplan */
+       struct ast_channel_snapshot_hangup *hangup;       /*!< Hangup information */
+       enum ast_channel_state state;                     /*!< State of line */
+       int amaflags;                                     /*!< AMA flags for billing */
+       struct ast_flags flags;                           /*!< channel flags of AST_FLAG_ type */
+       struct ast_flags softhangup_flags;                /*!< softhangup channel flags */
+       struct varshead *manager_vars;                    /*!< Variables to be appended to manager events */
+       struct varshead *ari_vars;                        /*!< Variables to be appended to ARI events */
 };
 
 /*!
@@ -360,6 +443,18 @@ void ast_channel_stage_snapshot(struct ast_channel *chan);
 void ast_channel_stage_snapshot_done(struct ast_channel *chan);
 
 /*!
+ * \since 17
+ * \brief Invalidate a channel snapshot segment from being reused
+ *
+ * \pre chan is locked
+ *
+ * \param chan Channel to invalidate the segment on.
+ * \param segment The segment to invalidate.
+ */
+void ast_channel_snapshot_invalidate_segment(struct ast_channel *chan,
+       enum ast_channel_snapshot_segment_invalidation segment);
+
+/*!
  * \since 12
  * \brief Publish a \ref ast_channel_snapshot for a channel.
  *
index 024c6ab..a65927d 100644 (file)
@@ -5157,7 +5157,7 @@ static int bridge_show_specific_print_channel(void *obj, void *arg, int flags)
                return 0;
        }
 
-       ast_cli(a->fd, "Channel: %s\n", snapshot->name);
+       ast_cli(a->fd, "Channel: %s\n", snapshot->base->name);
        ao2_ref(snapshot, -1);
 
        return 0;
index e321c22..2e3b205 100644 (file)
@@ -803,7 +803,7 @@ static void cdr_object_snapshot_copy(struct cdr_object_snapshot *dst, struct cdr
 static void cdr_object_transition_state(struct cdr_object *cdr, struct cdr_object_fn_table *fn_table)
 {
        CDR_DEBUG("%p - Transitioning CDR for %s from state %s to %s\n",
-               cdr, cdr->party_a.snapshot->name,
+               cdr, cdr->party_a.snapshot->base->name,
                cdr->fn_table ? cdr->fn_table->name : "NONE", fn_table->name);
        cdr->fn_table = fn_table;
        if (cdr->fn_table->init_function) {
@@ -938,9 +938,9 @@ static void cdr_all_relink(struct cdr_object *cdr)
 {
        ao2_lock(active_cdrs_all);
        if (cdr->party_b.snapshot) {
-               if (strcasecmp(cdr->party_b_name, cdr->party_b.snapshot->name)) {
+               if (strcasecmp(cdr->party_b_name, cdr->party_b.snapshot->base->name)) {
                        ao2_unlink_flags(active_cdrs_all, cdr, OBJ_NOLOCK);
-                       ast_string_field_set(cdr, party_b_name, cdr->party_b.snapshot->name);
+                       ast_string_field_set(cdr, party_b_name, cdr->party_b.snapshot->base->name);
                        ao2_link_flags(active_cdrs_all, cdr, OBJ_NOLOCK);
                }
        } else {
@@ -1039,16 +1039,16 @@ static struct cdr_object *cdr_object_alloc(struct ast_channel_snapshot *chan)
                ao2_cleanup(cdr);
                return NULL;
        }
-       ast_string_field_set(cdr, uniqueid, chan->uniqueid);
-       ast_string_field_set(cdr, name, chan->name);
-       ast_string_field_set(cdr, linkedid, chan->linkedid);
+       ast_string_field_set(cdr, uniqueid, chan->base->uniqueid);
+       ast_string_field_set(cdr, name, chan->base->name);
+       ast_string_field_set(cdr, linkedid, chan->peer->linkedid);
        cdr->disposition = AST_CDR_NULL;
        cdr->sequence = ast_atomic_fetchadd_int(&global_cdr_sequence, +1);
 
        cdr->party_a.snapshot = chan;
        ao2_t_ref(cdr->party_a.snapshot, +1, "bump snapshot during CDR creation");
 
-       CDR_DEBUG("%p - Created CDR for channel %s\n", cdr, chan->name);
+       CDR_DEBUG("%p - Created CDR for channel %s\n", cdr, chan->base->name);
 
        cdr_object_transition_state(cdr, &single_state_fn_table);
 
@@ -1145,11 +1145,11 @@ static int snapshot_cep_changed(struct ast_channel_snapshot *old_snapshot,
         * will attempt to clear the application and restore the dummy originate application
         * of "AppDialX". Ignore application changes to AppDialX as a result.
         */
-       if (strcmp(new_snapshot->appl, old_snapshot->appl)
-               && strncasecmp(new_snapshot->appl, "appdial", 7)
-               && (strcmp(new_snapshot->context, old_snapshot->context)
-                       || strcmp(new_snapshot->exten, old_snapshot->exten)
-                       || new_snapshot->priority != old_snapshot->priority)) {
+       if (strcmp(new_snapshot->dialplan->appl, old_snapshot->dialplan->appl)
+               && strncasecmp(new_snapshot->dialplan->appl, "appdial", 7)
+               && (strcmp(new_snapshot->dialplan->context, old_snapshot->dialplan->context)
+                       || strcmp(new_snapshot->dialplan->exten, old_snapshot->dialplan->exten)
+                       || new_snapshot->dialplan->priority != old_snapshot->dialplan->priority)) {
                return 1;
        }
 
@@ -1196,11 +1196,11 @@ static struct cdr_object_snapshot *cdr_object_pick_party_a(struct cdr_object_sna
 
        /* Neither party is dialed and neither has the Party A flag - defer to
         * creation time */
-       if (left->snapshot->creationtime.tv_sec < right->snapshot->creationtime.tv_sec) {
+       if (left->snapshot->base->creationtime.tv_sec < right->snapshot->base->creationtime.tv_sec) {
                return left;
-       } else if (left->snapshot->creationtime.tv_sec > right->snapshot->creationtime.tv_sec) {
+       } else if (left->snapshot->base->creationtime.tv_sec > right->snapshot->base->creationtime.tv_sec) {
                return right;
-       } else if (left->snapshot->creationtime.tv_usec > right->snapshot->creationtime.tv_usec) {
+       } else if (left->snapshot->base->creationtime.tv_usec > right->snapshot->base->creationtime.tv_usec) {
                return right;
        } else {
                /* Okay, fine, take the left one */
@@ -1285,7 +1285,7 @@ static struct ast_cdr *cdr_object_create_public_records(struct cdr_object *cdr)
                /* Don't create records for CDRs where the party A was a dialed channel */
                if (snapshot_is_dialed(it_cdr->party_a.snapshot) && !it_cdr->party_b.snapshot) {
                        ast_debug(1, "CDR for %s is dialed and has no Party B; discarding\n",
-                               it_cdr->party_a.snapshot->name);
+                               it_cdr->party_a.snapshot->base->name);
                        continue;
                }
 
@@ -1300,12 +1300,12 @@ static struct ast_cdr *cdr_object_create_public_records(struct cdr_object *cdr)
 
                /* Party A */
                ast_assert(party_a != NULL);
-               ast_copy_string(cdr_copy->accountcode, party_a->accountcode, sizeof(cdr_copy->accountcode));
+               ast_copy_string(cdr_copy->accountcode, party_a->base->accountcode, sizeof(cdr_copy->accountcode));
                cdr_copy->amaflags = party_a->amaflags;
-               ast_copy_string(cdr_copy->channel, party_a->name, sizeof(cdr_copy->channel));
-               ast_callerid_merge(cdr_copy->clid, sizeof(cdr_copy->clid), party_a->caller_name, party_a->caller_number, "");
-               ast_copy_string(cdr_copy->src, party_a->caller_number, sizeof(cdr_copy->src));
-               ast_copy_string(cdr_copy->uniqueid, party_a->uniqueid, sizeof(cdr_copy->uniqueid));
+               ast_copy_string(cdr_copy->channel, party_a->base->name, sizeof(cdr_copy->channel));
+               ast_callerid_merge(cdr_copy->clid, sizeof(cdr_copy->clid), party_a->caller->name, party_a->caller->number, "");
+               ast_copy_string(cdr_copy->src, party_a->caller->number, sizeof(cdr_copy->src));
+               ast_copy_string(cdr_copy->uniqueid, party_a->base->uniqueid, sizeof(cdr_copy->uniqueid));
                ast_copy_string(cdr_copy->lastapp, it_cdr->appl, sizeof(cdr_copy->lastapp));
                ast_copy_string(cdr_copy->lastdata, it_cdr->data, sizeof(cdr_copy->lastdata));
                ast_copy_string(cdr_copy->dst, it_cdr->exten, sizeof(cdr_copy->dst));
@@ -1313,8 +1313,8 @@ static struct ast_cdr *cdr_object_create_public_records(struct cdr_object *cdr)
 
                /* Party B */
                if (party_b) {
-                       ast_copy_string(cdr_copy->dstchannel, party_b->name, sizeof(cdr_copy->dstchannel));
-                       ast_copy_string(cdr_copy->peeraccount, party_b->accountcode, sizeof(cdr_copy->peeraccount));
+                       ast_copy_string(cdr_copy->dstchannel, party_b->base->name, sizeof(cdr_copy->dstchannel));
+                       ast_copy_string(cdr_copy->peeraccount, party_b->base->accountcode, sizeof(cdr_copy->peeraccount));
                        if (!ast_strlen_zero(it_cdr->party_b.userfield)) {
                                snprintf(cdr_copy->userfield, sizeof(cdr_copy->userfield), "%s;%s", it_cdr->party_a.userfield, it_cdr->party_b.userfield);
                        }
@@ -1375,8 +1375,8 @@ static void cdr_object_dispatch(struct cdr_object *cdr)
        struct ast_cdr *pub_cdr;
 
        CDR_DEBUG("%p - Dispatching CDR for Party A %s, Party B %s\n", cdr,
-               cdr->party_a.snapshot->name,
-               cdr->party_b.snapshot ? cdr->party_b.snapshot->name : "<none>");
+               cdr->party_a.snapshot->base->name,
+               cdr->party_b.snapshot ? cdr->party_b.snapshot->base->name : "<none>");
        pub_cdr = cdr_object_create_public_records(cdr);
        cdr_detach(pub_cdr);
 }
@@ -1434,10 +1434,10 @@ static void cdr_object_finalize(struct cdr_object *cdr)
        if (cdr->disposition == AST_CDR_NULL) {
                if (!ast_tvzero(cdr->answer)) {
                        cdr->disposition = AST_CDR_ANSWERED;
-               } else if (cdr->party_a.snapshot->hangupcause) {
-                       cdr_object_set_disposition(cdr, cdr->party_a.snapshot->hangupcause);
-               } else if (cdr->party_b.snapshot && cdr->party_b.snapshot->hangupcause) {
-                       cdr_object_set_disposition(cdr, cdr->party_b.snapshot->hangupcause);
+               } else if (cdr->party_a.snapshot->hangup->cause) {
+                       cdr_object_set_disposition(cdr, cdr->party_a.snapshot->hangup->cause);
+               } else if (cdr->party_b.snapshot && cdr->party_b.snapshot->hangup->cause) {
+                       cdr_object_set_disposition(cdr, cdr->party_b.snapshot->hangup->cause);
                } else {
                        cdr->disposition = AST_CDR_FAILED;
                }
@@ -1445,7 +1445,7 @@ static void cdr_object_finalize(struct cdr_object *cdr)
 
        /* tv_usec is suseconds_t, which could be int or long */
        ast_debug(1, "Finalized CDR for %s - start %ld.%06ld answer %ld.%06ld end %ld.%06ld dispo %s\n",
-                       cdr->party_a.snapshot->name,
+                       cdr->party_a.snapshot->base->name,
                        (long)cdr->start.tv_sec,
                        (long)cdr->start.tv_usec,
                        (long)cdr->answer.tv_sec,
@@ -1491,19 +1491,19 @@ static void cdr_object_check_party_a_answer(struct cdr_object *cdr)
 static void cdr_object_update_cid(struct cdr_object_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
 {
        if (!old_snapshot->snapshot) {
-               set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller_dnid);
-               set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller_subaddr);
-               set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->dialed_subaddr);
+               set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller->dnid);
+               set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller->subaddr);
+               set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->caller->dialed_subaddr);
                return;
        }
-       if (strcmp(old_snapshot->snapshot->caller_dnid, new_snapshot->caller_dnid)) {
-               set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller_dnid);
+       if (strcmp(old_snapshot->snapshot->caller->dnid, new_snapshot->caller->dnid)) {
+               set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller->dnid);
        }
-       if (strcmp(old_snapshot->snapshot->caller_subaddr, new_snapshot->caller_subaddr)) {
-               set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller_subaddr);
+       if (strcmp(old_snapshot->snapshot->caller->subaddr, new_snapshot->caller->subaddr)) {
+               set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller->subaddr);
        }
-       if (strcmp(old_snapshot->snapshot->dialed_subaddr, new_snapshot->dialed_subaddr)) {
-               set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->dialed_subaddr);
+       if (strcmp(old_snapshot->snapshot->caller->dialed_subaddr, new_snapshot->caller->dialed_subaddr)) {
+               set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->caller->dialed_subaddr);
        }
 }
 
@@ -1524,7 +1524,7 @@ static void cdr_object_swap_snapshot(struct cdr_object_snapshot *old_snapshot,
 
 static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
 {
-       ast_assert(strcasecmp(snapshot->name, cdr->party_a.snapshot->name) == 0);
+       ast_assert(strcasecmp(snapshot->base->name, cdr->party_a.snapshot->base->name) == 0);
 
        /* Finalize the CDR if we're in hangup logic and we're set to do so */
        if (ast_test_flag(&snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC)
@@ -1539,11 +1539,11 @@ static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snaps
         */
        if (!ast_test_flag(&snapshot->flags, AST_FLAG_SUBROUTINE_EXEC)
                || ast_test_flag(&snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC)) {
-               if (strcmp(cdr->context, snapshot->context)) {
-                       ast_string_field_set(cdr, context, snapshot->context);
+               if (strcmp(cdr->context, snapshot->dialplan->context)) {
+                       ast_string_field_set(cdr, context, snapshot->dialplan->context);
                }
-               if (strcmp(cdr->exten, snapshot->exten)) {
-                       ast_string_field_set(cdr, exten, snapshot->exten);
+               if (strcmp(cdr->exten, snapshot->dialplan->exten)) {
+                       ast_string_field_set(cdr, exten, snapshot->dialplan->exten);
                }
        }
 
@@ -1555,13 +1555,13 @@ static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snaps
         * here.
         */
        if (!ast_test_flag(&cdr->flags, AST_CDR_LOCK_APP)
-               && !ast_strlen_zero(snapshot->appl)
-               && (strncasecmp(snapshot->appl, "appdial", 7) || ast_strlen_zero(cdr->appl))) {
-               if (strcmp(cdr->appl, snapshot->appl)) {
-                       ast_string_field_set(cdr, appl, snapshot->appl);
+               && !ast_strlen_zero(snapshot->dialplan->appl)
+               && (strncasecmp(snapshot->dialplan->appl, "appdial", 7) || ast_strlen_zero(cdr->appl))) {
+               if (strcmp(cdr->appl, snapshot->dialplan->appl)) {
+                       ast_string_field_set(cdr, appl, snapshot->dialplan->appl);
                }
-               if (strcmp(cdr->data, snapshot->data)) {
-                       ast_string_field_set(cdr, data, snapshot->data);
+               if (strcmp(cdr->data, snapshot->dialplan->data)) {
+                       ast_string_field_set(cdr, data, snapshot->dialplan->data);
                }
 
                /* Dial (app_dial) is a special case. Because pre-dial handlers, which
@@ -1569,13 +1569,13 @@ static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snaps
                 * something people typically don't want to see, if we see a channel enter
                 * into Dial here, we set the appl/data accordingly and lock it.
                 */
-               if (!strcmp(snapshot->appl, "Dial")) {
+               if (!strcmp(snapshot->dialplan->appl, "Dial")) {
                        ast_set_flag(&cdr->flags, AST_CDR_LOCK_APP);
                }
        }
 
-       if (strcmp(cdr->linkedid, snapshot->linkedid)) {
-               ast_string_field_set(cdr, linkedid, snapshot->linkedid);
+       if (strcmp(cdr->linkedid, snapshot->peer->linkedid)) {
+               ast_string_field_set(cdr, linkedid, snapshot->peer->linkedid);
        }
        cdr_object_check_party_a_answer(cdr);
        cdr_object_check_party_a_hangup(cdr);
@@ -1603,7 +1603,7 @@ static int base_process_parked_channel(struct cdr_object *cdr, struct ast_parked
 {
        char park_info[128];
 
-       ast_assert(!strcasecmp(parking_info->parkee->name, cdr->party_a.snapshot->name));
+       ast_assert(!strcasecmp(parking_info->parkee->base->name, cdr->party_a.snapshot->base->name));
 
        /* Update Party A information regardless */
        cdr->fn_table->process_party_a(cdr, parking_info->parkee);
@@ -1637,25 +1637,25 @@ static void single_state_process_party_b(struct cdr_object *cdr, struct ast_chan
 
 static int single_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
 {
-       if (caller && !strcasecmp(cdr->party_a.snapshot->name, caller->name)) {
+       if (caller && !strcasecmp(cdr->party_a.snapshot->base->name, caller->base->name)) {
                base_process_party_a(cdr, caller);
                CDR_DEBUG("%p - Updated Party A %s snapshot\n", cdr,
-                       cdr->party_a.snapshot->name);
+                       cdr->party_a.snapshot->base->name);
                cdr_object_swap_snapshot(&cdr->party_b, peer);
                cdr_all_relink(cdr);
                CDR_DEBUG("%p - Updated Party B %s snapshot\n", cdr,
-                       cdr->party_b.snapshot->name);
+                       cdr->party_b.snapshot->base->name);
 
                /* If we have two parties, lock the application that caused the
                 * two parties to be associated. This prevents mid-call event
                 * macros/gosubs from perturbing the CDR application/data
                 */
                ast_set_flag(&cdr->flags, AST_CDR_LOCK_APP);
-       } else if (!strcasecmp(cdr->party_a.snapshot->name, peer->name)) {
+       } else if (!strcasecmp(cdr->party_a.snapshot->base->name, peer->base->name)) {
                /* We're the entity being dialed, i.e., outbound origination */
                base_process_party_a(cdr, peer);
                CDR_DEBUG("%p - Updated Party A %s snapshot\n", cdr,
-                       cdr->party_a.snapshot->name);
+                       cdr->party_a.snapshot->base->name);
        }
 
        cdr_object_transition_state(cdr, &dial_state_fn_table);
@@ -1680,15 +1680,15 @@ static int single_state_bridge_enter_comparison(struct cdr_object *cdr,
        struct cdr_object_snapshot *party_a;
 
        /* Don't match on ourselves */
-       if (!strcasecmp(cdr->party_a.snapshot->name, cand_cdr->party_a.snapshot->name)) {
+       if (!strcasecmp(cdr->party_a.snapshot->base->name, cand_cdr->party_a.snapshot->base->name)) {
                return 1;
        }
 
        /* Try the candidate CDR's Party A first */
        party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_a);
-       if (!strcasecmp(party_a->snapshot->name, cdr->party_a.snapshot->name)) {
+       if (!strcasecmp(party_a->snapshot->base->name, cdr->party_a.snapshot->base->name)) {
                CDR_DEBUG("%p - Party A %s has new Party B %s\n",
-                       cdr, cdr->party_a.snapshot->name, cand_cdr->party_a.snapshot->name);
+                       cdr, cdr->party_a.snapshot->base->name, cand_cdr->party_a.snapshot->base->name);
                cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a);
                cdr_all_relink(cdr);
                if (!cand_cdr->party_b.snapshot) {
@@ -1703,13 +1703,13 @@ static int single_state_bridge_enter_comparison(struct cdr_object *cdr,
 
        /* Try their Party B, unless it's us */
        if (!cand_cdr->party_b.snapshot
-               || !strcasecmp(cdr->party_a.snapshot->name, cand_cdr->party_b.snapshot->name)) {
+               || !strcasecmp(cdr->party_a.snapshot->base->name, cand_cdr->party_b.snapshot->base->name)) {
                return 1;
        }
        party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_b);
-       if (!strcasecmp(party_a->snapshot->name, cdr->party_a.snapshot->name)) {
+       if (!strcasecmp(party_a->snapshot->base->name, cdr->party_a.snapshot->base->name)) {
                CDR_DEBUG("%p - Party A %s has new Party B %s\n",
-                       cdr, cdr->party_a.snapshot->name, cand_cdr->party_b.snapshot->name);
+                       cdr, cdr->party_a.snapshot->base->name, cand_cdr->party_b.snapshot->base->name);
                cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_b);
                cdr_all_relink(cdr);
                return 0;
@@ -1788,7 +1788,7 @@ static void dial_state_process_party_b(struct cdr_object *cdr, struct ast_channe
 {
        ast_assert(snapshot != NULL);
        ast_assert(cdr->party_b.snapshot
-               && !strcasecmp(cdr->party_b.snapshot->name, snapshot->name));
+               && !strcasecmp(cdr->party_b.snapshot->base->name, snapshot->base->name));
 
        cdr_object_swap_snapshot(&cdr->party_b, snapshot);
 
@@ -1839,11 +1839,11 @@ static int dial_state_process_dial_end(struct cdr_object *cdr, struct ast_channe
        } else {
                party_a = peer;
        }
-       ast_assert(!strcasecmp(cdr->party_a.snapshot->name, party_a->name));
+       ast_assert(!strcasecmp(cdr->party_a.snapshot->base->name, party_a->base->name));
        cdr_object_swap_snapshot(&cdr->party_a, party_a);
 
        if (cdr->party_b.snapshot) {
-               if (strcasecmp(cdr->party_b.snapshot->name, peer->name)) {
+               if (strcasecmp(cdr->party_b.snapshot->base->name, peer->base->name)) {
                        /* Not the status for this CDR - defer back to the message router */
                        return 1;
                }
@@ -1901,7 +1901,7 @@ static enum process_bridge_enter_results dial_state_process_bridge_enter(struct
                                }
 
                                /* Skip any records that aren't our Party B */
-                               if (strcasecmp(cdr->party_b.snapshot->name, cand_cdr->party_a.snapshot->name)) {
+                               if (strcasecmp(cdr->party_b.snapshot->base->name, cand_cdr->party_a.snapshot->base->name)) {
                                        continue;
                                }
                                cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a);
@@ -1982,7 +1982,7 @@ static int dialed_pending_state_process_dial_begin(struct cdr_object *cdr, struc
 static void bridge_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
 {
        ast_assert(cdr->party_b.snapshot
-               && !strcasecmp(cdr->party_b.snapshot->name, snapshot->name));
+               && !strcasecmp(cdr->party_b.snapshot->base->name, snapshot->base->name));
 
        cdr_object_swap_snapshot(&cdr->party_b, snapshot);
 
@@ -1997,9 +1997,9 @@ static int bridge_state_process_bridge_leave(struct cdr_object *cdr, struct ast_
        if (strcmp(cdr->bridge, bridge->uniqueid)) {
                return 1;
        }
-       if (strcasecmp(cdr->party_a.snapshot->name, channel->name)
+       if (strcasecmp(cdr->party_a.snapshot->base->name, channel->base->name)
                && cdr->party_b.snapshot
-               && strcasecmp(cdr->party_b.snapshot->name, channel->name)) {
+               && strcasecmp(cdr->party_b.snapshot->base->name, channel->base->name)) {
                return 1;
        }
        cdr_object_transition_state(cdr, &finalized_state_fn_table);
@@ -2011,7 +2011,7 @@ static int bridge_state_process_bridge_leave(struct cdr_object *cdr, struct ast_
 
 static int parked_state_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
 {
-       if (strcasecmp(cdr->party_a.snapshot->name, channel->name)) {
+       if (strcasecmp(cdr->party_a.snapshot->base->name, channel->base->name)) {
                return 1;
        }
        cdr_object_transition_state(cdr, &finalized_state_fn_table);
@@ -2043,7 +2043,7 @@ static int finalized_state_process_party_a(struct cdr_object *cdr, struct ast_ch
  */
 static int filter_channel_snapshot(struct ast_channel_snapshot *snapshot)
 {
-       return snapshot->tech_properties & AST_CHAN_TP_INTERNAL;
+       return snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL;
 }
 
 /*!
@@ -2114,19 +2114,19 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str
 
        CDR_DEBUG("Dial %s message for %s, %s: %u.%08u\n",
                ast_strlen_zero(dial_status) ? "Begin" : "End",
-               caller ? caller->name : "(none)",
-               peer ? peer->name : "(none)",
+               caller ? caller->base->name : "(none)",
+               peer ? peer->base->name : "(none)",
                (unsigned int)stasis_message_timestamp(message)->tv_sec,
                (unsigned int)stasis_message_timestamp(message)->tv_usec);
 
        /* Figure out who is running this show */
        if (caller) {
-               cdr = ao2_find(active_cdrs_master, caller->uniqueid, OBJ_SEARCH_KEY);
+               cdr = ao2_find(active_cdrs_master, caller->base->uniqueid, OBJ_SEARCH_KEY);
        } else {
-               cdr = ao2_find(active_cdrs_master, peer->uniqueid, OBJ_SEARCH_KEY);
+               cdr = ao2_find(active_cdrs_master, peer->base->uniqueid, OBJ_SEARCH_KEY);
        }
        if (!cdr) {
-               ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", caller ? caller->name : peer->name);
+               ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", caller ? caller->base->name : peer->base->name);
                ast_assert(0);
                return;
        }
@@ -2139,8 +2139,8 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str
                        }
                        CDR_DEBUG("%p - Processing Dial Begin message for channel %s, peer %s\n",
                                it_cdr,
-                               caller ? caller->name : "(none)",
-                               peer ? peer->name : "(none)");
+                               caller ? caller->base->name : "(none)",
+                               peer ? peer->base->name : "(none)");
                        res &= it_cdr->fn_table->process_dial_begin(it_cdr,
                                        caller,
                                        peer);
@@ -2150,8 +2150,8 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str
                        }
                        CDR_DEBUG("%p - Processing Dial End message for channel %s, peer %s\n",
                                it_cdr,
-                               caller ? caller->name : "(none)",
-                               peer ? peer->name : "(none)");
+                               caller ? caller->base->name : "(none)",
+                               peer ? peer->base->name : "(none)");
                        it_cdr->fn_table->process_dial_end(it_cdr,
                                        caller,
                                        peer,
@@ -2185,7 +2185,7 @@ static int cdr_object_finalize_party_b(void *obj, void *arg, void *data, int fla
                 * is consistent with the key.
                 */
                ast_assert(cdr->party_b.snapshot
-                       && !strcasecmp(cdr->party_b.snapshot->name, party_b->name));
+                       && !strcasecmp(cdr->party_b.snapshot->base->name, party_b->base->name));
 #endif
 
                /* Don't transition to the finalized state - let the Party A do
@@ -2210,11 +2210,11 @@ static int cdr_object_update_party_b(void *obj, void *arg, void *data, int flags
                 * asserts the snapshot to be this way.
                 */
                if (!cdr->party_b.snapshot
-                       || strcasecmp(cdr->party_b.snapshot->name, party_b->name)) {
+                       || strcasecmp(cdr->party_b.snapshot->base->name, party_b->base->name)) {
                        ast_log(LOG_NOTICE,
                                "CDR for Party A %s(%s) has inconsistent Party B %s name.  Message can be ignored but this shouldn't happen.\n",
                                cdr->linkedid,
-                               cdr->party_a.snapshot->name,
+                               cdr->party_a.snapshot->base->name,
                                cdr->party_b_name);
                        return 0;
                }
@@ -2236,7 +2236,7 @@ static int check_new_cdr_needed(struct ast_channel_snapshot *old_snapshot,
        }
 
        /* Auto-fall through will increment the priority but have no application */
-       if (ast_strlen_zero(new_snapshot->appl)) {
+       if (ast_strlen_zero(new_snapshot->dialplan->appl)) {
                return 0;
        }
 
@@ -2272,12 +2272,12 @@ static void handle_channel_snapshot_update_message(void *data, struct stasis_sub
                cdr->is_root = 1;
                ao2_link(active_cdrs_master, cdr);
        } else {
-               cdr = ao2_find(active_cdrs_master, update->new_snapshot->uniqueid, OBJ_SEARCH_KEY);
+               cdr = ao2_find(active_cdrs_master, update->new_snapshot->base->uniqueid, OBJ_SEARCH_KEY);
        }
 
        /* Handle Party A */
        if (!cdr) {
-               ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", update->new_snapshot->name);
+               ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", update->new_snapshot->base->name);
                ast_assert(0);
        } else {
                int all_reject = 1;
@@ -2303,7 +2303,7 @@ static void handle_channel_snapshot_update_message(void *data, struct stasis_sub
 
        if (ast_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {
                ao2_lock(cdr);
-               CDR_DEBUG("%p - Beginning finalize/dispatch for %s\n", cdr, update->old_snapshot->name);
+               CDR_DEBUG("%p - Beginning finalize/dispatch for %s\n", cdr, update->old_snapshot->base->name);
                for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
                        cdr_object_finalize(it_cdr);
                }
@@ -2317,12 +2317,12 @@ static void handle_channel_snapshot_update_message(void *data, struct stasis_sub
        /* Handle Party B */
        if (update->new_snapshot) {
                ao2_callback_data(active_cdrs_all, OBJ_NODATA | OBJ_MULTIPLE | OBJ_SEARCH_KEY,
-                       cdr_object_update_party_b, (char *) update->new_snapshot->name, update->new_snapshot);
+                       cdr_object_update_party_b, (char *) update->new_snapshot->base->name, update->new_snapshot);
        }
 
        if (ast_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {
                ao2_callback_data(active_cdrs_all, OBJ_NODATA | OBJ_MULTIPLE | OBJ_SEARCH_KEY,
-                       cdr_object_finalize_party_b, (char *) update->new_snapshot->name, update->new_snapshot);
+                       cdr_object_finalize_party_b, (char *) update->new_snapshot->base->name, update->new_snapshot);
        }
 
        ao2_cleanup(cdr);
@@ -2347,7 +2347,7 @@ static int cdr_object_party_b_left_bridge_cb(void *obj, void *arg, void *data, i
                 * is consistent with the key.
                 */
                ast_assert(cdr->party_b.snapshot
-                       && !strcasecmp(cdr->party_b.snapshot->name, leave_data->channel->name));
+                       && !strcasecmp(cdr->party_b.snapshot->base->name, leave_data->channel->base->name));
 
                /* It is our Party B, in our bridge. Set the end time and let the handler
                 * transition our CDR appropriately when we leave the bridge.
@@ -2399,13 +2399,13 @@ static void handle_bridge_leave_message(void *data, struct stasis_subscription *
        }
 
        CDR_DEBUG("Bridge Leave message for %s: %u.%08u\n",
-               channel->name,
+               channel->base->name,
                (unsigned int)stasis_message_timestamp(message)->tv_sec,
                (unsigned int)stasis_message_timestamp(message)->tv_usec);
 
-       cdr = ao2_find(active_cdrs_master, channel->uniqueid, OBJ_SEARCH_KEY);
+       cdr = ao2_find(active_cdrs_master, channel->base->uniqueid, OBJ_SEARCH_KEY);
        if (!cdr) {
-               ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name);
+               ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->base->name);
                ast_assert(0);
                return;
        }
@@ -2417,7 +2417,7 @@ static void handle_bridge_leave_message(void *data, struct stasis_subscription *
                        continue;
                }
                CDR_DEBUG("%p - Processing Bridge Leave for %s\n",
-                       it_cdr, channel->name);
+                       it_cdr, channel->base->name);
                if (!it_cdr->fn_table->process_bridge_leave(it_cdr, bridge, channel)) {
                        ast_string_field_set(it_cdr, bridge, "");
                        left_bridge = 1;
@@ -2429,7 +2429,7 @@ static void handle_bridge_leave_message(void *data, struct stasis_subscription *
        if (left_bridge
                && strcmp(bridge->subclass, "parking")) {
                ao2_callback_data(active_cdrs_all, OBJ_NODATA | OBJ_MULTIPLE | OBJ_SEARCH_KEY,
-                       cdr_object_party_b_left_bridge_cb, (char *) leave_data.channel->name,
+                       cdr_object_party_b_left_bridge_cb, (char *) leave_data.channel->base->name,
                        &leave_data);
        }
 
@@ -2457,8 +2457,8 @@ static void bridge_candidate_add_to_cdr(struct cdr_object *cdr,
        ast_string_field_set(new_cdr, bridge, cdr->bridge);
        cdr_object_transition_state(new_cdr, &bridge_state_fn_table);
        CDR_DEBUG("%p - Party A %s has new Party B %s\n",
-               new_cdr, new_cdr->party_a.snapshot->name,
-               party_b->snapshot->name);
+               new_cdr, new_cdr->party_a.snapshot->base->name,
+               party_b->snapshot->base->name);
 }
 
 /*!
@@ -2487,16 +2487,16 @@ static void bridge_candidate_process(struct cdr_object *cdr, struct cdr_object *
                }
 
                /* If the candidate is us or someone we've taken on, pass on by */
-               if (!strcasecmp(cdr->party_a.snapshot->name, cand_cdr->party_a.snapshot->name)
+               if (!strcasecmp(cdr->party_a.snapshot->base->name, cand_cdr->party_a.snapshot->base->name)
                        || (cdr->party_b.snapshot
-                               && !strcasecmp(cdr->party_b.snapshot->name, cand_cdr->party_a.snapshot->name))) {
+                               && !strcasecmp(cdr->party_b.snapshot->base->name, cand_cdr->party_a.snapshot->base->name))) {
                        break;
                }
 
                party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_a);
                /* We're party A - make a new CDR, append it to us, and set the candidate as
                 * Party B */
-               if (!strcasecmp(party_a->snapshot->name, cdr->party_a.snapshot->name)) {
+               if (!strcasecmp(party_a->snapshot->base->name, cdr->party_a.snapshot->base->name)) {
                        bridge_candidate_add_to_cdr(cdr, &cand_cdr->party_a);
                        break;
                }
@@ -2504,12 +2504,12 @@ static void bridge_candidate_process(struct cdr_object *cdr, struct cdr_object *
                /* We're Party B. Check if we can add ourselves immediately or if we need
                 * a new CDR for them (they already have a Party B) */
                if (cand_cdr->party_b.snapshot
-                       && strcasecmp(cand_cdr->party_b.snapshot->name, cdr->party_a.snapshot->name)) {
+                       && strcasecmp(cand_cdr->party_b.snapshot->base->name, cdr->party_a.snapshot->base->name)) {
                        bridge_candidate_add_to_cdr(cand_cdr, &cdr->party_a);
                } else {
                        CDR_DEBUG("%p - Party A %s has new Party B %s\n",
-                               cand_cdr, cand_cdr->party_a.snapshot->name,
-                               cdr->party_a.snapshot->name);
+                               cand_cdr, cand_cdr->party_a.snapshot->base->name,
+                               cdr->party_a.snapshot->base->name);
                        cdr_object_snapshot_copy(&cand_cdr->party_b, &cdr->party_a);
                        cdr_all_relink(cand_cdr);
                        /* It's possible that this joined at one point and was never chosen
@@ -2572,7 +2572,7 @@ static void handle_parking_bridge_enter_message(struct cdr_object *cdr,
                }
                if (it_cdr->fn_table->process_party_a) {
                        CDR_DEBUG("%p - Updating Party A %s snapshot\n", it_cdr,
-                               channel->name);
+                               channel->base->name);
                        it_cdr->fn_table->process_party_a(it_cdr, channel);
                }
        }
@@ -2609,14 +2609,14 @@ try_again:
        for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
                if (it_cdr->fn_table->process_party_a) {
                        CDR_DEBUG("%p - Updating Party A %s snapshot\n", it_cdr,
-                               channel->name);
+                               channel->base->name);
                        it_cdr->fn_table->process_party_a(it_cdr, channel);
                }
 
                /* Notify all states that they have entered a bridge */
                if (it_cdr->fn_table->process_bridge_enter) {
                        CDR_DEBUG("%p - Processing bridge enter for %s\n", it_cdr,
-                               channel->name);
+                               channel->base->name);
                        result = it_cdr->fn_table->process_bridge_enter(it_cdr, bridge, channel);
                        switch (result) {
                        case BRIDGE_ENTER_ONLY_PARTY:
@@ -2689,13 +2689,13 @@ static void handle_bridge_enter_message(void *data, struct stasis_subscription *
        }
 
        CDR_DEBUG("Bridge Enter message for channel %s: %u.%08u\n",
-               channel->name,
+               channel->base->name,
                (unsigned int)stasis_message_timestamp(message)->tv_sec,
                (unsigned int)stasis_message_timestamp(message)->tv_usec);
 
-       cdr = ao2_find(active_cdrs_master, channel->uniqueid, OBJ_SEARCH_KEY);
+       cdr = ao2_find(active_cdrs_master, channel->base->uniqueid, OBJ_SEARCH_KEY);
        if (!cdr) {
-               ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name);
+               ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->base->name);
                ast_assert(0);
                return;
        }
@@ -2739,13 +2739,13 @@ static void handle_parked_call_message(void *data, struct stasis_subscription *s
        }
 
        CDR_DEBUG("Parked Call message for channel %s: %u.%08u\n",
-               channel->name,
+               channel->base->name,
                (unsigned int)stasis_message_timestamp(message)->tv_sec,
                (unsigned int)stasis_message_timestamp(message)->tv_usec);
 
-       cdr = ao2_find(active_cdrs_master, channel->uniqueid, OBJ_SEARCH_KEY);
+       cdr = ao2_find(active_cdrs_master, channel->base->uniqueid, OBJ_SEARCH_KEY);
        if (!cdr) {
-               ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name);
+               ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->base->name);
                ast_assert(0);
                return;
        }
@@ -3094,8 +3094,8 @@ static int cdr_object_select_all_by_name_cb(void *obj, void *arg, int flags)
        struct cdr_object *cdr = obj;
        const char *name = arg;
 
-       if (!strcasecmp(cdr->party_a.snapshot->name, name) ||
-                       (cdr->party_b.snapshot && !strcasecmp(cdr->party_b.snapshot->name, name))) {
+       if (!strcasecmp(cdr->party_a.snapshot->base->name, name) ||
+                       (cdr->party_b.snapshot && !strcasecmp(cdr->party_b.snapshot->base->name, name))) {
                return CMP_MATCH;
        }
        return 0;
@@ -3110,7 +3110,7 @@ static int cdr_object_get_by_name_cb(void *obj, void *arg, int flags)
        struct cdr_object *cdr = obj;
        const char *name = arg;
 
-       if (!strcasecmp(cdr->party_a.snapshot->name, name)) {
+       if (!strcasecmp(cdr->party_a.snapshot->base->name, name)) {
                return CMP_MATCH;
        }
        return 0;
@@ -3170,10 +3170,10 @@ int ast_cdr_setvar(const char *channel_name, const char *name, const char *value
                        if (it_cdr->fn_table == &finalized_state_fn_table && it_cdr->next != NULL) {
                                continue;
                        }
-                       if (!strcasecmp(channel_name, it_cdr->party_a.snapshot->name)) {
+                       if (!strcasecmp(channel_name, it_cdr->party_a.snapshot->base->name)) {
                                headp = &it_cdr->party_a.variables;
                        } else if (it_cdr->party_b.snapshot
-                               && !strcasecmp(channel_name, it_cdr->party_b.snapshot->name)) {
+                               && !strcasecmp(channel_name, it_cdr->party_b.snapshot->base->name)) {
                                headp = &it_cdr->party_b.variables;
                        }
                        if (headp) {
@@ -3212,25 +3212,25 @@ static int cdr_object_format_property(struct cdr_object *cdr_obj, const char *na
        struct ast_channel_snapshot *party_b = cdr_obj->party_b.snapshot;
 
        if (!strcasecmp(name, "clid")) {
-               ast_callerid_merge(value, length, party_a->caller_name, party_a->caller_number, "");
+               ast_callerid_merge(value, length, party_a->caller->name, party_a->caller->number, "");
        } else if (!strcasecmp(name, "src")) {
-               ast_copy_string(value, party_a->caller_number, length);
+               ast_copy_string(value, party_a->caller->number, length);
        } else if (!strcasecmp(name, "dst")) {
-               ast_copy_string(value, party_a->exten, length);
+               ast_copy_string(value, party_a->dialplan->exten, length);
        } else if (!strcasecmp(name, "dcontext")) {
-               ast_copy_string(value, party_a->context, length);
+               ast_copy_string(value, party_a->dialplan->context, length);
        } else if (!strcasecmp(name, "channel")) {
-               ast_copy_string(value, party_a->name, length);
+               ast_copy_string(value, party_a->base->name, length);
        } else if (!strcasecmp(name, "dstchannel")) {
                if (party_b) {
-                       ast_copy_string(value, party_b->name, length);
+                       ast_copy_string(value, party_b->base->name, length);
                } else {
                        ast_copy_string(value, "", length);
                }
        } else if (!strcasecmp(name, "lastapp")) {
-               ast_copy_string(value, party_a->appl, length);
+               ast_copy_string(value, party_a->dialplan->appl, length);
        } else if (!strcasecmp(name, "lastdata")) {
-               ast_copy_string(value, party_a->data, length);
+               ast_copy_string(value, party_a->dialplan->data, length);
        } else if (!strcasecmp(name, "start")) {
                cdr_get_tv(cdr_obj->start, NULL, value, length);
        } else if (!strcasecmp(name, "answer")) {
@@ -3246,15 +3246,15 @@ static int cdr_object_format_property(struct cdr_object *cdr_obj, const char *na
        } else if (!strcasecmp(name, "amaflags")) {
                snprintf(value, length, "%d", party_a->amaflags);
        } else if (!strcasecmp(name, "accountcode")) {
-               ast_copy_string(value, party_a->accountcode, length);
+               ast_copy_string(value, party_a->base->accountcode, length);
        } else if (!strcasecmp(name, "peeraccount")) {
                if (party_b) {
-                       ast_copy_string(value, party_b->accountcode, length);
+                       ast_copy_string(value, party_b->base->accountcode, length);
                } else {
                        ast_copy_string(value, "", length);
                }
        } else if (!strcasecmp(name, "uniqueid")) {
-               ast_copy_string(value, party_a->uniqueid, length);
+               ast_copy_string(value, party_a->base->uniqueid, length);
        } else if (!strcasecmp(name, "linkedid")) {
                ast_copy_string(value, cdr_obj->linkedid, length);
        } else if (!strcasecmp(name, "userfield")) {
@@ -3431,7 +3431,7 @@ static int cdr_object_update_party_b_userfield_cb(void *obj, void *arg, void *da
                 * is consistent with the key.
                 */
                ast_assert(cdr->party_b.snapshot
-                       && !strcasecmp(cdr->party_b.snapshot->name, info->channel_name));
+                       && !strcasecmp(cdr->party_b.snapshot->base->name, info->channel_name));
 
                ast_copy_string(cdr->party_b.userfield, info->userfield,
                        sizeof(cdr->party_b.userfield));
@@ -3624,7 +3624,7 @@ int ast_cdr_fork(const char *channel_name, struct ast_flags *options)
                /* Copy over the basic CDR information. The Party A information is
                 * copied over automatically as part of the append
                 */
-               ast_debug(1, "Forking CDR for channel %s\n", cdr->party_a.snapshot->name);
+               ast_debug(1, "Forking CDR for channel %s\n", cdr->party_a.snapshot->base->name);
                new_cdr = cdr_object_create_and_append(cdr);
                if (!new_cdr) {
                        return -1;
@@ -3938,8 +3938,8 @@ static char *cli_complete_show(struct ast_cli_args *a)
 
        it_cdrs = ao2_iterator_init(active_cdrs_master, 0);
        while ((cdr = ao2_iterator_next(&it_cdrs))) {
-               if (!strncasecmp(a->word, cdr->party_a.snapshot->name, wordlen)) {
-                       if (ast_cli_completion_add(ast_strdup(cdr->party_a.snapshot->name))) {
+               if (!strncasecmp(a->word, cdr->party_a.snapshot->base->name, wordlen)) {
+                       if (ast_cli_completion_add(ast_strdup(cdr->party_a.snapshot->base->name))) {
                                ao2_ref(cdr, -1);
                                break;
                        }
@@ -4001,8 +4001,8 @@ static void cli_show_channels(struct ast_cli_args *a)
                cdr_get_tv(start_time, "%T", start_time_buffer, sizeof(start_time_buffer));
                cdr_get_tv(answer_time, "%T", answer_time_buffer, sizeof(answer_time_buffer));
                cdr_get_tv(end_time, "%T", end_time_buffer, sizeof(end_time_buffer));
-               ast_cli(a->fd, FORMAT_STRING, it_cdr->party_a.snapshot->name,
-                               it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->name : "<none>",
+               ast_cli(a->fd, FORMAT_STRING, it_cdr->party_a.snapshot->base->name,
+                               it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<none>",
                                it_cdr->appl,
                                start_time_buffer,
                                answer_time_buffer,
@@ -4046,7 +4046,7 @@ static void cli_show_channel(struct ast_cli_args *a)
                if (snapshot_is_dialed(it_cdr->party_a.snapshot)) {
                        continue;
                }
-               ast_callerid_merge(clid, sizeof(clid), it_cdr->party_a.snapshot->caller_name, it_cdr->party_a.snapshot->caller_number, "");
+               ast_callerid_merge(clid, sizeof(clid), it_cdr->party_a.snapshot->caller->name, it_cdr->party_a.snapshot->caller->number, "");
                if (ast_tvzero(it_cdr->end)) {
                        end = ast_tvnow();
                } else {
@@ -4056,9 +4056,9 @@ static void cli_show_channel(struct ast_cli_args *a)
                cdr_get_tv(it_cdr->answer, "%T", answer_time_buffer, sizeof(answer_time_buffer));
                cdr_get_tv(end, "%T", end_time_buffer, sizeof(end_time_buffer));
                ast_cli(a->fd, FORMAT_STRING,
-                               it_cdr->party_a.snapshot->accountcode,
+                               it_cdr->party_a.snapshot->base->accountcode,
                                clid,
-                               it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->name : "<none>",
+                               it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<none>",
                                it_cdr->appl,
                                it_cdr->data,
                                start_time_buffer,
@@ -4415,8 +4415,8 @@ static void cdr_master_print_fn(void *v_obj, void *where, ao2_prnt_fn *prnt)
        }
        for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
                prnt(where, "Party A: %s; Party B: %s; Bridge %s\n",
-                       it_cdr->party_a.snapshot->name,
-                       it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->name : "<unknown>",
+                       it_cdr->party_a.snapshot->base->name,
+                       it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<unknown>",
                        it_cdr->bridge);
        }
 }
@@ -4440,8 +4440,8 @@ static void cdr_all_print_fn(void *v_obj, void *where, ao2_prnt_fn *prnt)
                return;
        }
        prnt(where, "Party A: %s; Party B: %s; Bridge %s",
-               cdr->party_a.snapshot->name,
-               cdr->party_b.snapshot ? cdr->party_b.snapshot->name : "<unknown>",
+               cdr->party_a.snapshot->base->name,
+               cdr->party_b.snapshot ? cdr->party_b.snapshot->base->name : "<unknown>",
                cdr->bridge);
 }
 
index 97e35ad..242aeff 100644 (file)
@@ -528,22 +528,22 @@ struct ast_event *ast_cel_create_event(struct ast_channel_snapshot *snapshot,
                AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_sec,
                AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_usec,
                AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_PLTYPE_STR, S_OR(userdefevname, ""),
-               AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR, snapshot->caller_name,
-               AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR, snapshot->caller_number,
-               AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR, snapshot->caller_ani,
-               AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR, snapshot->caller_rdnis,
-               AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR, snapshot->caller_dnid,
-               AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, snapshot->exten,
-               AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, snapshot->context,
-               AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, snapshot->name,
-               AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, snapshot->appl,
-               AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, snapshot->data,
+               AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR, snapshot->caller->name,
+               AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR, snapshot->caller->number,
+               AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR, snapshot->caller->ani,
+               AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR, snapshot->caller->rdnis,
+               AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR, snapshot->caller->dnid,
+               AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, snapshot->dialplan->exten,
+               AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, snapshot->dialplan->context,
+               AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, snapshot->base->name,
+               AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, snapshot->dialplan->appl,
+               AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, snapshot->dialplan->data,
                AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_PLTYPE_UINT, snapshot->amaflags,
-               AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_PLTYPE_STR, snapshot->accountcode,
-               AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, snapshot->peeraccount,
-               AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, snapshot->uniqueid,
-               AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, snapshot->linkedid,
-               AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, snapshot->userfield,
+               AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_PLTYPE_STR, snapshot->base->accountcode,
+               AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, snapshot->peer->account,
+               AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, snapshot->base->uniqueid,
+               AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, snapshot->peer->linkedid,
+               AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, snapshot->base->userfield,
                AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, S_OR(extra_txt, ""),
                AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, S_OR(peer, ""),
                AST_EVENT_IE_END);
@@ -573,7 +573,7 @@ static int cel_report_event(struct ast_channel_snapshot *snapshot,
         * reporting on CHANNEL_START so we can track when to send LINKEDID_END */
        if (event_type == AST_CEL_CHANNEL_START
                && ast_cel_track_event(AST_CEL_LINKEDID_END)) {
-               if (cel_linkedid_ref(snapshot->linkedid)) {
+               if (cel_linkedid_ref(snapshot->peer->linkedid)) {
                        return -1;
                }
        }
@@ -583,7 +583,7 @@ static int cel_report_event(struct ast_channel_snapshot *snapshot,
        }
 
        if ((event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END)
-               && !cel_track_app(snapshot->appl)) {
+               && !cel_track_app(snapshot->dialplan->appl)) {
                return 0;
        }
 
@@ -606,14 +606,14 @@ static void check_retire_linkedid(struct ast_channel_snapshot *snapshot)
        RAII_VAR(struct ao2_container *, linkedids, ao2_global_obj_ref(cel_linkedids), ao2_cleanup);
        struct cel_linkedid *lid;
 
-       if (!linkedids || ast_strlen_zero(snapshot->linkedid)) {
+       if (!linkedids || ast_strlen_zero(snapshot->peer->linkedid)) {
                /* The CEL module is shutdown.  Abort. */
                return;
        }
 
        ao2_lock(linkedids);
 
-       lid = ao2_find(linkedids, (void *) snapshot->linkedid, OBJ_SEARCH_KEY);
+       lid = ao2_find(linkedids, (void *) snapshot->peer->linkedid, OBJ_SEARCH_KEY);
        if (!lid) {
                ao2_unlock(linkedids);
 
@@ -623,7 +623,7 @@ static void check_retire_linkedid(struct ast_channel_snapshot *snapshot)
                 * of change to make after starting Asterisk.
                 */
                ast_log(LOG_ERROR, "Something weird happened, couldn't find linkedid %s\n",
-                       snapshot->linkedid);
+                       snapshot->peer->linkedid);
                return;
        }
 
@@ -898,11 +898,11 @@ static void cel_channel_state_change(
 
        if (!was_hungup && is_hungup) {
                struct ast_json *extra;
-               struct cel_dialstatus *dialstatus = get_dialstatus(new_snapshot->uniqueid);
+               struct cel_dialstatus *dialstatus = get_dialstatus(new_snapshot->base->uniqueid);
 
                extra = ast_json_pack("{s: i, s: s, s: s}",
-                       "hangupcause", new_snapshot->hangupcause,
-                       "hangupsource", new_snapshot->hangupsource,
+                       "hangupcause", new_snapshot->hangup->cause,
+                       "hangupsource", new_snapshot->hangup->source,
                        "dialstatus", dialstatus ? dialstatus->dialstatus : "");
                cel_report_event(new_snapshot, AST_CEL_HANGUP, NULL, extra, NULL);
                ast_json_unref(extra);
@@ -929,12 +929,12 @@ static void cel_channel_linkedid_change(
                return;
        }
 
-       ast_assert(!ast_strlen_zero(new_snapshot->linkedid));
-       ast_assert(!ast_strlen_zero(old_snapshot->linkedid));
+       ast_assert(!ast_strlen_zero(new_snapshot->peer->linkedid));
+       ast_assert(!ast_strlen_zero(old_snapshot->peer->linkedid));
 
        if (ast_cel_track_event(AST_CEL_LINKEDID_END)
-               && strcmp(old_snapshot->linkedid, new_snapshot->linkedid)) {
-               cel_linkedid_ref(new_snapshot->linkedid);
+               && strcmp(old_snapshot->peer->linkedid, new_snapshot->peer->linkedid)) {
+               cel_linkedid_ref(new_snapshot->peer->linkedid);
                check_retire_linkedid(old_snapshot);
        }
 }
@@ -943,17 +943,17 @@ static void cel_channel_app_change(
        struct ast_channel_snapshot *old_snapshot,
        struct ast_channel_snapshot *new_snapshot)
 {
-       if (old_snapshot && !strcmp(old_snapshot->appl, new_snapshot->appl)) {
+       if (old_snapshot && !strcmp(old_snapshot->dialplan->appl, new_snapshot->dialplan->appl)) {
                return;
        }
 
        /* old snapshot has an application, end it */
-       if (old_snapshot && !ast_strlen_zero(old_snapshot->appl)) {
+       if (old_snapshot && !ast_strlen_zero(old_snapshot->dialplan->appl)) {
                cel_report_event(old_snapshot, AST_CEL_APP_END, NULL, NULL, NULL);
        }
 
        /* new snapshot has an application, start it */
-       if (!ast_strlen_zero(new_snapshot->appl)) {
+       if (!ast_strlen_zero(new_snapshot->dialplan->appl)) {
                cel_report_event(new_snapshot, AST_CEL_APP_START, NULL, NULL, NULL);
        }
 }
@@ -974,7 +974,7 @@ static int cel_filter_channel_snapshot(struct ast_channel_snapshot *snapshot)
        if (!snapshot) {
                return 0;
        }
-       return snapshot->tech_properties & AST_CHAN_TP_INTERNAL;
+       return snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL;
 }
 
 static void cel_snapshot_update_cb(void *data, struct stasis_subscription *sub,
@@ -1010,7 +1010,7 @@ static struct ast_str *cel_generate_peer_str(
                struct ast_channel_snapshot *current_snapshot;
 
                /* Don't add the channel for which this message is being generated */
-               if (!strcmp(current_chan, chan->uniqueid)) {
+               if (!strcmp(current_chan, chan->base->uniqueid)) {
                        continue;
                }
 
@@ -1019,7 +1019,7 @@ static struct ast_str *cel_generate_peer_str(
                        continue;
                }
 
-               ast_str_append(&peer_str, 0, "%s,", current_snapshot->name);
+               ast_str_append(&peer_str, 0, "%s,", current_snapshot->base->name);
                ao2_cleanup(current_snapshot);
        }
        ao2_iterator_destroy(&i);
@@ -1125,7 +1125,7 @@ static void cel_parking_cb(
        if (parked_payload->retriever) {
                extra = ast_json_pack("{s: s, s: s}",
                        "reason", reason ?: "",
-                       "retriever", parked_payload->retriever->name);
+                       "retriever", parked_payload->retriever->base->name);
        } else {
                extra = ast_json_pack("{s: s}", "reason", reason ?: "");
        }
@@ -1147,7 +1147,7 @@ static void save_dialstatus(struct ast_multi_channel_blob *blob, struct ast_chan
                return;
        }
 
-       dialstatus = ao2_find(dial_statuses, snapshot->uniqueid, OBJ_SEARCH_KEY);
+       dialstatus = ao2_find(dial_statuses, snapshot->base->uniqueid, OBJ_SEARCH_KEY);
        if (dialstatus) {
                if (!strcasecmp(dialstatus_string, "ANSWER") && strcasecmp(dialstatus->dialstatus, "ANSWER")) {
                        /* In the case of an answer after we already have a dial status we give
@@ -1171,7 +1171,7 @@ static void save_dialstatus(struct ast_multi_channel_blob *blob, struct ast_chan
                return;
        }
 
-       ast_copy_string(dialstatus->uniqueid, snapshot->uniqueid, sizeof(dialstatus->uniqueid));
+       ast_copy_string(dialstatus->uniqueid, snapshot->base->uniqueid, sizeof(dialstatus->uniqueid));
        ast_copy_string(dialstatus->dialstatus, dialstatus_string, dialstatus_string_len);
 
        ao2_link(dial_statuses, dialstatus);
@@ -1273,8 +1273,8 @@ static void cel_blind_transfer_cb(
                "extension", transfer_msg->exten,
                "context", transfer_msg->context,
                "bridge_id", bridge_snapshot->uniqueid,
-               "transferee_channel_name", transfer_msg->transferee ? transfer_msg->transferee->name : "N/A",
-               "transferee_channel_uniqueid", transfer_msg->transferee ? transfer_msg->transferee->uniqueid  : "N/A");
+               "transferee_channel_name", transfer_msg->transferee ? transfer_msg->transferee->base->name : "N/A",
+               "transferee_channel_uniqueid", transfer_msg->transferee ? transfer_msg->transferee->base->uniqueid  : "N/A");
        if (extra) {
                cel_report_event(chan_snapshot, AST_CEL_BLINDTRANSFER, NULL, extra, NULL);
                ast_json_unref(extra);
@@ -1312,13 +1312,13 @@ static void cel_attended_transfer_cb(
        case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
                extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: s, s: s}",
                        "bridge1_id", bridge1->uniqueid,
-                       "channel2_name", channel2->name,
-                       "channel2_uniqueid", channel2->uniqueid,
+                       "channel2_name", channel2->base->name,
+                       "channel2_uniqueid", channel2->base->uniqueid,
                        "bridge2_id", bridge2->uniqueid,
-                       "transferee_channel_name", xfer->transferee ? xfer->transferee->name : "N/A",
-                       "transferee_channel_uniqueid", xfer->transferee ? xfer->transferee->uniqueid : "N/A",
-                       "transfer_target_channel_name", xfer->target ? xfer->target->name : "N/A",
-                       "transfer_target_channel_uniqueid", xfer->target ? xfer->target->uniqueid : "N/A");
+                       "transferee_channel_name", xfer->transferee ? xfer->transferee->base->name : "N/A",
+                       "transferee_channel_uniqueid", xfer->transferee ? xfer->transferee->base->uniqueid : "N/A",
+                       "transfer_target_channel_name", xfer->target ? xfer->target->base->name : "N/A",
+                       "transfer_target_channel_uniqueid", xfer->target ? xfer->target->base->uniqueid : "N/A");
                if (!extra) {
                        return;
                }
@@ -1327,13 +1327,13 @@ static void cel_attended_transfer_cb(
        case AST_ATTENDED_TRANSFER_DEST_LOCAL_APP:
                extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: s, s: s}",
                        "bridge1_id", bridge1->uniqueid,
-                       "channel2_name", channel2->name,
-                       "channel2_uniqueid", channel2->uniqueid,
+                       "channel2_name", channel2->base->name,
+                       "channel2_uniqueid", channel2->base->uniqueid,
                        "app", xfer->dest.app,
-                       "transferee_channel_name", xfer->transferee ? xfer->transferee->name : "N/A",
-                       "transferee_channel_uniqueid", xfer->transferee ? xfer->transferee->uniqueid : "N/A",
-                       "transfer_target_channel_name", xfer->target ? xfer->target->name : "N/A",
-                       "transfer_target_channel_uniqueid", xfer->target ? xfer->target->uniqueid : "N/A");
+                       "transferee_channel_name", xfer->transferee ? xfer->transferee->base->name : "N/A",
+                       "transferee_channel_uniqueid", xfer->transferee ? xfer->transferee->base->uniqueid : "N/A",
+                       "transfer_target_channel_name", xfer->target ? xfer->target->base->name : "N/A",
+                       "transfer_target_channel_uniqueid", xfer->target ? xfer->target->base->uniqueid : "N/A");
                if (!extra) {
                        return;
                }
@@ -1357,8 +1357,8 @@ static void cel_pickup_cb(
        }
 
        extra = ast_json_pack("{s: s, s: s}",
-               "pickup_channel", channel->name,
-               "pickup_channel_uniqueid", channel->uniqueid);
+               "pickup_channel", channel->base->name,
+               "pickup_channel_uniqueid", channel->base->uniqueid);
        if (!extra) {
                return;
        }
@@ -1381,8 +1381,8 @@ static void cel_local_cb(
        }
 
        extra = ast_json_pack("{s: s, s: s}",
-               "local_two", localtwo->name,
-               "local_two_uniqueid", localtwo->uniqueid);
+               "local_two", localtwo->base->name,
+               "local_two_uniqueid", localtwo->base->uniqueid);
        if (!extra) {
                return;
        }
index 3d8e244..7e12f30 100644 (file)
@@ -6761,6 +6761,12 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
                ast_channel_name(clonechan), ast_channel_state(clonechan),
                ast_channel_name(original), ast_channel_state(original));
 
+       /* When all is said and done force new snapshot segments so they are
+        * up to date.
+        */
+       ast_set_flag(ast_channel_snapshot_segment_flags(original), AST_FLAGS_ALL);
+       ast_set_flag(ast_channel_snapshot_segment_flags(clonechan), AST_FLAGS_ALL);
+
        /*
         * Remember the original read/write formats.  We turn off any
         * translation on either one
@@ -7183,6 +7189,7 @@ void ast_channel_set_caller(struct ast_channel *chan, const struct ast_party_cal
 
        ast_channel_lock(chan);
        ast_party_caller_set(ast_channel_caller(chan), caller, update);
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CALLER);
        ast_channel_unlock(chan);
 }
 
@@ -7195,6 +7202,7 @@ void ast_channel_set_caller_event(struct ast_channel *chan, const struct ast_par
 
        ast_channel_lock(chan);
        ast_party_caller_set(ast_channel_caller(chan), caller, update);
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CALLER);
        ast_channel_publish_snapshot(chan);
        ast_channel_unlock(chan);
 }
@@ -8120,6 +8128,7 @@ void ast_channel_set_connected_line(struct ast_channel *chan, const struct ast_p
 
        ast_channel_lock(chan);
        ast_party_connected_line_set(ast_channel_connected(chan), connected, update);
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CONNECTED);
        ast_channel_publish_snapshot(chan);
        ast_channel_unlock(chan);
 }
@@ -8930,6 +8939,7 @@ void ast_channel_set_redirecting(struct ast_channel *chan, const struct ast_part
 
        ast_channel_lock(chan);
        ast_party_redirecting_set(ast_channel_redirecting(chan), redirecting, update);
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CALLER);
        ast_channel_unlock(chan);
 }
 
index 436ba23..30d3909 100644 (file)
@@ -221,6 +221,7 @@ struct ast_channel {
        void *stream_topology_change_source; /*!< Source that initiated a stream topology change */
        struct ast_stream *default_streams[AST_MEDIA_TYPE_END]; /*!< Default streams indexed by media type */
        struct ast_channel_snapshot *snapshot; /*!< The current up to date snapshot of the channel */
+       struct ast_flags snapshot_segment_flags; /*!< Flags regarding the segments of the snapshot */
 };
 
 /*! \brief The monotonically increasing integer counter for channel uniqueids */
@@ -228,18 +229,40 @@ static int uniqueint;
 
 /* ACCESSORS */
 
-#define DEFINE_STRINGFIELD_SETTERS_FOR(field, publish, assert_on_null) \
+#define DEFINE_STRINGFIELD_SETTERS_FOR(field, assert_on_null) \
 void ast_channel_##field##_set(struct ast_channel *chan, const char *value) \
 { \
        if ((assert_on_null)) ast_assert(!ast_strlen_zero(value)); \
        if (!strcmp(value, chan->field)) return; \
        ast_string_field_set(chan, field, value); \
+} \
+  \
+void ast_channel_##field##_build_va(struct ast_channel *chan, const char *fmt, va_list ap) \
+{ \
+       ast_string_field_build_va(chan, field, fmt, ap); \
+} \
+void ast_channel_##field##_build(struct ast_channel *chan, const char *fmt, ...) \
+{ \
+       va_list ap; \
+       va_start(ap, fmt); \
+       ast_channel_##field##_build_va(chan, fmt, ap); \
+       va_end(ap); \
+}
+
+#define DEFINE_STRINGFIELD_SETTERS_AND_INVALIDATE_FOR(field, publish, assert_on_null, invalidate) \
+void ast_channel_##field##_set(struct ast_channel *chan, const char *value) \
+{ \
+       if ((assert_on_null)) ast_assert(!ast_strlen_zero(value)); \
+       if (!strcmp(value, chan->field)) return; \
+       ast_string_field_set(chan, field, value); \
+       ast_channel_snapshot_invalidate_segment(chan, invalidate); \
        if (publish && ast_channel_internal_is_finalized(chan)) ast_channel_publish_snapshot(chan); \
 } \
   \
 void ast_channel_##field##_build_va(struct ast_channel *chan, const char *fmt, va_list ap) \
 { \
        ast_string_field_build_va(chan, field, fmt, ap); \
+       ast_channel_snapshot_invalidate_segment(chan, invalidate); \
        if (publish && ast_channel_internal_is_finalized(chan)) ast_channel_publish_snapshot(chan); \
 } \
 void ast_channel_##field##_build(struct ast_channel *chan, const char *fmt, ...) \
@@ -250,17 +273,17 @@ void ast_channel_##field##_build(struct ast_channel *chan, const char *fmt, ...)
        va_end(ap); \
 }
 
-DEFINE_STRINGFIELD_SETTERS_FOR(name, 0, 1);
-DEFINE_STRINGFIELD_SETTERS_FOR(language, 1, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(musicclass, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(latest_musicclass, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(accountcode, 1, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(peeraccount, 1, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(userfield, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(call_forward, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(parkinglot, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(hangupsource, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(dialcontext, 0, 0);
+DEFINE_STRINGFIELD_SETTERS_AND_INVALIDATE_FOR(name, 0, 1, AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE);
+DEFINE_STRINGFIELD_SETTERS_AND_INVALIDATE_FOR(language, 1, 0, AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE);
+DEFINE_STRINGFIELD_SETTERS_FOR(musicclass, 0);
+DEFINE_STRINGFIELD_SETTERS_FOR(latest_musicclass, 0);
+DEFINE_STRINGFIELD_SETTERS_AND_INVALIDATE_FOR(accountcode, 1, 0, AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE);
+DEFINE_STRINGFIELD_SETTERS_AND_INVALIDATE_FOR(peeraccount, 1, 0, AST_CHANNEL_SNAPSHOT_INVALIDATE_PEER);
+DEFINE_STRINGFIELD_SETTERS_AND_INVALIDATE_FOR(userfield, 0, 0, AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE);
+DEFINE_STRINGFIELD_SETTERS_FOR(call_forward, 0);
+DEFINE_STRINGFIELD_SETTERS_FOR(parkinglot, 0);
+DEFINE_STRINGFIELD_SETTERS_AND_INVALIDATE_FOR(hangupsource, 0, 0, AST_CHANNEL_SNAPSHOT_INVALIDATE_HANGUP);
+DEFINE_STRINGFIELD_SETTERS_FOR(dialcontext, 0);
 
 #define DEFINE_STRINGFIELD_GETTER_FOR(field) const char *ast_channel_##field(const struct ast_channel *chan) \
 { \
@@ -298,6 +321,7 @@ const char *ast_channel_appl(const struct ast_channel *chan)
 void ast_channel_appl_set(struct ast_channel *chan, const char *value)
 {
        chan->appl = value;
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN);
 }
 const char *ast_channel_blockproc(const struct ast_channel *chan)
 {
@@ -314,6 +338,7 @@ const char *ast_channel_data(const struct ast_channel *chan)
 void ast_channel_data_set(struct ast_channel *chan, const char *value)
 {
        chan->data = value;
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN);
 }
 
 const char *ast_channel_context(const struct ast_channel *chan)
@@ -323,6 +348,7 @@ const char *ast_channel_context(const struct ast_channel *chan)
 void ast_channel_context_set(struct ast_channel *chan, const char *value)
 {
        ast_copy_string(chan->context, value, sizeof(chan->context));
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN);
 }
 const char *ast_channel_exten(const struct ast_channel *chan)
 {
@@ -331,6 +357,7 @@ const char *ast_channel_exten(const struct ast_channel *chan)
 void ast_channel_exten_set(struct ast_channel *chan, const char *value)
 {
        ast_copy_string(chan->exten, value, sizeof(chan->exten));
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN);
 }
 const char *ast_channel_macrocontext(const struct ast_channel *chan)
 {
@@ -404,6 +431,7 @@ int ast_channel_hangupcause(const struct ast_channel *chan)
 void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
 {
        chan->hangupcause = value;
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_HANGUP);
 }
 int ast_channel_macropriority(const struct ast_channel *chan)
 {
@@ -420,6 +448,7 @@ int ast_channel_priority(const struct ast_channel *chan)
 void ast_channel_priority_set(struct ast_channel *chan, int value)
 {
        chan->priority = value;
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN);
 }
 int ast_channel_rings(const struct ast_channel *chan)
 {
@@ -909,18 +938,22 @@ void ast_channel_jb_set(struct ast_channel *chan, struct ast_jb *value)
 void ast_channel_caller_set(struct ast_channel *chan, struct ast_party_caller *value)
 {
        chan->caller = *value;
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CALLER);
 }
 void ast_channel_connected_set(struct ast_channel *chan, struct ast_party_connected_line *value)
 {
        chan->connected = *value;
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CONNECTED);
 }
 void ast_channel_dialed_set(struct ast_channel *chan, struct ast_party_dialed *value)
 {
        chan->dialed = *value;
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CALLER);
 }
 void ast_channel_redirecting_set(struct ast_channel *chan, struct ast_party_redirecting *value)
 {
        chan->redirecting = *value;
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CALLER);
 }
 void ast_channel_dtmf_tv_set(struct ast_channel *chan, struct timeval *value)
 {
@@ -941,6 +974,7 @@ struct timeval ast_channel_creationtime(struct ast_channel *chan)
 void ast_channel_creationtime_set(struct ast_channel *chan, struct timeval *value)
 {
        chan->creationtime = *value;
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE);
 }
 
 struct timeval ast_channel_answertime(struct ast_channel *chan)
@@ -1204,6 +1238,7 @@ struct ast_bridge *ast_channel_internal_bridge(const struct ast_channel *chan)
 void ast_channel_internal_bridge_set(struct ast_channel *chan, struct ast_bridge *value)
 {
        chan->bridge = value;
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_BRIDGE);
        ast_channel_publish_snapshot(chan);
 }
 
@@ -1335,6 +1370,11 @@ struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj),
 
        AST_VECTOR_INIT(&tmp->fds, AST_MAX_FDS);
 
+       /* Force all channel snapshot segments to be created on first use, so we don't have to check if
+        * an old snapshot exists.
+        */
+       ast_set_flag(&tmp->snapshot_segment_flags, AST_FLAGS_ALL);
+
        return tmp;
 }
 
@@ -1363,6 +1403,7 @@ void ast_channel_internal_copy_linkedid(struct ast_channel *dest, struct ast_cha
                return;
        }
        dest->linkedid = source->linkedid;
+       ast_channel_snapshot_invalidate_segment(dest, AST_CHANNEL_SNAPSHOT_INVALIDATE_PEER);
        ast_channel_publish_snapshot(dest);
 }
 
@@ -1370,6 +1411,10 @@ void ast_channel_internal_swap_uniqueid_and_linkedid(struct ast_channel *a, stru
 {
        struct ast_channel_id temp;
 
+       /* This operation is used as part of masquerading and so does not invalidate the peer
+        * segment. This is due to the masquerade process invalidating all segments.
+        */
+
        temp = a->uniqueid;
        a->uniqueid = b->uniqueid;
        b->uniqueid = temp;
@@ -1584,3 +1629,8 @@ void ast_channel_snapshot_set(struct ast_channel *chan, struct ast_channel_snaps
        ao2_cleanup(chan->snapshot);
        chan->snapshot = ao2_bump(snapshot);
 }
+
+struct ast_flags *ast_channel_snapshot_segment_flags(struct ast_channel *chan)
+{
+       return &chan->snapshot_segment_flags;
+}
index 5484e47..e2224f7 100644 (file)
@@ -1004,8 +1004,8 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
                char durbuf[16] = "-";
 
                if (!count) {
-                       if ((concise || verbose)  && !ast_tvzero(cs->creationtime)) {
-                               int duration = (int)(ast_tvdiff_ms(ast_tvnow(), cs->creationtime) / 1000);
+                       if ((concise || verbose)  && !ast_tvzero(cs->base->creationtime)) {
+                               int duration = (int)(ast_tvdiff_ms(ast_tvnow(), cs->base->creationtime) / 1000);
                                if (verbose) {
                                        int durh = duration / 3600;
                                        int durm = (duration % 3600) / 60;
@@ -1016,36 +1016,36 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
                                }
                        }
                        if (concise) {
-                               ast_cli(a->fd, CONCISE_FORMAT_STRING, cs->name, cs->context, cs->exten, cs->priority, ast_state2str(cs->state),
-                                       S_OR(cs->appl, "(None)"),
-                                       cs->data,
-                                       cs->caller_number,
-                                       cs->accountcode,
-                                       cs->peeraccount,
+                               ast_cli(a->fd, CONCISE_FORMAT_STRING, cs->base->name, cs->dialplan->context, cs->dialplan->exten, cs->dialplan->priority, ast_state2str(cs->state),
+                                       S_OR(cs->dialplan->appl, "(None)"),
+                                       cs->dialplan->data,
+                                       cs->caller->number,
+                                       cs->base->accountcode,
+                                       cs->peer->account,
                                        cs->amaflags,
                                        durbuf,
-                                       cs->bridgeid,
-                                       cs->uniqueid);
+                                       cs->bridge->id,
+                                       cs->base->uniqueid);
                        } else if (verbose) {
-                               ast_cli(a->fd, VERBOSE_FORMAT_STRING, cs->name, cs->context, cs->exten, cs->priority, ast_state2str(cs->state),
-                                       S_OR(cs->appl, "(None)"),
-                                       S_OR(cs->data, "(Empty)"),
-                                       cs->caller_number,
+                               ast_cli(a->fd, VERBOSE_FORMAT_STRING, cs->base->name, cs->dialplan->context, cs->dialplan->exten, cs->dialplan->priority, ast_state2str(cs->state),
+                                       S_OR(cs->dialplan->appl, "(None)"),
+                                       S_OR(cs->dialplan->data, "(Empty)"),
+                                       cs->caller->number,
                                        durbuf,
-                                       cs->accountcode,
-                                       cs->peeraccount,
-                                       cs->bridgeid);
+                                       cs->base->accountcode,
+                                       cs->peer->account,
+                                       cs->bridge->id);
                        } else {
                                char locbuf[40] = "(None)";
                                char appdata[40] = "(None)";
 
-                               if (!ast_strlen_zero(cs->context) && !ast_strlen_zero(cs->exten)) {
-                                       snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", cs->exten, cs->context, cs->priority);
+                               if (!ast_strlen_zero(cs->dialplan->context) && !ast_strlen_zero(cs->dialplan->exten)) {
+                                       snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", cs->dialplan->exten, cs->dialplan->context, cs->dialplan->priority);
                                }
-                               if (!ast_strlen_zero(cs->appl)) {
-                                       snprintf(appdata, sizeof(appdata), "%s(%s)", cs->appl, S_OR(cs->data, ""));
+                               if (!ast_strlen_zero(cs->dialplan->appl)) {
+                                       snprintf(appdata, sizeof(appdata), "%s(%s)", cs->dialplan->appl, S_OR(cs->dialplan->data, ""));
                                }
-                               ast_cli(a->fd, FORMAT_STRING, cs->name, locbuf, ast_state2str(cs->state), appdata);
+                               ast_cli(a->fd, FORMAT_STRING, cs->base->name, locbuf, ast_state2str(cs->state), appdata);
                        }
                }
        }
@@ -1684,14 +1684,14 @@ char *ast_complete_channels(const char *line, const char *word, int pos, int sta
 
        iter = ao2_iterator_init(cached_channels, 0);
        for (; (snapshot = ao2_iterator_next(&iter)); ao2_ref(snapshot, -1)) {
-               if (!strncasecmp(word, snapshot->name, wordlen) && (++which > state)) {
+               if (!strncasecmp(word, snapshot->base->name, wordlen) && (++which > state)) {
                        if (state != -1) {
-                               ret = ast_strdup(snapshot->name);
+                               ret = ast_strdup(snapshot->base->name);
                                ao2_ref(snapshot, -1);
                                break;
                        }
 
-                       if (ast_cli_completion_add(ast_strdup(snapshot->name))) {
+                       if (ast_cli_completion_add(ast_strdup(snapshot->base->name))) {
                                ao2_ref(snapshot, -1);
                                break;
                        }
index c3fa15f..f56aac7 100644 (file)
@@ -493,7 +493,7 @@ static struct ast_manager_event_blob *local_message_to_ami(struct stasis_message
                }
 
                dest_uniqueid = ast_json_object_get(blob, "dest") == AST_UNREAL_OWNER ?
-                               local_snapshot_one->uniqueid : local_snapshot_two->uniqueid;
+                               local_snapshot_one->base->uniqueid : local_snapshot_two->base->uniqueid;
 
                event = "LocalOptimizationBegin";
                if (source_str) {
index f3e3372..b958932 100644 (file)
@@ -195,7 +195,7 @@ static void endpoint_cache_clear(void *data,
        ast_assert(endpoint != NULL);
 
        ao2_lock(endpoint);
-       ast_str_container_remove(endpoint->channel_ids, update->new_snapshot->uniqueid);
+       ast_str_container_remove(endpoint->channel_ids, update->new_snapshot->base->uniqueid);
        ao2_unlock(endpoint);
        endpoint_publish_snapshot(endpoint);
 }
index 76a827c..3e41198 100644 (file)
@@ -6271,10 +6271,10 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m
                        continue;
                }
 
-               if (!ast_tvzero(cs->creationtime)) {
+               if (!ast_tvzero(cs->base->creationtime)) {
                        int duration, durh, durm, durs;
 
-                       duration = (int)(ast_tvdiff_ms(ast_tvnow(), cs->creationtime) / 1000);
+                       duration = (int)(ast_tvdiff_ms(ast_tvnow(), cs->base->creationtime) / 1000);
                        durh = duration / 3600;
                        durm = (duration % 3600) / 60;
                        durs = duration % 60;
@@ -6292,10 +6292,10 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m
                        "\r\n",
                        idText,
                        ast_str_buffer(built),
-                       cs->appl,
-                       cs->data,
+                       cs->dialplan->appl,
+                       cs->dialplan->data,
                        durbuf,
-                       cs->bridgeid);
+                       cs->bridge->id);
 
                numchans++;
 
index 1b57049..4f2cb35 100644 (file)
@@ -536,7 +536,7 @@ static int send_bridge_info_item_cb(void *obj, void *arg, void *data, int flags)
                return 0;
        }
 
-       if (snapshot->tech_properties & AST_CHAN_TP_INTERNAL) {
+       if (snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL) {
                return 0;
        }
 
index 887f77e..edbc770 100644 (file)
@@ -493,7 +493,7 @@ struct ast_str *ast_manager_build_channel_state_string_prefix(
        char *connected_name;
        int res;
 
-       if (snapshot->tech_properties & AST_CHAN_TP_INTERNAL) {
+       if (snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL) {
                return NULL;
        }
 
@@ -502,8 +502,8 @@ struct ast_str *ast_manager_build_channel_state_string_prefix(
                return NULL;
        }
 
-       caller_name = ast_escape_c_alloc(snapshot->caller_name);
-       connected_name = ast_escape_c_alloc(snapshot->connected_name);
+       caller_name = ast_escape_c_alloc(snapshot->caller->name);
+       connected_name = ast_escape_c_alloc(snapshot->connected->name);
 
        res = ast_str_set(&out, 0,
                "%sChannel: %s\r\n"
@@ -520,20 +520,20 @@ struct ast_str *ast_manager_build_channel_state_string_prefix(
                "%sPriority: %d\r\n"
                "%sUniqueid: %s\r\n"
                "%sLinkedid: %s\r\n",
-               prefix, snapshot->name,
+               prefix, snapshot->base->name,
                prefix, snapshot->state,
                prefix, ast_state2str(snapshot->state),
-               prefix, S_OR(snapshot->caller_number, "<unknown>"),
+               prefix, S_OR(snapshot->caller->number, "<unknown>"),
                prefix, S_OR(caller_name, "<unknown>"),
-               prefix, S_OR(snapshot->connected_number, "<unknown>"),
+               prefix, S_OR(snapshot->connected->number, "<unknown>"),
                prefix, S_OR(connected_name, "<unknown>"),
-               prefix, snapshot->language,
-               prefix, snapshot->accountcode,
-               prefix, snapshot->context,
-               prefix, snapshot->exten,
-               prefix, snapshot->priority,
-               prefix, snapshot->uniqueid,
-               prefix, snapshot->linkedid);
+               prefix, snapshot->base->language,
+               prefix, snapshot->base->accountcode,
+               prefix, snapshot->dialplan->context,
+               prefix, snapshot->dialplan->exten,
+               prefix, snapshot->dialplan->priority,
+               prefix, snapshot->base->uniqueid,
+               prefix, snapshot->peer->linkedid);
 
        ast_free(caller_name);
        ast_free(connected_name);
@@ -594,8 +594,8 @@ static struct ast_manager_event_blob *channel_state_change(
                        EVENT_FLAG_CALL, "Hangup",
                        "Cause: %d\r\n"
                        "Cause-txt: %s\r\n",
-                       new_snapshot->hangupcause,
-                       ast_cause2str(new_snapshot->hangupcause));
+                       new_snapshot->hangup->cause,
+                       ast_cause2str(new_snapshot->hangup->cause));
        }
 
        if (old_snapshot->state != new_snapshot->state) {
@@ -612,7 +612,7 @@ static struct ast_manager_event_blob *channel_newexten(
        struct ast_channel_snapshot *new_snapshot)
 {
        /* Empty application is not valid for a Newexten event */
-       if (ast_strlen_zero(new_snapshot->appl)) {
+       if (ast_strlen_zero(new_snapshot->dialplan->appl)) {
                return NULL;
        }
 
@@ -632,9 +632,9 @@ static struct ast_manager_event_blob *channel_newexten(
                "Extension: %s\r\n"
                "Application: %s\r\n"
                "AppData: %s\r\n",
-               new_snapshot->exten,
-               new_snapshot->appl,
-               new_snapshot->data);
+               new_snapshot->dialplan->exten,
+               new_snapshot->dialplan->appl,
+               new_snapshot->dialplan->data);
 }
 
 static struct ast_manager_event_blob *channel_new_callerid(
@@ -654,14 +654,14 @@ static struct ast_manager_event_blob *channel_new_callerid(
        }
 
        if (!(callerid = ast_escape_c_alloc(
-                     ast_describe_caller_presentation(new_snapshot->caller_pres)))) {
+                     ast_describe_caller_presentation(new_snapshot->caller->pres)))) {
                return NULL;
        }
 
        res = ast_manager_event_blob_create(
                EVENT_FLAG_CALL, "NewCallerid",
                "CID-CallingPres: %d (%s)\r\n",
-               new_snapshot->caller_pres,
+               new_snapshot->caller->pres,
                callerid);
 
        ast_free(callerid);
@@ -693,13 +693,13 @@ static struct ast_manager_event_blob *channel_new_accountcode(
                return NULL;
        }
 
-       if (!strcmp(old_snapshot->accountcode, new_snapshot->accountcode)) {
+       if (!strcmp(old_snapshot->base->accountcode, new_snapshot->base->accountcode)) {
                return NULL;
        }
 
        return ast_manager_event_blob_create(
                EVENT_FLAG_CALL, "NewAccountCode",
-               "OldAccountCode: %s\r\n", old_snapshot->accountcode);
+               "OldAccountCode: %s\r\n", old_snapshot->base->accountcode);
 }
 
 channel_snapshot_monitor channel_monitors[] = {
index 59b9685..42bf6bc 100644 (file)
@@ -1069,7 +1069,7 @@ static struct ast_manager_event_blob *attended_transfer_to_ami(struct stasis_mes
        case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
                ast_str_append(&variable_data, 0, "DestType: Threeway\r\n");
                ast_str_append(&variable_data, 0, "DestBridgeUniqueid: %s\r\n", transfer_msg->dest.threeway.bridge_snapshot->uniqueid);
-               ast_str_append(&variable_data, 0, "DestTransfererChannel: %s\r\n", transfer_msg->dest.threeway.channel_snapshot->name);
+               ast_str_append(&variable_data, 0, "DestTransfererChannel: %s\r\n", transfer_msg->dest.threeway.channel_snapshot->base->name);
                break;
        case AST_ATTENDED_TRANSFER_DEST_FAIL:
                ast_str_append(&variable_data, 0, "DestType: Fail\r\n");
@@ -1189,7 +1189,7 @@ int ast_attended_transfer_message_add_threeway(struct ast_attended_transfer_mess
 {
        transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_THREEWAY;
 
-       if (!strcmp(ast_channel_uniqueid(survivor_channel), transfer_msg->to_transferee.channel_snapshot->uniqueid)) {
+       if (!strcmp(ast_channel_uniqueid(survivor_channel), transfer_msg->to_transferee.channel_snapshot->base->uniqueid)) {
                transfer_msg->dest.threeway.channel_snapshot = transfer_msg->to_transferee.channel_snapshot;
        } else {
                transfer_msg->dest.threeway.channel_snapshot = transfer_msg->to_transfer_target.channel_snapshot;
index ec8d70c..d39fb08 100644 (file)
@@ -149,7 +149,7 @@ static int channel_snapshot_hash_cb(const void *obj, const int flags)
                key = obj;
                break;
        case OBJ_SEARCH_OBJECT:
-               key = object->name;
+               key = object->base->name;
                break;
        default:
                ast_assert(0);
@@ -171,12 +171,12 @@ static int channel_snapshot_cmp_cb(void *obj, void *arg, int flags)
 
        switch (flags & OBJ_SEARCH_MASK) {
        case OBJ_SEARCH_OBJECT:
-               right_key = object_right->name;
+               right_key = object_right->base->name;
        case OBJ_SEARCH_KEY:
-               cmp = strcasecmp(object_left->name, right_key);
+               cmp = strcasecmp(object_left->base->name, right_key);
                break;
        case OBJ_SEARCH_PARTIAL_KEY:
-               cmp = strncasecmp(object_left->name, right_key, strlen(right_key));
+               cmp = strncasecmp(object_left->base->name, right_key, strlen(right_key));
                break;
        default:
                cmp = 0;
@@ -202,7 +202,7 @@ static int channel_snapshot_uniqueid_hash_cb(const void *obj, const int flags)
                key = obj;
                break;
        case OBJ_SEARCH_OBJECT:
-               key = object->uniqueid;
+               key = object->base->uniqueid;
                break;
        default:
                ast_assert(0);
@@ -224,12 +224,12 @@ static int channel_snapshot_uniqueid_cmp_cb(void *obj, void *arg, int flags)
 
        switch (flags & OBJ_SEARCH_MASK) {
        case OBJ_SEARCH_OBJECT:
-               right_key = object_right->uniqueid;
+               right_key = object_right->base->uniqueid;
        case OBJ_SEARCH_KEY:
-               cmp = strcasecmp(object_left->uniqueid, right_key);
+               cmp = strcasecmp(object_left->base->uniqueid, right_key);
                break;
        case OBJ_SEARCH_PARTIAL_KEY:
-               cmp = strncasecmp(object_left->uniqueid, right_key, strlen(right_key));
+               cmp = strncasecmp(object_left->base->uniqueid, right_key, strlen(right_key));
                break;
        default:
                cmp = 0;
@@ -245,88 +245,312 @@ static void channel_snapshot_dtor(void *obj)
 {
        struct ast_channel_snapshot *snapshot = obj;
 
-       ast_string_field_free_memory(snapshot);
+       ao2_cleanup(snapshot->base);
+       ao2_cleanup(snapshot->peer);
+       ao2_cleanup(snapshot->caller);
+       ao2_cleanup(snapshot->connected);
+       ao2_cleanup(snapshot->bridge);
+       ao2_cleanup(snapshot->dialplan);
+       ao2_cleanup(snapshot->hangup);
        ao2_cleanup(snapshot->manager_vars);
        ao2_cleanup(snapshot->ari_vars);
 }
 
-struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *chan)
+static void channel_snapshot_base_dtor(void *obj)
 {
-       struct ast_channel_snapshot *snapshot;
-       struct ast_bridge *bridge;
+       struct ast_channel_snapshot_base *snapshot = obj;
 
-       /* no snapshots for dummy channels */
-       if (!ast_channel_tech(chan)) {
+       ast_string_field_free_memory(snapshot);
+}
+
+static struct ast_channel_snapshot_base *channel_snapshot_base_create(struct ast_channel *chan)
+{
+       struct ast_channel_snapshot_base *snapshot;
+
+       snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_base_dtor,
+               AO2_ALLOC_OPT_LOCK_NOLOCK);
+       if (!snapshot) {
                return NULL;
        }
 
-       snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_dtor,
-               AO2_ALLOC_OPT_LOCK_NOLOCK);
-       if (!snapshot || ast_string_field_init(snapshot, 1024)) {
-               ao2_cleanup(snapshot);
+       if (ast_string_field_init(snapshot, 256)) {
+               ao2_ref(snapshot, -1);
                return NULL;
        }
 
        ast_string_field_set(snapshot, name, ast_channel_name(chan));
        ast_string_field_set(snapshot, type, ast_channel_tech(chan)->type);
        ast_string_field_set(snapshot, accountcode, ast_channel_accountcode(chan));
-       ast_string_field_set(snapshot, peeraccount, ast_channel_peeraccount(chan));
        ast_string_field_set(snapshot, userfield, ast_channel_userfield(chan));
        ast_string_field_set(snapshot, uniqueid, ast_channel_uniqueid(chan));
-       ast_string_field_set(snapshot, linkedid, ast_channel_linkedid(chan));
-       ast_string_field_set(snapshot, hangupsource, ast_channel_hangupsource(chan));
-       if (ast_channel_appl(chan)) {
-               ast_string_field_set(snapshot, appl, ast_channel_appl(chan));
+       ast_string_field_set(snapshot, language, ast_channel_language(chan));
+
+       snapshot->creationtime = ast_channel_creationtime(chan);
+       snapshot->tech_properties = ast_channel_tech(chan)->properties;
+
+       return snapshot;
+}
+
+static struct ast_channel_snapshot_peer *channel_snapshot_peer_create(struct ast_channel *chan)
+{
+       const char *linkedid = S_OR(ast_channel_linkedid(chan), "");
+       const char *peeraccount = S_OR(ast_channel_peeraccount(chan), "");
+       size_t linkedid_len = strlen(linkedid) + 1;
+       size_t peeraccount_len = strlen(peeraccount) + 1;
+       struct ast_channel_snapshot_peer *snapshot;
+
+       snapshot = ao2_alloc_options(sizeof(*snapshot) + linkedid_len + peeraccount_len, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
+       if (!snapshot) {
+               return NULL;
        }
-       if (ast_channel_data(chan)) {
-               ast_string_field_set(snapshot, data, ast_channel_data(chan));
+
+       strcpy(snapshot->account, peeraccount); /* Safe */
+       snapshot->linkedid = snapshot->account + peeraccount_len;
+       strcpy(snapshot->linkedid, linkedid); /* Safe */
+
+       return snapshot;
+}
+
+static void channel_snapshot_caller_dtor(void *obj)
+{
+       struct ast_channel_snapshot_caller *snapshot = obj;
+
+       ast_string_field_free_memory(snapshot);
+}
+
+static struct ast_channel_snapshot_caller *channel_snapshot_caller_create(struct ast_channel *chan)
+{
+       struct ast_channel_snapshot_caller *snapshot;
+
+       snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_caller_dtor,
+               AO2_ALLOC_OPT_LOCK_NOLOCK);
+       if (!snapshot) {
+               return NULL;
+       }
+
+       if (ast_string_field_init(snapshot, 256)) {
+               ao2_ref(snapshot, -1);
+               return NULL;
        }
-       ast_string_field_set(snapshot, context, ast_channel_context(chan));
-       ast_string_field_set(snapshot, exten, ast_channel_exten(chan));
 
-       ast_string_field_set(snapshot, caller_name,
+       ast_string_field_set(snapshot, name,
                S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, ""));
-       ast_string_field_set(snapshot, caller_number,
+       ast_string_field_set(snapshot, number,
                S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""));
-       ast_string_field_set(snapshot, caller_subaddr,
+       ast_string_field_set(snapshot, subaddr,
                S_COR(ast_channel_caller(chan)->id.subaddress.valid, ast_channel_caller(chan)->id.subaddress.str, ""));
-       ast_string_field_set(snapshot, caller_ani,
+       ast_string_field_set(snapshot, ani,
                S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, ""));
 
-       ast_string_field_set(snapshot, caller_rdnis,
+       ast_string_field_set(snapshot, rdnis,
                S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, ""));
 
-       ast_string_field_set(snapshot, caller_dnid,
+       ast_string_field_set(snapshot, dnid,
                S_OR(ast_channel_dialed(chan)->number.str, ""));
        ast_string_field_set(snapshot, dialed_subaddr,
                S_COR(ast_channel_dialed(chan)->subaddress.valid, ast_channel_dialed(chan)->subaddress.str, ""));
 
-       ast_string_field_set(snapshot, connected_name,
-               S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, ""));
-       ast_string_field_set(snapshot, connected_number,
-               S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, ""));
+       snapshot->pres = ast_party_id_presentation(&ast_channel_caller(chan)->id);
 
-       ast_string_field_set(snapshot, language, ast_channel_language(chan));
+       return snapshot;
+}
+
+static struct ast_channel_snapshot_connected *channel_snapshot_connected_create(struct ast_channel *chan)
+{
+       const char *name = S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, "");
+       const char *number = S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, "");
+       size_t name_len = strlen(name) + 1;
+       size_t number_len = strlen(number) + 1;
+       struct ast_channel_snapshot_connected *snapshot;
+
+       snapshot = ao2_alloc_options(sizeof(*snapshot) + name_len + number_len, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
+       if (!snapshot) {
+               return NULL;
+       }
+
+       strcpy(snapshot->name, name); /* Safe */
+       snapshot->number = snapshot->name + name_len;
+       strcpy(snapshot->number, number); /* Safe */
+
+       return snapshot;
+}
+
+static struct ast_channel_snapshot_bridge *channel_snapshot_bridge_create(struct ast_channel *chan)
+{
+       const char *uniqueid = "";
+       struct ast_bridge *bridge;
+       struct ast_channel_snapshot_bridge *snapshot;
+
+       bridge = ast_channel_get_bridge(chan);
+       if (bridge && !ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) {
+               uniqueid = bridge->uniqueid;
+       }
+       ao2_cleanup(bridge);
+
+       snapshot = ao2_alloc_options(sizeof(*snapshot) + strlen(uniqueid) + 1, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
+       if (!snapshot) {
+               return NULL;
+       }
+
+       strcpy(snapshot->id, uniqueid); /* Safe */
+
+       return snapshot;
+}
+
+static void channel_snapshot_dialplan_dtor(void *obj)
+{
+       struct ast_channel_snapshot_dialplan *snapshot = obj;
+
+       ast_string_field_free_memory(snapshot);
+}
+
+static struct ast_channel_snapshot_dialplan *channel_snapshot_dialplan_create(struct ast_channel *chan)
+{
+       struct ast_channel_snapshot_dialplan *snapshot;
+
+       snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_dialplan_dtor,
+               AO2_ALLOC_OPT_LOCK_NOLOCK);
+       if (!snapshot) {
+               return NULL;
+       }
 
-       if ((bridge = ast_channel_get_bridge(chan))) {
-               if (!ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) {
-                       ast_string_field_set(snapshot, bridgeid, bridge->uniqueid);
+       if (ast_string_field_init(snapshot, 256)) {
+               ao2_ref(snapshot, -1);
+               return NULL;
+       }
+
+       if (ast_channel_appl(chan)) {
+               ast_string_field_set(snapshot, appl, ast_channel_appl(chan));
+       }
+       if (ast_channel_data(chan)) {
+               ast_string_field_set(snapshot, data, ast_channel_data(chan));
+       }
+       ast_string_field_set(snapshot, context, ast_channel_context(chan));
+       ast_string_field_set(snapshot, exten, ast_channel_exten(chan));
+       snapshot->priority = ast_channel_priority(chan);
+
+       return snapshot;
+}
+
+static struct ast_channel_snapshot_hangup *channel_snapshot_hangup_create(struct ast_channel *chan)
+{
+       const char *hangupsource = S_OR(ast_channel_hangupsource(chan), "");
+       struct ast_channel_snapshot_hangup *snapshot;
+
+       snapshot = ao2_alloc_options(sizeof(*snapshot) + strlen(hangupsource) + 1, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
+       if (!snapshot) {
+               return NULL;
+       }
+
+       snapshot->cause = ast_channel_hangupcause(chan);
+       strcpy(snapshot->source, hangupsource); /* Safe */
+
+       return snapshot;
+}
+
+struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *chan)
+{
+       struct ast_channel_snapshot *old_snapshot;
+       struct ast_channel_snapshot *snapshot;
+
+       /* no snapshots for dummy channels */
+       if (!ast_channel_tech(chan)) {
+               return NULL;
+       }
+
+       snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_dtor,
+               AO2_ALLOC_OPT_LOCK_NOLOCK);
+       if (!snapshot) {
+               return NULL;
+       }
+
+       old_snapshot = ast_channel_snapshot(chan);
+
+       /* Channels automatically have all segments invalidated on them initially so a check for an old
+        * snapshot existing before usage is not done here, as it can not happen. If the stored snapshot
+        * on the channel is updated as a result of this then all segments marked as invalidated will be
+        * cleared.
+        */
+       if (ast_test_flag(ast_channel_snapshot_segment_flags(chan), AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE)) {
+               /* The base information has changed so update our snapshot */
+               snapshot->base = channel_snapshot_base_create(chan);
+               if (!snapshot->base) {
+                       ao2_ref(snapshot, -1);
+                       return NULL;
                }
-               ao2_cleanup(bridge);
+       } else {
+               snapshot->base = ao2_bump(old_snapshot->base);
+       }
+
+       if (ast_test_flag(ast_channel_snapshot_segment_flags(chan), AST_CHANNEL_SNAPSHOT_INVALIDATE_PEER)) {
+               /* The peer information has changed so update our snapshot */
+               snapshot->peer = channel_snapshot_peer_create(chan);
+               if (!snapshot->peer) {
+                       ao2_ref(snapshot, -1);
+                       return NULL;
+               }
+       } else {
+               snapshot->peer = ao2_bump(old_snapshot->peer);
+       }
+
+       /* Unfortunately both caller and connected information do not have an enforced contract with
+        * the channel API. This has allowed consumers to directly get the caller or connected structure
+        * and manipulate it. Until such time as there is an enforced contract (which is being tracked under
+        * ASTERISK-28164) they are each regenerated every time a channel snapshot is created.
+        */
+       snapshot->caller = channel_snapshot_caller_create(chan);
+       if (!snapshot->caller) {
+               ao2_ref(snapshot, -1);
+               return NULL;
+       }
+
+       snapshot->connected = channel_snapshot_connected_create(chan);
+       if (!snapshot->connected) {
+               ao2_ref(snapshot, -1);
+               return NULL;
+       }
+
+       if (ast_test_flag(ast_channel_snapshot_segment_flags(chan), AST_CHANNEL_SNAPSHOT_INVALIDATE_BRIDGE)) {
+               /* The bridge has changed so update our snapshot */
+               snapshot->bridge = channel_snapshot_bridge_create(chan);
+               if (!snapshot->bridge) {
+                       ao2_ref(snapshot, -1);
+                       return NULL;
+               }
+       } else {
+               snapshot->bridge = ao2_bump(old_snapshot->bridge);
+       }
+
+       if (ast_test_flag(ast_channel_snapshot_segment_flags(chan), AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN)) {
+               /* The dialplan information has changed so update our snapshot */
+               snapshot->dialplan = channel_snapshot_dialplan_create(chan);
+               if (!snapshot->dialplan) {
+                       ao2_ref(snapshot, -1);
+                       return NULL;
+               }
+       } else {
+               snapshot->dialplan = ao2_bump(old_snapshot->dialplan);
+       }
+
+       if (ast_test_flag(ast_channel_snapshot_segment_flags(chan), AST_CHANNEL_SNAPSHOT_INVALIDATE_HANGUP)) {
+               /* The hangup information has changed so update our snapshot */
+               snapshot->hangup = channel_snapshot_hangup_create(chan);
+               if (!snapshot->hangup) {
+                       ao2_ref(snapshot, -1);
+                       return NULL;
+               }
+       } else {
+               snapshot->hangup = ao2_bump(old_snapshot->hangup);
        }
 
-       snapshot->creationtime = ast_channel_creationtime(chan);
        snapshot->state = ast_channel_state(chan);
-       snapshot->priority = ast_channel_priority(chan);
        snapshot->amaflags = ast_channel_amaflags(chan);
-       snapshot->hangupcause = ast_channel_hangupcause(chan);
        ast_copy_flags(&snapshot->flags, ast_channel_flags(chan), 0xFFFFFFFF);
-       snapshot->caller_pres = ast_party_id_presentation(&ast_channel_caller(chan)->id);
        ast_set_flag(&snapshot->softhangup_flags, ast_channel_softhangup_internal_flag(chan));
 
+       /* These have to be recreated as they may have changed, unfortunately */
        snapshot->manager_vars = ast_channel_get_manager_vars(chan);
        snapshot->ari_vars = ast_channel_get_ari_vars(chan);
-       snapshot->tech_properties = ast_channel_tech(chan)->properties;
 
        return snapshot;
 }
@@ -822,6 +1046,12 @@ void ast_channel_stage_snapshot_done(struct ast_channel *chan)
        ast_channel_publish_snapshot(chan);
 }
 
+void ast_channel_snapshot_invalidate_segment(struct ast_channel *chan,
+       enum ast_channel_snapshot_segment_invalidation segment)
+{
+       ast_set_flag(ast_channel_snapshot_segment_flags(chan), segment);
+}
+
 void ast_channel_publish_snapshot(struct ast_channel *chan)
 {
        struct ast_channel_snapshot_update *update;
@@ -840,6 +1070,14 @@ void ast_channel_publish_snapshot(struct ast_channel *chan)
                return;
        }
 
+       /* If an old snapshot exists and is the same as this newly created one don't bother
+        * raising a message as it hasn't changed.
+        */
+       if (update->old_snapshot && !memcmp(update->old_snapshot, update->new_snapshot, sizeof(struct ast_channel_snapshot))) {
+               ao2_ref(update, -1);
+               return;
+       }
+
        message = stasis_message_create(ast_channel_snapshot_type(), update);
        /* In the success path message holds a reference to update so it will be valid
         * for the lifetime of this function until the end.
@@ -869,6 +1107,11 @@ void ast_channel_publish_snapshot(struct ast_channel *chan)
 
        ast_channel_snapshot_set(chan, update->new_snapshot);
 
+       /* As this is now the new snapshot any existing invalidated segments have been
+        * created fresh and are up to date.
+        */
+       ast_clear_flag(ast_channel_snapshot_segment_flags(chan), AST_FLAGS_ALL);
+
        ast_assert(ast_channel_topic(chan) != NULL);
        stasis_publish(ast_channel_topic(chan), message);
        ao2_ref(message, -1);
@@ -1028,20 +1271,20 @@ struct ast_json *ast_channel_snapshot_to_json(
                "  s: o, s: o, s: s,"
                "  s: o, s: o, s: s }",
                /* First line */
-               "id", snapshot->uniqueid,
-               "name", snapshot->name,
+               "id", snapshot->base->uniqueid,
+               "name", snapshot->base->name,
                "state", ast_state2str(snapshot->state),
                /* Second line */
                "caller", ast_json_name_number(
-                       snapshot->caller_name, snapshot->caller_number),
+                       snapshot->caller->name, snapshot->caller->number),
                "connected", ast_json_name_number(
-                       snapshot->connected_name, snapshot->connected_number),
-               "accountcode", snapshot->accountcode,
+                       snapshot->connected->name, snapshot->connected->number),
+               "accountcode", snapshot->base->accountcode,
                /* Third line */
                "dialplan", ast_json_dialplan_cep(
-                       snapshot->context, snapshot->exten, snapshot->priority),
-               "creationtime", ast_json_timeval(snapshot->creationtime, NULL),
-               "language", snapshot->language);
+                       snapshot->dialplan->context, snapshot->dialplan->exten, snapshot->dialplan->priority),
+               "creationtime", ast_json_timeval(snapshot->base->creationtime, NULL),
+               "language", snapshot->base->language);
 
        if (snapshot->ari_vars && !AST_LIST_EMPTY(snapshot->ari_vars)) {
                ast_json_object_set(json_chan, "channelvars", ast_json_channel_vars(snapshot->ari_vars));
@@ -1061,14 +1304,14 @@ int ast_channel_snapshot_cep_equal(
         * application is set. Since empty application is invalid, we treat
         * setting the application from nothing as a CEP change.
         */
-       if (ast_strlen_zero(old_snapshot->appl) &&
-           !ast_strlen_zero(new_snapshot->appl)) {
+       if (ast_strlen_zero(old_snapshot->dialplan->appl) &&
+           !ast_strlen_zero(new_snapshot->dialplan->appl)) {
                return 0;
        }
 
-       return old_snapshot->priority == new_snapshot->priority &&
-               strcmp(old_snapshot->context, new_snapshot->context) == 0 &&
-               strcmp(old_snapshot->exten, new_snapshot->exten) == 0;
+       return old_snapshot->dialplan->priority == new_snapshot->dialplan->priority &&
+               strcmp(old_snapshot->dialplan->context, new_snapshot->dialplan->context) == 0 &&
+               strcmp(old_snapshot->dialplan->exten, new_snapshot->dialplan->exten) == 0;
 }
 
 int ast_channel_snapshot_caller_id_equal(
@@ -1077,8 +1320,8 @@ int ast_channel_snapshot_caller_id_equal(
 {
        ast_assert(old_snapshot != NULL);
        ast_assert(new_snapshot != NULL);
-       return strcmp(old_snapshot->caller_number, new_snapshot->caller_number) == 0 &&
-               strcmp(old_snapshot->caller_name, new_snapshot->caller_name) == 0;
+       return strcmp(old_snapshot->caller->number, new_snapshot->caller->number) == 0 &&
+               strcmp(old_snapshot->caller->name, new_snapshot->caller->name) == 0;
 }
 
 int ast_channel_snapshot_connected_line_equal(
@@ -1087,8 +1330,8 @@ int ast_channel_snapshot_connected_line_equal(
 {
        ast_assert(old_snapshot != NULL);
        ast_assert(new_snapshot != NULL);
-       return strcmp(old_snapshot->connected_number, new_snapshot->connected_number) == 0 &&
-               strcmp(old_snapshot->connected_name, new_snapshot->connected_name) == 0;
+       return strcmp(old_snapshot->connected->number, new_snapshot->connected->number) == 0 &&
+               strcmp(old_snapshot->connected->name, new_snapshot->connected->name) == 0;
 }
 
 static struct ast_json *channel_blob_to_json(
index 75e6654..970bb3c 100644 (file)
@@ -344,6 +344,11 @@ static int realtime_exec(struct ast_channel *chan, const char *context, const ch
                                                 term_color(tmp3, S_OR(appdata, ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)));
                                if (ast_channel_snapshot_type()) {
                                        ast_channel_lock(chan);
+                                       /* Force a new dialplan segment that will be unique to use so we can update it with the
+                                        * information we want. In the future when a channel snapshot is published this will
+                                        * occur again and unset this flag.
+                                        */
+                                       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN);
                                        snapshot = ast_channel_snapshot_create(chan);
                                        ast_channel_unlock(chan);
                                }
@@ -351,8 +356,8 @@ static int realtime_exec(struct ast_channel *chan, const char *context, const ch
                                        /* pbx_exec sets application name and data, but we don't want to log
                                         * every exec. Just update the snapshot here instead.
                                         */
-                                       ast_string_field_set(snapshot, appl, app);
-                                       ast_string_field_set(snapshot, data, !ast_strlen_zero(appdata) ? appdata : "(NULL)");
+                                       ast_string_field_set(snapshot->dialplan, appl, app);
+                                       ast_string_field_set(snapshot->dialplan, data, !ast_strlen_zero(appdata) ? appdata : "(NULL)");
                                        msg = stasis_message_create(ast_channel_snapshot_type(), snapshot);
                                        if (msg) {
                                                stasis_publish(ast_channel_topic(chan), msg);
index e5fa41c..3c0eeb7 100644 (file)
@@ -377,7 +377,7 @@ static int ari_bridges_play_helper(const char **args_media,
                return -1;
        }
 
-       language = S_OR(args_lang, snapshot->language);
+       language = S_OR(args_lang, snapshot->base->language);
 
        playback = stasis_app_control_play_uri(control, args_media, args_media_count,
                language, bridge->uniqueid, STASIS_PLAYBACK_TARGET_BRIDGE, args_skipms,
index f96192b..311358e 100644 (file)
@@ -170,8 +170,8 @@ void ast_ari_channels_continue_in_dialplan(
        }
 
        if (ast_strlen_zero(args->context)) {
-               context = snapshot->context;
-               exten = S_OR(args->extension, snapshot->exten);
+               context = snapshot->dialplan->context;
+               exten = S_OR(args->extension, snapshot->dialplan->exten);
        } else {
                context = args->context;
                exten = S_OR(args->extension, "s");
@@ -203,7 +203,7 @@ void ast_ari_channels_continue_in_dialplan(
                ipri = args->priority;
        } else if (ast_strlen_zero(args->context) && ast_strlen_zero(args->extension)) {
                /* Special case. No exten, context, or priority provided, then move on to the next priority */
-               ipri = snapshot->priority + 1;
+               ipri = snapshot->dialplan->priority + 1;
        } else {
                ipri = 1;
        }
@@ -263,10 +263,10 @@ void ast_ari_channels_redirect(struct ast_variable *headers,
                return;
        }
 
-       if (strncasecmp(chan_snapshot->type, tech, tech_len)) {
+       if (strncasecmp(chan_snapshot->base->type, tech, tech_len)) {
                ast_ari_response_error(response, 422, "Unprocessable Entity",
                        "Endpoint technology '%s' does not match channel technology '%s'",
-                       tech, chan_snapshot->type);
+                       tech, chan_snapshot->base->type);
                return;
        }
 
@@ -628,7 +628,7 @@ static void ari_channels_handle_play(
                return;
        }
 
-       language = S_OR(args_lang, snapshot->language);
+       language = S_OR(args_lang, snapshot->base->language);
 
        playback = stasis_app_control_play_uri(control, args_media, args_media_count, language,
                args_channel_id, STASIS_PLAYBACK_TARGET_CHANNEL, args_skipms, args_offsetms, args_playback_id);
index f9b3e85..46dbedf 100644 (file)
@@ -819,12 +819,12 @@ static void announce_to_dial(char *dial_string, char *announce_string, int parki
        snprintf(buf, sizeof(buf), "%d", parkingspace);
        oh.vars = ast_variable_new("_PARKEDAT", buf, "");
 
-       inherit_channel_vars_from_id(&oh, parkee_snapshot->uniqueid);
+       inherit_channel_vars_from_id(&oh, parkee_snapshot->base->uniqueid);
 
        dchan = __ast_request_and_dial(dial_tech, cap_slin, NULL, NULL, dial_string, 30000,
                &outstate,
-               parkee_snapshot->caller_number,
-               parkee_snapshot->caller_name,
+               parkee_snapshot->caller->number,
+               parkee_snapshot->caller->name,
                &oh);
 
        ast_variables_destroy(oh.vars);
@@ -877,7 +877,7 @@ static void park_announce_update_cb(void *data, struct stasis_subscription *sub,
                return;
        }
 
-       if (strcmp(payload->parkee->uniqueid, pa_data->parkee_uuid)) {
+       if (strcmp(payload->parkee->base->uniqueid, pa_data->parkee_uuid)) {
                /* We are only concerned with the parkee we are subscribed for. */
                return;
        }
index 1d3b9e4..d619471 100644 (file)
@@ -111,7 +111,7 @@ static void parker_parked_call_message_response(struct ast_parked_call_payload *
        RAII_VAR(struct ast_channel *, parker, NULL, ast_channel_cleanup);
        RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
 
-       if (strcmp(parkee_to_act_on, parkee_snapshot->uniqueid)) {
+       if (strcmp(parkee_to_act_on, parkee_snapshot->base->uniqueid)) {
                return;
        }
 
index bed95a0..e32498b 100644 (file)
@@ -110,7 +110,7 @@ static void updates(void *data, struct stasis_subscription *sub,
                int64_t age;
 
                age = ast_tvdiff_ms(*stasis_message_timestamp(message),
-                       update->new_snapshot->creationtime);
+                       update->new_snapshot->base->creationtime);
                ast_statsd_log("channels.calltime", AST_STATSD_TIMER, age);
 
                /* And decrement the channel count */
index 41195be..d88024a 100644 (file)
@@ -1351,7 +1351,7 @@ static int active_channels_to_str_cb(void *object, void *arg, int flags)
 {
        const struct ast_channel_snapshot *snapshot = object;
        struct ast_str **buf = arg;
-       ast_str_append(buf, 0, "%s,", snapshot->name);
+       ast_str_append(buf, 0, "%s,", snapshot->base->name);
        return 0;
 }
 
index 3dfaabc..9b75146 100644 (file)
@@ -179,7 +179,7 @@ static void refer_progress_bridge(void *data, struct stasis_subscription *sub,
        }
 
        enter_blob = stasis_message_data(message);
-       if (strcmp(enter_blob->channel->uniqueid, progress->transferee)) {
+       if (strcmp(enter_blob->channel->base->uniqueid, progress->transferee)) {
                /* Don't care */
                return;
        }
index 704d779..43833e1 100644 (file)
@@ -1019,7 +1019,7 @@ static int send_start_msg_snapshots(struct ast_channel *chan, struct stasis_app
        }
 
        if (replace_channel_snapshot) {
-               app_unsubscribe_channel_id(app, replace_channel_snapshot->uniqueid);
+               app_unsubscribe_channel_id(app, replace_channel_snapshot->base->uniqueid);
        }
        stasis_publish(ast_app_get_topic(app), msg);
        ao2_ref(msg, -1);
@@ -2051,7 +2051,7 @@ static int unload_module(void)
 /* \brief Sanitization callback for channel snapshots */
 static int channel_snapshot_sanitizer(const struct ast_channel_snapshot *snapshot)
 {
-       if (!snapshot || !(snapshot->tech_properties & AST_CHAN_TP_INTERNAL)) {
+       if (!snapshot || !(snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL)) {
                return 0;
        }
        return 1;
index b4f3bc6..78f5765 100644 (file)
@@ -315,7 +315,7 @@ static void call_forwarded_handler(struct stasis_app *app, struct stasis_message
                return;
        }
 
-       chan = ast_channel_get_by_name(snapshot->uniqueid);
+       chan = ast_channel_get_by_name(snapshot->base->uniqueid);
        if (!chan) {
                return;
        }
@@ -391,8 +391,8 @@ static struct ast_json *channel_destroyed_event(
        return ast_json_pack("{s: s, s: o, s: i, s: s, s: o}",
                "type", "ChannelDestroyed",
                "timestamp", ast_json_timeval(*tv, NULL),
-               "cause", snapshot->hangupcause,
-               "cause_txt", ast_cause2str(snapshot->hangupcause),
+               "cause", snapshot->hangup->cause,
+               "cause_txt", ast_cause2str(snapshot->hangup->cause),
                "channel", json_channel);
 }
 
@@ -436,7 +436,7 @@ static struct ast_json *channel_dialplan(
        }
 
        /* Empty application is not valid for a Newexten event */
-       if (ast_strlen_zero(new_snapshot->appl)) {
+       if (ast_strlen_zero(new_snapshot->dialplan->appl)) {
                return NULL;
        }
 
@@ -452,8 +452,8 @@ static struct ast_json *channel_dialplan(
        return ast_json_pack("{s: s, s: o, s: s, s: s, s: o}",
                "type", "ChannelDialplan",
                "timestamp", ast_json_timeval(*tv, NULL),
-               "dialplan_app", new_snapshot->appl,
-               "dialplan_app_data", AST_JSON_UTF8_VALIDATE(new_snapshot->data),
+               "dialplan_app", new_snapshot->dialplan->appl,
+               "dialplan_app_data", AST_JSON_UTF8_VALIDATE(new_snapshot->dialplan->data),
                "channel", json_channel);
 }
 
@@ -481,9 +481,9 @@ static struct ast_json *channel_callerid(
        return ast_json_pack("{s: s, s: o, s: i, s: s, s: o}",
                "type", "ChannelCallerId",
                "timestamp", ast_json_timeval(*tv, NULL),
-               "caller_presentation", new_snapshot->caller_pres,
+               "caller_presentation", new_snapshot->caller->pres,
                "caller_presentation_txt", ast_describe_caller_presentation(
-                       new_snapshot->caller_pres),
+                       new_snapshot->caller->pres),
                "channel", json_channel);
 }
 
@@ -541,7 +541,7 @@ static void sub_channel_update_handler(void *data,
        }
 
        if (ast_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {
-               unsubscribe(app, "channel", update->new_snapshot->uniqueid, 1);
+               unsubscribe(app, "channel", update->new_snapshot->base->uniqueid, 1);
        }
 }
 
@@ -768,7 +768,7 @@ static void bridge_blind_transfer_handler(void *data, struct stasis_subscription
        struct ast_blind_transfer_message *transfer_msg = stasis_message_data(message);
        struct ast_bridge_snapshot *bridge = transfer_msg->bridge;
 
-       if (bridge_app_subscribed(app, transfer_msg->transferer->uniqueid) ||
+       if (bridge_app_subscribed(app, transfer_msg->transferer->base->uniqueid) ||
                (bridge && bridge_app_subscribed_involved(app, bridge))) {
                stasis_publish(app->topic, message);
        }
@@ -781,9 +781,9 @@ static void bridge_attended_transfer_handler(void *data, struct stasis_subscript
        struct ast_attended_transfer_message *transfer_msg = stasis_message_data(message);
        int subscribed = 0;
 
-       subscribed = bridge_app_subscribed(app, transfer_msg->to_transferee.channel_snapshot->uniqueid);
+       subscribed = bridge_app_subscribed(app, transfer_msg->to_transferee.channel_snapshot->base->uniqueid);
        if (!subscribed) {
-               subscribed = bridge_app_subscribed(app, transfer_msg->to_transfer_target.channel_snapshot->uniqueid);
+               subscribed = bridge_app_subscribed(app, transfer_msg->to_transfer_target.channel_snapshot->base->uniqueid);
        }
        if (!subscribed && transfer_msg->to_transferee.bridge_snapshot) {
                subscribed = bridge_app_subscribed_involved(app, transfer_msg->to_transferee.bridge_snapshot);
@@ -798,16 +798,16 @@ static void bridge_attended_transfer_handler(void *data, struct stasis_subscript
                        subscribed = bridge_app_subscribed(app, transfer_msg->dest.bridge);
                        break;
                case AST_ATTENDED_TRANSFER_DEST_LINK:
-                       subscribed = bridge_app_subscribed(app, transfer_msg->dest.links[0]->uniqueid);
+                       subscribed = bridge_app_subscribed(app, transfer_msg->dest.links[0]->base->uniqueid);
                        if (!subscribed) {
-                               subscribed = bridge_app_subscribed(app, transfer_msg->dest.links[1]->uniqueid);
+                               subscribed = bridge_app_subscribed(app, transfer_msg->dest.links[1]->base->uniqueid);
                        }
                        break;
                break;
                case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
                        subscribed = bridge_app_subscribed_involved(app, transfer_msg->dest.threeway.bridge_snapshot);
                        if (!subscribed) {
-                               subscribed = bridge_app_subscribed(app, transfer_msg->dest.threeway.channel_snapshot->uniqueid);
+                               subscribed = bridge_app_subscribed(app, transfer_msg->dest.threeway.channel_snapshot->base->uniqueid);
                        }
                        break;
                default:
index c1e7340..6c8bd61 100644 (file)
@@ -329,7 +329,7 @@ static struct ast_str *__test_cel_generate_peer_str(struct ast_channel_snapshot
                        ao2_cleanup);
 
                /* Don't add the channel for which this message is being generated */
-               if (!strcmp(current_chan, chan->uniqueid)) {
+               if (!strcmp(current_chan, chan->base->uniqueid)) {
                        continue;
                }
 
@@ -338,7 +338,7 @@ static struct ast_str *__test_cel_generate_peer_str(struct ast_channel_snapshot
                        continue;
                }
 
-               ast_str_append(&peer_str, 0, "%s,", current_snapshot->name);
+               ast_str_append(&peer_str, 0, "%s,", current_snapshot->base->name);
        }
        ao2_iterator_destroy(&i);
 
@@ -1668,8 +1668,8 @@ AST_TEST_DEFINE(test_cel_local_optimize)
        stasis_publish(ast_channel_topic(chan_alice), local_opt_begin);
        stasis_publish(ast_channel_topic(chan_alice), local_opt_end);
 
-       extra = ast_json_pack("{s: s, s: s}", "local_two", bob_snapshot->name,
-               "local_two_uniqueid", bob_snapshot->uniqueid);
+       extra = ast_json_pack("{s: s, s: s}", "local_two", bob_snapshot->base->name,
+               "local_two_uniqueid", bob_snapshot->base->uniqueid);
        ast_test_validate(test, extra != NULL);
 
        APPEND_EVENT_SNAPSHOT(alice_snapshot, AST_CEL_LOCAL_OPTIMIZE, NULL, extra, NULL);
index f73d882..f8d2a03 100644 (file)
@@ -220,12 +220,12 @@ AST_TEST_DEFINE(multi_channel_blob_snapshots)
        /* Test for single match */
        snapshot = ast_multi_channel_blob_get_channel(blob, "Caller");
        ast_test_validate(test, NULL != snapshot);
-       ast_test_validate(test, 0 == strcmp("TEST/Alice", snapshot->name));
+       ast_test_validate(test, 0 == strcmp("TEST/Alice", snapshot->base->name));
 
        /* Test for single match, multiple possibilities */
        snapshot = ast_multi_channel_blob_get_channel(blob, "Peer");
        ast_test_validate(test, NULL != snapshot);
-       ast_test_validate(test, 0 != strcmp("TEST/Alice", snapshot->name));
+       ast_test_validate(test, 0 != strcmp("TEST/Alice", snapshot->base->name));
 
        /* Multi-match */
        matches = ast_multi_channel_blob_get_channels(blob, "Peer");