diff --git a/CHANGES b/CHANGES index 111a03099276979e91e7e02011bd08edd5f18f85..5a680015250172d5d5249e72c39e5de4b4d84dfb 100644 --- a/CHANGES +++ b/CHANGES @@ -35,6 +35,42 @@ Channels ast_channel_snapshot_update structure as it's data. ast_channel_snapshot_get_latest() still returns the latest snapshot. +Bridging +------------------ + * The bridging core no longer uses the stasis cache for bridge + snapshots. The latest bridge snapshot is now stored on the + ast_bridge structure itself. + + * The following APIs are no longer available since the stasis cache + is no longer used: + ast_bridge_topic_cached() + ast_bridge_topic_all_cached() + + * A topic pool is now used for individual bridge topics. + + * The ast_bridge_cache() function was removed since there's no + longer a separate container of snapshots. + + * A new function "ast_bridges()" was created to retrieve the + container of all bridges. Users formerly calling + ast_bridge_cache() can use the new function to iterate over + bridges and retrieve the latest snapshot directly from the + bridge. + + * The ast_bridge_snapshot_get_latest() function was renamed to + ast_bridge_get_snapshot_by_uniqueid(). + + * A new function "ast_bridge_get_snapshot()" was created to retrieve + the bridge snapshot directly from the bridge structure. + + * The ast_bridge_topic_all() function now returns a normal topic + not a cached one so you can't use stasis cache functions on it + either. + + * The ast_bridge_snapshot_type() stasis message now has the + ast_bridge_snapshot_update structure as it's data. It contains + the last snapshot and the new one. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 16.0.0 to Asterisk 16.1.0 ------------ ------------------------------------------------------------------------------ diff --git a/UPGRADE.txt b/UPGRADE.txt index c299d83d67c25c41b23bc9b0fac1078dc81b7d5c..53e9c4a9b9ed40ca0c872abb909ff7f0bac1c2be 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -58,3 +58,34 @@ Channels: The ast_channel_snapshot_type() stasis message now has the ast_channel_snapshot_update structure as it's data. ast_channel_snapshot_get_latest() still returns the latest snapshot. + +Applications + - The JabberStatus application, deprecated in Asterisk 12, has been removed. + +Bridging + - The bridging core no longer uses the stasis cache for bridge + snapshots. The latest bridge snapshot is now stored on the + ast_bridge structure itself. + - The following APIs are no longer available since the stasis cache + is no longer used: + ast_bridge_topic_cached() + ast_bridge_topic_all_cached() + - A topic pool is now used for individual bridge topics. + - The ast_bridge_cache() function was removed since there's no + longer a separate container of snapshots. + - A new function "ast_bridges()" was created to retrieve the + container of all bridges. Users formerly calling + ast_bridge_cache() can use the new function to iterate over + bridges and retrieve the latest snapshot directly from the + bridge. + - The ast_bridge_snapshot_get_latest() function was renamed to + ast_bridge_get_snapshot_by_uniqueid(). + - A new function "ast_bridge_get_snapshot()" was created to retrieve + the bridge snapshot directly from the bridge structure. + - The ast_bridge_topic_all() function now returns a normal topic + not a cached one so you can't use stasis cache functions on it + either. + - The ast_bridge_snapshot_type() stasis message now has the + ast_bridge_snapshot_update structure as it's data. It contains + the last snapshot and the new one. + diff --git a/apps/confbridge/confbridge_manager.c b/apps/confbridge/confbridge_manager.c index 2d8503338c69a5be86100a0fb168252a49d727d6..b1819caf615a6b7c4a0363a62383020dda534449 100644 --- a/apps/confbridge/confbridge_manager.c +++ b/apps/confbridge/confbridge_manager.c @@ -712,7 +712,7 @@ int manager_confbridge_init(void) STASIS_MESSAGE_TYPE_INIT(confbridge_welcome_type); bridge_state_router = stasis_message_router_create( - ast_bridge_topic_all_cached()); + ast_bridge_topic_all()); if (!bridge_state_router) { return -1; diff --git a/include/asterisk/bridge.h b/include/asterisk/bridge.h index f4b1df8e04d7ac44bf13c34abced806265b3b2d8..e4d11e81d49ae633ebc58cbb4860614abf68a9c8 100644 --- a/include/asterisk/bridge.h +++ b/include/asterisk/bridge.h @@ -75,6 +75,7 @@ extern "C" { #include "asterisk/dsp.h" #include "asterisk/uuid.h" +struct a02_container; struct ast_bridge_technology; struct ast_bridge; struct ast_bridge_tech_optimizations; @@ -299,6 +300,39 @@ struct ast_bridge_softmix { AST_LIST_HEAD_NOLOCK(ast_bridge_channels_list, ast_bridge_channel); +/*! + * \brief Structure that contains a snapshot of information about a bridge + */ +struct ast_bridge_snapshot { + AST_DECLARE_STRING_FIELDS( + /*! Immutable bridge UUID. */ + AST_STRING_FIELD(uniqueid); + /*! Bridge technology that is handling the bridge */ + AST_STRING_FIELD(technology); + /*! Bridge subclass that is handling the bridge */ + AST_STRING_FIELD(subclass); + /*! Creator of the bridge */ + AST_STRING_FIELD(creator); + /*! Name given to the bridge by its creator */ + AST_STRING_FIELD(name); + /*! Unique ID of the channel providing video, if one exists */ + AST_STRING_FIELD(video_source_id); + ); + /*! AO2 container of bare channel uniqueid strings participating in the bridge. + * Allocated from ast_str_container_alloc() */ + struct ao2_container *channels; + /*! Bridge flags to tweak behavior */ + struct ast_flags feature_flags; + /*! Bridge capabilities */ + uint32_t capabilities; + /*! Number of channels participating in the bridge */ + unsigned int num_channels; + /*! Number of active channels in the bridge. */ + unsigned int num_active; + /*! The video mode of the bridge */ + enum ast_bridge_video_mode_type video_mode; +}; + /*! * \brief Structure that contains information about a bridge */ @@ -312,7 +346,7 @@ struct ast_bridge { /*! Private information unique to the bridge technology */ void *tech_pvt; /*! Per-bridge topics */ - struct stasis_cp_single *topics; + struct stasis_topic *topic; /*! Call ID associated with the bridge */ ast_callid callid; /*! Linked list of channels participating in the bridge */ @@ -358,11 +392,26 @@ struct ast_bridge { /*! Type mapping used for media routing */ struct ast_vector_int media_types; + /*! Current bridge snapshot */ + struct ast_bridge_snapshot *current_snapshot; }; /*! \brief Bridge base class virtual method table. */ extern struct ast_bridge_methods ast_bridge_base_v_table; +/*! + * \brief Returns the global bridges container + * \since 17.0 + * + * \retval a pointer to the bridges container success + * \retval NULL on failure + * + * \note You must use ao2_ref(<container>, -1) when done with it + * + * \warning You must not attempt to modify the container returned. + */ +struct ao2_container *ast_bridges(void); + /*! * \brief Create a new base class bridge * diff --git a/include/asterisk/stasis_bridges.h b/include/asterisk/stasis_bridges.h index a455a5b02656c86b9e3b551b646304ddd7fc0cf4..4d80955c42a74b13b092f3c96cfad62d22ea283d 100644 --- a/include/asterisk/stasis_bridges.h +++ b/include/asterisk/stasis_bridges.h @@ -31,37 +31,9 @@ extern "C" { #include "asterisk/bridge.h" #include "asterisk/pbx.h" -/*! - * \brief Structure that contains a snapshot of information about a bridge - */ -struct ast_bridge_snapshot { - AST_DECLARE_STRING_FIELDS( - /*! Immutable bridge UUID. */ - AST_STRING_FIELD(uniqueid); - /*! Bridge technology that is handling the bridge */ - AST_STRING_FIELD(technology); - /*! Bridge subclass that is handling the bridge */ - AST_STRING_FIELD(subclass); - /*! Creator of the bridge */ - AST_STRING_FIELD(creator); - /*! Name given to the bridge by its creator */ - AST_STRING_FIELD(name); - /*! Unique ID of the channel providing video, if one exists */ - AST_STRING_FIELD(video_source_id); - ); - /*! AO2 container of bare channel uniqueid strings participating in the bridge. - * Allocated from ast_str_container_alloc() */ - struct ao2_container *channels; - /*! Bridge flags to tweak behavior */ - struct ast_flags feature_flags; - /*! Bridge capabilities */ - uint32_t capabilities; - /*! Number of channels participating in the bridge */ - unsigned int num_channels; - /*! Number of active channels in the bridge. */ - unsigned int num_active; - /*! The video mode of the bridge */ - enum ast_bridge_video_mode_type video_mode; +struct ast_bridge_snapshot_update { + struct ast_bridge_snapshot *old_snapshot; + struct ast_bridge_snapshot *new_snapshot; }; /*! @@ -99,22 +71,6 @@ struct stasis_message_type *ast_bridge_snapshot_type(void); */ struct stasis_topic *ast_bridge_topic(struct ast_bridge *bridge); -/*! - * \since 12 - * \brief A topic which publishes the events for a particular bridge. - * - * \ref ast_bridge_snapshot messages are replaced with stasis_cache_update - * messages. - * - * If the given \a bridge is \c NULL, ast_bridge_topic_all_cached() is returned. - * - * \param bridge Bridge for which to get a topic or \c NULL. - * - * \retval Topic for bridge's events. - * \retval ast_bridge_topic_all() if \a bridge is \c NULL. - */ -struct stasis_topic *ast_bridge_topic_cached(struct ast_bridge *bridge); - /*! * \since 12 * \brief A topic which publishes the events for all bridges. @@ -122,22 +78,6 @@ struct stasis_topic *ast_bridge_topic_cached(struct ast_bridge *bridge); */ struct stasis_topic *ast_bridge_topic_all(void); -/*! - * \since 12 - * \brief A caching topic which caches \ref ast_bridge_snapshot messages from - * ast_bridge_events_all(void). - * - * \retval Caching topic for all bridge events. - */ -struct stasis_topic *ast_bridge_topic_all_cached(void); - -/*! - * \since 12 - * \brief Backend cache for ast_bridge_topic_all_cached(). - * \retval Cache of \ref ast_bridge_snapshot. - */ -struct stasis_cache *ast_bridge_cache(void); - /*! * \since 12 * \brief Publish the state of a bridge @@ -490,17 +430,31 @@ void ast_bridge_publish_attended_transfer(struct ast_attended_transfer_message * struct stasis_message_type *ast_attended_transfer_type(void); /*! - * \brief Returns the most recent snapshot for the bridge. + * \brief Returns the current snapshot for the bridge. + * \since 17.0 * * The returned pointer is AO2 managed, so ao2_cleanup() when you're done. * - * \param bridge_id Uniqueid of the bridge for which to get the snapshot. + * \param bridge_id Uniqueid of the bridge from which to get the snapshot. * \return Most recent snapshot. ao2_cleanup() when done. - * \return \c NULL if channel isn't in cache. + * \return \c NULL if bridge or snapshot doesn't exist. */ -struct ast_bridge_snapshot *ast_bridge_snapshot_get_latest( +struct ast_bridge_snapshot *ast_bridge_get_snapshot_by_uniqueid( const char *bridge_id); +/*! + * \brief Returns the current snapshot for the bridge. + * \since 17.0 + * + * The returned pointer is AO2 managed, so ao2_cleanup() when you're done. + * + * \param bridge The bridge from which to get the snapshot. + * \return Most recent snapshot. ao2_cleanup() when done. + * \return \c NULL if there isn't a snapshot. + */ +struct ast_bridge_snapshot *ast_bridge_get_snapshot( + struct ast_bridge *bridge); + /*! * \internal * \brief Initialize the topics for a single bridge. @@ -509,6 +463,15 @@ struct ast_bridge_snapshot *ast_bridge_snapshot_get_latest( */ int bridge_topics_init(struct ast_bridge *bridge); +/*! + * \internal + * \since 17.0 + * \brief Publish destroy then cleanup topics. + * + * \param bridge The bridge to clean up + */ +void bridge_topics_destroy(struct ast_bridge *bridge); + /*! * \internal * \brief Initialize the stasis bridging topic and message types diff --git a/main/Makefile b/main/Makefile index 1cb2c25eff5aa9ffbce1cec53b8f105a48b2526e..a22a1ad2f9b2ce497b010cdacee20a4996b35473 100644 --- a/main/Makefile +++ b/main/Makefile @@ -167,6 +167,7 @@ options.o: _ASTCFLAGS+=$(call get_menuselect_cflags,REF_DEBUG) sched.o: _ASTCFLAGS+=$(call get_menuselect_cflags,DEBUG_SCHEDULER DUMP_SCHEDULER) tcptls.o: _ASTCFLAGS+=$(OPENSSL_INCLUDE) -Wno-deprecated-declarations uuid.o: _ASTCFLAGS+=$(UUID_INCLUDE) +stasis.o: _ASTCFLAGS+=$(call get_menuselect_cflags,AO2_DEBUG) OBJS:=$(sort $(OBJS)) diff --git a/main/bridge.c b/main/bridge.c index a65927d4b558f308e7faece7741dd4b9596bd5c9..1bee2e6518cfd919f2db595777d221bba4d3931c 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -171,6 +171,11 @@ struct bridge_manager_controller { /*! Bridge manager controller. */ static struct bridge_manager_controller *bridge_manager; +struct ao2_container *ast_bridges(void) +{ + return ao2_bump(bridges); +} + /*! * \internal * \brief Request service for a bridge from the bridge manager. @@ -650,25 +655,6 @@ static void bridge_handle_actions(struct ast_bridge *bridge) } } -static struct stasis_message *create_bridge_snapshot_message(struct ast_bridge *bridge) -{ - RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup); - - if (!ast_bridge_snapshot_type()) { - return NULL; - } - - ast_bridge_lock(bridge); - snapshot = ast_bridge_snapshot_create(bridge); - ast_bridge_unlock(bridge); - - if (!snapshot) { - return NULL; - } - - return stasis_message_create(ast_bridge_snapshot_type(), snapshot); -} - static void destroy_bridge(void *obj) { struct ast_bridge *bridge = obj; @@ -677,17 +663,7 @@ static void destroy_bridge(void *obj) bridge->uniqueid, bridge->v_table->name); if (bridge->construction_completed) { - RAII_VAR(struct stasis_message *, clear_msg, NULL, ao2_cleanup); - - clear_msg = create_bridge_snapshot_message(bridge); - if (clear_msg) { - RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); - - msg = stasis_cache_clear_create(clear_msg); - if (msg) { - stasis_publish(ast_bridge_topic(bridge), msg); - } - } + bridge_topics_destroy(bridge); } /* Do any pending actions in the context of destruction. */ @@ -726,9 +702,8 @@ static void destroy_bridge(void *obj) cleanup_video_mode(bridge); - stasis_cp_single_unsubscribe(bridge->topics); - ast_string_field_free_memory(bridge); + ao2_cleanup(bridge->current_snapshot); } struct ast_bridge *bridge_register(struct ast_bridge *bridge) @@ -2008,6 +1983,9 @@ int ast_bridge_remove(struct ast_bridge *bridge, struct ast_channel *chan) { struct ast_bridge_channel *bridge_channel; + ast_debug(1, "Removing channel %s from bridge %s\n", + ast_channel_name(chan), bridge->uniqueid); + ast_bridge_lock(bridge); /* Try to find the channel that we want to remove */ @@ -5071,43 +5049,13 @@ static char *complete_bridge_live(const char *word) return NULL; } -static char *complete_bridge_stasis(const char *word) -{ - int wordlen = strlen(word); - struct ao2_container *cached_bridges; - struct ao2_iterator iter; - struct stasis_message *msg; - - cached_bridges = stasis_cache_dump(ast_bridge_cache(), ast_bridge_snapshot_type()); - if (!cached_bridges) { - return NULL; - } - - 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); - - if (!strncasecmp(word, snapshot->uniqueid, wordlen)) { - if (ast_cli_completion_add(ast_strdup(snapshot->uniqueid))) { - ao2_ref(msg, -1); - break; - } - } - } - ao2_iterator_destroy(&iter); - ao2_ref(cached_bridges, -1); - - return NULL; -} - static char *handle_bridge_show_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { #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 stasis_message *msg; + struct ast_bridge *bridge; switch (cmd) { case CLI_INIT: @@ -5120,25 +5068,23 @@ static char *handle_bridge_show_all(struct ast_cli_entry *e, int cmd, struct ast return NULL; } - cached_bridges = stasis_cache_dump(ast_bridge_cache(), ast_bridge_snapshot_type()); - if (!cached_bridges) { - 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(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, - snapshot->uniqueid, - snapshot->num_channels, - S_OR(snapshot->subclass, "<unknown>"), - S_OR(snapshot->technology, "<unknown>")); + iter = ao2_iterator_init(bridges, 0); + for (; (bridge = ao2_iterator_next(&iter)); ao2_ref(bridge, -1)) { + struct ast_bridge_snapshot *snapshot = ast_bridge_get_snapshot(bridge); + + if (snapshot) { + ast_cli(a->fd, FORMAT_ROW, + snapshot->uniqueid, + snapshot->num_channels, + S_OR(snapshot->subclass, "<unknown>"), + S_OR(snapshot->technology, "<unknown>")); + ao2_ref(snapshot, -1); + } } ao2_iterator_destroy(&iter); + return CLI_SUCCESS; #undef FORMAT_HDR @@ -5165,7 +5111,6 @@ static int bridge_show_specific_print_channel(void *obj, void *arg, int flags) static char *handle_bridge_show_specific(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); struct ast_bridge_snapshot *snapshot; switch (cmd) { @@ -5177,7 +5122,7 @@ static char *handle_bridge_show_specific(struct ast_cli_entry *e, int cmd, struc return NULL; case CLI_GENERATE: if (a->pos == 2) { - return complete_bridge_stasis(a->word); + return complete_bridge_live(a->word); } return NULL; } @@ -5186,18 +5131,17 @@ static char *handle_bridge_show_specific(struct ast_cli_entry *e, int cmd, struc return CLI_SHOWUSAGE; } - msg = stasis_cache_get(ast_bridge_cache(), ast_bridge_snapshot_type(), a->argv[2]); - if (!msg) { + snapshot = ast_bridge_get_snapshot_by_uniqueid(a->argv[2]); + if (!snapshot) { ast_cli(a->fd, "Bridge '%s' not found\n", a->argv[2]); return CLI_SUCCESS; } - - 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); + ao2_ref(snapshot, -1); return CLI_SUCCESS; } diff --git a/main/cdr.c b/main/cdr.c index 2e3b2058a93ed1442a79b0a6325474b738b23ea9..462c3e6a2fb7d84ef6527d855c1d71c7963774b3 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -4288,7 +4288,7 @@ static int create_subscriptions(void) if (!channel_subscription) { return -1; } - bridge_subscription = stasis_forward_all(ast_bridge_topic_all_cached(), cdr_topic); + bridge_subscription = stasis_forward_all(ast_bridge_topic_all(), cdr_topic); if (!bridge_subscription) { return -1; } diff --git a/main/cel.c b/main/cel.c index 242aeffa6be8a50cb94b291555cfd3a739a0460f..95376db6e3c729153d9137e641d8ea4b700e861d 100644 --- a/main/cel.c +++ b/main/cel.c @@ -1449,7 +1449,7 @@ static int create_subscriptions(void) } cel_bridge_forwarder = stasis_forward_all( - ast_bridge_topic_all_cached(), + ast_bridge_topic_all(), cel_aggregation_topic); if (!cel_bridge_forwarder) { return -1; diff --git a/main/manager_bridges.c b/main/manager_bridges.c index 4f2cb35306c24927577ad290ce5cb7d374dd4e0b..d49b783f270f86643cda12cc72e850f58bc020b2 100644 --- a/main/manager_bridges.c +++ b/main/manager_bridges.c @@ -330,22 +330,15 @@ static void bridge_snapshot_update(void *data, struct stasis_subscription *sub, struct stasis_message *message) { RAII_VAR(struct ast_str *, bridge_event_string, NULL, ast_free); - struct stasis_cache_update *update; - struct ast_bridge_snapshot *old_snapshot; - struct ast_bridge_snapshot *new_snapshot; + struct ast_bridge_snapshot_update *update; size_t i; update = stasis_message_data(message); - ast_assert(ast_bridge_snapshot_type() == update->type); - - old_snapshot = stasis_message_data(update->old_snapshot); - new_snapshot = stasis_message_data(update->new_snapshot); - for (i = 0; i < ARRAY_LEN(bridge_monitors); ++i) { RAII_VAR(struct ast_manager_event_blob *, event, NULL, ao2_cleanup); - event = bridge_monitors[i](old_snapshot, new_snapshot); + event = bridge_monitors[i](update->old_snapshot, update->new_snapshot); if (!event) { continue; } @@ -354,7 +347,7 @@ static void bridge_snapshot_update(void *data, struct stasis_subscription *sub, if (!bridge_event_string) { bridge_event_string = ast_manager_build_bridge_state_string( - new_snapshot ? new_snapshot : old_snapshot); + update->new_snapshot ? update->new_snapshot : update->old_snapshot); if (!bridge_event_string) { return; } @@ -446,26 +439,30 @@ static void channel_leave_cb(void *data, struct stasis_subscription *sub, ast_str_buffer(channel_text)); } -static int filter_bridge_type_cb(void *obj, void *arg, int flags) -{ - char *bridge_type = arg; - struct ast_bridge_snapshot *snapshot = stasis_message_data(obj); - /* unlink all the snapshots that do not match the bridge type */ - return strcmp(bridge_type, snapshot->technology) ? CMP_MATCH : 0; -} - struct bridge_list_data { - const char *id_text; + struct ast_str *id_text; + const char *type_filter; int count; }; static int send_bridge_list_item_cb(void *obj, void *arg, void *data, int flags) { - struct ast_bridge_snapshot *snapshot = stasis_message_data(obj); + struct ast_bridge *bridge = obj; + RAII_VAR(struct ast_bridge_snapshot *, snapshot, ast_bridge_get_snapshot(bridge), ao2_cleanup); struct mansession *s = arg; struct bridge_list_data *list_data = data; - RAII_VAR(struct ast_str *, bridge_info, ast_manager_build_bridge_state_string(snapshot), ast_free); + struct ast_str * bridge_info; + + if (!snapshot) { + return 0; + } + + if (!ast_strlen_zero(list_data->type_filter) + && strcmp(list_data->type_filter, snapshot->technology)) { + return 0; + } + bridge_info = ast_manager_build_bridge_state_string(snapshot); if (!bridge_info) { return 0; } @@ -475,9 +472,12 @@ static int send_bridge_list_item_cb(void *obj, void *arg, void *data, int flags) "%s" "%s" "\r\n", - list_data->id_text, + ast_str_buffer(list_data->id_text), ast_str_buffer(bridge_info)); ++list_data->count; + + ast_free(bridge_info); + return 0; } @@ -485,41 +485,37 @@ static int manager_bridges_list(struct mansession *s, const struct message *m) { const char *id = astman_get_header(m, "ActionID"); const char *type_filter = astman_get_header(m, "BridgeType"); - RAII_VAR(struct ast_str *, id_text, ast_str_create(128), ast_free); - RAII_VAR(struct ao2_container *, bridges, NULL, ao2_cleanup); - struct bridge_list_data list_data; + struct ao2_container *bridges; + struct bridge_list_data list_data = { 0 }; - if (!id_text) { + bridges = ast_bridges(); + if (!bridges) { astman_send_error(s, m, "Internal error"); return -1; } - if (!ast_strlen_zero(id)) { - ast_str_set(&id_text, 0, "ActionID: %s\r\n", id); - } - - bridges = stasis_cache_dump(ast_bridge_cache(), ast_bridge_snapshot_type()); - if (!bridges) { + list_data.id_text = ast_str_create(128); + if (!list_data.id_text) { + ao2_ref(bridges, -1); astman_send_error(s, m, "Internal error"); return -1; } - astman_send_listack(s, m, "Bridge listing will follow", "start"); - - if (!ast_strlen_zero(type_filter)) { - char *type_filter_dup = ast_strdupa(type_filter); - - ao2_callback(bridges, OBJ_MULTIPLE | OBJ_NODATA | OBJ_UNLINK, - filter_bridge_type_cb, type_filter_dup); + if (!ast_strlen_zero(id)) { + ast_str_set(&list_data.id_text, 0, "ActionID: %s\r\n", id); } + list_data.type_filter = type_filter; + + astman_send_listack(s, m, "Bridge listing will follow", "start"); - list_data.id_text = ast_str_buffer(id_text); - list_data.count = 0; ao2_callback_data(bridges, OBJ_NODATA, send_bridge_list_item_cb, s, &list_data); astman_send_list_complete_start(s, m, "BridgeListComplete", list_data.count); astman_send_list_complete_end(s); + ast_free(list_data.id_text); + ao2_ref(bridges, -1); + return 0; } @@ -550,7 +546,7 @@ static int send_bridge_info_item_cb(void *obj, void *arg, void *data, int flags) "%s" "%s" "\r\n", - list_data->id_text, + ast_str_buffer(list_data->id_text), ast_str_buffer(channel_text)); ++list_data->count; return 0; @@ -560,43 +556,39 @@ static int manager_bridge_info(struct mansession *s, const struct message *m) { const char *id = astman_get_header(m, "ActionID"); const char *bridge_uniqueid = astman_get_header(m, "BridgeUniqueid"); - RAII_VAR(struct ast_str *, id_text, ast_str_create(128), ast_free); - RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); RAII_VAR(struct ast_str *, bridge_info, NULL, ast_free); - struct ast_bridge_snapshot *snapshot; - struct bridge_list_data list_data; - - if (!id_text) { - astman_send_error(s, m, "Internal error"); - return -1; - } + RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup); + struct bridge_list_data list_data = { 0 }; if (ast_strlen_zero(bridge_uniqueid)) { astman_send_error(s, m, "BridgeUniqueid must be provided"); return 0; } - if (!ast_strlen_zero(id)) { - ast_str_set(&id_text, 0, "ActionID: %s\r\n", id); - } - - msg = stasis_cache_get(ast_bridge_cache(), ast_bridge_snapshot_type(), bridge_uniqueid); - if (!msg) { + snapshot = ast_bridge_get_snapshot_by_uniqueid(bridge_uniqueid); + if (!snapshot) { astman_send_error(s, m, "Specified BridgeUniqueid not found"); return 0; } - snapshot = stasis_message_data(msg); bridge_info = ast_manager_build_bridge_state_string(snapshot); if (!bridge_info) { astman_send_error(s, m, "Internal error"); return -1; } + list_data.id_text = ast_str_create(128); + if (!list_data.id_text) { + astman_send_error(s, m, "Internal error"); + return -1; + } + + if (!ast_strlen_zero(id)) { + ast_str_set(&list_data.id_text, 0, "ActionID: %s\r\n", id); + } + astman_send_listack(s, m, "Bridge channel listing will follow", "start"); - list_data.id_text = ast_str_buffer(id_text); - list_data.count = 0; ao2_callback_data(snapshot->channels, OBJ_NODATA, send_bridge_info_item_cb, s, &list_data); astman_send_list_complete_start(s, m, "BridgeInfoComplete", list_data.count); @@ -604,6 +596,7 @@ static int manager_bridge_info(struct mansession *s, const struct message *m) astman_append(s, "%s", ast_str_buffer(bridge_info)); } astman_send_list_complete_end(s); + ast_free(list_data.id_text); return 0; } @@ -703,7 +696,7 @@ int manager_bridging_init(void) return -1; } - bridge_topic = ast_bridge_topic_all_cached(); + bridge_topic = ast_bridge_topic_all(); if (!bridge_topic) { return -1; } @@ -718,7 +711,7 @@ int manager_bridging_init(void) return -1; } - ret |= stasis_message_router_add_cache_update(bridge_state_router, + ret |= stasis_message_router_add(bridge_state_router, ast_bridge_snapshot_type(), bridge_snapshot_update, NULL); ret |= stasis_message_router_add(bridge_state_router, diff --git a/main/stasis_bridges.c b/main/stasis_bridges.c index 42bf6bc2dae899c79b32deafc5f6ae4855edb94f..bed28ba60e04f0635ee5c429da695822f3655730 100644 --- a/main/stasis_bridges.c +++ b/main/stasis_bridges.c @@ -155,7 +155,8 @@ static struct ast_json *ast_bridge_merge_message_to_json( struct stasis_message *msg, const struct stasis_message_sanitizer *sanitize); -static struct stasis_cp_all *bridge_cache_all; +static struct stasis_topic *bridge_topic_all; +static struct stasis_topic_pool *bridge_topic_pool; /*! * @{ \brief Define bridge message types. @@ -175,33 +176,9 @@ STASIS_MESSAGE_TYPE_DEFN(ast_attended_transfer_type, .to_ami = attended_transfer_to_ami); /*! @} */ -struct stasis_cache *ast_bridge_cache(void) -{ - return stasis_cp_all_cache(bridge_cache_all); -} - struct stasis_topic *ast_bridge_topic_all(void) { - return stasis_cp_all_topic(bridge_cache_all); -} - -struct stasis_topic *ast_bridge_topic_all_cached(void) -{ - return stasis_cp_all_topic_cached(bridge_cache_all); -} - -int bridge_topics_init(struct ast_bridge *bridge) -{ - if (ast_strlen_zero(bridge->uniqueid)) { - ast_log(LOG_ERROR, "Bridge id initialization required\n"); - return -1; - } - bridge->topics = stasis_cp_single_create(bridge_cache_all, - bridge->uniqueid); - if (!bridge->topics) { - return -1; - } - return 0; + return bridge_topic_all; } struct stasis_topic *ast_bridge_topic(struct ast_bridge *bridge) @@ -210,16 +187,7 @@ struct stasis_topic *ast_bridge_topic(struct ast_bridge *bridge) return ast_bridge_topic_all(); } - return stasis_cp_single_topic(bridge->topics); -} - -struct stasis_topic *ast_bridge_topic_cached(struct ast_bridge *bridge) -{ - if (!bridge) { - return ast_bridge_topic_all_cached(); - } - - return stasis_cp_single_topic_cached(bridge->topics); + return bridge->topic; } /*! \brief Destructor for bridge snapshots */ @@ -292,24 +260,106 @@ struct ast_bridge_snapshot *ast_bridge_snapshot_create(struct ast_bridge *bridge return snapshot; } -void ast_bridge_publish_state(struct ast_bridge *bridge) +static void bridge_snapshot_update_dtor(void *obj) { - struct ast_bridge_snapshot *snapshot; + struct ast_bridge_snapshot_update *update = obj; + + ast_debug(3, "Update: %p Old: %s New: %s\n", update, + update->old_snapshot ? update->old_snapshot->uniqueid : "<none>", + update->new_snapshot ? update->new_snapshot->uniqueid : "<none>"); + ao2_cleanup(update->old_snapshot); + ao2_cleanup(update->new_snapshot); +} + +static struct ast_bridge_snapshot_update *bridge_snapshot_update_create( + struct ast_bridge_snapshot *old, struct ast_bridge_snapshot *new) +{ + struct ast_bridge_snapshot_update *update; + + update = ao2_alloc_options(sizeof(*update), bridge_snapshot_update_dtor, + AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!update) { + return NULL; + } + update->old_snapshot = ao2_bump(old); + update->new_snapshot = ao2_bump(new); + + ast_debug(3, "Update: %p Old: %s New: %s\n", update, + update->old_snapshot ? update->old_snapshot->uniqueid : "<none>", + update->new_snapshot ? update->new_snapshot->uniqueid : "<none>"); + + return update; +} + +int bridge_topics_init(struct ast_bridge *bridge) +{ + if (ast_strlen_zero(bridge->uniqueid)) { + ast_log(LOG_ERROR, "Bridge id initialization required\n"); + return -1; + } + + bridge->topic = stasis_topic_pool_get_topic(bridge_topic_pool, bridge->uniqueid); + if (!bridge->topic) { + return -1; + } + + return 0; +} + +void bridge_topics_destroy(struct ast_bridge *bridge) +{ + struct ast_bridge_snapshot_update *update; struct stasis_message *msg; - if (!ast_bridge_snapshot_type()) { + ast_assert(bridge != NULL); + + if (!bridge->current_snapshot) { + bridge->current_snapshot = ast_bridge_snapshot_create(bridge); + if (!bridge->current_snapshot) { + return; + } + } + + update = bridge_snapshot_update_create(bridge->current_snapshot, NULL); + if (!update) { + return; + } + + msg = stasis_message_create(ast_bridge_snapshot_type(), update); + ao2_ref(update, -1); + if (!msg) { return; } + stasis_publish(ast_bridge_topic(bridge), msg); + ao2_ref(msg, -1); + + stasis_topic_pool_delete_topic(bridge_topic_pool, stasis_topic_name(ast_bridge_topic(bridge))); +} + +void ast_bridge_publish_state(struct ast_bridge *bridge) +{ + struct ast_bridge_snapshot *new_snapshot; + struct ast_bridge_snapshot_update *update; + struct stasis_message *msg; + ast_assert(bridge != NULL); - snapshot = ast_bridge_snapshot_create(bridge); - if (!snapshot) { + new_snapshot = ast_bridge_snapshot_create(bridge); + if (!new_snapshot) { return; } - msg = stasis_message_create(ast_bridge_snapshot_type(), snapshot); - ao2_ref(snapshot, -1); + update = bridge_snapshot_update_create(bridge->current_snapshot, new_snapshot); + /* There may not have been an old snapshot */ + ao2_cleanup(bridge->current_snapshot); + bridge->current_snapshot = new_snapshot; + if (!update) { + return; + } + + msg = stasis_message_create(ast_bridge_snapshot_type(), update); + ao2_ref(update, -1); if (!msg) { return; } @@ -321,11 +371,20 @@ void ast_bridge_publish_state(struct ast_bridge *bridge) static void bridge_publish_state_from_blob(struct ast_bridge *bridge, struct ast_bridge_blob *obj) { + struct ast_bridge_snapshot_update *update; struct stasis_message *msg; ast_assert(obj != NULL); - msg = stasis_message_create(ast_bridge_snapshot_type(), obj->bridge); + update = bridge_snapshot_update_create(bridge->current_snapshot, obj->bridge); + ao2_cleanup(bridge->current_snapshot); + bridge->current_snapshot = ao2_bump(obj->bridge); + if (!update) { + return; + } + + msg = stasis_message_create(ast_bridge_snapshot_type(), update); + ao2_ref(update, -1); if (!msg) { return; } @@ -1250,35 +1309,37 @@ void ast_bridge_publish_attended_transfer(struct ast_attended_transfer_message * ao2_ref(msg, -1); } -struct ast_bridge_snapshot *ast_bridge_snapshot_get_latest(const char *uniqueid) +struct ast_bridge_snapshot *ast_bridge_get_snapshot_by_uniqueid(const char *uniqueid) { - struct stasis_message *message; + struct ast_bridge *bridge; struct ast_bridge_snapshot *snapshot; ast_assert(!ast_strlen_zero(uniqueid)); - message = stasis_cache_get(ast_bridge_cache(), - ast_bridge_snapshot_type(), - uniqueid); - if (!message) { + bridge = ast_bridge_find_by_id(uniqueid); + if (!bridge) { return NULL; } - - snapshot = ao2_bump(stasis_message_data(message)); - ao2_ref(message, -1); + ast_bridge_lock(bridge); + snapshot = ao2_bump(bridge->current_snapshot); + ast_bridge_unlock(bridge); + ao2_ref(bridge, -1); return snapshot; } -/*! \brief snapshot ID getter for caching topic */ -static const char *bridge_snapshot_get_id(struct stasis_message *msg) +struct ast_bridge_snapshot *ast_bridge_get_snapshot(struct ast_bridge *bridge) { struct ast_bridge_snapshot *snapshot; - if (stasis_message_type(msg) != ast_bridge_snapshot_type()) { + + if (!bridge) { return NULL; } - snapshot = stasis_message_data(msg); - return snapshot->uniqueid; + ast_bridge_lock(bridge); + snapshot = ao2_bump(bridge->current_snapshot); + ast_bridge_unlock(bridge); + + return snapshot; } static void stasis_bridging_cleanup(void) @@ -1290,8 +1351,10 @@ static void stasis_bridging_cleanup(void) STASIS_MESSAGE_TYPE_CLEANUP(ast_blind_transfer_type); STASIS_MESSAGE_TYPE_CLEANUP(ast_attended_transfer_type); - ao2_cleanup(bridge_cache_all); - bridge_cache_all = NULL; + ao2_cleanup(bridge_topic_pool); + bridge_topic_pool = NULL; + ao2_cleanup(bridge_topic_all); + bridge_topic_all = NULL; } int ast_stasis_bridging_init(void) @@ -1300,10 +1363,12 @@ int ast_stasis_bridging_init(void) ast_register_cleanup(stasis_bridging_cleanup); - bridge_cache_all = stasis_cp_all_create("ast_bridge_topic_all", - bridge_snapshot_get_id); - - if (!bridge_cache_all) { + bridge_topic_all = stasis_topic_create("ast_bridge_topic_all"); + if (!bridge_topic_all) { + return -1; + } + bridge_topic_pool = stasis_topic_pool_create(bridge_topic_all); + if (!bridge_topic_pool) { return -1; } diff --git a/res/ari/resource_bridges.c b/res/ari/resource_bridges.c index 3c0eeb7751e2dc8268796abf78c0501c0bafb482..33e4cd18175216dfc3a336ba860a270a55f0035a 100644 --- a/res/ari/resource_bridges.c +++ b/res/ari/resource_bridges.c @@ -65,7 +65,7 @@ static struct ast_bridge *find_bridge( bridge = stasis_app_bridge_find_by_id(bridge_id); if (bridge == NULL) { RAII_VAR(struct ast_bridge_snapshot *, snapshot, - ast_bridge_snapshot_get_latest(bridge_id), ao2_cleanup); + ast_bridge_get_snapshot_by_uniqueid(bridge_id), ao2_cleanup); if (!snapshot) { ast_ari_response_error(response, 404, "Not found", "Bridge not found"); @@ -856,7 +856,7 @@ void ast_ari_bridges_get(struct ast_variable *headers, struct ast_ari_bridges_get_args *args, struct ast_ari_response *response) { - RAII_VAR(struct ast_bridge_snapshot *, snapshot, ast_bridge_snapshot_get_latest(args->bridge_id), ao2_cleanup); + RAII_VAR(struct ast_bridge_snapshot *, snapshot, ast_bridge_get_snapshot_by_uniqueid(args->bridge_id), ao2_cleanup); if (!snapshot) { ast_ari_response_error( response, 404, "Not Found", @@ -885,23 +885,13 @@ void ast_ari_bridges_list(struct ast_variable *headers, struct ast_ari_bridges_list_args *args, struct ast_ari_response *response) { - RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup); - RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup); + RAII_VAR(struct ao2_container *, bridges, NULL, ao2_cleanup); RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); struct ao2_iterator i; - void *obj; - - cache = ast_bridge_cache(); - if (!cache) { - ast_ari_response_error( - response, 500, "Internal Server Error", - "Message bus not initialized"); - return; - } - ao2_ref(cache, +1); + struct ast_bridge *bridge; - snapshots = stasis_cache_dump(cache, ast_bridge_snapshot_type()); - if (!snapshots) { + bridges = ast_bridges(); + if (!bridges) { ast_ari_response_alloc_failed(response); return; } @@ -912,12 +902,14 @@ void ast_ari_bridges_list(struct ast_variable *headers, return; } - i = ao2_iterator_init(snapshots, 0); - while ((obj = ao2_iterator_next(&i))) { - RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup); - struct ast_bridge_snapshot *snapshot = stasis_message_data(msg); + i = ao2_iterator_init(bridges, 0); + while ((bridge = ao2_iterator_next(&i))) { + struct ast_bridge_snapshot *snapshot = ast_bridge_get_snapshot(bridge); + /* ast_bridge_snapshot_to_json will return NULL if snapshot is NULL */ struct ast_json *json_bridge = ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer()); + ao2_ref(bridge, -1); + ao2_cleanup(snapshot); if (!json_bridge || ast_json_array_append(json, json_bridge)) { ao2_iterator_destroy(&i); ast_ari_response_alloc_failed(response); diff --git a/res/res_stasis.c b/res/res_stasis.c index 43833e17cd3d785369bd68e017eea891548d6db9..86723a1d12bf36237640ca7ec24f474570af3350 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -1974,7 +1974,7 @@ enum stasis_app_user_event_res stasis_app_user_event(const char *app_name, have_channel = 1; } else if (ast_begins_with(uri, "bridge:")) { type = STASIS_UMOS_BRIDGE; - snapshot = ast_bridge_snapshot_get_latest(uri + 7); + snapshot = ast_bridge_get_snapshot_by_uniqueid(uri + 7); } else if (ast_begins_with(uri, "endpoint:")) { type = STASIS_UMOS_ENDPOINT; snapshot = ast_endpoint_latest_snapshot(uri + 9, NULL); diff --git a/res/stasis/app.c b/res/stasis/app.c index 78f5765809d085fd67cf1cfa89959997efb26266..eb49243c58c7686fa0c30578ada630b6b4d12ea5 100644 --- a/res/stasis/app.c +++ b/res/stasis/app.c @@ -172,16 +172,9 @@ static struct app_forwards *forwards_create_bridge(struct stasis_app *app, } forwards->forward_type = FORWARD_BRIDGE; - if (bridge) { - forwards->topic_forward = stasis_forward_all(ast_bridge_topic(bridge), - app->topic); - } - forwards->topic_cached_forward = stasis_forward_all( - bridge ? ast_bridge_topic_cached(bridge) : ast_bridge_topic_all_cached(), - app->topic); + forwards->topic_forward = stasis_forward_all(ast_bridge_topic(bridge), app->topic); - if ((!forwards->topic_forward && bridge) || !forwards->topic_cached_forward) { - /* Half-subscribed is a bad thing */ + if (!forwards->topic_forward && bridge) { forwards_unsubscribe(forwards); ao2_ref(forwards, -1); return NULL; @@ -666,33 +659,23 @@ static void sub_bridge_update_handler(void *data, { struct ast_json *json = NULL; struct stasis_app *app = data; - struct stasis_cache_update *update; - struct ast_bridge_snapshot *new_snapshot; - struct ast_bridge_snapshot *old_snapshot; + struct ast_bridge_snapshot_update *update; const struct timeval *tv; - ast_assert(stasis_message_type(message) == stasis_cache_update_type()); - update = stasis_message_data(message); - ast_assert(update->type == ast_bridge_snapshot_type()); + tv = stasis_message_timestamp(message); - new_snapshot = stasis_message_data(update->new_snapshot); - old_snapshot = stasis_message_data(update->old_snapshot); - tv = update->new_snapshot ? - stasis_message_timestamp(update->new_snapshot) : - stasis_message_timestamp(message); - - if (!new_snapshot) { - json = simple_bridge_event("BridgeDestroyed", old_snapshot, tv); - } else if (!old_snapshot) { - json = simple_bridge_event("BridgeCreated", new_snapshot, tv); - } else if (new_snapshot && old_snapshot - && strcmp(new_snapshot->video_source_id, old_snapshot->video_source_id)) { - json = simple_bridge_event("BridgeVideoSourceChanged", new_snapshot, tv); - if (json && !ast_strlen_zero(old_snapshot->video_source_id)) { + if (!update->new_snapshot) { + json = simple_bridge_event("BridgeDestroyed", update->old_snapshot, tv); + } else if (!update->old_snapshot) { + json = simple_bridge_event("BridgeCreated", update->new_snapshot, tv); + } else if (update->new_snapshot && update->old_snapshot + && strcmp(update->new_snapshot->video_source_id, update->old_snapshot->video_source_id)) { + json = simple_bridge_event("BridgeVideoSourceChanged", update->new_snapshot, tv); + if (json && !ast_strlen_zero(update->old_snapshot->video_source_id)) { ast_json_object_set(json, "old_video_source_id", - ast_json_string_create(old_snapshot->video_source_id)); + ast_json_string_create(update->old_snapshot->video_source_id)); } } @@ -701,8 +684,8 @@ static void sub_bridge_update_handler(void *data, ast_json_unref(json); } - if (!new_snapshot && old_snapshot) { - unsubscribe(app, "bridge", old_snapshot->uniqueid, 1); + if (!update->new_snapshot && update->old_snapshot) { + unsubscribe(app, "bridge", update->old_snapshot->uniqueid, 1); } } @@ -961,7 +944,7 @@ struct stasis_app *app_create(const char *name, stasis_app_cb handler, void *dat return NULL; } - res |= stasis_message_router_add_cache_update(app->router, + res |= stasis_message_router_add(app->router, ast_bridge_snapshot_type(), sub_bridge_update_handler, app); res |= stasis_message_router_add(app->router, diff --git a/tests/test_cel.c b/tests/test_cel.c index a71276e6234733ec530439b200601a2427d22886..0d51b9f76b7f3ee4dd1dc0ad74385593f7c7b871 100644 --- a/tests/test_cel.c +++ b/tests/test_cel.c @@ -351,7 +351,7 @@ static struct ast_str *__test_cel_generate_peer_str(struct ast_channel_snapshot static struct ast_str *test_cel_generate_peer_str_snapshot(struct ast_channel_snapshot *chan, struct ast_bridge *bridge) { RAII_VAR(struct ast_bridge_snapshot *, snapshot, - ast_bridge_snapshot_get_latest(bridge->uniqueid), + ast_bridge_get_snapshot(bridge), ao2_cleanup); if (!snapshot) {