aboutsummaryrefslogtreecommitdiffstats
path: root/main
diff options
context:
space:
mode:
authorrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2010-11-20 00:45:51 +0000
committerrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2010-11-20 00:45:51 +0000
commit36625964a25edf229f9d836284f45753f1d866be (patch)
tree37ed7a5b6ccd38e519cc4057b04d9431c5075c23 /main
parente8d8da0a1afc44aedeb1fc46305bd4a77c4c9822 (diff)
Fix cache of device state changes for multiple servers.
This patch addresses a regression where device states across multiple servers were not being processing completely correctly. The code works to determine the overall state by looking at the last known state of a device on each server. However, there was a regression due to some invasive rewrites of how the cache works that led to the cache only storing the last device state change for a device, regardless of which server it was on. The code is set up to cache device state change events by ensuring that each event in the cache has a unique device name + entity ID (server ID). The code that was responsible for comparing raw information elements (which EID is) always returned a match due to a memcmp() with a length of 0. There isn't much code to fix the actual bug. This patch also introduces a new CLI command that was very useful for debugging this problem. The command allows you to dump the contents of the event cache. (closes issue #18284) Reported by: klaus3000 Patches: issue18284.rev1.txt uploaded by russell (license 2) Tested by: russell, klaus3000 (closes issue #18280) Reported by: klaus3000 Review: https://reviewboard.asterisk.org/r/1012/ git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.6.2@295710 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'main')
-rw-r--r--main/event.c157
1 files changed, 154 insertions, 3 deletions
diff --git a/main/event.c b/main/event.c
index f83a15c6f..33234711c 100644
--- a/main/event.c
+++ b/main/event.c
@@ -38,6 +38,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/utils.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/astobj2.h"
+#include "asterisk/cli.h"
struct ast_taskprocessor *event_dispatcher;
@@ -182,6 +183,13 @@ static struct {
};
/*!
+ * \brief Names of cached event types, for CLI tab completion
+ *
+ * \note These names must match what is in the event_names array.
+ */
+static char * const cached_event_types[] = { "MWI", "DeviceState", "DeviceStateChange", NULL };
+
+/*!
* The index of each entry _must_ match the event type number!
*/
static struct event_name {
@@ -470,9 +478,9 @@ static int match_ie_val(const struct ast_event *event,
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;
+ uint16_t ie_payload_len = event2 ? ast_event_get_ie_raw_payload_len(event2, ie_val->ie_type) : ie_val->raw_datalen;
+
+ return (buf && !memcmp(buf, ast_event_get_ie_raw(event, ie_val->ie_type), ie_payload_len)) ? 1 : 0;
}
if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS) {
@@ -855,6 +863,11 @@ void *ast_event_iterator_get_ie_raw(struct ast_event_iterator *iterator)
return iterator->ie->ie_payload;
}
+uint16_t ast_event_iterator_get_ie_raw_payload_len(struct ast_event_iterator *iterator)
+{
+ return ntohs(iterator->ie->ie_payload_len);
+}
+
enum ast_event_type ast_event_get_type(const struct ast_event *event)
{
return ntohs(event->type);
@@ -901,6 +914,20 @@ const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_i
return NULL;
}
+uint16_t ast_event_get_ie_raw_payload_len(const struct ast_event *event, enum ast_event_ie_type ie_type)
+{
+ struct ast_event_iterator iterator;
+ int res;
+
+ for (res = ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
+ if (ast_event_iterator_get_ie_type(&iterator) == ie_type) {
+ return ast_event_iterator_get_ie_raw_payload_len(&iterator);
+ }
+ }
+
+ return 0;
+}
+
int ast_event_append_ie_str(struct ast_event **event, enum ast_event_ie_type ie_type,
const char *str)
{
@@ -1334,6 +1361,128 @@ static int ast_event_cmp(void *obj, void *arg, int flags)
return res;
}
+static void dump_raw_ie(struct ast_event_iterator *i, struct ast_cli_args *a)
+{
+ char eid_buf[32];
+ enum ast_event_ie_type ie_type;
+ const char *ie_type_name;
+
+ ie_type = ast_event_iterator_get_ie_type(i);
+ ie_type_name = ast_event_get_ie_type_name(ie_type);
+
+ switch (ie_type) {
+ case AST_EVENT_IE_EID:
+ ast_eid_to_str(eid_buf, sizeof(eid_buf), ast_event_iterator_get_ie_raw(i));
+ ast_cli(a->fd, "%.30s: %s\n", ie_type_name, eid_buf);
+ break;
+ default:
+ ast_cli(a->fd, "%s\n", ie_type_name);
+ break;
+ }
+}
+
+static int event_dump_cli(void *obj, void *arg, int flags)
+{
+ const struct ast_event_ref *event_ref = obj;
+ const struct ast_event *event = event_ref->event;
+ struct ast_cli_args *a = arg;
+ struct ast_event_iterator i;
+
+ if (ast_event_iterator_init(&i, event)) {
+ ast_cli(a->fd, "Failed to initialize event iterator. :-(\n");
+ return 0;
+ }
+
+ ast_cli(a->fd, "Event: %s\n", ast_event_get_type_name(event));
+
+ do {
+ enum ast_event_ie_type ie_type;
+ enum ast_event_ie_pltype ie_pltype;
+ const char *ie_type_name;
+
+ ie_type = ast_event_iterator_get_ie_type(&i);
+ ie_type_name = ast_event_get_ie_type_name(ie_type);
+ ie_pltype = ast_event_get_ie_pltype(ie_type);
+
+ switch (ie_pltype) {
+ case AST_EVENT_IE_PLTYPE_UNKNOWN:
+ case AST_EVENT_IE_PLTYPE_EXISTS:
+ ast_cli(a->fd, "%s\n", ie_type_name);
+ break;
+ case AST_EVENT_IE_PLTYPE_STR:
+ ast_cli(a->fd, "%.30s: %s\n", ie_type_name,
+ ast_event_iterator_get_ie_str(&i));
+ break;
+ case AST_EVENT_IE_PLTYPE_UINT:
+ ast_cli(a->fd, "%.30s: %u\n", ie_type_name,
+ ast_event_iterator_get_ie_uint(&i));
+ break;
+ case AST_EVENT_IE_PLTYPE_RAW:
+ dump_raw_ie(&i, a);
+ break;
+ }
+ } while (!ast_event_iterator_next(&i));
+
+ ast_cli(a->fd, "\n");
+
+ return 0;
+}
+
+static char *event_dump_cache(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ enum ast_event_type event_type;
+ enum ast_event_ie_type *cache_args;
+ int i;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "event dump cache";
+ e->usage =
+ "Usage: event dump cache <event type>\n"
+ " Dump all of the cached events for the given event type.\n"
+ " This is primarily intended for debugging.\n";
+ return NULL;
+ case CLI_GENERATE:
+ if (a->pos == 3) {
+ return ast_cli_complete(a->word, cached_event_types, a->n);
+ }
+ return NULL;
+ case CLI_HANDLER:
+ break;
+ }
+
+ if (a->argc != e->args + 1) {
+ return CLI_SHOWUSAGE;
+ }
+
+ if (ast_event_str_to_event_type(a->argv[e->args], &event_type)) {
+ ast_cli(a->fd, "Invalid cached event type: '%s'\n", a->argv[e->args]);
+ return CLI_SHOWUSAGE;
+ }
+
+ if (!ast_event_cache[event_type].container) {
+ ast_cli(a->fd, "Event type '%s' has no cache.\n", a->argv[e->args]);
+ return CLI_SUCCESS;
+ }
+
+ ast_cli(a->fd, "Event Type: %s\n", a->argv[e->args]);
+ ast_cli(a->fd, "Cache Unique Keys:\n");
+ cache_args = ast_event_cache[event_type].cache_args;
+ for (i = 0; i < ARRAY_LEN(ast_event_cache[0].cache_args) && cache_args[i]; i++) {
+ ast_cli(a->fd, "--> %s\n", ast_event_get_ie_type_name(cache_args[i]));
+ }
+
+ ast_cli(a->fd, "\n--- Begin Cache Dump ---\n\n");
+ ao2_callback(ast_event_cache[event_type].container, OBJ_NODATA, event_dump_cli, a);
+ ast_cli(a->fd, "--- End Cache Dump ---\n\n");
+
+ return CLI_SUCCESS;
+}
+
+static struct ast_cli_entry event_cli[] = {
+ AST_CLI_DEFINE(event_dump_cache, "Dump the internal event cache (for debugging)"),
+};
+
int ast_event_init(void)
{
int i;
@@ -1358,5 +1507,7 @@ int ast_event_init(void)
return -1;
}
+ ast_cli_register_multiple(event_cli, ARRAY_LEN(event_cli));
+
return 0;
}