summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorDavid M. Lee <dlee@digium.com>2013-05-08 13:39:08 +0000
committerDavid M. Lee <dlee@digium.com>2013-05-08 13:39:08 +0000
commite06e519a908dd7640764778cfb91c29699f3f679 (patch)
treef85a10cf963caba787a9e506963e0ef4d63c0ff1 /include
parentefd28c676a4a467f1bb31d3359c43c2f1d70029b (diff)
Initial support for endpoints.
An endpoint is an external device/system that may offer/accept channels to/from Asterisk. While this is a very useful concept for end users, it is surprisingly not a core concept within Asterisk itself. This patch defines ast_endpoint as a separate object, which channel drivers may use to expose their concept of an endpoint. As the channel driver creates channels, it can use ast_endpoint_add_channel() to associate channels to the endpoint. This updated the endpoint appropriately, and forwards all of the channel's events to the endpoint's topic. In order to avoid excessive locking on the endpoint object itself, the mutable state is not accessible via getters. Instead, you can create a snapshot using ast_endpoint_snapshot_create() to get a consistent snapshot of the internal state. This patch also includes a set of topics and messages associated with endpoints, and implementations of the endpoint-related RESTful API. chan_sip was updated to create endpoints with SIP peers, but the state of the endpoints is not updated with the state of the peer. Along for the ride in this patch is a Stasis test API. This is a stasis_message_sink object, which can be subscribed to a Stasis topic. It has functions for blocking while waiting for conditions in the message sink to be fulfilled. (closes issue ASTERISK-21421) Review: https://reviewboard.asterisk.org/r/2492/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@387932 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'include')
-rw-r--r--include/asterisk/astobj2.h51
-rw-r--r--include/asterisk/endpoints.h170
-rw-r--r--include/asterisk/stasis.h16
-rw-r--r--include/asterisk/stasis_endpoints.h154
-rw-r--r--include/asterisk/stasis_test.h142
5 files changed, 533 insertions, 0 deletions
diff --git a/include/asterisk/astobj2.h b/include/asterisk/astobj2.h
index 70a9041c3..502cc744c 100644
--- a/include/asterisk/astobj2.h
+++ b/include/asterisk/astobj2.h
@@ -1890,4 +1890,55 @@ void __ao2_cleanup_debug(void *obj, const char *file, int line, const char *func
#define ao2_cleanup(obj) __ao2_cleanup(obj)
#endif
void ao2_iterator_cleanup(struct ao2_iterator *iter);
+
+
+/* XXX TODO BUGBUG and all the other things...
+ * These functions should eventually be moved elsewhere, but the utils folder
+ * won't compile with them in strings.h
+ */
+
+/*!
+ * \since 12
+ * \brief Allocates a hash container for bare strings
+ *
+ * \param buckets The number of buckets to use for the hash container
+ *
+ * \retval AO2 container for strings
+ * \retval NULL if allocation failed
+ */
+#define ast_str_container_alloc(buckets) ast_str_container_alloc_options(AO2_ALLOC_OPT_LOCK_MUTEX, buckets)
+
+/*!
+ * \since 12
+ * \brief Allocates a hash container for bare strings
+ *
+ * \param opts Options to be provided to the container
+ * \param buckets The number of buckets to use for the hash container
+ *
+ * \retval AO2 container for strings
+ * \retval NULL if allocation failed
+ */
+struct ao2_container *ast_str_container_alloc_options(enum ao2_container_opts opts, int buckets);
+
+/*!
+ * \since 12
+ * \brief Adds a string to a string container allocated by ast_str_container_alloc
+ *
+ * \param str_container The container to which to add a string
+ * \param add The string to add to the container
+ *
+ * \retval zero on success
+ * \retval non-zero if the operation failed
+ */
+int ast_str_container_add(struct ao2_container *str_container, const char *add);
+
+/*!
+ * \since 12
+ * \brief Removes a string from a string container allocated by ast_str_container_alloc
+ *
+ * \param str_container The container from which to remove a string
+ * \param remove The string to remove from the container
+ */
+void ast_str_container_remove(struct ao2_container *str_container, const char *remove);
+
#endif /* _ASTERISK_ASTOBJ2_H */
diff --git a/include/asterisk/endpoints.h b/include/asterisk/endpoints.h
new file mode 100644
index 000000000..b0be1cf38
--- /dev/null
+++ b/include/asterisk/endpoints.h
@@ -0,0 +1,170 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#ifndef _ASTERISK_ENDPOINTS_H
+#define _ASTERISK_ENDPOINTS_H
+
+/*! \file
+ *
+ * \brief Endpoint abstractions.
+ *
+ * \author David M. Lee, II <dlee@digium.com>
+ * \since 12
+ *
+ * An endpoint is an external device/system that may offer/accept channels
+ * to/from Asterisk. While this is a very useful concept for end users, it is
+ * surprisingly \a not a core concept within Asterisk iteself.
+ *
+ * This file defines \ref ast_endpoint as a seperate object, which channel
+ * drivers may use to expose their concept of an endpoint. As the channel driver
+ * creates channels, it can use ast_endpoint_add_channel() to associate channels
+ * to the endpoint. This updates the endpoint appropriately, and forwards all of
+ * the channel's events to the endpoint's topic.
+ *
+ * In order to avoid excessive locking on the endpoint object itself, the
+ * mutable state is not accessible via getters. Instead, you can create a
+ * snapshot using ast_endpoint_snapshot_create() to get a consistent snapshot of
+ * the internal state.
+ */
+
+#include "asterisk/json.h"
+
+/*!
+ * \brief Valid states for an endpoint.
+ * \since 12
+ */
+enum ast_endpoint_state {
+ /*! The endpoint state is not known. */
+ AST_ENDPOINT_UNKNOWN,
+ /*! The endpoint is not available. */
+ AST_ENDPOINT_OFFLINE,
+ /*! The endpoint is available. */
+ AST_ENDPOINT_ONLINE,
+};
+
+/*!
+ * \brief Returns a string representation of the given endpoint state.
+ *
+ * \param state Endpoint state.
+ * \return String representation of \a state.
+ * \return \c "?" if \a state isn't in \ref ast_endpoint_state.
+ */
+const char *ast_endpoint_state_to_string(enum ast_endpoint_state state);
+
+/*!
+ * \brief Opaque struct representing an endpoint.
+ *
+ * An endpoint is an external device/system that may offer/accept channels
+ * to/from Asterisk.
+ *
+ * \since 12
+ */
+struct ast_endpoint;
+
+/*!
+ * \brief Create an endpoint struct.
+ *
+ * The endpoint is created with a state of UNKNOWN and max_channels of -1
+ * (unlimited). While \ref ast_endpoint is AO2 managed, you have to
+ * shut it down with ast_endpoint_shutdown() to clean up references from
+ * subscriptions.
+ *
+ * \param tech Technology for this endpoint.
+ * \param resource Name of this endpoint.
+ * \return Newly created endpoint.
+ * \return \c NULL on error.
+ * \since 12
+ */
+struct ast_endpoint *ast_endpoint_create(const char *tech, const char *resource);
+
+/*!
+ * \brief Shutsdown an \ref ast_endpoint.
+ *
+ * \param endpoint Endpoint to shut down.
+ * \since 12
+ */
+void ast_endpoint_shutdown(struct ast_endpoint *endpoint);
+
+/*!
+ * \brief Gets the technology of the given endpoint.
+ *
+ * This is an immutable string describing the channel provider technology
+ * (SIP, IAX2, etc.).
+ *
+ * \param endpoint The endpoint.
+ * \return Tec of the endpoint.
+ * \return \c NULL if endpoint is \c NULL.
+ * \since 12
+ */
+const char *ast_endpoint_get_tech(const struct ast_endpoint *endpoint);
+
+/*!
+ * \brief Gets the resource name of the given endpoint.
+ *
+ * This is unique for the endpoint's technology, and immutable.
+ *
+ * \param endpoint The endpoint.
+ * \return Resource name of the endpoint.
+ * \return \c NULL if endpoint is \c NULL.
+ * \since 12
+ */
+const char *ast_endpoint_get_resource(const struct ast_endpoint *endpoint);
+
+/*!
+ * \brief Updates the state of the given endpoint.
+ *
+ * \param endpoint Endpoint to modify.
+ * \param state New state.
+ * \since 12
+ */
+void ast_endpoint_set_state(struct ast_endpoint *endpoint,
+ enum ast_endpoint_state state);
+
+/*!
+ * \brief Updates the maximum number of channels an endpoint supports.
+ *
+ * Set to -1 for unlimited channels.
+ *
+ * \param endpoint Endpoint to modify.
+ * \param max_channels Maximum number of concurrent channels this endpoint
+ * supports.
+ */
+void ast_endpoint_set_max_channels(struct ast_endpoint *endpoint,
+ int max_channels);
+
+
+/*!
+ * \since 12
+ * \brief Adds a channel to the given endpoint.
+ *
+ * This updates the endpoint's statistics, as well as forwarding all of the
+ * channel's messages to the endpoint's topic.
+ *
+ * The channel is automagically removed from the endpoint when it is disposed
+ * of.
+ *
+ * \param endpoint
+ * \param chan Channel.
+ * \retval 0 on success.
+ * \retval Non-zero on error.
+ */
+int ast_endpoint_add_channel(struct ast_endpoint *endpoint,
+ struct ast_channel *chan);
+
+
+#endif /* _ASTERISK_ENDPOINTS_H */
diff --git a/include/asterisk/stasis.h b/include/asterisk/stasis.h
index 07c3c5c6b..48d51e369 100644
--- a/include/asterisk/stasis.h
+++ b/include/asterisk/stasis.h
@@ -431,6 +431,22 @@ struct stasis_cache_update {
};
/*!
+ * \brief Cache clear message.
+ */
+struct stasis_cache_clear {
+ /*! Type of object being cleared from the cache */
+ struct stasis_message_type *type;
+ /*! Id of the object being cleared from the cache */
+ char id[];
+};
+
+/*!
+ * \brief Message type for \ref stasis_cache_clear.
+ * \since 12
+ */
+struct stasis_message_type *stasis_cache_clear_type(void);
+
+/*!
* \brief A message which instructs the caching topic to remove an entry from its cache.
* \param type Message type.
* \param id Unique id of the snapshot to clear.
diff --git a/include/asterisk/stasis_endpoints.h b/include/asterisk/stasis_endpoints.h
new file mode 100644
index 000000000..2aeb614e6
--- /dev/null
+++ b/include/asterisk/stasis_endpoints.h
@@ -0,0 +1,154 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#ifndef _ASTERISK_STASIS_ENDPOINTS_H
+#define _ASTERISK_STASIS_ENDPOINTS_H
+
+/*! \file
+ *
+ * \brief Endpoint abstractions.
+ *
+ * \author David M. Lee, II <dlee@digium.com>
+ * \since 12
+ */
+
+#include "asterisk/endpoints.h"
+#include "asterisk/json.h"
+#include "asterisk/stasis.h"
+#include "asterisk/stringfields.h"
+
+/*! \addtogroup StasisTopicsAndMessages
+ * @{
+ */
+
+/*!
+ * \brief A snapshot of an endpoint's state.
+ *
+ * The id for an endpoint is tech/resource. The duplication is needed because
+ * there are several cases where any of the three values would be needed, and
+ * constantly splitting or reassembling would be a pain.
+ *
+ * \since 12
+ */
+struct ast_endpoint_snapshot {
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(id); /*!< unique id for this endpoint. */
+ AST_STRING_FIELD(tech); /*!< Channel technology */
+ AST_STRING_FIELD(resource); /*!< Tech-unique name */
+ );
+
+ /*! Endpoint state */
+ enum ast_endpoint_state state;
+ /*!
+ * Maximum number of channels this endpoint supports. If the upper limit
+ * for an endpoint is unknown, this field is set to -1.
+ */
+ int max_channels;
+ /*! Number of channels currently active on this endpoint */
+ int num_channels;
+ /*! Channel ids */
+ char *channel_ids[];
+};
+
+/*!
+ * \brief Blob of data associated with an endpoint.
+ *
+ * The blob is actually a JSON object of structured data. It has a "type" field
+ * which contains the type string describing this blob.
+ *
+ * \since 12
+ */
+struct ast_endpoint_blob {
+ struct ast_endpoint_snapshot *snapshot;
+ struct ast_json *blob;
+};
+
+/*!
+ * \brief Message type for \ref ast_endpoint_snapshot.
+ * \since 12
+ */
+struct stasis_message_type *ast_endpoint_snapshot_type(void);
+
+/*!
+ * \brief Create a snapshot of an endpoint
+ * \param endpoint Endpoint to snap a shot of.
+ * \return Snapshot of the endpoint.
+ * \return \c NULL on error.
+ * \since 12
+ */
+struct ast_endpoint_snapshot *ast_endpoint_snapshot_create(
+ struct ast_endpoint *endpoint);
+
+/*!
+ * \brief Returns the topic for a specific endpoint.
+ *
+ * \param endpoint The endpoint.
+ * \return The topic for the given endpoint.
+ * \return ast_endpoint_topic_all() if endpoint is \c NULL.
+ * \since 12
+ */
+struct stasis_topic *ast_endpoint_topic(struct ast_endpoint *endpoint);
+
+/*!
+ * \brief Topic for all endpoint releated messages.
+ * \since 12
+ */
+struct stasis_topic *ast_endpoint_topic_all(void);
+
+/*!
+ * \brief Cached topic for all endpoint related messages.
+ * \since 12
+ */
+struct stasis_caching_topic *ast_endpoint_topic_all_cached(void);
+
+/*!
+ * \brief Retrieve the most recent snapshot for the endpoint with the given
+ * name.
+ *
+ * \param tech Name of the endpoint's technology.
+ * \param resource Resource name of the endpoint.
+ * \return Snapshot of the endpoint with the given name.
+ * \return \c NULL if endpoint is not found, or on error.
+ * \since 12
+ */
+struct ast_endpoint_snapshot *ast_endpoint_latest_snapshot(const char *tech,
+ const char *resource
+);
+
+/*! @} */
+
+/*!
+ * \brief Build a JSON object from a \ref ast_endpoint_snapshot.
+ *
+ * \param snapshot Endpoint snapshot.
+ * \return JSON object representing endpoint snapshot.
+ * \return \c NULL on error
+ */
+struct ast_json *ast_endpoint_snapshot_to_json(
+ const struct ast_endpoint_snapshot *snapshot);
+
+/*!
+ * \brief Initialization function for endpoint stasis support.
+ *
+ * \return 0 on success.
+ * \return non-zero on error.
+ * \since 12
+ */
+int ast_endpoint_stasis_init(void);
+
+#endif /* _ASTERISK_STASIS_ENDPOINTS_H */
diff --git a/include/asterisk/stasis_test.h b/include/asterisk/stasis_test.h
new file mode 100644
index 000000000..ad4020a08
--- /dev/null
+++ b/include/asterisk/stasis_test.h
@@ -0,0 +1,142 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#ifndef _ASTERISK_STASIS_TEST_H
+#define _ASTERISK_STASIS_TEST_H
+
+/*!
+ * \file \brief Test infrastructure for dealing with Stasis.
+ *
+ * \author David M. Lee, II <dlee@digium.com>
+ *
+ * This file contains some helpful utilities for testing Stasis related topics
+ * and messages. The \ref stasis_message_sink is something you can subscribe to
+ * a topic which will receive all of the messages from the topic. This messages
+ * are accumulated in its \c messages field.
+ *
+ * There are a set of wait functions (stasis_message_sink_wait_for_count(),
+ * stasis_message_sink_wait_for(), etc.) which will block waiting for conditions
+ * to be met in the \ref stasis_message_sink.
+ */
+
+#include "asterisk/lock.h"
+#include "asterisk/stasis.h"
+
+#define STASIS_SINK_DEFAULT_WAIT 5000
+
+/*! \brief Structure that collects messages from a topic */
+struct stasis_message_sink {
+ /*! Condition mutex. */
+ ast_mutex_t lock;
+ /*! Condition to signal state changes */
+ ast_cond_t cond;
+ /*! Maximum number of messages messages field can hold without
+ * realloc */
+ size_t max_messages;
+ /*! Current number of messages in messages field. */
+ size_t num_messages;
+ /*! Boolean flag to be set when unsubscribe is received */
+ int is_done:1;
+ /*! Ordered array of messages received */
+ struct stasis_message **messages;
+};
+
+/*!
+ * \brief Create a message sink.
+ *
+ * This is an AO2 managed object, which you ao2_cleanup() when done. The
+ * destructor waits for an unsubscribe message to be received, to ensure the
+ * object isn't disposed of before the topic is finished.
+ */
+struct stasis_message_sink *stasis_message_sink_create(void);
+
+/*!
+ * \brief Topic callback to receive messages.
+ *
+ * We return a function pointer instead of simply exposing the function because
+ * of the vagaries of dlopen(), \c RTLD_LAZY, and function pointers. See the
+ * comment on the implementation for details why.
+ *
+ * \return Function pointer to \ref stasis_message_sink's message handling
+ * function
+ */
+stasis_subscription_cb stasis_message_sink_cb(void);
+
+/*!
+ * \brief Wait for a sink's num_messages field to reach a certain level.
+ *
+ * The optional timeout prevents complete deadlock in a test.
+ *
+ * \param sink Sink to wait on.
+ * \param num_messages sink->num_messages value to wait for.
+ * \param timeout_millis Number of milliseconds to wait. -1 to wait forever.
+ * \return Actual sink->num_messages value at return.
+ * If this is < \a num_messages, then the timeout expired.
+ */
+int stasis_message_sink_wait_for_count(struct stasis_message_sink *sink,
+ int num_messages, int timeout_millis);
+
+typedef int (*stasis_wait_cb)(struct stasis_message *msg, const void *data);
+
+/*!
+ * \brief Wait for a message that matches the given criteria.
+ *
+ * \param sink Sink to wait on.
+ * \param start Index of message to start with.
+ * \param cmp_cb comparison function. This returns true (non-zero) on match
+ * and false (zero) on match.
+ * \param timeout_millis Number of milliseconds to wait.
+ * \return Index of the matching message.
+ * \return Negative for no match.
+ */
+int stasis_message_sink_wait_for(struct stasis_message_sink *sink, int start,
+ stasis_wait_cb cmp_cb, const void *data, int timeout_millis);
+
+/*!
+ * \brief Ensures that no new messages are received.
+ *
+ * The optional timeout prevents complete deadlock in a test.
+ *
+ * \param sink Sink to wait on.
+ * \param num_messages expecte \a sink->num_messages.
+ * \param timeout_millis Number of milliseconds to wait for.
+ * \return Actual sink->num_messages value at return.
+ * If this is < \a num_messages, then the timeout expired.
+ */
+int stasis_message_sink_should_stay(struct stasis_message_sink *sink,
+ int num_messages, int timeout_millis);
+
+/*! \addtogroup StasisTopicsAndMessages
+ * @{
+ */
+
+/*!
+ * \brief Creates a test message.
+ */
+struct stasis_message *stasis_test_message_create(void);
+
+/*!
+ * \brief Gets the type of messages created by stasis_test_message_create().
+ */
+struct stasis_message_type *stasis_test_message_type(void);
+
+/*!
+ * @}
+ */
+
+#endif /* _ASTERISK_STASIS_TEST_H */