bridging: Give bridges a name and a known creator
authorJonathan Rose <jrose@digium.com>
Tue, 17 Dec 2013 23:25:49 +0000 (23:25 +0000)
committerJonathan Rose <jrose@digium.com>
Tue, 17 Dec 2013 23:25:49 +0000 (23:25 +0000)
Bridges have two new optional properties, a creator and a name.
Certain consumers of bridges will automatically provide bridges that
they create with these properties. Examples include app_bridgewait,
res_parking, app_confbridge, and app_agent_pool. In addition, a name
may now be provided as an argument to the POST function for creating
new bridges via ARI.

(closes issue AFS-47)
Review: https://reviewboard.asterisk.org/r/3070/
........

Merged revisions 404042 from http://svn.asterisk.org/svn/asterisk/branches/12

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@404043 65c4cc65-6c06-0410-ace0-fbb531ad65f3

20 files changed:
apps/app_agent_pool.c
apps/app_bridgewait.c
apps/app_confbridge.c
doc/appdocsxml.xslt
include/asterisk/bridge.h
include/asterisk/bridge_internal.h
include/asterisk/stasis_app.h
include/asterisk/stasis_bridges.h
main/bridge.c
main/bridge_basic.c
main/manager_bridges.c
main/stasis_bridges.c
res/ari/ari_model_validators.c
res/ari/ari_model_validators.h
res/ari/resource_bridges.c
res/ari/resource_bridges.h
res/parking/parking_bridge.c
res/res_ari_bridges.c
res/res_stasis.c
rest-api/api-docs/bridges.json

index c968153..2b0d1f8 100644 (file)
@@ -1366,7 +1366,8 @@ static struct ast_bridge *bridge_agent_hold_new(void)
        bridge = bridge_alloc(sizeof(struct ast_bridge), &bridge_agent_hold_v_table);
        bridge = bridge_base_init(bridge, AST_BRIDGE_CAPABILITY_HOLDING,
                AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
-                       | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM | AST_BRIDGE_FLAG_TRANSFER_PROHIBITED);
+                       | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM | AST_BRIDGE_FLAG_TRANSFER_PROHIBITED,
+               "AgentPool", NULL);
        bridge = bridge_register(bridge);
        return bridge;
 }
