diff --git a/build_tools/cflags-devmode.xml b/build_tools/cflags-devmode.xml index cfcc26c207..0ed9f6780d 100644 --- a/build_tools/cflags-devmode.xml +++ b/build_tools/cflags-devmode.xml @@ -24,9 +24,6 @@ <member name="THREAD_CRASH" displayname="Crash on mutex errors"> <support_level>extended</support_level> </member> - <member name="CHANNEL_TRACE" displayname="Enable CHANNEL(trace) function"> - <support_level>extended</support_level> - </member> <member name="TEST_FRAMEWORK" displayname="Enable Test Framework API"> <support_level>extended</support_level> </member> diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index a5f5210046..bc8358d44d 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -1420,39 +1420,6 @@ void ast_channel_unregister(const struct ast_channel_tech *tech); */ const struct ast_channel_tech *ast_get_channel_tech(const char *name); -#ifdef CHANNEL_TRACE -/*! - * \brief Update the context backtrace if tracing is enabled - * \return Returns 0 on success, -1 on failure - */ -int ast_channel_trace_update(struct ast_channel *chan); - -/*! - * \brief Enable context tracing in the channel - * \return Returns 0 on success, -1 on failure - */ -int ast_channel_trace_enable(struct ast_channel *chan); - -/*! - * \brief Disable context tracing in the channel. - * \note Does not remove current trace entries - * \return Returns 0 on success, -1 on failure - */ -int ast_channel_trace_disable(struct ast_channel *chan); - -/*! - * \brief Whether or not context tracing is enabled - * \return Returns -1 when the trace is enabled. 0 if not. - */ -int ast_channel_trace_is_enabled(struct ast_channel *chan); - -/*! - * \brief Put the channel backtrace in a string - * \return Returns the amount of lines in the backtrace. -1 on error. - */ -int ast_channel_trace_serialize(struct ast_channel *chan, struct ast_str **out); -#endif - /*! * \brief Hang up a channel * \note Absolutely _NO_ channel locks should be held before calling this function. @@ -4228,6 +4195,18 @@ void ast_channel_set_manager_vars(size_t varc, char **vars); */ struct varshead *ast_channel_get_manager_vars(struct ast_channel *chan); +/*! + * \since 12 + * \brief Gets the variables for a given channel, as set using pbx_builtin_setvar_helper(). + * + * The returned variable list is an AO2 object, so ao2_cleanup() to free it. + * + * \param chan Channel to get variables for + * \return List of channel variables. + * \return \c NULL on error + */ +struct varshead *ast_channel_get_vars(struct ast_channel *chan); + /*! * \since 12 * \brief A topic which publishes the events for a particular channel. diff --git a/include/asterisk/stasis_channels.h b/include/asterisk/stasis_channels.h index e8fc48606a..d5c320119f 100644 --- a/include/asterisk/stasis_channels.h +++ b/include/asterisk/stasis_channels.h @@ -39,6 +39,7 @@ struct ast_channel_snapshot { AST_DECLARE_STRING_FIELDS( AST_STRING_FIELD(name); /*!< ASCII unique channel name */ + AST_STRING_FIELD(type); /*!< Type of channel technology */ 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 */ @@ -58,18 +59,31 @@ struct ast_channel_snapshot { 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(effective_name); /*!< Effective Connected Line Name */ + AST_STRING_FIELD(effective_number); /*!< Effective Connected Line Number */ AST_STRING_FIELD(language); /*!< The default spoken language for the channel */ + AST_STRING_FIELD(bridgeid); /*!< Unique Bridge Identifier */ + AST_STRING_FIELD(nativeformats); /*!< Native formats on the channel */ + AST_STRING_FIELD(readformat); /*!< The current read format */ + AST_STRING_FIELD(writeformat); /*!< The current write format */ + AST_STRING_FIELD(writetrans); /*!< The current write translation path */ + AST_STRING_FIELD(readtrans); /*!< The current read translation path */ ); + char callid[AST_CALLID_BUFFER_LENGTH]; /*!< Callid for the channel */ struct timeval creationtime; /*!< The time of channel creation */ + struct timeval hanguptime; /*!< When the channel should hang up */ 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 */ + ast_group_t callgroup; /*!< Call group */ + ast_group_t pickupgroup; /*!< Pickup group */ struct ast_flags softhangup_flags; /*!< softhangup channel flags */ struct varshead *manager_vars; /*!< Variables to be appended to manager events */ + struct varshead *channel_vars; /*!< Variables set on the channel */ }; /*! diff --git a/main/bridging.c b/main/bridging.c index e9f70911cb..38ec43195f 100644 --- a/main/bridging.c +++ b/main/bridging.c @@ -6885,38 +6885,29 @@ static int bridge_sort_cmp(const void *obj_left, const void *obj_right, int flag return cmp; } -struct bridge_complete { - /*! Nth match to return. */ - int state; - /*! Which match currently on. */ - int which; -}; - -static int complete_bridge_search(void *obj, void *arg, void *data, int flags) +static char *complete_bridge(const char *word, int state) { - struct bridge_complete *search = data; + char *ret = NULL; + int wordlen = strlen(word), which = 0; + RAII_VAR(struct ao2_container *, cached_bridges, NULL, ao2_cleanup); + struct ao2_iterator iter; + struct stasis_message *msg; - if (++search->which > search->state) { - return CMP_MATCH; + if (!(cached_bridges = stasis_cache_dump(ast_bridge_topic_all_cached(), ast_bridge_snapshot_type()))) { + return NULL; } - return 0; -} -static char *complete_bridge(const char *word, int state) -{ - char *ret; - struct ast_bridge *bridge; - struct bridge_complete search = { - .state = state, - }; + iter = ao2_iterator_init(cached_bridges, 0); + for (; (msg = ao2_iterator_next(&iter)); ao2_ref(msg, -1)) { + struct ast_bridge_snapshot *snapshot = stasis_message_data(msg); - bridge = ao2_callback_data(bridges, ast_strlen_zero(word) ? 0 : OBJ_PARTIAL_KEY, - complete_bridge_search, (char *) word, &search); - if (!bridge) { - return NULL; + if (!strncasecmp(word, snapshot->uniqueid, wordlen) && (++which > state)) { + ret = ast_strdup(snapshot->uniqueid); + break; + } } - ret = ast_strdup(bridge->uniqueid); - ao2_ref(bridge, -1); + ao2_iterator_destroy(&iter); + return ret; } @@ -6925,8 +6916,9 @@ static char *handle_bridge_show_all(struct ast_cli_entry *e, int cmd, struct ast #define FORMAT_HDR "%-36s %5s %-15s %s\n" #define FORMAT_ROW "%-36s %5u %-15s %s\n" + RAII_VAR(struct ao2_container *, cached_bridges, NULL, ao2_cleanup); struct ao2_iterator iter; - struct ast_bridge *bridge; + struct stasis_message *msg; switch (cmd) { case CLI_INIT: @@ -6939,17 +6931,22 @@ static char *handle_bridge_show_all(struct ast_cli_entry *e, int cmd, struct ast return NULL; } -/* BUGBUG this command may need to be changed to look at the stasis cache. */ + if (!(cached_bridges = stasis_cache_dump(ast_bridge_topic_all_cached(), ast_bridge_snapshot_type()))) { + ast_cli(a->fd, "Failed to retrieve cached bridges\n"); + return CLI_SUCCESS; + } + ast_cli(a->fd, FORMAT_HDR, "Bridge-ID", "Chans", "Type", "Technology"); - iter = ao2_iterator_init(bridges, 0); - for (; (bridge = ao2_iterator_next(&iter)); ao2_ref(bridge, -1)) { - ast_bridge_lock(bridge); + + iter = ao2_iterator_init(cached_bridges, 0); + for (; (msg = ao2_iterator_next(&iter)); ao2_ref(msg, -1)) { + struct ast_bridge_snapshot *snapshot = stasis_message_data(msg); + ast_cli(a->fd, FORMAT_ROW, - bridge->uniqueid, - bridge->num_channels, - bridge->v_table ? bridge->v_table->name : "<unknown>", - bridge->technology ? bridge->technology->name : "<unknown>"); - ast_bridge_unlock(bridge); + snapshot->uniqueid, + snapshot->num_channels, + S_OR(snapshot->subclass, "<unknown>"), + S_OR(snapshot->technology, "<unknown>")); } ao2_iterator_destroy(&iter); return CLI_SUCCESS; @@ -6958,10 +6955,28 @@ static char *handle_bridge_show_all(struct ast_cli_entry *e, int cmd, struct ast #undef FORMAT_ROW } +/*! \brief Internal callback function for sending channels in a bridge to the CLI */ +static int bridge_show_specific_print_channel(void *obj, void *arg, int flags) +{ + const char *uniqueid = obj; + struct ast_cli_args *a = arg; + RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); + struct ast_channel_snapshot *snapshot; + + if (!(msg = stasis_cache_get(ast_channel_topic_all_cached(), ast_channel_snapshot_type(), uniqueid))) { + return 0; + } + snapshot = stasis_message_data(msg); + + ast_cli(a->fd, "Channel: %s\n", snapshot->name); + + return 0; +} + static char *handle_bridge_show_specific(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - struct ast_bridge *bridge; - struct ast_bridge_channel *bridge_channel; + RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); + struct ast_bridge_snapshot *snapshot; switch (cmd) { case CLI_INIT: @@ -6977,28 +6992,22 @@ static char *handle_bridge_show_specific(struct ast_cli_entry *e, int cmd, struc return NULL; } -/* BUGBUG this command may need to be changed to look at the stasis cache. */ if (a->argc != 3) { return CLI_SHOWUSAGE; } - bridge = ao2_find(bridges, a->argv[2], OBJ_KEY); - if (!bridge) { + msg = stasis_cache_get(ast_bridge_topic_all_cached(), ast_bridge_snapshot_type(), a->argv[2]); + if (!msg) { ast_cli(a->fd, "Bridge '%s' not found\n", a->argv[2]); return CLI_SUCCESS; } - ast_bridge_lock(bridge); - ast_cli(a->fd, "Id: %s\n", bridge->uniqueid); - ast_cli(a->fd, "Type: %s\n", bridge->v_table ? bridge->v_table->name : "<unknown>"); - ast_cli(a->fd, "Technology: %s\n", - bridge->technology ? bridge->technology->name : "<unknown>"); - ast_cli(a->fd, "Num-Channels: %u\n", bridge->num_channels); - AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) { - ast_cli(a->fd, "Channel: %s\n", ast_channel_name(bridge_channel->chan)); - } - ast_bridge_unlock(bridge); - ao2_ref(bridge, -1); + snapshot = stasis_message_data(msg); + ast_cli(a->fd, "Id: %s\n", snapshot->uniqueid); + ast_cli(a->fd, "Type: %s\n", S_OR(snapshot->subclass, "<unknown>")); + ast_cli(a->fd, "Technology: %s\n", S_OR(snapshot->technology, "<unknown>")); + ast_cli(a->fd, "Num-Channels: %u\n", snapshot->num_channels); + ao2_callback(snapshot->channels, OBJ_NODATA, bridge_show_specific_print_channel, a); return CLI_SUCCESS; } diff --git a/main/channel.c b/main/channel.c index 8ff9bf2132..2d73bf1128 100644 --- a/main/channel.c +++ b/main/channel.c @@ -127,22 +127,6 @@ struct chanlist { AST_LIST_ENTRY(chanlist) list; }; -#ifdef CHANNEL_TRACE -/*! \brief Structure to hold channel context backtrace data */ -struct ast_chan_trace_data { - int enabled; - AST_LIST_HEAD_NOLOCK(, ast_chan_trace) trace; -}; - -/*! \brief Structure to save contexts where an ast_chan has been into */ -struct ast_chan_trace { - char context[AST_MAX_CONTEXT]; - char exten[AST_MAX_EXTENSION]; - int priority; - AST_LIST_ENTRY(ast_chan_trace) entry; -}; -#endif - /*! \brief the list of registered channel types */ static AST_RWLIST_HEAD_STATIC(backends, chanlist); @@ -472,132 +456,6 @@ const struct ast_channel_tech ast_kill_tech = { .hangup = kill_hangup, }; -#ifdef CHANNEL_TRACE -/*! \brief Destructor for the channel trace datastore */ -static void ast_chan_trace_destroy_cb(void *data) -{ - struct ast_chan_trace *trace; - struct ast_chan_trace_data *traced = data; - while ((trace = AST_LIST_REMOVE_HEAD(&traced->trace, entry))) { - ast_free(trace); - } - ast_free(traced); -} - -/*! \brief Datastore to put the linked list of ast_chan_trace and trace status */ -static const struct ast_datastore_info ast_chan_trace_datastore_info = { - .type = "ChanTrace", - .destroy = ast_chan_trace_destroy_cb -}; - -/*! \brief Put the channel backtrace in a string */ -int ast_channel_trace_serialize(struct ast_channel *chan, struct ast_str **buf) -{ - int total = 0; - struct ast_chan_trace *trace; - struct ast_chan_trace_data *traced; - struct ast_datastore *store; - - ast_channel_lock(chan); - store = ast_channel_datastore_find(chan, &ast_chan_trace_datastore_info, NULL); - if (!store) { - ast_channel_unlock(chan); - return total; - } - traced = store->data; - ast_str_reset(*buf); - AST_LIST_TRAVERSE(&traced->trace, trace, entry) { - if (ast_str_append(buf, 0, "[%d] => %s, %s, %d\n", total, trace->context, trace->exten, trace->priority) < 0) { - ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n"); - total = -1; - break; - } - total++; - } - ast_channel_unlock(chan); - return total; -} - -/* !\brief Whether or not context tracing is enabled */ -int ast_channel_trace_is_enabled(struct ast_channel *chan) -{ - struct ast_datastore *store = ast_channel_datastore_find(chan, &ast_chan_trace_datastore_info, NULL); - if (!store) - return 0; - return ((struct ast_chan_trace_data *)store->data)->enabled; -} - -/*! \brief Update the context backtrace data if tracing is enabled */ -static int ast_channel_trace_data_update(struct ast_channel *chan, struct ast_chan_trace_data *traced) -{ - struct ast_chan_trace *trace; - if (!traced->enabled) - return 0; - /* If the last saved context does not match the current one - OR we have not saved any context so far, then save the current context */ - if ((!AST_LIST_EMPTY(&traced->trace) && strcasecmp(AST_LIST_FIRST(&traced->trace)->context, ast_channel_context(chan))) || - (AST_LIST_EMPTY(&traced->trace))) { - /* Just do some debug logging */ - if (AST_LIST_EMPTY(&traced->trace)) - ast_debug(1, "Setting initial trace context to %s\n", ast_channel_context(chan)); - else - ast_debug(1, "Changing trace context from %s to %s\n", AST_LIST_FIRST(&traced->trace)->context, ast_channel_context(chan)); - /* alloc or bail out */ - trace = ast_malloc(sizeof(*trace)); - if (!trace) - return -1; - /* save the current location and store it in the trace list */ - ast_copy_string(trace->context, ast_channel_context(chan), sizeof(trace->context)); - ast_copy_string(trace->exten, ast_channel_exten(chan), sizeof(trace->exten)); - trace->priority = ast_channel_priority(chan); - AST_LIST_INSERT_HEAD(&traced->trace, trace, entry); - } - return 0; -} - -/*! \brief Update the context backtrace if tracing is enabled */ -int ast_channel_trace_update(struct ast_channel *chan) -{ - struct ast_datastore *store = ast_channel_datastore_find(chan, &ast_chan_trace_datastore_info, NULL); - if (!store) - return 0; - return ast_channel_trace_data_update(chan, store->data); -} - -/*! \brief Enable context tracing in the channel */ -int ast_channel_trace_enable(struct ast_channel *chan) -{ - struct ast_datastore *store = ast_channel_datastore_find(chan, &ast_chan_trace_datastore_info, NULL); - struct ast_chan_trace_data *traced; - if (!store) { - store = ast_datastore_alloc(&ast_chan_trace_datastore_info, "ChanTrace"); - if (!store) - return -1; - traced = ast_calloc(1, sizeof(*traced)); - if (!traced) { - ast_datastore_free(store); - return -1; - } - store->data = traced; - AST_LIST_HEAD_INIT_NOLOCK(&traced->trace); - ast_channel_datastore_add(chan, store); - } - ((struct ast_chan_trace_data *)store->data)->enabled = 1; - ast_channel_trace_data_update(chan, store->data); - return 0; -} - -/*! \brief Disable context tracing in the channel */ -int ast_channel_trace_disable(struct ast_channel *chan) -{ - struct ast_datastore *store = ast_channel_datastore_find(chan, &ast_chan_trace_datastore_info, NULL); - if (!store) - return 0; - ((struct ast_chan_trace_data *)store->data)->enabled = 0; - return 0; -} -#endif /* CHANNEL_TRACE */ - /*! \brief Checks to see if a channel is needing hang up */ int ast_check_hangup(struct ast_channel *chan) { @@ -5357,6 +5215,9 @@ static int set_format(struct ast_channel *chan, if (direction && ast_channel_generatordata(chan)) { generator_write_format_change(chan); } + + ast_channel_publish_snapshot(chan); + return 0; } @@ -5429,6 +5290,9 @@ static int set_format(struct ast_channel *chan, if (direction && ast_channel_generatordata(chan)) { generator_write_format_change(chan); } + + ast_channel_publish_snapshot(chan); + return res; } @@ -7782,7 +7646,7 @@ void ast_channel_set_manager_vars(size_t varc, char **vars) } /*! - * \brief Destructor for the return value from ast_channel_get_manager_vars(). + * \brief Destructor for lists of variables. * \param obj AO2 object. */ static void varshead_dtor(void *obj) @@ -7795,6 +7659,31 @@ static void varshead_dtor(void *obj) } } +struct varshead *ast_channel_get_vars(struct ast_channel *chan) +{ + RAII_VAR(struct varshead *, ret, NULL, ao2_cleanup); + struct ast_var_t *cv; + + ret = ao2_alloc(sizeof(*ret), varshead_dtor); + + if (!ret) { + return NULL; + } + + AST_LIST_TRAVERSE(ast_channel_varshead(chan), cv, entries) { + struct ast_var_t *var = ast_var_assign(ast_var_name(cv), ast_var_value(cv)); + + if (!var) { + return NULL; + } + + AST_LIST_INSERT_TAIL(ret, var, entries); + } + + ao2_ref(ret, +1); + return ret; +} + struct varshead *ast_channel_get_manager_vars(struct ast_channel *chan) { RAII_VAR(struct varshead *, ret, NULL, ao2_cleanup); diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index 085052a715..bb63eebe10 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -868,6 +868,7 @@ const struct ast_channel_tech *ast_channel_tech(const struct ast_channel *chan) void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tech *value) { chan->tech = value; + ast_channel_publish_snapshot(chan); } enum ast_channel_adsicpe ast_channel_adsicpe(const struct ast_channel *chan) { @@ -913,6 +914,7 @@ void ast_channel_callid_set(struct ast_channel *chan, struct ast_callid *callid) call_identifier_to, call_identifier_from); + ast_channel_publish_snapshot(chan); } void ast_channel_state_set(struct ast_channel *chan, enum ast_channel_state value) { @@ -1037,6 +1039,7 @@ void ast_channel_dtmf_tv_set(struct ast_channel *chan, struct timeval *value) void ast_channel_whentohangup_set(struct ast_channel *chan, struct timeval *value) { chan->whentohangup = *value; + ast_channel_publish_snapshot(chan); } void ast_channel_varshead_set(struct ast_channel *chan, struct varshead *value) { @@ -1094,6 +1097,7 @@ ast_group_t ast_channel_callgroup(const struct ast_channel *chan) void ast_channel_callgroup_set(struct ast_channel *chan, ast_group_t value) { chan->callgroup = value; + ast_channel_publish_snapshot(chan); } ast_group_t ast_channel_pickupgroup(const struct ast_channel *chan) { @@ -1102,6 +1106,7 @@ ast_group_t ast_channel_pickupgroup(const struct ast_channel *chan) void ast_channel_pickupgroup_set(struct ast_channel *chan, ast_group_t value) { chan->pickupgroup = value; + ast_channel_publish_snapshot(chan); } struct ast_namedgroups *ast_channel_named_callgroups(const struct ast_channel *chan) { @@ -1277,6 +1282,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_publish_snapshot(chan); } struct ast_bridge_channel *ast_channel_internal_bridge_channel(const struct ast_channel *chan) diff --git a/main/cli.c b/main/cli.c index 3431d1de82..34951711fb 100644 --- a/main/cli.c +++ b/main/cli.c @@ -61,6 +61,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/threadstorage.h" #include "asterisk/translate.h" #include "asterisk/bridging.h" +#include "asterisk/stasis_channels.h" +#include "asterisk/stasis_bridging.h" /*! * \brief List of restrictions per user. @@ -877,9 +879,10 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar #define VERBOSE_FORMAT_STRING "%-20.20s %-20.20s %-16.16s %4d %-7.7s %-12.12s %-25.25s %-15.15s %8.8s %-11.11s %-11.11s %-20.20s\n" #define VERBOSE_FORMAT_STRING2 "%-20.20s %-20.20s %-16.16s %-4.4s %-7.7s %-12.12s %-25.25s %-15.15s %8.8s %-11.11s %-11.11s %-20.20s\n" - struct ast_channel *c = NULL; + RAII_VAR(struct ao2_container *, channels, NULL, ao2_cleanup); + struct ao2_iterator it_chans; + struct stasis_message *msg; int numchans = 0, concise = 0, verbose = 0, count = 0; - struct ast_channel_iterator *iter = NULL; switch (cmd) { case CLI_INIT: @@ -911,6 +914,12 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar } else if (a->argc != e->args - 1) return CLI_SHOWUSAGE; + + if (!(channels = stasis_cache_dump(ast_channel_topic_all_cached_by_name(), ast_channel_snapshot_type()))) { + ast_cli(a->fd, "Failed to retrieve cached channels\n"); + return CLI_SUCCESS; + } + if (!count) { if (!concise && !verbose) ast_cli(a->fd, FORMAT_STRING2, "Channel", "Location", "State", "Application(Data)"); @@ -919,21 +928,14 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar "CallerID", "Duration", "Accountcode", "PeerAccount", "BridgeID"); } - if (!count && !(iter = ast_channel_iterator_all_new())) { - return CLI_FAILURE; - } - - for (; iter && (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) { - struct ast_bridge *bridge; + it_chans = ao2_iterator_init(channels, 0); + for (; (msg = ao2_iterator_next(&it_chans)); ao2_ref(msg, -1)) { + struct ast_channel_snapshot *cs = stasis_message_data(msg); char durbuf[10] = "-"; - ast_channel_lock(c); - - bridge = ast_channel_get_bridge(c); - if (!count) { - if ((concise || verbose) && !ast_tvzero(ast_channel_creationtime(c))) { - int duration = (int)(ast_tvdiff_ms(ast_tvnow(), ast_channel_creationtime(c)) / 1000); + if ((concise || verbose) && !ast_tvzero(cs->creationtime)) { + int duration = (int)(ast_tvdiff_ms(ast_tvnow(), cs->creationtime) / 1000); if (verbose) { int durh = duration / 3600; int durm = (duration % 3600) / 60; @@ -944,43 +946,38 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar } } if (concise) { - ast_cli(a->fd, CONCISE_FORMAT_STRING, ast_channel_name(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_state2str(ast_channel_state(c)), - ast_channel_appl(c) ? ast_channel_appl(c) : "(None)", - S_OR(ast_channel_data(c), ""), /* XXX different from verbose ? */ - S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, ""), - S_OR(ast_channel_accountcode(c), ""), - S_OR(ast_channel_peeraccount(c), ""), - ast_channel_amaflags(c), + 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, + cs->amaflags, durbuf, - bridge ? bridge->uniqueid : "(Not bridged)", - ast_channel_uniqueid(c)); + cs->bridgeid, + cs->uniqueid); } else if (verbose) { - ast_cli(a->fd, VERBOSE_FORMAT_STRING, ast_channel_name(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_state2str(ast_channel_state(c)), - ast_channel_appl(c) ? ast_channel_appl(c) : "(None)", - ast_channel_data(c) ? S_OR(ast_channel_data(c), "(Empty)" ): "(None)", - S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, ""), + 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, durbuf, - S_OR(ast_channel_accountcode(c), ""), - S_OR(ast_channel_peeraccount(c), ""), - bridge ? bridge->uniqueid : "(Not bridged)"); + cs->accountcode, + cs->peeraccount, + cs->bridgeid); } else { char locbuf[40] = "(None)"; char appdata[40] = "(None)"; - if (!ast_strlen_zero(ast_channel_context(c)) && !ast_strlen_zero(ast_channel_exten(c))) - snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", ast_channel_exten(c), ast_channel_context(c), ast_channel_priority(c)); - if (ast_channel_appl(c)) - snprintf(appdata, sizeof(appdata), "%s(%s)", ast_channel_appl(c), S_OR(ast_channel_data(c), "")); - ast_cli(a->fd, FORMAT_STRING, ast_channel_name(c), locbuf, ast_state2str(ast_channel_state(c)), appdata); + if (!cs->context && !cs->exten) + snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", cs->exten, cs->context, cs->priority); + if (cs->appl) + snprintf(appdata, sizeof(appdata), "%s(%s)", cs->appl, S_OR(cs->data, "")); + ast_cli(a->fd, FORMAT_STRING, cs->name, locbuf, ast_state2str(cs->state), appdata); } } - ast_channel_unlock(c); - ao2_cleanup(bridge); - } - - if (iter) { - ast_channel_iterator_destroy(iter); } + ao2_iterator_destroy(&it_chans); if (!concise) { numchans = ast_active_channels(); @@ -1414,23 +1411,15 @@ static char *handle_nodebugchan_deprecated(struct ast_cli_entry *e, int cmd, str static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - struct ast_channel *c=NULL; + RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); + struct ast_channel_snapshot *snapshot; struct timeval now; char cdrtime[256]; - char nf[256]; - struct ast_str *write_transpath = ast_str_alloca(256); - struct ast_str *read_transpath = ast_str_alloca(256); - struct ast_str *obuf;/*!< Buffer for variable, CDR variable, and trace output. */ + struct ast_str *obuf;/*!< Buffer for CDR variables. */ struct ast_str *output;/*!< Accumulation buffer for all output. */ long elapsed_seconds=0; int hour=0, min=0, sec=0; - struct ast_callid *callid; - char call_identifier_str[AST_CALLID_BUFFER_LENGTH] = ""; - struct ast_party_id effective_connected_id; -#ifdef CHANNEL_TRACE - int trace_enabled; -#endif - struct ast_bridge *bridge; + struct ast_var_t *var; switch (cmd) { case CLI_INIT: @@ -1449,10 +1438,11 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar now = ast_tvnow(); - if (!(c = ast_channel_get_by_name(a->argv[3]))) { + if (!(msg = stasis_cache_get(ast_channel_topic_all_cached_by_name(), ast_channel_snapshot_type(), a->argv[3]))) { ast_cli(a->fd, "%s is not a known channel\n", a->argv[3]); return CLI_SUCCESS; } + snapshot = stasis_message_data(msg); obuf = ast_str_thread_get(&ast_str_thread_global_buf, 16); if (!obuf) { @@ -1463,10 +1453,8 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar return CLI_FAILURE; } - ast_channel_lock(c); - - if (!ast_tvzero(ast_channel_creationtime(c))) { - elapsed_seconds = now.tv_sec - ast_channel_creationtime(c).tv_sec; + if (!ast_tvzero(snapshot->creationtime)) { + elapsed_seconds = now.tv_sec - snapshot->creationtime.tv_sec; hour = elapsed_seconds / 3600; min = (elapsed_seconds % 3600) / 60; sec = elapsed_seconds % 60; @@ -1475,15 +1463,6 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar strcpy(cdrtime, "N/A"); } - /* Construct the call identifier string based on the status of the channel's call identifier */ - if ((callid = ast_channel_callid(c))) { - ast_callid_strnprint(call_identifier_str, sizeof(call_identifier_str), callid); - ast_callid_unref(callid); - } - - effective_connected_id = ast_channel_connected_effective_id(c); - bridge = ast_channel_get_bridge(c); - ast_str_append(&output, 0, " -- General --\n" " Name: %s\n" @@ -1499,15 +1478,11 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar " DNID Digits: %s\n" " Language: %s\n" " State: %s (%d)\n" - " Rings: %d\n" " NativeFormats: %s\n" " WriteFormat: %s\n" " ReadFormat: %s\n" " WriteTranscode: %s %s\n" " ReadTranscode: %s %s\n" - "1st File Descriptor: %d\n" - " Frames in: %d%s\n" - " Frames out: %d%s\n" " Time to Hangup: %ld\n" " Elapsed Time: %s\n" " Bridge ID: %s\n" @@ -1519,68 +1494,49 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar " Pickup Group: %llu\n" " Application: %s\n" " Data: %s\n" - " Blocking in: %s\n" " Call Identifer: %s\n", - ast_channel_name(c), - ast_channel_tech(c)->type, - ast_channel_uniqueid(c), - ast_channel_linkedid(c), - S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, "(N/A)"), - S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, "(N/A)"), - S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, "(N/A)"), - S_COR(ast_channel_connected(c)->id.name.valid, ast_channel_connected(c)->id.name.str, "(N/A)"), - S_COR(effective_connected_id.number.valid, effective_connected_id.number.str, "(N/A)"), - S_COR(effective_connected_id.name.valid, effective_connected_id.name.str, "(N/A)"), - S_OR(ast_channel_dialed(c)->number.str, "(N/A)"), - ast_channel_language(c), - ast_state2str(ast_channel_state(c)), - ast_channel_state(c), - ast_channel_rings(c), - ast_getformatname_multiple(nf, sizeof(nf), ast_channel_nativeformats(c)), - ast_getformatname(ast_channel_writeformat(c)), - ast_getformatname(ast_channel_readformat(c)), - ast_channel_writetrans(c) ? "Yes" : "No", - ast_translate_path_to_str(ast_channel_writetrans(c), &write_transpath), - ast_channel_readtrans(c) ? "Yes" : "No", - ast_translate_path_to_str(ast_channel_readtrans(c), &read_transpath), - ast_channel_fd(c, 0), - ast_channel_fin(c) & ~DEBUGCHAN_FLAG, - (ast_channel_fin(c) & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "", - ast_channel_fout(c) & ~DEBUGCHAN_FLAG, - (ast_channel_fout(c) & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "", - (long) ast_channel_whentohangup(c)->tv_sec, + snapshot->name, + snapshot->type, + snapshot->uniqueid, + snapshot->linkedid, + S_OR(snapshot->caller_number, "(N/A)"), + S_OR(snapshot->caller_name, "(N/A)"), + S_OR(snapshot->connected_number, "(N/A)"), + S_OR(snapshot->connected_name, "(N/A)"), + S_OR(snapshot->effective_number, "(N/A)"), + S_OR(snapshot->effective_name, "(N/A)"), + S_OR(snapshot->caller_dnid, "(N/A)"), + snapshot->language, + ast_state2str(snapshot->state), + snapshot->state, + snapshot->nativeformats, + snapshot->writeformat, + snapshot->readformat, + !ast_strlen_zero(snapshot->writetrans) ? "Yes" : "No", + snapshot->writetrans, + !ast_strlen_zero(snapshot->readtrans) ? "Yes" : "No", + snapshot->readtrans, + (long) snapshot->hanguptime.tv_sec, cdrtime, - bridge ? bridge->uniqueid : "(Not bridged)", - ast_channel_context(c), - ast_channel_exten(c), - ast_channel_priority(c), - ast_channel_callgroup(c), - ast_channel_pickupgroup(c), - (ast_channel_appl(c) ? ast_channel_appl(c) : "(N/A)" ), - (ast_channel_data(c) ? S_OR(ast_channel_data(c), "(Empty)") : "(None)"), - (ast_test_flag(ast_channel_flags(c), AST_FLAG_BLOCKING) ? ast_channel_blockproc(c) : "(Not Blocking)"), - S_OR(call_identifier_str, "(None)")); - - if (pbx_builtin_serialize_variables(c, &obuf)) { - ast_str_append(&output, 0, " Variables:\n%s\n", ast_str_buffer(obuf)); - } - - if (ast_cdr_serialize_variables(ast_channel_name(c), &obuf, '=', '\n')) { - ast_str_append(&output, 0, " CDR Variables:\n%s\n", ast_str_buffer(obuf)); - } + S_OR(snapshot->bridgeid, "(Not bridged)"), + snapshot->context, + snapshot->exten, + snapshot->priority, + snapshot->callgroup, + snapshot->pickupgroup, + S_OR(snapshot->appl, "(N/A)"), + S_OR(snapshot->data, "(Empty)"), + S_OR(snapshot->callid, "(None)")); + + ast_str_append(&output, 0, " Variables:\n"); -#ifdef CHANNEL_TRACE - trace_enabled = ast_channel_trace_is_enabled(c); - ast_str_append(&output, 0, " Context Trace: %s\n", - trace_enabled ? "Enabled" : "Disabled"); - if (trace_enabled && ast_channel_trace_serialize(c, &obuf)) { - ast_str_append(&output, 0, " Trace:\n%s\n", ast_str_buffer(obuf)); + AST_LIST_TRAVERSE(snapshot->channel_vars, var, entries) { + ast_str_append(&output, 0, "%s=%s\n", ast_var_name(var), ast_var_value(var)); } -#endif - ast_channel_unlock(c); - c = ast_channel_unref(c); - ao2_cleanup(bridge); + if (ast_cdr_serialize_variables(snapshot->name, &obuf, '=', '\n')) { + ast_str_append(&output, 0, " CDR Variables:\n%s\n", ast_str_buffer(obuf)); + } ast_cli(a->fd, "%s", ast_str_buffer(output)); ast_free(output); @@ -1605,38 +1561,32 @@ char *ast_cli_complete(const char *word, const char * const choices[], int state char *ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos) { - struct ast_channel *c = NULL; - int which = 0; - char notfound = '\0'; - char *ret = ¬found; /* so NULL can break the loop */ - struct ast_channel_iterator *iter; + int wordlen = strlen(word), which = 0; + RAII_VAR(struct ao2_container *, cached_channels, NULL, ao2_cleanup); + char *ret = NULL; + struct ao2_iterator iter; + struct stasis_message *msg; if (pos != rpos) { return NULL; } - if (ast_strlen_zero(word)) { - iter = ast_channel_iterator_all_new(); - } else { - iter = ast_channel_iterator_by_name_new(word, strlen(word)); - } - - if (!iter) { + if (!(cached_channels = stasis_cache_dump(ast_channel_topic_all_cached(), ast_channel_snapshot_type()))) { return NULL; } - while (ret == ¬found && (c = ast_channel_iterator_next(iter))) { - if (++which > state) { - ast_channel_lock(c); - ret = ast_strdup(ast_channel_name(c)); - ast_channel_unlock(c); + iter = ao2_iterator_init(cached_channels, 0); + for (; (msg = ao2_iterator_next(&iter)); ao2_ref(msg, -1)) { + struct ast_channel_snapshot *snapshot = stasis_message_data(msg); + + if (!strncasecmp(word, snapshot->name, wordlen) && (++which > state)) { + ret = ast_strdup(snapshot->name); + break; } - ast_channel_unref(c); } + ao2_iterator_destroy(&iter); - ast_channel_iterator_destroy(iter); - - return ret == ¬found ? NULL : ret; + return ret; } static char *group_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) @@ -2037,7 +1987,7 @@ static char *is_prefix(const char *word, const char *token, * \param cmds * \param match_type has 3 possible values: * 0 returns if the search key is equal or longer than the entry. - * note that trailing optional arguments are skipped. + * note that trailing optional arguments are skipped. * -1 true if the mismatch is on the last word XXX not true! * 1 true only on complete, exact match. * diff --git a/main/manager.c b/main/manager.c index b8b067dea6..d5efc47565 100644 --- a/main/manager.c +++ b/main/manager.c @@ -92,8 +92,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/strings.h" #include "asterisk/stringfields.h" #include "asterisk/presencestate.h" -#include "asterisk/stasis.h" #include "asterisk/stasis_message_router.h" +#include "asterisk/stasis_channels.h" +#include "asterisk/stasis_bridging.h" #include "asterisk/test.h" #include "asterisk/json.h" #include "asterisk/bridging.h" @@ -221,6 +222,106 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") value for the specified channel variables.</para> </description> </manager> + <managerEvent language="en_US" name="Status"> + <managerEventInstance class="EVENT_FLAG_CALL"> + <synopsis>Raised in response to a Status command.</synopsis> + <syntax> + <parameter name="ActionID" required="false"/> + <parameter name="Channel"> + <para>Name of the channel</para> + </parameter> + <parameter name="Type"> + <para>Type of channel</para> + </parameter> + <parameter name="DNID"> + <para>Dialed number identifier</para> + </parameter> + <parameter name="ChannelState"> + <para>A numeric code for the channel's current state, related to ChannelStateDesc</para> + </parameter> + <parameter name="ChannelStateDesc"> + <para>Name for the channel's current state</para> + <enumlist> + <enum name="Down"/> + <enum name="Rsrvd"/> + <enum name="OffHook"/> + <enum name="Dialing"/> + <enum name="Ring"/> + <enum name="Ringing"/> + <enum name="Up"/> + <enum name="Busy"/> + <enum name="Dialing Offhook"/> + <enum name="Pre-ring"/> + <enum name="Unknown"/> + </enumlist> + </parameter> + <parameter name="CallerIDNum"> + </parameter> + <parameter name="CallerIDName"> + </parameter> + <parameter name="ConnectedLineNum"> + </parameter> + <parameter name="ConnectedLineName"> + </parameter> + <parameter name="EffectiveConnectedLineNum"> + </parameter> + <parameter name="EffectiveConnectedLineName"> + </parameter> + <parameter name="AccountCode"> + </parameter> + <parameter name="Context"> + </parameter> + <parameter name="Exten"> + </parameter> + <parameter name="Priority"> + </parameter> + <parameter name="Uniqueid"> + <para>Unique identifier for the channel</para> + </parameter> + <parameter name="TimeToHangup"> + <para>Absolute lifetime of the channel</para> + </parameter> + <parameter name="BridgeID"> + <para>Identifier of the bridge the channel is in, may be empty if not in one</para> + </parameter> + <parameter name="Linkedid"> + </parameter> + <parameter name="Application"> + <para>Application currently executing on the channel</para> + </parameter> + <parameter name="Data"> + <para>Data given to the currently executing channel</para> + </parameter> + <parameter name="Nativeformats"> + <para>Media formats the connected party is willing to send or receive</para> + </parameter> + <parameter name="Readformat"> + <para>Media formats that frames from the channel are received in</para> + </parameter> + <parameter name="Readtrans"> + <para>Translation path for media received in native formats</para> + </parameter> + <parameter name="Writeformat"> + <para>Media formats that frames to the channel are accepted in</para> + </parameter> + <parameter name="Writetrans"> + <para>Translation path for media sent to the connected party</para> + </parameter> + <parameter name="Callgroup"> + <para>Configured call group on the channel</para> + </parameter> + <parameter name="Pickupgroup"> + <para>Configured pickup group on the channel</para> + </parameter> + <parameter name="Seconds"> + <para>Number of seconds the channel has been active</para> + </parameter> + </syntax> + <see-also> + <ref type="manager">Status</ref> + </see-also> + </managerEventInstance> + </managerEvent> <manager name="Setvar" language="en_US"> <synopsis> Set a channel variable. @@ -3745,11 +3846,8 @@ static int action_status(struct mansession *s, const struct message *m) const char *name = astman_get_header(m, "Channel"); const char *cvariables = astman_get_header(m, "Variables"); char *variables = ast_strdupa(S_OR(cvariables, "")); - struct ast_channel *c; - struct ast_bridge *bridge; - char bridge_text[256]; - struct timeval now = ast_tvnow(); - long elapsed_seconds = 0; + RAII_VAR(struct ao2_container *, cached_channels, NULL, ao2_cleanup); + struct stasis_message *msg; int channels = 0; int all = ast_strlen_zero(name); /* set if we want all channels */ const char *id = astman_get_header(m, "ActionID"); @@ -3758,7 +3856,8 @@ static int action_status(struct mansession *s, const struct message *m) AST_APP_ARG(name)[100]; ); struct ast_str *str = ast_str_create(1000); - struct ast_channel_iterator *iter = NULL; + struct ao2_iterator it_chans; + struct timeval now = ast_tvnow(); if (!ast_strlen_zero(id)) { snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); @@ -3772,14 +3871,15 @@ static int action_status(struct mansession *s, const struct message *m) } if (all) { - if (!(iter = ast_channel_iterator_all_new())) { + if (!(cached_channels = stasis_cache_dump(ast_channel_topic_all_cached_by_name(), ast_channel_snapshot_type()))) { ast_free(str); astman_send_error(s, m, "Memory Allocation Failure"); return 1; } - c = ast_channel_iterator_next(iter); + it_chans = ao2_iterator_init(cached_channels, 0); + msg = ao2_iterator_next(&it_chans); } else { - if (!(c = ast_channel_get_by_name(name))) { + if (!(msg = stasis_cache_get(ast_channel_topic_all_cached_by_name(), ast_channel_snapshot_type(), name))) { astman_send_error(s, m, "No such channel"); ast_free(str); return 0; @@ -3793,10 +3893,17 @@ static int action_status(struct mansession *s, const struct message *m) } /* if we look by name, we break after the first iteration */ - for (; c; c = ast_channel_iterator_next(iter)) { - ast_channel_lock(c); + for (; msg; ao2_ref(msg, -1), msg = ao2_iterator_next(&it_chans)) { + struct ast_channel_snapshot *snapshot = stasis_message_data(msg); + struct ast_channel *c; + struct ast_str *built = ast_manager_build_channel_state_string_prefix(snapshot, ""); + long elapsed_seconds = 0; + + if (!built) { + continue; + } - if (!ast_strlen_zero(cvariables)) { + if (!ast_strlen_zero(cvariables) && (c = ast_channel_get_by_name(snapshot->name))) { int i; ast_str_reset(str); for (i = 0; i < vars.argc; i++) { @@ -3813,94 +3920,70 @@ static int action_status(struct mansession *s, const struct message *m) ast_str_append(&str, 0, "Variable: %s=%s\r\n", vars.name[i], ret); } + ast_channel_unref(c); } channels++; - bridge = ast_channel_get_bridge(c); - if (bridge) { - snprintf(bridge_text, sizeof(bridge_text), "BridgeID: %s\r\n", - bridge->uniqueid); - ao2_ref(bridge, -1); - } else { - bridge_text[0] = '\0'; + + + if (!ast_tvzero(snapshot->creationtime)) { + elapsed_seconds = now.tv_sec - snapshot->creationtime.tv_sec; } - if (ast_channel_pbx(c)) { - if (!ast_tvzero(ast_channel_creationtime(c))) { - elapsed_seconds = now.tv_sec - ast_channel_creationtime(c).tv_sec; - } - astman_append(s, - "Event: Status\r\n" - "Privilege: Call\r\n" - "Channel: %s\r\n" - "CallerIDNum: %s\r\n" - "CallerIDName: %s\r\n" - "ConnectedLineNum: %s\r\n" - "ConnectedLineName: %s\r\n" - "Accountcode: %s\r\n" - "ChannelState: %d\r\n" - "ChannelStateDesc: %s\r\n" - "Context: %s\r\n" - "Extension: %s\r\n" - "Priority: %d\r\n" - "Seconds: %ld\r\n" - "%s" - "Uniqueid: %s\r\n" - "%s" - "%s" - "\r\n", - ast_channel_name(c), - S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, "<unknown>"), - S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, "<unknown>"), - S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, "<unknown>"), - S_COR(ast_channel_connected(c)->id.name.valid, ast_channel_connected(c)->id.name.str, "<unknown>"), - ast_channel_accountcode(c), - ast_channel_state(c), - ast_state2str(ast_channel_state(c)), - ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), - (long) elapsed_seconds, - bridge_text, - ast_channel_uniqueid(c), - ast_str_buffer(str), - idText); - } else { - astman_append(s, - "Event: Status\r\n" - "Privilege: Call\r\n" - "Channel: %s\r\n" - "CallerIDNum: %s\r\n" - "CallerIDName: %s\r\n" - "ConnectedLineNum: %s\r\n" - "ConnectedLineName: %s\r\n" - "Account: %s\r\n" - "State: %s\r\n" - "%s" - "Uniqueid: %s\r\n" - "%s" - "%s" - "\r\n", - ast_channel_name(c), - S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, "<unknown>"), - S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, "<unknown>"), - S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, "<unknown>"), - S_COR(ast_channel_connected(c)->id.name.valid, ast_channel_connected(c)->id.name.str, "<unknown>"), - ast_channel_accountcode(c), - ast_state2str(ast_channel_state(c)), - bridge_text, - ast_channel_uniqueid(c), - ast_str_buffer(str), - idText); - } - - ast_channel_unlock(c); - c = ast_channel_unref(c); + + astman_append(s, + "Event: Status\r\n" + "Privilege: Call\r\n" + "Type: %s\r\n" + "DNID: %s\r\n" + "EffectiveConnectedLineNum: %s\r\n" + "EffectiveConnectedLineName: %s\r\n" + "TimeToHangup: %ld\r\n" + "BridgeID: %s\r\n" + "Linkedid: %s\r\n" + "Application: %s\r\n" + "Data: %s\r\n" + "Nativeformats: %s\r\n" + "Readformat: %s\r\n" + "Readtrans: %s\r\n" + "Writeformat: %s\r\n" + "Writetrans: %s\r\n" + "Callgroup: %llu\r\n" + "Pickupgroup: %llu\r\n" + "Seconds: %ld\r\n" + "%s" + "%s" + "%s" + "\r\n", + snapshot->type, + snapshot->caller_dnid, + S_OR(snapshot->effective_number, "<unknown>"), + S_OR(snapshot->effective_name, "<unknown>"), + snapshot->hanguptime.tv_sec, + snapshot->bridgeid, + snapshot->linkedid, + snapshot->appl, + snapshot->data, + snapshot->nativeformats, + snapshot->readformat, + snapshot->readtrans, + snapshot->writeformat, + snapshot->writetrans, + snapshot->callgroup, + snapshot->pickupgroup, + (long) elapsed_seconds, + ast_str_buffer(built), + ast_str_buffer(str), + idText); + + ast_free(built); if (!all) { break; } } - if (iter) { - ast_channel_iterator_destroy(iter); + if (all) { + ao2_iterator_destroy(&it_chans); } astman_append(s, @@ -5259,10 +5342,10 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m { const char *actionid = astman_get_header(m, "ActionID"); char idText[256]; - struct ast_channel *c = NULL; int numchans = 0; - int duration, durh, durm, durs; - struct ast_channel_iterator *iter; + RAII_VAR(struct ao2_container *, channels, NULL, ao2_cleanup); + struct ao2_iterator it_chans; + struct stasis_message *msg; if (!ast_strlen_zero(actionid)) { snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid); @@ -5270,60 +5353,35 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m idText[0] = '\0'; } - if (!(iter = ast_channel_iterator_all_new())) { - astman_send_error(s, m, "Memory Allocation Failure"); - return 1; + if (!(channels = stasis_cache_dump(ast_channel_topic_all_cached_by_name(), ast_channel_snapshot_type()))) { + astman_send_error(s, m, "Could not get cached channels"); + return 0; } astman_send_listack(s, m, "Channels will follow", "start"); - for (; (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) { - struct ast_channel *bc; - char durbuf[10] = ""; - - ast_channel_lock(c); + it_chans = ao2_iterator_init(channels, 0); + for (; (msg = ao2_iterator_next(&it_chans)); ao2_ref(msg, -1)) { + struct ast_channel_snapshot *cs = stasis_message_data(msg); + struct ast_str *built = ast_manager_build_channel_state_string_prefix(cs, ""); - bc = ast_bridged_channel(c); - if (!ast_tvzero(ast_channel_creationtime(c))) { - duration = (int)(ast_tvdiff_ms(ast_tvnow(), ast_channel_creationtime(c)) / 1000); - durh = duration / 3600; - durm = (duration % 3600) / 60; - durs = duration % 60; - snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs); + if (!built) { + continue; } astman_append(s, "Event: CoreShowChannel\r\n" "%s" - "Channel: %s\r\n" - "UniqueID: %s\r\n" - "Context: %s\r\n" - "Extension: %s\r\n" - "Priority: %d\r\n" - "ChannelState: %d\r\n" - "ChannelStateDesc: %s\r\n" - "Application: %s\r\n" - "ApplicationData: %s\r\n" - "CallerIDnum: %s\r\n" - "CallerIDname: %s\r\n" - "ConnectedLineNum: %s\r\n" - "ConnectedLineName: %s\r\n" - "Duration: %s\r\n" - "AccountCode: %s\r\n" - "BridgedChannel: %s\r\n" - "BridgedUniqueID: %s\r\n" - "\r\n", idText, ast_channel_name(c), ast_channel_uniqueid(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_channel_state(c), - ast_state2str(ast_channel_state(c)), ast_channel_appl(c) ? ast_channel_appl(c) : "", ast_channel_data(c) ? S_OR(ast_channel_data(c), "") : "", - S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, ""), - S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, ""), - S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, ""), - S_COR(ast_channel_connected(c)->id.name.valid, ast_channel_connected(c)->id.name.str, ""), - durbuf, S_OR(ast_channel_accountcode(c), ""), bc ? ast_channel_name(bc) : "", bc ? ast_channel_uniqueid(bc) : ""); - - ast_channel_unlock(c); + "%s" + "\r\n", + idText, + ast_str_buffer(built)); numchans++; + + ast_free(built); } + ao2_iterator_destroy(&it_chans); astman_append(s, "Event: CoreShowChannelsComplete\r\n" @@ -5332,8 +5390,6 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m "%s" "\r\n", numchans, idText); - ast_channel_iterator_destroy(iter); - return 0; } diff --git a/main/manager_bridging.c b/main/manager_bridging.c index 5e5f409ee0..7fbbbea0bb 100644 --- a/main/manager_bridging.c +++ b/main/manager_bridging.c @@ -41,10 +41,17 @@ static struct stasis_message_router *bridge_state_router; <synopsis>Raised when a bridge is created.</synopsis> <syntax> <parameter name="BridgeUniqueid"> + <para>The unique identifier of the bridge</para> </parameter> <parameter name="BridgeType"> <para>The type of bridge</para> </parameter> + <parameter name="BridgeTechnology"> + <para>Technology in use by the bridge</para> + </parameter> + <parameter name="BridgeNumChannels"> + <para>Number of channels in the bridge</para> + </parameter> </syntax> </managerEventInstance> </managerEvent> @@ -124,9 +131,13 @@ struct ast_str *ast_manager_build_bridge_state_string( } res = ast_str_set(&out, 0, "BridgeUniqueid%s: %s\r\n" - "BridgeType%s: %s\r\n", + "BridgeType%s: %s\r\n" + "BridgeTechnology%s: %s\r\n" + "BridgeNumChannels%s: %d\r\n", suffix, snapshot->uniqueid, - suffix, snapshot->technology); + suffix, snapshot->subclass, + suffix, snapshot->technology, + suffix, snapshot->num_channels); if (!res) { return NULL; diff --git a/main/manager_channels.c b/main/manager_channels.c index 7dd91a63bb..bc9e83d6e8 100644 --- a/main/manager_channels.c +++ b/main/manager_channels.c @@ -43,11 +43,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") <synopsis>Raised when a new channel is created.</synopsis> <syntax> <parameter name="Channel"> + <para>Name of the channel</para> </parameter> <parameter name="ChannelState"> <para>A numeric code for the channel's current state, related to ChannelStateDesc</para> </parameter> <parameter name="ChannelStateDesc"> + <para>Name for the channel's current state</para> <enumlist> <enum name="Down"/> <enum name="Rsrvd"/> @@ -79,6 +81,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") <parameter name="Priority"> </parameter> <parameter name="Uniqueid"> + <para>Unique identifier for the channel</para> </parameter> </syntax> </managerEventInstance> @@ -525,9 +528,11 @@ struct ast_str *ast_manager_build_channel_state_string_prefix( { struct ast_str *out = ast_str_create(1024); int res = 0; + if (!out) { return NULL; } + res = ast_str_set(&out, 0, "%sChannel: %s\r\n" "%sChannelState: %d\r\n" diff --git a/main/pbx.c b/main/pbx.c index f3d91842c0..21a1a149b0 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -4643,9 +4643,6 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con, ast_channel_exten_set(c, exten); ast_channel_priority_set(c, priority); pbx_substitute_variables(passdata, sizeof(passdata), c, e); -#ifdef CHANNEL_TRACE - ast_channel_trace_update(c); -#endif ast_debug(1, "Launching '%s'\n", app->name); { ast_verb(3, "Executing [%s@%s:%d] " COLORIZE_FMT "(\"" COLORIZE_FMT "\", \"" COLORIZE_FMT "\") %s\n", @@ -8028,8 +8025,9 @@ static char *handle_show_device2extenstate(struct ast_cli_entry *e, int cmd, str /*! \brief CLI support for listing chanvar's variables in a parseable way */ static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - struct ast_channel *chan = NULL; - struct ast_str *vars = ast_str_alloca(BUFSIZ * 4); /* XXX large because we might have lots of channel vars */ + RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); + struct ast_channel_snapshot *snapshot; + struct ast_var_t *var; switch (cmd) { case CLI_INIT: @@ -8045,19 +8043,16 @@ static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cl if (a->argc != e->args + 1) return CLI_SHOWUSAGE; - if (!(chan = ast_channel_get_by_name(a->argv[e->args]))) { + if (!(msg = stasis_cache_get(ast_channel_topic_all_cached_by_name(), ast_channel_snapshot_type(), a->argv[3]))) { ast_cli(a->fd, "Channel '%s' not found\n", a->argv[e->args]); return CLI_FAILURE; } + snapshot = stasis_message_data(msg); - pbx_builtin_serialize_variables(chan, &vars); - - if (ast_str_strlen(vars)) { - ast_cli(a->fd, "\nVariables for channel %s:\n%s\n", a->argv[e->args], ast_str_buffer(vars)); + AST_LIST_TRAVERSE(snapshot->channel_vars, var, entries) { + ast_cli(a->fd, "%s=%s\n", ast_var_name(var), ast_var_value(var)); } - chan = ast_channel_unref(chan); - return CLI_SUCCESS; } @@ -10985,6 +10980,10 @@ int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const newvariable = ast_var_assign(name, value); AST_LIST_INSERT_HEAD(headp, newvariable, entries); ast_channel_publish_varset(chan, name, value); + + if (headp != &globals) { + ast_channel_publish_snapshot(chan); + } } if (chan) diff --git a/main/stasis_channels.c b/main/stasis_channels.c index 9179878d59..eb71531c2d 100644 --- a/main/stasis_channels.c +++ b/main/stasis_channels.c @@ -35,6 +35,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/astobj2.h" #include "asterisk/json.h" #include "asterisk/pbx.h" +#include "asterisk/bridging.h" +#include "asterisk/translate.h" #include "asterisk/stasis.h" #include "asterisk/stasis_channels.h" @@ -121,13 +123,21 @@ static int channel_snapshot_cmp_cb(void *obj, void *arg, int flags) static void channel_snapshot_dtor(void *obj) { struct ast_channel_snapshot *snapshot = obj; + ast_string_field_free_memory(snapshot); ao2_cleanup(snapshot->manager_vars); + ao2_cleanup(snapshot->channel_vars); } struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *chan) { RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup); + RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup); + char nativeformats[256]; + struct ast_str *write_transpath = ast_str_alloca(256); + struct ast_str *read_transpath = ast_str_alloca(256); + struct ast_party_id effective_connected_id; + struct ast_callid *callid; /* no snapshots for dummy channels */ if (!ast_channel_tech(chan)) { @@ -140,6 +150,7 @@ struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *cha } 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)); @@ -180,16 +191,42 @@ struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *cha S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, "")); ast_string_field_set(snapshot, language, ast_channel_language(chan)); + if ((bridge = ast_channel_get_bridge(chan))) { + ast_string_field_set(snapshot, bridgeid, bridge->uniqueid); + } + + ast_string_field_set(snapshot, nativeformats, ast_getformatname_multiple(nativeformats, sizeof(nativeformats), + ast_channel_nativeformats(chan))); + ast_string_field_set(snapshot, readformat, ast_getformatname(ast_channel_readformat(chan))); + ast_string_field_set(snapshot, writeformat, ast_getformatname(ast_channel_writeformat(chan))); + ast_string_field_set(snapshot, writetrans, ast_translate_path_to_str(ast_channel_writetrans(chan), &write_transpath)); + ast_string_field_set(snapshot, readtrans, ast_translate_path_to_str(ast_channel_readtrans(chan), &read_transpath)); + + effective_connected_id = ast_channel_connected_effective_id(chan); + ast_string_field_set(snapshot, effective_name, + S_COR(effective_connected_id.name.valid, effective_connected_id.name.str, "")); + ast_string_field_set(snapshot, effective_number, + S_COR(effective_connected_id.number.valid, effective_connected_id.number.str, "")); + + if ((callid = ast_channel_callid(chan))) { + ast_callid_strnprint(snapshot->callid, sizeof(snapshot->callid), callid); + ast_callid_unref(callid); + } + snapshot->creationtime = ast_channel_creationtime(chan); + snapshot->hanguptime = *(ast_channel_whentohangup(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); + snapshot->callgroup = ast_channel_callgroup(chan); + snapshot->pickupgroup = ast_channel_pickupgroup(chan); ast_set_flag(&snapshot->softhangup_flags, ast_channel_softhangup_internal_flag(chan)); snapshot->manager_vars = ast_channel_get_manager_vars(chan); + snapshot->channel_vars = ast_channel_get_vars(chan); ao2_ref(snapshot, +1); return snapshot; diff --git a/res/res_agi.c b/res/res_agi.c index eff753e5ce..1e22ff98f5 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -2753,16 +2753,18 @@ static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, cons static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[]) { - struct ast_channel *c; if (argc == 2) { /* no argument: supply info on the current channel */ ast_agi_send(agi->fd, chan, "200 result=%d\n", ast_channel_state(chan)); return RESULT_SUCCESS; } else if (argc == 3) { + RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); + /* one argument: look for info on the specified channel */ - if ((c = ast_channel_get_by_name(argv[2]))) { - ast_agi_send(agi->fd, chan, "200 result=%d\n", ast_channel_state(c)); - c = ast_channel_unref(c); + if ((msg = stasis_cache_get(ast_channel_topic_all_cached_by_name(), ast_channel_snapshot_type(), argv[2]))) { + struct ast_channel_snapshot *snapshot = stasis_message_data(msg); + + ast_agi_send(agi->fd, chan, "200 result=%d\n", snapshot->state); return RESULT_SUCCESS; } /* if we get this far no channel name matched the argument given */