summaryrefslogtreecommitdiff
path: root/main/endpoints.c
diff options
context:
space:
mode:
Diffstat (limited to 'main/endpoints.c')
-rw-r--r--main/endpoints.c110
1 files changed, 84 insertions, 26 deletions
diff --git a/main/endpoints.c b/main/endpoints.c
index 10b32e268..985f6e634 100644
--- a/main/endpoints.c
+++ b/main/endpoints.c
@@ -46,8 +46,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
/*! Buckets for endpoint hash. Keep it prime! */
#define ENDPOINT_BUCKETS 127
+/*! Buckets for technology endpoints. */
+#define TECH_ENDPOINT_BUCKETS 11
+
static struct ao2_container *endpoints;
+static struct ao2_container *tech_endpoints;
+
struct ast_endpoint {
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(tech); /*!< Technology (SIP, IAX2, etc.). */
@@ -69,6 +74,8 @@ struct ast_endpoint {
struct stasis_message_router *router;
/*! ast_str_container of channels associated with this endpoint */
struct ao2_container *channel_ids;
+ /*! Forwarding subscription from an endpoint to its tech endpoint */
+ struct stasis_forward *tech_forward;
};
static int endpoint_hash(const void *obj, int flags)
@@ -121,7 +128,13 @@ static int endpoint_cmp(void *obj, void *arg, int flags)
struct ast_endpoint *ast_endpoint_find_by_id(const char *id)
{
- return ao2_find(endpoints, id, OBJ_KEY);
+ struct ast_endpoint *endpoint = ao2_find(endpoints, id, OBJ_KEY);
+
+ if (!endpoint) {
+ endpoint = ao2_find(tech_endpoints, id, OBJ_KEY);
+ }
+
+ return endpoint;
}
struct stasis_topic *ast_endpoint_topic(struct ast_endpoint *endpoint)
@@ -181,6 +194,8 @@ static void endpoint_dtor(void *obj)
ao2_cleanup(endpoint->router);
endpoint->router = NULL;
+ endpoint->tech_forward = stasis_forward_cancel(endpoint->tech_forward);
+
stasis_cp_single_unsubscribe(endpoint->topics);
endpoint->topics = NULL;
@@ -196,6 +211,7 @@ int ast_endpoint_add_channel(struct ast_endpoint *endpoint,
{
ast_assert(chan != NULL);
ast_assert(endpoint != NULL);
+ ast_assert(!ast_strlen_zero(endpoint->resource));
ast_channel_forward_endpoint(chan, endpoint);
@@ -242,19 +258,21 @@ static void endpoint_default(void *data,
}
}
-struct ast_endpoint *ast_endpoint_create(const char *tech, const char *resource)
+static struct ast_endpoint *endpoint_internal_create(const char *tech, const char *resource)
{
RAII_VAR(struct ast_endpoint *, endpoint, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_endpoint *, tech_endpoint, NULL, ao2_cleanup);
int r = 0;
- if (ast_strlen_zero(tech)) {
- ast_log(LOG_ERROR, "Endpoint tech cannot be empty\n");
- return NULL;
- }
-
- if (ast_strlen_zero(resource)) {
- ast_log(LOG_ERROR, "Endpoint resource cannot be empty\n");
- return NULL;
+ /* Get/create the technology endpoint */
+ if (!ast_strlen_zero(resource)) {
+ tech_endpoint = ao2_find(tech_endpoints, tech, OBJ_KEY);
+ if (!tech_endpoint) {
+ tech_endpoint = endpoint_internal_create(tech, NULL);
+ if (!tech_endpoint) {
+ return NULL;
+ }
+ }
}
endpoint = ao2_alloc(sizeof(*endpoint), endpoint_dtor);
@@ -268,10 +286,12 @@ struct ast_endpoint *ast_endpoint_create(const char *tech, const char *resource)
if (ast_string_field_init(endpoint, 80) != 0) {
return NULL;
}
-
ast_string_field_set(endpoint, tech, tech);
- ast_string_field_set(endpoint, resource, resource);
- ast_string_field_build(endpoint, id, "%s/%s", tech, resource);
+ ast_string_field_set(endpoint, resource, S_OR(resource, ""));
+ ast_string_field_build(endpoint, id, "%s%s%s",
+ tech,
+ !ast_strlen_zero(resource) ? "/" : "",
+ S_OR(resource, ""));
/* All access to channel_ids should be covered by the endpoint's
* lock; no extra lock needed. */
@@ -287,24 +307,47 @@ struct ast_endpoint *ast_endpoint_create(const char *tech, const char *resource)
return NULL;
}
- endpoint->router = stasis_message_router_create(ast_endpoint_topic(endpoint));
- if (!endpoint->router) {
- return NULL;
- }
- r |= stasis_message_router_add(endpoint->router,
- stasis_cache_clear_type(), endpoint_cache_clear,
- endpoint);
- r |= stasis_message_router_set_default(endpoint->router,
- endpoint_default, endpoint);
-
- endpoint_publish_snapshot(endpoint);
+ if (!ast_strlen_zero(resource)) {
+ endpoint->router = stasis_message_router_create(ast_endpoint_topic(endpoint));
+ if (!endpoint->router) {
+ return NULL;
+ }
+ r |= stasis_message_router_add(endpoint->router,
+ stasis_cache_clear_type(), endpoint_cache_clear,
+ endpoint);
+ r |= stasis_message_router_set_default(endpoint->router,
+ endpoint_default, endpoint);
+ if (r) {
+ return NULL;
+ }
- ao2_link(endpoints, endpoint);
+ endpoint->tech_forward = stasis_forward_all(stasis_cp_single_topic(endpoint->topics),
+ stasis_cp_single_topic(tech_endpoint->topics));
+ endpoint_publish_snapshot(endpoint);
+ ao2_link(endpoints, endpoint);
+ } else {
+ ao2_link(tech_endpoints, endpoint);
+ }
ao2_ref(endpoint, +1);
return endpoint;
}
+struct ast_endpoint *ast_endpoint_create(const char *tech, const char *resource)
+{
+ if (ast_strlen_zero(tech)) {
+ ast_log(LOG_ERROR, "Endpoint tech cannot be empty\n");
+ return NULL;
+ }
+
+ if (ast_strlen_zero(resource)) {
+ ast_log(LOG_ERROR, "Endpoint resource cannot be empty\n");
+ return NULL;
+ }
+
+ return endpoint_internal_create(tech, resource);
+}
+
static struct stasis_message *create_endpoint_snapshot_message(struct ast_endpoint *endpoint)
{
RAII_VAR(struct ast_endpoint_snapshot *, snapshot, NULL, ao2_cleanup);
@@ -368,6 +411,8 @@ void ast_endpoint_set_state(struct ast_endpoint *endpoint,
enum ast_endpoint_state state)
{
ast_assert(endpoint != NULL);
+ ast_assert(!ast_strlen_zero(endpoint->resource));
+
ao2_lock(endpoint);
endpoint->state = state;
ao2_unlock(endpoint);
@@ -378,6 +423,8 @@ void ast_endpoint_set_max_channels(struct ast_endpoint *endpoint,
int max_channels)
{
ast_assert(endpoint != NULL);
+ ast_assert(!ast_strlen_zero(endpoint->resource));
+
ao2_lock(endpoint);
endpoint->max_channels = max_channels;
ao2_unlock(endpoint);
@@ -407,6 +454,9 @@ struct ast_endpoint_snapshot *ast_endpoint_snapshot_create(
void *obj;
SCOPED_AO2LOCK(lock, endpoint);
+ ast_assert(endpoint != NULL);
+ ast_assert(!ast_strlen_zero(endpoint->resource));
+
channel_count = ao2_container_count(endpoint->channel_ids);
snapshot = ao2_alloc(
@@ -440,6 +490,9 @@ static void endpoint_cleanup(void)
{
ao2_cleanup(endpoints);
endpoints = NULL;
+
+ ao2_cleanup(tech_endpoints);
+ tech_endpoints = NULL;
}
int ast_endpoint_init(void)
@@ -448,10 +501,15 @@ int ast_endpoint_init(void)
endpoints = ao2_container_alloc(ENDPOINT_BUCKETS, endpoint_hash,
endpoint_cmp);
-
if (!endpoints) {
return -1;
}
+ tech_endpoints = ao2_container_alloc(TECH_ENDPOINT_BUCKETS, endpoint_hash,
+ endpoint_cmp);
+ if (!tech_endpoints) {
+ return -1;
+ }
+
return 0;
}