index 8e615f0..aa83e0b 100644 (file)
@@ -360,7 +360,8 @@ static struct wait_bridge_wrapper *get_wait_bridge_wrapper(const char *bridge_na
        bridge = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_HOLDING,
                AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
                | AST_BRIDGE_FLAG_SWAP_INHIBIT_TO | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM
-               | AST_BRIDGE_FLAG_TRANSFER_PROHIBITED | AST_BRIDGE_FLAG_DISSOLVE_EMPTY);
+               | AST_BRIDGE_FLAG_TRANSFER_PROHIBITED | AST_BRIDGE_FLAG_DISSOLVE_EMPTY,
+               APP_NAME, bridge_name);
 
        if (!bridge) {
                return NULL;
index 9688f2f..300d2c7 100644 (file)
@@ -1218,7 +1218,8 @@ static struct confbridge_conference *join_conference_bridge(const char *conferen
 
                /* Create an actual bridge that will do the audio mixing */
                conference->bridge = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_MULTIMIX,
-                       AST_BRIDGE_FLAG_MASQUERADE_ONLY | AST_BRIDGE_FLAG_TRANSFER_BRIDGE_ONLY);
+                       AST_BRIDGE_FLAG_MASQUERADE_ONLY | AST_BRIDGE_FLAG_TRANSFER_BRIDGE_ONLY,
+                       app, conference_name);
                if (!conference->bridge) {
                        ao2_ref(conference, -1);
                        conference = NULL;
index 33ff733..8cbeaa3 100644 (file)
         </xsl:element>
         <xsl:element name="parameter">
             <xsl:attribute name="name">
+                <xsl:value-of select="concat(@prefix, 'BridgeCreator')"/>
+            </xsl:attribute>
+            <para>Entity that created the bridge if applicable</para>
+        </xsl:element>
+        <xsl:element name="parameter">
+            <xsl:attribute name="name">
+                <xsl:value-of select="concat(@prefix, 'BridgeName')"/>
+            </xsl:attribute>
+            <para>Name used to refer to the bridge by its BridgeCreator if applicable</para>
+        </xsl:element>
+        <xsl:element name="parameter">
+            <xsl:attribute name="name">
                 <xsl:value-of select="concat(@prefix,'BridgeNumChannels')"/>
             </xsl:attribute>
             <para>Number of channels in the bridge</para>
index fdb3803..0706b3a 100644 (file)
@@ -312,8 +312,15 @@ struct ast_bridge {
        unsigned int dissolved:1;
        /*! TRUE if the bridge construction was completed. */
        unsigned int construction_completed:1;
-       /*! Immutable bridge UUID. */
-       char uniqueid[AST_UUID_STR_LEN];
+
+       AST_DECLARE_STRING_FIELDS(
+               /*! Immutable name of the creator for the bridge */
+               AST_STRING_FIELD(creator);
+               /*! Immutable name given to the bridge by its creator */
+               AST_STRING_FIELD(name);
+               /*! Immutable bridge UUID. */
+               AST_STRING_FIELD(uniqueid);
+       );
 };
 
 /*! \brief Bridge base class virtual method table. */
@@ -324,6 +331,8 @@ extern struct ast_bridge_methods ast_bridge_base_v_table;
  *
  * \param capabilities The capabilities that we require to be used on the bridge
  * \param flags Flags that will alter the behavior of the bridge
+ * \param creator Entity that created the bridge (optional)
+ * \param name Name given to the bridge by its creator (optional, requires named creator)
  *
  * \retval a pointer to a new bridge on success
  * \retval NULL on failure
@@ -338,7 +347,7 @@ extern struct ast_bridge_methods ast_bridge_base_v_table;
  * This creates a no frills two party bridge that will be
  * destroyed once one of the channels hangs up.
  */
-struct ast_bridge *ast_bridge_base_new(uint32_t capabilities, unsigned int flags);
+struct ast_bridge *ast_bridge_base_new(uint32_t capabilities, unsigned int flags, const char *creator, const char *name);
 
 /*!
  * \brief Try locking the bridge.
index 871abb8..e9726a1 100644 (file)
@@ -87,6 +87,8 @@ struct ast_bridge *bridge_alloc(size_t size, const struct ast_bridge_methods *v_
  * \param self Bridge to operate upon. (Tolerates a NULL pointer)
  * \param capabilities The capabilities that we require to be used on the bridge
  * \param flags Flags that will alter the behavior of the bridge
+ * \param creator Entity that created the bridge (optional)
+ * \param name Name given to the bridge by its creator (optional, requires named creator)
  *
  * \retval self on success
  * \retval NULL on failure, self is already destroyed
@@ -96,13 +98,13 @@ struct ast_bridge *bridge_alloc(size_t size, const struct ast_bridge_methods *v_
  * \code
  * struct ast_bridge *bridge;
  * bridge = bridge_alloc(sizeof(*bridge), &ast_bridge_base_v_table);
- * bridge = bridge_base_init(bridge, AST_BRIDGE_CAPABILITY_1TO1MIX, AST_BRIDGE_FLAG_DISSOLVE_HANGUP);
+ * bridge = bridge_base_init(bridge, AST_BRIDGE_CAPABILITY_1TO1MIX, AST_BRIDGE_FLAG_DISSOLVE_HANGUP, NULL, NULL);
  * \endcode
  *
  * This creates a no frills two party bridge that will be
  * destroyed once one of the channels hangs up.
  */
-struct ast_bridge *bridge_base_init(struct ast_bridge *self, uint32_t capabilities, unsigned int flags);
+struct ast_bridge *bridge_base_init(struct ast_bridge *self, uint32_t capabilities, unsigned int flags, const char *creator, const char *name);
 
 /*!
  * \internal
index 56e039b..ac5c648 100644 (file)
@@ -597,11 +597,12 @@ int stasis_app_control_queue_control(struct stasis_app_control *control,
  * \brief Create a bridge of the specified type.
  *
  * \param type The type of bridge to be created
+ * \param name Optional name to give to the bridge
  *
  * \return New bridge.
  * \return \c NULL on error.
  */
-struct ast_bridge *stasis_app_bridge_create(const char *type);
+struct ast_bridge *stasis_app_bridge_create(const char *type, const char *name);
 
 /*!
  * \brief Returns the bridge with the given id.
index 9412bf0..2d15a33 100644 (file)
@@ -42,6 +42,10 @@ struct ast_bridge_snapshot {
                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);
        );
        /*! AO2 container of bare channel uniqueid strings participating in the bridge.
         * Allocated from ast_str_container_alloc() */
index e2c46ac..8fd7847 100644 (file)
@@ -533,9 +533,11 @@ static void bridge_tech_deferred_destroy(struct ast_bridge *bridge, struct ast_f
        struct ast_bridge dummy_bridge = {
                .technology = deferred->tech,
                .tech_pvt = deferred->tech_pvt,
+               .creator = bridge->creator,
+               .name = bridge->name,
+               .uniqueid = bridge->uniqueid,
                };
 
-       ast_copy_string(dummy_bridge.uniqueid, bridge->uniqueid, sizeof(dummy_bridge.uniqueid));
        ast_debug(1, "Bridge %s: calling %s technology destructor (deferred, dummy)\n",
                dummy_bridge.uniqueid, dummy_bridge.technology->name);
        dummy_bridge.technology->destroy(&dummy_bridge);
@@ -679,6 +681,8 @@ static void destroy_bridge(void *obj)
        cleanup_video_mode(bridge);
 
        stasis_cp_single_unsubscribe(bridge->topics);
+
+       ast_string_field_free_memory(bridge);
 }
 
 struct ast_bridge *bridge_register(struct ast_bridge *bridge)
@@ -714,19 +718,35 @@ struct ast_bridge *bridge_alloc(size_t size, const struct ast_bridge_methods *v_
        }
 
        bridge = ao2_alloc(size, destroy_bridge);
-       if (bridge) {
-               bridge->v_table = v_table;
+       if (!bridge) {
+               return NULL;
+       }
+
+       if (ast_string_field_init(bridge, 80)) {
+               ao2_cleanup(bridge);
+               return NULL;
        }
+
+       bridge->v_table = v_table;
+
        return bridge;
 }
 
-struct ast_bridge *bridge_base_init(struct ast_bridge *self, uint32_t capabilities, unsigned int flags)
+struct ast_bridge *bridge_base_init(struct ast_bridge *self, uint32_t capabilities, unsigned int flags, const char *creator, const char *name)
 {
+       char uuid_hold[AST_UUID_STR_LEN];
+
        if (!self) {
                return NULL;
        }
 
-       ast_uuid_generate_str(self->uniqueid, sizeof(self->uniqueid));
+       ast_uuid_generate_str(uuid_hold, AST_UUID_STR_LEN);
+       ast_string_field_set(self, uniqueid, uuid_hold);
+       ast_string_field_set(self, creator, creator);
+       if (!ast_strlen_zero(creator)) {
+               ast_string_field_set(self, name, name);
+       }
+
        ast_set_flag(&self->feature_flags, flags);
        self->allowed_capabilities = capabilities;
 
@@ -881,12 +901,12 @@ struct ast_bridge_methods ast_bridge_base_v_table = {
        .get_merge_priority = bridge_base_get_merge_priority,
 };
 
-struct ast_bridge *ast_bridge_base_new(uint32_t capabilities, unsigned int flags)
+struct ast_bridge *ast_bridge_base_new(uint32_t capabilities, unsigned int flags, const char *creator, const char *name)
 {
        void *bridge;
 
        bridge = bridge_alloc(sizeof(struct ast_bridge), &ast_bridge_base_v_table);
-       bridge = bridge_base_init(bridge, capabilities, flags);
+       bridge = bridge_base_init(bridge, capabilities, flags, creator, name);
        bridge = bridge_register(bridge);
        return bridge;
 }
@@ -991,6 +1011,9 @@ static int smart_bridge_operation(struct ast_bridge *bridge)
        struct ast_bridge dummy_bridge = {
                .technology = bridge->technology,
                .tech_pvt = bridge->tech_pvt,
+               .creator = bridge->creator,
+               .name = bridge->name,
+               .uniqueid = bridge->uniqueid,
        };
 
        if (bridge->dissolved) {
@@ -1043,8 +1066,6 @@ static int smart_bridge_operation(struct ast_bridge *bridge)
                return 0;
        }
 
-       ast_copy_string(dummy_bridge.uniqueid, bridge->uniqueid, sizeof(dummy_bridge.uniqueid));
-
        if (old_technology->destroy) {
                struct tech_deferred_destroy deferred_tech_destroy = {
                        .tech = dummy_bridge.technology,
index eaec689..317c574 100644 (file)
@@ -3239,7 +3239,7 @@ struct ast_bridge *ast_bridge_basic_new(void)
        bridge = bridge_alloc(sizeof(struct ast_bridge), &ast_bridge_basic_v_table);
        bridge = bridge_base_init(bridge,
                AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_1TO1MIX
-                       | AST_BRIDGE_CAPABILITY_MULTIMIX, NORMAL_FLAGS);
+                       | AST_BRIDGE_CAPABILITY_MULTIMIX, NORMAL_FLAGS, NULL, NULL);
        bridge = bridge_basic_personality_alloc(bridge);
        bridge = bridge_register(bridge);
        return bridge;
index e012ebb..9028128 100644 (file)
@@ -156,10 +156,14 @@ struct ast_str *ast_manager_build_bridge_state_string_prefix(
                "%sBridgeUniqueid: %s\r\n"
                "%sBridgeType: %s\r\n"
                "%sBridgeTechnology: %s\r\n"
+               "%sBridgeCreator: %s\r\n"
+               "%sBridgeName: %s\r\n"
                "%sBridgeNumChannels: %d\r\n",
                prefix, snapshot->uniqueid,
                prefix, snapshot->subclass,
                prefix, snapshot->technology,
+               prefix, ast_strlen_zero(snapshot->creator) ? "<unknown>": snapshot->creator,
+               prefix, ast_strlen_zero(snapshot->name) ? "<unknown>": snapshot->name,
                prefix, snapshot->num_channels);
        if (!res) {
                ast_free(out);
index b92d048..7f6679b 100644 (file)
@@ -242,6 +242,8 @@ struct ast_bridge_snapshot *ast_bridge_snapshot_create(struct ast_bridge *bridge
        ast_string_field_set(snapshot, uniqueid, bridge->uniqueid);
        ast_string_field_set(snapshot, technology, bridge->technology->name);
        ast_string_field_set(snapshot, subclass, bridge->v_table->name);
+       ast_string_field_set(snapshot, creator, bridge->creator);
+       ast_string_field_set(snapshot, name, bridge->name);
 
        snapshot->feature_flags = bridge->feature_flags;
        snapshot->capabilities = bridge->technology->capabilities;
@@ -548,11 +550,13 @@ struct ast_json *ast_bridge_snapshot_to_json(
                return NULL;
        }
 
-       json_bridge = ast_json_pack("{s: s, s: s, s: s, s: s, s: o}",
+       json_bridge = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: o}",
                "id", snapshot->uniqueid,
                "technology", snapshot->technology,
                "bridge_type", capability2str(snapshot->capabilities),
                "bridge_class", snapshot->subclass,
+               "creator", snapshot->creator,
+               "name", snapshot->name,
                "channels", json_channels);
        if (!json_bridge) {
                return NULL;
index d99240b..a048180 100644 (file)
@@ -891,7 +891,9 @@ int ast_ari_validate_bridge(struct ast_json *json)
        int has_bridge_class = 0;
        int has_bridge_type = 0;
        int has_channels = 0;
+       int has_creator = 0;
        int has_id = 0;
+       int has_name = 0;
        int has_technology = 0;
 
        for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
@@ -926,6 +928,16 @@ int ast_ari_validate_bridge(struct ast_json *json)
                                res = 0;
                        }
                } else
+               if (strcmp("creator", ast_json_object_iter_key(iter)) == 0) {
+                       int prop_is_valid;
+                       has_creator = 1;
+                       prop_is_valid = ast_ari_validate_string(
+                               ast_json_object_iter_value(iter));
+                       if (!prop_is_valid) {
+                               ast_log(LOG_ERROR, "ARI Bridge field creator failed validation\n");
+                               res = 0;
+                       }
+               } else
                if (strcmp("id", ast_json_object_iter_key(iter)) == 0) {
                        int prop_is_valid;
                        has_id = 1;
@@ -936,6 +948,16 @@ int ast_ari_validate_bridge(struct ast_json *json)
                                res = 0;
                        }
                } else
+               if (strcmp("name", ast_json_object_iter_key(iter)) == 0) {
+                       int prop_is_valid;
+                       has_name = 1;
+                       prop_is_valid = ast_ari_validate_string(
+                               ast_json_object_iter_value(iter));
+                       if (!prop_is_valid) {
+                               ast_log(LOG_ERROR, "ARI Bridge field name failed validation\n");
+                               res = 0;
+                       }
+               } else
                if (strcmp("technology", ast_json_object_iter_key(iter)) == 0) {
                        int prop_is_valid;
                        has_technology = 1;
@@ -969,11 +991,21 @@ int ast_ari_validate_bridge(struct ast_json *json)
                res = 0;
        }
 
+       if (!has_creator) {
+               ast_log(LOG_ERROR, "ARI Bridge missing required field creator\n");
+               res = 0;
+       }
+
        if (!has_id) {
                ast_log(LOG_ERROR, "ARI Bridge missing required field id\n");
                res = 0;
        }
 
+       if (!has_name) {
+               ast_log(LOG_ERROR, "ARI Bridge missing required field name\n");
+               res = 0;
+       }
+
        if (!has_technology) {
                ast_log(LOG_ERROR, "ARI Bridge missing required field technology\n");
                res = 0;
index 22ab43b..3266939 100644 (file)
@@ -1083,7 +1083,9 @@ ari_validator ast_ari_validate_application_fn(void);
  * - bridge_class: string (required)
  * - bridge_type: string (required)
  * - channels: List[string] (required)
+ * - creator: string (required)
  * - id: string (required)
+ * - name: string (required)
  * - technology: string (required)
  * LiveRecording
  * - cause: string
index c074718..ed3eba8 100644 (file)
@@ -695,7 +695,7 @@ void ast_ari_bridges_create(struct ast_variable *headers,
        struct ast_ari_bridges_create_args *args,
        struct ast_ari_response *response)
 {
-       RAII_VAR(struct ast_bridge *, bridge, stasis_app_bridge_create(args->type), ao2_cleanup);
+       RAII_VAR(struct ast_bridge *, bridge, stasis_app_bridge_create(args->type, args->name), ao2_cleanup);
        RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
 
        if (!bridge) {
index c5a8322..a7ccd31 100644 (file)
@@ -54,6 +54,8 @@ void ast_ari_bridges_list(struct ast_variable *headers, struct ast_ari_bridges_l
 struct ast_ari_bridges_create_args {
        /*! \brief Type of bridge to create. */
        const char *type;
+       /*! \brief Name to give to the bridge being created. */
+       const char *name;
 };
 /*!
  * \brief Create a new bridge.
index 9bc1345..bb9dbf3 100644 (file)
@@ -456,7 +456,7 @@ struct ast_bridge *bridge_parking_new(struct parking_lot *bridge_lot)
        bridge = bridge_alloc(sizeof(struct ast_bridge_parking), &ast_bridge_parking_v_table);
        bridge = bridge_base_init(bridge, AST_BRIDGE_CAPABILITY_HOLDING,
                AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
-               | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM);
+               | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM,  "Parking", bridge_lot->name);
        bridge = ast_bridge_parking_init(bridge, bridge_lot);
        bridge = bridge_register(bridge);
        return bridge;
index a68fbf6..242512d 100644 (file)
@@ -127,6 +127,9 @@ static void ast_ari_bridges_create_cb(
                if (strcmp(i->name, "type") == 0) {
                        args.type = (i->value);
                } else
+               if (strcmp(i->name, "name") == 0) {
+                       args.name = (i->value);
+               } else
                {}
        }
        /* Look for a JSON request entity */
@@ -149,6 +152,10 @@ static void ast_ari_bridges_create_cb(
        if (field) {
                args.type = ast_json_string_get(field);
        }
+       field = ast_json_object_get(body, "name");
+       if (field) {
+               args.name = ast_json_string_get(field);
+       }
        ast_ari_bridges_create(headers, &args, response);
 #if defined(AST_DEVMODE)
        code = response->response_code;
index 6914627..71a18a0 100644 (file)
@@ -585,7 +585,7 @@ static void control_unlink(struct stasis_app_control *control)
        ao2_cleanup(control);
 }
 
-struct ast_bridge *stasis_app_bridge_create(const char *type)
+struct ast_bridge *stasis_app_bridge_create(const char *type, const char *name)
 {
        struct ast_bridge *bridge;
        int capabilities;
@@ -604,7 +604,7 @@ struct ast_bridge *stasis_app_bridge_create(const char *type)
                return NULL;
        }
 
-       bridge = ast_bridge_base_new(capabilities, flags);
+       bridge = ast_bridge_base_new(capabilities, flags, "Stasis", name);
        if (bridge) {
                if (!ao2_link(app_bridges, bridge)) {
                        ast_bridge_destroy(bridge, 0);
index d7f63ad..33a0d65 100644 (file)
                                                                        "holding"
                                                                ]
                                                        }
+                                               },
+                                               {
+                                                       "name": "name",
+                                                       "description": "Name to give to the bridge being created.",
+                                                       "paramType": "query",
+                                                       "required": false,
+                                                       "allowMultiple": false,
+                                                       "dataType": "string"
                                                }
                                        ]
                                }
                                        "description": "Bridging class",
                                        "required": true
                                },
+                               "creator": {
+                                       "type": "string",
+                                       "description": "Entity that created the bridge",
+                                       "required": true
+                               },
+                               "name": {
+                                       "type": "string",
+                                       "description": "Name the creator gave the bridge",
+                                       "required": true
+                               },
                                "channels": {
                                        "type": "List[string]",
                                        "description": "Ids of channels participating in this bridge",