[asterisk-commits] russell: trunk r121559 - in /trunk: ./ apps/ configs/ doc/ main/ res/ res/ais/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Jun 10 10:12:17 CDT 2008


Author: russell
Date: Tue Jun 10 10:12:17 2008
New Revision: 121559

URL: http://svn.digium.com/view/asterisk?view=rev&rev=121559
Log:
Merge another big set of changes from team/russell/events

This commit merges in the rest of the code needed to support distributed device
state.  There are two main parts to this commit.

Core changes:
 - The device state handling in the core has been updated to understand device
   state across a cluster of Asterisk servers.  Every time the state of a device
   changes, it looks at all of the device states on each node, and determines the
   aggregate device state.  That resulting device state is what is provided to
   modules in Asterisk that take actions based on the state of a device.

New module, res_ais:
 - A module has been written to facilitate the communication of events between
   nodes in a cluster of Asterisk servers.  This module uses the SAForum AIS
   (Service Availability Forum Application Interface Specification) CLM and EVT
   services (Cluster Management and Event) to handle this task.  This module
   currently supports sharing Voicemail MWI (Message Waiting Indication) and
   device state events between servers.  It has been tested with openais, though
   other implementations of the spec do exist.

For more information on testing distributed device state, see the following doc:
  - doc/distributed_devstate.txt

Added:
    trunk/configs/ais.conf.sample
      - copied unchanged from r121557, team/russell/events/configs/ais.conf.sample
    trunk/doc/distributed_devstate.txt
      - copied unchanged from r121557, team/russell/events/doc/distributed_devstate.txt
    trunk/res/ais/
      - copied from r121557, team/russell/events/res/ais/
    trunk/res/ais/ais.h
      - copied, changed from r121557, team/russell/events/res/ais/ais.h
    trunk/res/ais/clm.c
      - copied unchanged from r121557, team/russell/events/res/ais/clm.c
    trunk/res/ais/evt.c
      - copied unchanged from r121557, team/russell/events/res/ais/evt.c
    trunk/res/res_ais.c
      - copied unchanged from r121557, team/russell/events/res/res_ais.c
Modified:
    trunk/CHANGES
    trunk/apps/app_queue.c
    trunk/main/devicestate.c
    trunk/main/pbx.c
    trunk/res/Makefile

Modified: trunk/CHANGES
URL: http://svn.digium.com/view/asterisk/trunk/CHANGES?view=diff&rev=121559&r1=121558&r2=121559
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Tue Jun 10 10:12:17 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: trunk/apps/app_queue.c
URL: http://svn.digium.com/view/asterisk/trunk/apps/app_queue.c?view=diff&rev=121559&r1=121558&r2=121559
==============================================================================
--- trunk/apps/app_queue.c (original)
+++ trunk/apps/app_queue.c Tue Jun 10 10:12:17 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: trunk/main/devicestate.c
URL: http://svn.digium.com/view/asterisk/trunk/main/devicestate.c?view=diff&rev=121559&r1=121558&r2=121559
==============================================================================
--- trunk/main/devicestate.c (original)
+++ trunk/main/devicestate.c Tue Jun 10 10:12:17 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: trunk/main/pbx.c
URL: http://svn.digium.com/view/asterisk/trunk/main/pbx.c?view=diff&rev=121559&r1=121558&r2=121559
==============================================================================
--- trunk/main/pbx.c (original)
+++ trunk/main/pbx.c Tue Jun 10 10:12:17 2008
@@ -8070,7 +8070,7 @@
 	/* Register manager application */
 	ast_manager_register2("ShowDialPlan", EVENT_FLAG_CONFIG | EVENT_FLAG_REPORTING, manager_show_dialplan, "List dialplan", mandescr_show_dialplan);
 
-	if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, NULL,
+	if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE, device_state_cb, NULL,
 			AST_EVENT_IE_END))) {
 		return -1;
 	}

Modified: trunk/res/Makefile
URL: http://svn.digium.com/view/asterisk/trunk/res/Makefile?view=diff&rev=121559&r1=121558&r2=121559
==============================================================================
--- trunk/res/Makefile (original)
+++ trunk/res/Makefile Tue Jun 10 10:12:17 2008
@@ -35,6 +35,8 @@
 ael/ael.tab.o: ael/ael.tab.c ael/ael.tab.h ../include/asterisk/ael_structs.h
 ael/ael.tab.o: ASTCFLAGS+=-I. -Iael -DYYENABLE_NLS=0
 
+$(if $(filter res_ais,$(EMBEDDED_MODS)),modules.link,res_ais.so): ais/clm.o ais/evt.o
+
 $(if $(filter res_snmp,$(EMBEDDED_MODS)),modules.link,res_snmp.so): snmp/agent.o
 
 $(if $(filter res_ael_share,$(EMBEDDED_MODS)),modules.link,res_ael_share.so): ael/ael_lex.o ael/ael.tab.o ael/pval.o
@@ -49,5 +51,4 @@
 ael/pval.o: ael/pval.c
 
 clean::
-	rm -f snmp/*.o
-	rm -f ael/*.o
+	rm -f snmp/*.o ael/*.o ais/*.o

Copied: trunk/res/ais/ais.h (from r121557, team/russell/events/res/ais/ais.h)
URL: http://svn.digium.com/view/asterisk/trunk/res/ais/ais.h?view=diff&rev=121559&p1=team/russell/events/res/ais/ais.h&r1=121557&p2=trunk/res/ais/ais.h&r2=121559
==============================================================================
--- team/russell/events/res/ais/ais.h (original)
+++ trunk/res/ais/ais.h Tue Jun 10 10:12:17 2008
@@ -29,25 +29,13 @@
 #define AST_AIS_H
 
 #include <openais/saAis.h>
-#include <openais/saAmf.h>
-#include <openais/saCkpt.h>
 #include <openais/saClm.h>
 #include <openais/saEvt.h>
-#include <openais/saLck.h>
 
 extern SaVersionT ais_version;
 
-extern SaAmfHandleT  amf_handle;
-extern SaCkptHandleT ckpt_handle;
 extern SaClmHandleT  clm_handle;
 extern SaEvtHandleT  evt_handle;
-extern SaLckHandleT  lck_handle;
-
-int ast_ais_amf_load_module(void);
-int ast_ais_amf_unload_module(void);
-
-int ast_ais_ckpt_load_module(void);
-int ast_ais_ckpt_unload_module(void);
 
 int ast_ais_clm_load_module(void);
 int ast_ais_clm_unload_module(void);
@@ -55,9 +43,6 @@
 int ast_ais_evt_load_module(void);
 int ast_ais_evt_unload_module(void);
 
-int ast_ais_lck_load_module(void);
-int ast_ais_lck_unload_module(void);
-
 const char *ais_err2str(SaAisErrorT error);
 
 #endif /* AST_AIS_H */




More information about the asterisk-commits mailing list