[asterisk-commits] russell: branch russell/bindings r121595 - in /team/russell/bindings: ./ apps...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Tue Jun 10 12:10:24 CDT 2008
Author: russell
Date: Tue Jun 10 12:10:24 2008
New Revision: 121595
URL: http://svn.digium.com/view/asterisk?view=rev&rev=121595
Log:
resolve, reset
Added:
team/russell/bindings/configs/ais.conf.sample
- copied unchanged from r121559, trunk/configs/ais.conf.sample
team/russell/bindings/doc/distributed_devstate.txt
- copied unchanged from r121559, trunk/doc/distributed_devstate.txt
team/russell/bindings/res/ais/
- copied from r121559, trunk/res/ais/
team/russell/bindings/res/ais/ais.h
- copied unchanged from r121559, trunk/res/ais/ais.h
team/russell/bindings/res/ais/amf.c
- copied unchanged from r121559, trunk/res/ais/amf.c
team/russell/bindings/res/ais/ckpt.c
- copied unchanged from r121559, trunk/res/ais/ckpt.c
team/russell/bindings/res/ais/clm.c
- copied unchanged from r121559, trunk/res/ais/clm.c
team/russell/bindings/res/ais/evt.c
- copied unchanged from r121559, trunk/res/ais/evt.c
team/russell/bindings/res/ais/lck.c
- copied unchanged from r121559, trunk/res/ais/lck.c
team/russell/bindings/res/res_ais.c
- copied unchanged from r121559, trunk/res/res_ais.c
Modified:
team/russell/bindings/ (props changed)
team/russell/bindings/CHANGES
team/russell/bindings/apps/app_queue.c
team/russell/bindings/include/asterisk/event.h
team/russell/bindings/include/asterisk/event_defs.h
team/russell/bindings/main/devicestate.c
team/russell/bindings/main/event.c
team/russell/bindings/main/pbx.c
team/russell/bindings/res/Makefile
Propchange: team/russell/bindings/
------------------------------------------------------------------------------
automerge = *
Propchange: team/russell/bindings/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Tue Jun 10 12:10:24 2008
@@ -1,1 +1,1 @@
-/trunk:1-121539
+/trunk:1-121594
Modified: team/russell/bindings/CHANGES
URL: http://svn.digium.com/view/asterisk/team/russell/bindings/CHANGES?view=diff&rev=121595&r1=121594&r2=121595
==============================================================================
--- team/russell/bindings/CHANGES (original)
+++ team/russell/bindings/CHANGES Tue Jun 10 12:10:24 2008
@@ -1,6 +1,17 @@
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 1.6.0 to Asterisk 1.6.1 -------------
------------------------------------------------------------------------------
+
+Device State Handling
+---------------------
+ * The event infrastructure in Asterisk got another big update to help support
+ distributed events. It currently supports distributed device state and
+ distributed Voicemail MWI (Message Waiting Indication). A new module has
+ been merged, res_ais, which facilitates communicating events between servers.
+ It uses the SAForum AIS (Service Availability Forum Application Interface
+ Specification) CLM (Cluster Management) and EVT (Event) services to maintain
+ a cluster of Asterisk servers, and to share events between them. For more
+ information on setting this up, see doc/distributed_devstate.txt.
Dialplan Functions
------------------
@@ -17,9 +28,9 @@
* TIMEOUT() has been modified to be accurate down to the millisecond.
* ENUM*() functions now include the following new options:
- 'u' returns the full URI and does not strip off the URI-scheme.
- - 's' triggers ISN specific rewriting
- - 'i' looks for branches into an Infrastructure ENUM tree
- - 'd' for a direct DNS lookup without any flipping of digits.
+ - 's' triggers ISN specific rewriting
+ - 'i' looks for branches into an Infrastructure ENUM tree
+ - 'd' for a direct DNS lookup without any flipping of digits.
* TXCIDNAME() has a new zone-suffix parameter (which defaults to 'e164.arpa')
* CHANNEL() now has options for the maximum, minimum, and standard or normal
deviation of jitter, rtt, and loss for a call using chan_sip.
@@ -116,9 +127,9 @@
which shows which configuration files are in use.
* New CLI commands, "pri show version" and "ss7 show version" that will
display which version of libpri and libss7 are being used, respectively.
- A new API call was added so trunk will now have to be compiled against
- a versions of libpri and libss7 that have them or it will not know that
- these libraries exist.
+ A new API call was added so trunk will now have to be compiled against
+ a versions of libpri and libss7 that have them or it will not know that
+ these libraries exist.
DNS manager changes
-------------------
@@ -443,10 +454,10 @@
a web interface of some kind).
* Added the support for marking messages as "urgent." There are two methods to accomplish
this. One is to pass the 'U' option to VoiceMail(). Another way to mark a message as urgent
- is to specify "review=yes" in voicemail.conf. Doing this will cause allow the user to mark
- the message as urgent after he has recorded a voicemail by following the voice instructions.
- When listening to voicemails using VoiceMailMain urgent messages will be presented before other
- messages
+ is to specify "review=yes" in voicemail.conf. Doing this will cause allow the user to mark
+ the message as urgent after he has recorded a voicemail by following the voice instructions.
+ When listening to voicemails using VoiceMailMain urgent messages will be presented before other
+ messages
Queue changes
-------------
@@ -480,18 +491,18 @@
device state reported.
* New configuration option: randomperiodicannounce. If a list of periodic announcements is
specified by the periodic-announce option, then one will be chosen randomly when it is time
- to play a periodic announcment
+ to play a periodic announcment
* New configuration options: announce-position now takes two more values in addition to "yes" and
"no." Two new options, "limit" and "more," are allowed. These are tied to another option,
- announce-position-limit. By setting announce-position to "limit" callers will only have their
- position announced if their position is less than what is specified by announce-position-limit.
- If announce-position is set to "more" then callers beyond the position specified by announce-position-limit
- will be told that their are more than announce-position-limit callers waiting.
+ announce-position-limit. By setting announce-position to "limit" callers will only have their
+ position announced if their position is less than what is specified by announce-position-limit.
+ If announce-position is set to "more" then callers beyond the position specified by announce-position-limit
+ will be told that their are more than announce-position-limit callers waiting.
* Two new queue log events have been added. An ADDMEMBER event will be logged
when a realtime queue member is added and a REMOVEMEMBER event will be logged
- when a realtime queue member is removed. Since there is no calling channel associated
- with these events, the string "REALTIME" is placed where the channel's unique id
- is typically placed.
+ when a realtime queue member is removed. Since there is no calling channel associated
+ with these events, the string "REALTIME" is placed where the channel's unique id
+ is typically placed.
MeetMe Changes
--------------
@@ -761,7 +772,7 @@
* iLBC source code no longer included (see UPGRADE.txt for details)
* If compiled with DETECT_DEADLOCKS enabled and if you have glibc, then if
deadlock is detected, a backtrace of the stack which led to the lock calls
- will be output to the CLI.
+ will be output to the CLI.
* If compiled with DEBUG_THREADS enabled and if you have glibc, then issuing
the "core show locks" CLI command will give lock information output as well
- as a backtrace of the stack which led to the lock calls.
+ as a backtrace of the stack which led to the lock calls.
Modified: team/russell/bindings/apps/app_queue.c
URL: http://svn.digium.com/view/asterisk/team/russell/bindings/apps/app_queue.c?view=diff&rev=121595&r1=121594&r2=121595
==============================================================================
--- team/russell/bindings/apps/app_queue.c (original)
+++ team/russell/bindings/apps/app_queue.c Tue Jun 10 12:10:24 2008
@@ -6334,8 +6334,10 @@
ast_log(LOG_WARNING, "devicestate taskprocessor reference failed - devicestate notifications will not occur\n");
}
- if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, NULL, AST_EVENT_IE_END)))
+ if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE, device_state_cb, NULL, AST_EVENT_IE_END))) {
res = -1;
+ }
+
ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, NULL);
return res ? AST_MODULE_LOAD_DECLINE : 0;
Modified: team/russell/bindings/include/asterisk/event.h
URL: http://svn.digium.com/view/asterisk/team/russell/bindings/include/asterisk/event.h?view=diff&rev=121595&r1=121594&r2=121595
==============================================================================
--- team/russell/bindings/include/asterisk/event.h (original)
+++ team/russell/bindings/include/asterisk/event.h Tue Jun 10 12:10:24 2008
@@ -1,7 +1,7 @@
/*
* Asterisk -- An open source telephony toolkit.
*
- * Copyright (C) 2007, Digium, Inc.
+ * Copyright (C) 2007 - 2008, Digium, Inc.
*
* Russell Bryant <russell at digium.com>
*
@@ -114,14 +114,110 @@
ast_event_cb_t cb, void *userdata, ...);
/*!
+ * \brief Allocate a subscription, but do not activate it
+ *
+ * \arg type the event type to subscribe to
+ * \arg cb the function to call when an event matches this subscription
+ * \arg userdata data to pass to the provided callback
+ *
+ * This function should be used when you want to dynamically build a
+ * subscription.
+ *
+ * \return the allocated subscription, or NULL on failure
+ */
+struct ast_event_sub *ast_event_subscribe_new(enum ast_event_type type,
+ ast_event_cb_t cb, void *userdata);
+
+/*!
+ * \brief Destroy an allocated subscription
+ *
+ * \arg sub the subscription to destroy
+ *
+ * This function should be used when a subscription is allocated with
+ * ast_event_subscribe_new(), but for some reason, you want to destroy it
+ * instead of activating it. This could be because of an error when
+ * reading in the configuration for the dynamically built subscription.
+ */
+void ast_event_sub_destroy(struct ast_event_sub *sub);
+
+/*!
+ * \brief Append a uint parameter to a subscription
+ *
+ * \arg sub the dynamic subscription allocated with ast_event_subscribe_new()
+ * \arg ie_type the information element type for the parameter
+ * \arg uint the value that must be present in the event to match this subscription
+ *
+ * \retval 0 success
+ * \retval non-zero failure
+ */
+int ast_event_sub_append_ie_uint(struct ast_event_sub *sub,
+ enum ast_event_ie_type ie_type, uint32_t uint);
+
+/*!
+ * \brief Append a string parameter to a subscription
+ *
+ * \arg sub the dynamic subscription allocated with ast_event_subscribe_new()
+ * \arg ie_type the information element type for the parameter
+ * \arg str the string that must be present in the event to match this subscription
+ *
+ * \retval 0 success
+ * \retval non-zero failure
+ */
+int ast_event_sub_append_ie_str(struct ast_event_sub *sub,
+ enum ast_event_ie_type ie_type, const char *str);
+
+/*!
+ * \brief Append a raw parameter to a subscription
+ *
+ * \arg sub the dynamic subscription allocated with ast_event_subscribe_new()
+ * \arg ie_type the information element type for the parameter
+ * \arg raw the data that must be present in the event to match this subscription
+ *
+ * \retval 0 success
+ * \retval non-zero failure
+ */
+int ast_event_sub_append_ie_raw(struct ast_event_sub *sub,
+ enum ast_event_ie_type ie_type, void *data, size_t raw_datalen);
+
+/*!
+ * \brief Append an 'exists' parameter to a subscription
+ *
+ * \arg sub the dynamic subscription allocated with ast_event_subscribe_new()
+ * \arg ie_type the information element type that must be present in the event
+ * for it to match this subscription.
+ *
+ * \retval 0 success
+ * \retval non-zero failure
+ */
+int ast_event_sub_append_ie_exists(struct ast_event_sub *sub,
+ enum ast_event_ie_type ie_type);
+
+/*!
+ * \brief Activate a dynamically built subscription
+ *
+ * \arg sub the subscription to activate that was allocated using
+ * ast_event_subscribe_new()
+ *
+ * Once a dynamically built subscription has had all of the parameters added
+ * to it, it should be activated using this function.
+ *
+ * \retval 0 success
+ * \retval non-zero failure
+ */
+int ast_event_sub_activate(struct ast_event_sub *sub);
+
+/*!
* \brief Un-subscribe from events
*
* \param event_sub This is the reference to the subscription returned by
* ast_event_subscribe.
- *
- * \return Nothing
- */
-void ast_event_unsubscribe(struct ast_event_sub *event_sub);
+ *
+ * This function will remove a subscription and free the associated data
+ * structures.
+ *
+ * \return NULL for convenience.
+ */
+struct ast_event_sub *ast_event_unsubscribe(struct ast_event_sub *event_sub);
/*!
* \brief Check if subscribers exist
@@ -177,6 +273,9 @@
* all of the subscriptions to that event type that already exist.
*/
void ast_event_report_subs(const struct ast_event_sub *sub);
+
+/*! \brief Dump the event cache for the subscriber */
+void ast_event_dump_cache(const struct ast_event_sub *event_sub);
/*!
* \brief Create a new event
@@ -412,6 +511,24 @@
const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_ie_type ie_type);
/*!
+ * \brief Get the string representation of an information element type
+ *
+ * \arg ie_type the information element type to get the string representation of
+ *
+ * \return the string representation of the information element type
+ */
+const char *ast_event_get_ie_type_name(enum ast_event_ie_type ie_type);
+
+/*!
+ * \brief Get the payload type for a given information element type
+ *
+ * \arg ie_type the information element type to get the payload type of
+ *
+ * \return the payload type for the provided IE type
+ */
+enum ast_event_ie_pltype ast_event_get_ie_pltype(enum ast_event_ie_type ie_type);
+
+/*!
* \brief Get the type for an event
*
* \param event the event to get the type for
@@ -420,6 +537,46 @@
* ast_event_type enum
*/
enum ast_event_type ast_event_get_type(const struct ast_event *event);
+
+/*!
+ * \brief Get the string representation of the type of the given event
+ *
+ * \arg event the event to get the type of
+ *
+ * \return the string representation of the event type of the provided event
+ */
+const char *ast_event_get_type_name(const struct ast_event *event);
+
+/*!
+ * \brief Convert a string into an event type
+ *
+ * \arg str the string to convert
+ * \arg event_type an output parameter for the event type
+ *
+ * \retval 0 success
+ * \retval non-zero failure
+ */
+int ast_event_str_to_event_type(const char *str, enum ast_event_type *event_type);
+
+/*!
+ * \brief Convert a string to an IE type
+ *
+ * \arg str the string to convert
+ * \arg ie_type an output parameter for the IE type
+ *
+ * \retval 0 success
+ * \retval non-zero failure
+ */
+int ast_event_str_to_ie_type(const char *str, enum ast_event_ie_type *ie_type);
+
+/*!
+ * \brief Get the size of an event
+ *
+ * \param event the event to get the size of
+ *
+ * \return the number of bytes contained in the event
+ */
+size_t ast_event_get_size(const struct ast_event *event);
/*!
* \brief Initialize an event iterator instance
Modified: team/russell/bindings/include/asterisk/event_defs.h
URL: http://svn.digium.com/view/asterisk/team/russell/bindings/include/asterisk/event_defs.h?view=diff&rev=121595&r1=121594&r2=121595
==============================================================================
--- team/russell/bindings/include/asterisk/event_defs.h (original)
+++ team/russell/bindings/include/asterisk/event_defs.h Tue Jun 10 12:10:24 2008
@@ -1,7 +1,7 @@
/*
* Asterisk -- An open source telephony toolkit.
*
- * Copyright (C) 2007, Digium, Inc.
+ * Copyright (C) 2007 - 2008, Digium, Inc.
*
* Russell Bryant <russell at digium.com>
*
@@ -29,23 +29,27 @@
* \note These values can *never* change. */
enum ast_event_type {
/*! Reserved to provide the ability to subscribe to all events. A specific
- event should never have a payload of 0. */
- AST_EVENT_ALL = 0x00,
+ * event should never have a payload of 0. */
+ AST_EVENT_ALL = 0x00,
/*! This event type is reserved for use by third-party modules to create
- custom events without having to modify this file.
- \note There are no "custom" IE types, because IEs only have to be
- unique to the event itself, not necessarily across all events. */
- AST_EVENT_CUSTOM = 0x01,
+ * custom events without having to modify this file.
+ * \note There are no "custom" IE types, because IEs only have to be
+ * unique to the event itself, not necessarily across all events. */
+ AST_EVENT_CUSTOM = 0x01,
/*! Voicemail message waiting indication */
- AST_EVENT_MWI = 0x02,
+ AST_EVENT_MWI = 0x02,
/*! Someone has subscribed to events */
- AST_EVENT_SUB = 0x03,
+ AST_EVENT_SUB = 0x03,
/*! Someone has unsubscribed from events */
- AST_EVENT_UNSUB = 0x04,
- /*! The state of a device has changed */
- AST_EVENT_DEVICE_STATE = 0x05,
+ AST_EVENT_UNSUB = 0x04,
+ /*! The aggregate state of a device across all servers configured to be
+ * a part of a device state cluster has changed. */
+ AST_EVENT_DEVICE_STATE = 0x05,
+ /*! The state of a device has changed on _one_ server. This should not be used
+ * directly, in general. Use AST_EVENT_DEVICE_STATE instead. */
+ AST_EVENT_DEVICE_STATE_CHANGE = 0x06,
/*! Number of event types. This should be the last event type + 1 */
- AST_EVENT_TOTAL = 0x06,
+ AST_EVENT_TOTAL = 0x07,
};
/*! \brief Event Information Element types */
@@ -91,13 +95,13 @@
AST_EVENT_IE_EXISTS = 0x06,
/*!
* \brief Device Name
- * Used by AST_EVENT_DEVICE_STATE
+ * Used by AST_EVENT_DEVICE_STATE_CHANGE
* Payload type: STR
*/
AST_EVENT_IE_DEVICE = 0x07,
/*!
* \brief Generic State IE
- * Used by AST_EVENT_DEVICE_STATE
+ * Used by AST_EVENT_DEVICE_STATE_CHANGE
* Payload type: UINT
* The actual state values depend on the event which
* this IE is a part of.
@@ -109,18 +113,30 @@
* Payload type: str
*/
AST_EVENT_IE_CONTEXT = 0x09,
+ /*!
+ * \brief Entity ID
+ * Used by All events
+ * Payload type: RAW
+ * This IE indicates which server the event originated from
+ */
+ AST_EVENT_IE_EID = 0x0A,
};
+
+#define AST_EVENT_IE_MAX AST_EVENT_IE_EID
/*!
* \brief Payload types for event information elements
*/
enum ast_event_ie_pltype {
+ AST_EVENT_IE_PLTYPE_UNKNOWN = -1,
/*! Just check if it exists, not the value */
AST_EVENT_IE_PLTYPE_EXISTS,
/*! Unsigned Integer (Can be used for signed, too ...) */
AST_EVENT_IE_PLTYPE_UINT,
/*! String */
AST_EVENT_IE_PLTYPE_STR,
+ /*! Raw data, compared with memcmp */
+ AST_EVENT_IE_PLTYPE_RAW,
};
/*!
@@ -140,4 +156,15 @@
struct ast_event_sub;
struct ast_event_iterator;
+/*!
+ * \brief supposed to be an opaque type
+ *
+ * This is only here so that it can be declared on the stack.
+ */
+struct ast_event_iterator {
+ uint16_t event_len;
+ const struct ast_event *event;
+ struct ast_event_ie *ie;
+};
+
#endif /* AST_EVENT_DEFS_H */
Modified: team/russell/bindings/main/devicestate.c
URL: http://svn.digium.com/view/asterisk/team/russell/bindings/main/devicestate.c?view=diff&rev=121595&r1=121594&r2=121595
==============================================================================
--- team/russell/bindings/main/devicestate.c (original)
+++ team/russell/bindings/main/devicestate.c Tue Jun 10 12:10:24 2008
@@ -1,9 +1,10 @@
/*
* Asterisk -- An open source telephony toolkit.
*
- * Copyright (C) 1999 - 2007, Digium, Inc.
+ * Copyright (C) 1999 - 2008, Digium, Inc.
*
* Mark Spencer <markster at digium.com>
+ * Russell Bryant <russell at digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
@@ -20,13 +21,17 @@
*
* \brief Device state management
*
- *
* \author Mark Spencer <markster at digium.com>
+ * \author Russell Bryant <russell at digium.com>
*
* \arg \ref AstExtState
*/
/*! \page AstExtState Extension and device states in Asterisk
+ *
+ * (Note that these descriptions of device states and extension
+ * states have not been updated to the way things work
+ * in Asterisk 1.6.)
*
* Asterisk has an internal system that reports states
* for an extension. By using the dialplan priority -1,
@@ -169,6 +174,23 @@
* We only want to cache results from device state providers that are being nice
* and pushing state change events up to us as they happen. */
CACHE_OFF,
+};
+
+struct devstate_change {
+ AST_LIST_ENTRY(devstate_change) entry;
+ uint32_t state;
+ struct ast_eid eid;
+ char device[1];
+};
+
+struct {
+ pthread_t thread;
+ struct ast_event_sub *event_sub;
+ ast_cond_t cond;
+ ast_mutex_t lock;
+ AST_LIST_HEAD_NOLOCK(, devstate_change) devstate_change_q;
+} devstate_collector = {
+ .thread = AST_PTHREADT_NULL,
};
/* Forward declarations */
@@ -271,7 +293,7 @@
enum ast_device_state res = AST_DEVICE_UNKNOWN;
struct ast_event *event;
- event = ast_event_get_cached(AST_EVENT_DEVICE_STATE,
+ event = ast_event_get_cached(AST_EVENT_DEVICE_STATE_CHANGE,
AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
AST_EVENT_IE_END);
@@ -383,7 +405,6 @@
struct devstate_prov *devprov;
int res = AST_DEVICE_INVALID;
-
AST_RWLIST_RDLOCK(&devstate_provs);
AST_RWLIST_TRAVERSE(&devstate_provs, devprov, list) {
ast_debug(5, "Checking provider %s with %s\n", devprov->label, provider);
@@ -394,6 +415,7 @@
}
}
AST_RWLIST_UNLOCK(&devstate_provs);
+
return res;
}
@@ -401,7 +423,9 @@
{
struct ast_event *event;
- if (!(event = ast_event_new(AST_EVENT_DEVICE_STATE,
+ ast_debug(1, "device '%s' state '%d'\n", device, state);
+
+ if (!(event = ast_event_new(AST_EVENT_DEVICE_STATE_CHANGE,
AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
AST_EVENT_IE_END))) {
@@ -413,6 +437,7 @@
* device name if it exists. */
ast_event_queue_and_cache(event,
AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR,
+ AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW, sizeof(struct ast_eid),
AST_EVENT_IE_END);
} else {
ast_event_queue(event);
@@ -540,9 +565,189 @@
return NULL;
}
+static void destroy_devstate_change(struct devstate_change *sc)
+{
+ ast_free(sc);
+}
+
+#define MAX_SERVERS 64
+struct change_collection {
+ struct devstate_change states[MAX_SERVERS];
+ size_t num_states;
+};
+
+static void devstate_cache_cb(const struct ast_event *event, void *data)
+{
+ struct change_collection *collection = data;
+ int i;
+ const struct ast_eid *eid;
+
+ if (collection->num_states == ARRAY_LEN(collection->states)) {
+ ast_log(LOG_ERROR, "More per-server state values than we have room for (MAX_SERVERS is %d)\n",
+ MAX_SERVERS);
+ return;
+ }
+
+ if (!(eid = ast_event_get_ie_raw(event, AST_EVENT_IE_EID))) {
+ ast_log(LOG_ERROR, "Device state change event with no EID\n");
+ return;
+ }
+
+ i = collection->num_states;
+
+ collection->states[i].state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
+ collection->states[i].eid = *eid;
+
+ collection->num_states++;
+}
+
+static void process_collection(const char *device, struct change_collection *collection)
+{
+ int i;
+ struct ast_devstate_aggregate agg;
+ enum ast_device_state state;
+ struct ast_event *event;
+
+ ast_devstate_aggregate_init(&agg);
+
+ for (i = 0; i < collection->num_states; i++) {
+ ast_debug(1, "Adding per-server state of '%s' for '%s'\n",
+ devstate2str(collection->states[i].state), device);
+ ast_devstate_aggregate_add(&agg, collection->states[i].state);
+ }
+
+ state = ast_devstate_aggregate_result(&agg);
+
+ ast_debug(1, "Aggregate devstate result is %d\n", state);
+
+ event = ast_event_get_cached(AST_EVENT_DEVICE_STATE,
+ AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
+ AST_EVENT_IE_END);
+
+ if (event) {
+ enum ast_device_state old_state;
+
+ old_state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
+
+ ast_event_destroy(event);
+
+ if (state == old_state) {
+ /* No change since last reported device state */
+ ast_debug(1, "Aggregate state for device '%s' has not changed from '%s'\n",
+ device, devstate2str(state));
+ return;
+ }
+ }
+
+ ast_debug(1, "Aggregate state for device '%s' has changed to '%s'\n",
+ device, devstate2str(state));
+
+ event = ast_event_new(AST_EVENT_DEVICE_STATE,
+ AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
+ AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
+ AST_EVENT_IE_END);
+
+ if (!event)
+ return;
+
+ ast_event_queue_and_cache(event,
+ AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR,
+ AST_EVENT_IE_END);
+}
+
+static void handle_devstate_change(struct devstate_change *sc)
+{
+ struct ast_event_sub *tmp_sub;
+ struct change_collection collection = {
+ .num_states = 0,
+ };
+
+ ast_debug(1, "Processing device state change for '%s'\n", sc->device);
+
+ if (!(tmp_sub = ast_event_subscribe_new(AST_EVENT_DEVICE_STATE_CHANGE, devstate_cache_cb, &collection))) {
+ ast_log(LOG_ERROR, "Failed to create subscription\n");
+ return;
+ }
+
+ if (ast_event_sub_append_ie_str(tmp_sub, AST_EVENT_IE_DEVICE, sc->device)) {
+ ast_log(LOG_ERROR, "Failed to append device IE\n");
+ ast_event_sub_destroy(tmp_sub);
+ return;
+ }
+
+ /* Populate the collection of device states from the cache */
+ ast_event_dump_cache(tmp_sub);
+
+ process_collection(sc->device, &collection);
+
+ ast_event_sub_destroy(tmp_sub);
+}
+
+static void *run_devstate_collector(void *data)
+{
+ for (;;) {
+ struct devstate_change *sc;
+
+ ast_mutex_lock(&devstate_collector.lock);
+ while (!(sc = AST_LIST_REMOVE_HEAD(&devstate_collector.devstate_change_q, entry)))
+ ast_cond_wait(&devstate_collector.cond, &devstate_collector.lock);
+ ast_mutex_unlock(&devstate_collector.lock);
+
+ handle_devstate_change(sc);
+
+ destroy_devstate_change(sc);
+ }
+
+ return NULL;
+}
+
+static void devstate_change_collector_cb(const struct ast_event *event, void *data)
+{
+ struct devstate_change *sc;
+ const char *device;
+ const struct ast_eid *eid;
+ uint32_t state;
+
+ device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
+ eid = ast_event_get_ie_raw(event, AST_EVENT_IE_EID);
+ state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
+
+ if (ast_strlen_zero(device) || !eid) {
+ ast_log(LOG_ERROR, "Invalid device state change event received\n");
+ return;
+ }
+
+ if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(device))))
+ return;
+
+ strcpy(sc->device, device);
+ sc->eid = *eid;
+ sc->state = state;
+
+ ast_mutex_lock(&devstate_collector.lock);
+ AST_LIST_INSERT_TAIL(&devstate_collector.devstate_change_q, sc, entry);
+ ast_cond_signal(&devstate_collector.cond);
+ ast_mutex_unlock(&devstate_collector.lock);
+}
+
/*! \brief Initialize the device state engine in separate thread */
int ast_device_state_engine_init(void)
{
+ devstate_collector.event_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE,
+ devstate_change_collector_cb, NULL, AST_EVENT_IE_END);
+
+ if (!devstate_collector.event_sub) {
+ ast_log(LOG_ERROR, "Failed to create subscription for the device state change collector\n");
+ return -1;
+ }
+
+ ast_mutex_init(&devstate_collector.lock);
+ ast_cond_init(&devstate_collector.cond, NULL);
+ if (ast_pthread_create_background(&devstate_collector.thread, NULL, run_devstate_collector, NULL) < 0) {
+ ast_log(LOG_ERROR, "Unable to start device state collector thread.\n");
+ return -1;
+ }
+
ast_cond_init(&change_pending, NULL);
if (ast_pthread_create_background(&change_thread, NULL, do_devstate_changes, NULL) < 0) {
ast_log(LOG_ERROR, "Unable to start device state change thread.\n");
Modified: team/russell/bindings/main/event.c
URL: http://svn.digium.com/view/asterisk/team/russell/bindings/main/event.c?view=diff&rev=121595&r1=121594&r2=121595
==============================================================================
--- team/russell/bindings/main/event.c (original)
+++ team/russell/bindings/main/event.c Tue Jun 10 12:10:24 2008
@@ -1,7 +1,7 @@
/*
* Asterisk -- An open source telephony toolkit.
*
- * Copyright (C) 2007, Digium, Inc.
+ * Copyright (C) 2007 - 2008, Digium, Inc.
*
* Russell Bryant <russell at digium.com>
*
@@ -34,6 +34,7 @@
#include "asterisk/lock.h"
#include "asterisk/utils.h"
#include "asterisk/unaligned.h"
+#include "asterisk/utils.h"
#include "asterisk/taskprocessor.h"
struct ast_taskprocessor *event_dispatcher;
@@ -78,12 +79,6 @@
AST_LIST_ENTRY(ast_event_ref) entry;
};
-struct ast_event_iterator {
- uint16_t event_len;
- const struct ast_event *event;
- struct ast_event_ie *ie;
-};
-
struct ast_event_ie_val {
AST_LIST_ENTRY(ast_event_ie_val) entry;
enum ast_event_ie_type ie_type;
@@ -91,7 +86,9 @@
union {
uint32_t uint;
const char *str;
+ void *raw;
} payload;
+ size_t raw_datalen;
};
/*! \brief Event subscription */
@@ -116,10 +113,128 @@
* needs to know this state, it can get the last known state from the cache. */
static AST_RWLIST_HEAD(ast_event_ref_list, ast_event_ref) ast_event_cache[AST_EVENT_TOTAL];
+/*!
+ * The index of each entry _must_ match the event type number!
+ */
+static struct event_name {
+ enum ast_event_type type;
+ const char *name;
+} event_names[] = {
+ { 0, "" },
+ { AST_EVENT_CUSTOM, "Custom" },
+ { AST_EVENT_MWI, "MWI" },
+ { AST_EVENT_SUB, "Subscription" },
+ { AST_EVENT_UNSUB, "Unsubscription" },
+ { AST_EVENT_DEVICE_STATE, "DeviceState" },
+ { AST_EVENT_DEVICE_STATE_CHANGE, "DeviceStateChange" },
+};
+
+/*!
+ * The index of each entry _must_ match the event ie number!
+ */
+static struct ie_map {
+ enum ast_event_ie_type ie_type;
+ enum ast_event_ie_pltype ie_pltype;
+ const char *name;
+} ie_maps[] = {
+ { 0, 0, "" },
+ { AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, "NewMessages" },
+ { AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, "OldMessages" },
+ { AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, "Mailbox" },
+ { AST_EVENT_IE_UNIQUEID, AST_EVENT_IE_PLTYPE_UINT, "UniqueID" },
+ { AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, "EventType" },
+ { AST_EVENT_IE_EXISTS, AST_EVENT_IE_PLTYPE_UINT, "Exists" },
+ { AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "Device" },
+ { AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, "State" },
+ { AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, "Context" },
+ { AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW, "EntityID" },
+};
+
+const char *ast_event_get_type_name(const struct ast_event *event)
+{
+ enum ast_event_type type;
+
+ type = ast_event_get_type(event);
+
+ if (type >= AST_EVENT_TOTAL || type < 0) {
+ ast_log(LOG_ERROR, "Invalid event type - '%d'\n", type);
+ return "";
+ }
+
+ return event_names[type].name;
+}
+
+int ast_event_str_to_event_type(const char *str, enum ast_event_type *event_type)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_LEN(event_names); i++) {
+ if (strcasecmp(event_names[i].name, str))
+ continue;
+
+ *event_type = event_names[i].type;
+ return 0;
+ }
+
+ return -1;
+}
+
+const char *ast_event_get_ie_type_name(enum ast_event_ie_type ie_type)
+{
+ if (ie_type <= 0 || ie_type > AST_EVENT_IE_MAX) {
+ ast_log(LOG_ERROR, "Invalid IE type - '%d'\n", ie_type);
+ return "";
+ }
+
+ return ie_maps[ie_type].name;
+}
+
+enum ast_event_ie_pltype ast_event_get_ie_pltype(enum ast_event_ie_type ie_type)
+{
+ if (ie_type <= 0 || ie_type > AST_EVENT_IE_MAX) {
+ ast_log(LOG_ERROR, "Invalid IE type - '%d'\n", ie_type);
+ return AST_EVENT_IE_PLTYPE_UNKNOWN;
+ }
+
+ return ie_maps[ie_type].ie_pltype;
+}
+
+int ast_event_str_to_ie_type(const char *str, enum ast_event_ie_type *ie_type)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_LEN(ie_maps); i++) {
+ if (strcasecmp(ie_maps[i].name, str))
+ continue;
+
+ *ie_type = ie_maps[i].ie_type;
+ return 0;
+ }
+
+ return -1;
+}
+
+size_t ast_event_get_size(const struct ast_event *event)
+{
+ size_t res;
+
+ res = ntohs(event->event_len);
+
+ return res;
+}
+
static void ast_event_ie_val_destroy(struct ast_event_ie_val *ie_val)
{
- if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
- ast_free((void *) ie_val->payload.str);
+ switch (ie_val->ie_pltype) {
+ case AST_EVENT_IE_PLTYPE_STR:
+ case AST_EVENT_IE_PLTYPE_RAW:
+ ast_free(ie_val->payload.raw);
+ break;
+ case AST_EVENT_IE_PLTYPE_UINT:
+ case AST_EVENT_IE_PLTYPE_EXISTS:
+ case AST_EVENT_IE_PLTYPE_UNKNOWN:
+ break;
+ }
ast_free(ie_val);
}
@@ -151,6 +266,13 @@
ie_val->payload.uint = va_arg(ap, uint32_t);
else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
ie_val->payload.str = ast_strdupa(va_arg(ap, const char *));
+ else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
+ void *data = va_arg(ap, void *);
+ size_t datalen = va_arg(ap, size_t);
+ ie_val->payload.raw = alloca(datalen);
+ memcpy(ie_val->payload.raw, data, datalen);
+ ie_val->raw_datalen = datalen;
+ }
AST_LIST_INSERT_TAIL(&ie_vals, ie_val, entry);
}
va_end(ap);
@@ -176,6 +298,9 @@
if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR &&
strcmp(ie_val->payload.str, sub_ie_val->payload.str))
break;
+ if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW &&
+ memcmp(ie_val->payload.raw, sub_ie_val->payload.raw, ie_val->raw_datalen))
+ break;
}
if (!ie_val)
break;
@@ -193,6 +318,97 @@
return res;
}
+static int match_ie_val(struct ast_event *event, struct ast_event_ie_val *ie_val, struct ast_event *event2)
+{
+ if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT) {
+ uint32_t val = event2 ? ast_event_get_ie_uint(event2, ie_val->ie_type) : ie_val->payload.uint;
+ if (val == ast_event_get_ie_uint(event, ie_val->ie_type))
+ return 1;
+ return 0;
+ }
+
+ if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR) {
+ const char *str = event2 ? ast_event_get_ie_str(event2, ie_val->ie_type) : ie_val->payload.str;
+ if (str && !strcmp(str, ast_event_get_ie_str(event, ie_val->ie_type)))
+ return 1;
+ return 0;
+ }
+
+ if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
+ const void *buf = event2 ? ast_event_get_ie_raw(event2, ie_val->ie_type) : ie_val->payload.raw;
+ if (buf && !memcmp(buf, ast_event_get_ie_raw(event, ie_val->ie_type), ie_val->raw_datalen))
+ return 1;
+ return 0;
+ }
+
+ if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS) {
+ if (ast_event_get_ie_raw(event, ie_val->ie_type))
+ return 1;
+ return 0;
+ }
+
+ return 0;
+}
+
+/*! \brief Dump the event cache for the subscribed event type */
+void ast_event_dump_cache(const struct ast_event_sub *event_sub)
+{
+ struct ast_event_ref *event_ref;
+ enum ast_event_type type = event_sub->type;
+
+ AST_RWLIST_RDLOCK(&ast_event_cache[type]);
+ AST_RWLIST_TRAVERSE_SAFE_BEGIN(&ast_event_cache[type], event_ref, entry) {
+ struct ast_event_ie_val *ie_val;
+ AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
+ if (!match_ie_val(event_ref->event, ie_val, NULL))
+ break;
+ }
+ if (!ie_val) {
+ /* All parameters were matched on this cache entry, so dump it */
+ event_sub->cb(event_ref->event, event_sub->userdata);
+ }
+ }
+ AST_RWLIST_TRAVERSE_SAFE_END
+ AST_RWLIST_UNLOCK(&ast_event_cache[type]);
+}
+
+static struct ast_event *gen_sub_event(struct ast_event_sub *sub)
+{
+ struct ast_event_ie_val *ie_val;
+ struct ast_event *event;
+
+ event = ast_event_new(AST_EVENT_SUB,
+ AST_EVENT_IE_UNIQUEID, AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
+ AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
+ AST_EVENT_IE_END);
+
+ if (!event)
+ return NULL;
+
+ AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
+ switch (ie_val->ie_pltype) {
+ case AST_EVENT_IE_PLTYPE_UNKNOWN:
+ break;
+ case AST_EVENT_IE_PLTYPE_EXISTS:
+ ast_event_append_ie_uint(&event, AST_EVENT_IE_EXISTS, ie_val->ie_type);
+ break;
+ case AST_EVENT_IE_PLTYPE_UINT:
+ ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
+ break;
+ case AST_EVENT_IE_PLTYPE_STR:
+ ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
+ break;
+ case AST_EVENT_IE_PLTYPE_RAW:
+ ast_event_append_ie_raw(&event, ie_val->ie_type, ie_val->payload.raw, ie_val->raw_datalen);
+ break;
+ }
+ if (!event)
+ break;
+ }
+
+ return event;
+}
+
/*! \brief Send AST_EVENT_SUB events to this subscriber of ... subscriber events */
void ast_event_report_subs(const struct ast_event_sub *event_sub)
{
@@ -219,26 +435,7 @@
if (event_sub == sub)
continue;
- event = ast_event_new(AST_EVENT_SUB,
- AST_EVENT_IE_UNIQUEID, AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
- AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
- AST_EVENT_IE_END);
-
- AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
- switch (ie_val->ie_pltype) {
- case AST_EVENT_IE_PLTYPE_EXISTS:
- ast_event_append_ie_uint(&event, AST_EVENT_IE_EXISTS, ie_val->ie_type);
- break;
- case AST_EVENT_IE_PLTYPE_UINT:
- ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
- break;
- case AST_EVENT_IE_PLTYPE_STR:
- ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
- break;
- }
- if (!event)
- break;
- }
+ event = gen_sub_event(sub);
if (!event)
continue;
@@ -248,6 +445,137 @@
ast_event_destroy(event);
}
AST_RWDLLIST_UNLOCK(&ast_event_subs[event_type]);
+}
+
+struct ast_event_sub *ast_event_subscribe_new(enum ast_event_type type,
+ ast_event_cb_t cb, void *userdata)
+{
+ struct ast_event_sub *sub;
+
+ if (type < 0 || type >= AST_EVENT_TOTAL) {
+ ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
+ return NULL;
+ }
+
+ if (!(sub = ast_calloc(1, sizeof(*sub))))
+ return NULL;
+
+ sub->type = type;
+ sub->cb = cb;
+ sub->userdata = userdata;
+ sub->uniqueid = ast_atomic_fetchadd_int((int *) &sub_uniqueid, 1);
+
+ return sub;
+}
+
+int ast_event_sub_append_ie_uint(struct ast_event_sub *sub,
+ enum ast_event_ie_type ie_type, uint32_t uint)
+{
+ struct ast_event_ie_val *ie_val;
+
+ if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
+ return -1;
+
+ if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
+ return -1;
+
+ ie_val->ie_type = ie_type;
+ ie_val->payload.uint = uint;
+ ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_UINT;
+
+ AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
+
+ return 0;
+}
+
+int ast_event_sub_append_ie_exists(struct ast_event_sub *sub,
+ enum ast_event_ie_type ie_type)
+{
+ struct ast_event_ie_val *ie_val;
+
+ if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
+ return -1;
+
+ if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
+ return -1;
+
+ ie_val->ie_type = ie_type;
+ ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_EXISTS;
+
+ AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
+
+ return 0;
+}
+
+int ast_event_sub_append_ie_str(struct ast_event_sub *sub,
+ enum ast_event_ie_type ie_type, const char *str)
+{
+ struct ast_event_ie_val *ie_val;
+
+ if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
+ return -1;
+
+ if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
+ return -1;
+
+ ie_val->ie_type = ie_type;
+ ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_STR;
+
+ if (!(ie_val->payload.str = ast_strdup(str))) {
+ ast_free(ie_val);
+ return -1;
+ }
+
+ AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
+
+ return 0;
+}
+
[... 385 lines stripped ...]
More information about the asterisk-commits
mailing list