[asterisk-commits] russell: branch russell/events r111242 - in /team/russell/events: include/ast...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Mar 26 17:03:44 CDT 2008
Author: russell
Date: Wed Mar 26 17:03:44 2008
New Revision: 111242
URL: http://svn.digium.com/view/asterisk?view=rev&rev=111242
Log:
Commit everything from my working copy. The most significant changes are
adding res_xmlevents, and associated supporting code in the event API.
res_xmlevents is what I started playing with while traveling this week. It is
a socket API for monitoring internal Asterisk events that supports the following:
- connecting via TCP and TLS
- XML encoded interface
- per-connection dynamic subscription support to allow clients to decide what
events they receive
The biggest thing left to do is to add user accounts with access control and
authentication.
Added:
team/russell/events/res/res_xmlevents.c
- copied, changed from r110870, team/russell/events/res/res_xmlevents.c
Modified:
team/russell/events/include/asterisk/event.h
team/russell/events/include/asterisk/event_defs.h
team/russell/events/include/asterisk/tcptls.h
team/russell/events/main/devicestate.c
team/russell/events/main/event.c
team/russell/events/main/tcptls.c
team/russell/events/res/res_ais.c
Modified: team/russell/events/include/asterisk/event.h
URL: http://svn.digium.com/view/asterisk/team/russell/events/include/asterisk/event.h?view=diff&rev=111242&r1=111241&r2=111242
==============================================================================
--- team/russell/events/include/asterisk/event.h (original)
+++ team/russell/events/include/asterisk/event.h Wed Mar 26 17:03:44 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>
*
@@ -436,6 +436,10 @@
*/
const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_ie_type ie_type);
+const char *ast_event_get_ie_type_name(enum ast_event_ie_type 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
*
@@ -445,6 +449,12 @@
* ast_event_type enum
*/
enum ast_event_type ast_event_get_type(const struct ast_event *event);
+
+const char *ast_event_get_type_name(const struct ast_event *event);
+
+int ast_event_str_to_event_type(const char *str, enum ast_event_type *event_type);
+
+int ast_event_str_to_ie_type(const char *str, enum ast_event_ie_type *ie_type);
/*!
* \brief Get the size of an event
Modified: team/russell/events/include/asterisk/event_defs.h
URL: http://svn.digium.com/view/asterisk/team/russell/events/include/asterisk/event_defs.h?view=diff&rev=111242&r1=111241&r2=111242
==============================================================================
--- team/russell/events/include/asterisk/event_defs.h (original)
+++ team/russell/events/include/asterisk/event_defs.h Wed Mar 26 17:03:44 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>
*
@@ -30,26 +30,26 @@
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,
+ 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,
+ 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,
+ 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,
+ 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 = 0x07,
+ AST_EVENT_TOTAL = 0x07,
};
/*! \brief Event Information Element types */
@@ -122,6 +122,8 @@
AST_EVENT_IE_EID = 0x0A,
};
+#define AST_EVENT_IE_MAX AST_EVENT_IE_EID
+
/*!
* \brief Payload types for event information elements
*/
@@ -154,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/events/include/asterisk/tcptls.h
URL: http://svn.digium.com/view/asterisk/team/russell/events/include/asterisk/tcptls.h?view=diff&rev=111242&r1=111241&r2=111242
==============================================================================
--- team/russell/events/include/asterisk/tcptls.h (original)
+++ team/russell/events/include/asterisk/tcptls.h Wed Mar 26 17:03:44 2008
@@ -48,6 +48,8 @@
#ifndef _ASTERISK_SERVER_H
#define _ASTERISK_SERVER_H
+
+#include <fcntl.h>
#include "asterisk/utils.h"
@@ -127,6 +129,7 @@
int client;
struct sockaddr_in requestor;
struct server_args *parent;
+ pthread_t worker_thread;
};
/*! \brief
Modified: team/russell/events/main/devicestate.c
URL: http://svn.digium.com/view/asterisk/team/russell/events/main/devicestate.c?view=diff&rev=111242&r1=111241&r2=111242
==============================================================================
--- team/russell/events/main/devicestate.c (original)
+++ team/russell/events/main/devicestate.c Wed Mar 26 17:03:44 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
@@ -21,11 +22,16 @@
* \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,
@@ -417,6 +423,8 @@
{
struct ast_event *event;
+ 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,
@@ -697,6 +705,8 @@
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);
Modified: team/russell/events/main/event.c
URL: http://svn.digium.com/view/asterisk/team/russell/events/main/event.c?view=diff&rev=111242&r1=111241&r2=111242
==============================================================================
--- team/russell/events/main/event.c (original)
+++ team/russell/events/main/event.c Wed Mar 26 17:03:44 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>
*
@@ -78,12 +78,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;
-};
-
/*! \brief data shared between event dispatching threads */
static struct {
ast_cond_t cond;
@@ -126,6 +120,107 @@
* for events that express some sort of state. So, when someone first
* 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)
{
@@ -365,7 +460,7 @@
{
struct ast_event_sub *sub;
- if (type >= AST_EVENT_TOTAL) {
+ if (type < 0 || type >= AST_EVENT_TOTAL) {
ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
return NULL;
}
@@ -386,6 +481,9 @@
{
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;
@@ -403,6 +501,9 @@
{
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;
@@ -419,6 +520,9 @@
{
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;
@@ -439,6 +543,9 @@
enum ast_event_ie_type ie_type, void *data, size_t raw_datalen)
{
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;
@@ -547,7 +654,7 @@
struct ast_event *event;
AST_RWLIST_WRLOCK(&ast_event_subs[sub->type]);
- AST_LIST_REMOVE(&ast_event_subs[sub->type], sub, entry);
+ AST_RWLIST_REMOVE(&ast_event_subs[sub->type], sub, entry);
AST_RWLIST_UNLOCK(&ast_event_subs[sub->type]);
if (ast_event_check_subscriber(AST_EVENT_UNSUB,
@@ -752,7 +859,7 @@
struct ast_event *dup_event;
uint16_t event_len;
- event_len = ntohs(event->event_len);
+ event_len = ast_event_get_size(event);
if (!(dup_event = ast_calloc(1, event_len)))
return NULL;
Modified: team/russell/events/main/tcptls.c
URL: http://svn.digium.com/view/asterisk/team/russell/events/main/tcptls.c?view=diff&rev=111242&r1=111241&r2=111242
==============================================================================
--- team/russell/events/main/tcptls.c (original)
+++ team/russell/events/main/tcptls.c Wed Mar 26 17:03:44 2008
@@ -106,7 +106,6 @@
struct sockaddr_in sin;
socklen_t sinlen;
struct ast_tcptls_session_instance *ser;
- pthread_t launched;
for (;;) {
int i, flags;
@@ -137,7 +136,7 @@
ser->client = 0;
- if (ast_pthread_create_detached_background(&launched, NULL, ast_make_file_from_fd, ser)) {
+ if (ast_pthread_create_detached_background(&ser->worker_thread, NULL, ast_make_file_from_fd, ser)) {
ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno));
close(ser->fd);
ast_free(ser);
Modified: team/russell/events/res/res_ais.c
URL: http://svn.digium.com/view/asterisk/team/russell/events/res/res_ais.c?view=diff&rev=111242&r1=111241&r2=111242
==============================================================================
--- team/russell/events/res/res_ais.c (original)
+++ team/russell/events/res/res_ais.c Wed Mar 26 17:03:44 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>
*
Copied: team/russell/events/res/res_xmlevents.c (from r110870, team/russell/events/res/res_xmlevents.c)
URL: http://svn.digium.com/view/asterisk/team/russell/events/res/res_xmlevents.c?view=diff&rev=111242&p1=team/russell/events/res/res_xmlevents.c&r1=110870&p2=team/russell/events/res/res_xmlevents.c&r2=111242
==============================================================================
--- team/russell/events/res/res_xmlevents.c (original)
+++ team/russell/events/res/res_xmlevents.c Wed Mar 26 17:03:44 2008
@@ -27,9 +27,16 @@
* \todo subscription support instead of spamming all events
*/
+/*** MODULEINFO
+ <depend>xml2</depend>
+ ***/
+
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
#include "asterisk/logger.h"
#include "asterisk/module.h"
@@ -57,9 +64,19 @@
AST_LIST_ENTRY(pending_event) entry;
};
+static unsigned int unique_sub_id;
+
+struct xml_event_sub {
+ unsigned int sub_id;
+ char *request_id;
+ struct ast_event_sub *sub;
+ unsigned int subscribed:1;
+ AST_LIST_ENTRY(xml_event_sub) entry;
+};
+
struct xml_events_session {
- struct ast_event_sub *sub;
struct ast_tcptls_session_instance *ser;
+ AST_LIST_HEAD_NOLOCK(, xml_event_sub) event_subs;
AST_LIST_HEAD_NOLOCK(, pending_event) pending_events;
unsigned int stop:1;
};
@@ -90,10 +107,32 @@
.worker_fn = session_do, /* thread handling the session */
};
+static struct xml_event_sub *xml_event_sub_destroy(struct xml_event_sub *event_sub)
+{
+ if (event_sub->sub) {
+ if (event_sub->subscribed)
+ ast_event_unsubscribe(event_sub->sub);
+ else
+ ast_event_sub_destroy(event_sub->sub);
+
+ event_sub->sub = NULL;
+ }
+
+ if (event_sub->request_id) {
+ ast_free(event_sub->request_id);
+ event_sub->request_id = NULL;
+ }
+
+ ast_free(event_sub);
+
+ return NULL;
+}
+
static void xml_events_session_destructor(void *obj)
{
struct xml_events_session *session = obj;
struct pending_event *pending_event;
+ struct xml_event_sub *event_sub;
if (session->ser) {
fclose(session->ser->f);
@@ -101,13 +140,12 @@
session->ser = NULL;
}
- if (session->sub) {
- ast_event_unsubscribe(session->sub);
- session->sub = NULL;
- }
-
while ((pending_event = AST_LIST_REMOVE_HEAD(&session->pending_events, entry))) {
ast_free(pending_event);
+ }
+
+ while ((event_sub = AST_LIST_REMOVE_HEAD(&session->event_subs, entry))) {
+ xml_event_sub_destroy(event_sub);
}
}
@@ -142,21 +180,12 @@
static void begin_event_tag(struct ast_str **buf, const struct ast_event *event)
{
- const char *name;
-
- ast_str_set(buf, 0, "<event type=\"%d\"", ast_event_get_type(event));
-
- name = ast_event_get_type_name(event);
- if (!ast_strlen_zero(name)) {
- ast_str_append(buf, 0, " name=\"%s\"", name);
- }
-
- ast_str_append(buf, 0, ">\n");
+ ast_str_set(buf, 0, "<event name=\"%s\">\n", ast_event_get_type_name(event));
}
static void end_event_tag(struct ast_str **buf)
{
- ast_str_append(buf, 0, "</event>\n");
+ ast_str_append(buf, 0, "</event>\n\n");
}
static int handle_raw_ie(struct ast_str **buf, enum ast_event_ie_type ie_type, struct ast_event_iterator *iter)
@@ -183,16 +212,10 @@
{
enum ast_event_ie_type ie_type;
enum ast_event_ie_pltype ie_pltype;
- const char *name;
ie_type = ast_event_iterator_get_ie_type(iter);
- ast_str_append(buf, 0, " <ie type=\"%d\"", ie_type);
-
- name = ast_event_get_ie_type_name(ie_type);
- if (!ast_strlen_zero(name)) {
- ast_str_append(buf, 0, " name=\"%s\"", name);
- }
+ ast_str_append(buf, 0, " <ie name=\"%s\"", ast_event_get_ie_type_name(ie_type));
ie_pltype = ast_event_get_ie_pltype(ie_type);
switch (ie_pltype) {
@@ -263,10 +286,212 @@
return 0;
}
+static void finalize_parsing(xmlParserCtxtPtr ctxt)
+{
+ int errors;
+ char buf[1] = "";
+
+ /* Indicate that parsing is complete */
+ if ((errors = xmlParseChunk(ctxt, buf, 0, 1))) {
+ ast_debug(1, "Error(s) occurred when finalizing parsing: %d\n", errors);
+ return;
+ }
+}
+
+static int append_raw_ie_to_sub(struct ast_event_sub *sub, int type, xmlNode *ie_node)
+{
+ enum ast_event_ie_type ie_type = type;
+
+ switch (ie_type) {
+ case AST_EVENT_IE_EID:
+ {
+ struct ast_eid eid;
+
+ ast_str_to_eid(&eid, (const char *) ie_node->content);
+
+ return ast_event_sub_append_ie_raw(sub, type, &eid, sizeof(eid)) ? -1 : 0;
+ }
+ default:
+ return -1;
+ }
+}
+
+static int handle_subscription_ie(struct xml_event_sub *event_sub, xmlNode *ie_node)
+{
+ const char *attr_str;
+ enum ast_event_ie_type type;
+ enum ast_event_ie_pltype ie_pltype;
+ int res;
+
+ attr_str = (const char *) xmlGetProp(ie_node, (const xmlChar *) "name");
+ if (ast_strlen_zero(attr_str)) {
+ ast_log(LOG_ERROR, "Subscription received with no type.\n");
+ return -1;
+ }
+
+ if (ast_event_str_to_ie_type(attr_str, &type)) {
+ ast_log(LOG_ERROR, "Invalid IE type - '%s'\n", attr_str);
+ return -1;
+ }
+
+ if (ast_strlen_zero((const char *) ie_node->content)) {
+ return ast_event_sub_append_ie_exists(event_sub->sub, type) ? -1 : 0;
+ }
+
+ ie_pltype = ast_event_get_ie_pltype(type);
+ switch (ie_pltype) {
+ case AST_EVENT_IE_PLTYPE_UINT:
+ {
+ uint32_t payload;
+
+ if (sscanf((const char *) ie_node->content, "%u", &payload) != 1) {
+ ast_log(LOG_ERROR, "Invalid payload for IE\n");
+ return -1;
+ }
+
+ res = ast_event_sub_append_ie_uint(event_sub->sub, type, payload);
+ }
+ case AST_EVENT_IE_PLTYPE_STR:
+ res = ast_event_sub_append_ie_str(event_sub->sub, type, (const char *) ie_node->content);
+ break;
+ case AST_EVENT_IE_PLTYPE_RAW:
+ res = append_raw_ie_to_sub(event_sub->sub, type, ie_node);
+ break;
+ case AST_EVENT_IE_PLTYPE_UNKNOWN:
+ ast_log(LOG_WARNING, "Payload type unknown for IE of type '%d'\n", type);
+ /* fall through */
+ case AST_EVENT_IE_PLTYPE_EXISTS:
+ res = ast_event_sub_append_ie_exists(event_sub->sub, type);
+ break;
+ }
+
+ return res;
+}
+
+static void handle_unsubscribe(struct xml_events_session *session, xmlNode *root_node)
+{
+ const char *attr_str;
+ unsigned int id;
+ struct xml_event_sub *event_sub;
+
+ attr_str = (const char *) xmlGetProp(root_node, (const xmlChar *) "id");
+ if (ast_strlen_zero(attr_str)) {
+ ast_log(LOG_ERROR, "Subscription received with no type.\n");
+ return;
+ }
+
+ if (sscanf(attr_str, "%u", &id) != 1) {
+ ast_log(LOG_WARNING, "Subscription id not valid - '%d'\n", id);
+ return;
+ }
+
+ ao2_lock(session);
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&session->event_subs, event_sub, entry) {
+ if (event_sub->sub_id != id)
+ continue;
+
+ AST_LIST_REMOVE_CURRENT(entry);
+ event_sub = xml_event_sub_destroy(event_sub);
+ break;
+ }
+ AST_LIST_TRAVERSE_SAFE_END
+ ao2_unlock(session);
+}
+
+/*! \todo XXX Send failure responses, too */
+static void handle_subscribe(struct xml_events_session *session, xmlNode *root_node)
+{
+ xmlNode *cur_node;
+ const char *attr_str;
+ enum ast_event_type type;
+ struct xml_event_sub *event_sub;
+
+ attr_str = (const char *) xmlGetProp(root_node, (const xmlChar *) "name");
+ if (ast_strlen_zero(attr_str)) {
+ ast_log(LOG_ERROR, "Subscription received with no name.\n");
+ return;
+ }
+
+ if (ast_event_str_to_event_type(attr_str, &type)) {
+ ast_log(LOG_ERROR, "Invalid event type - '%s'\n", attr_str);
+ return;
+ }
+
+ if (!(event_sub = ast_calloc(1, sizeof(*event_sub)))) {
+ return;
+ }
+
+ event_sub->sub_id = ast_atomic_fetchadd_int((int *) &unique_sub_id, +1);
+
+ attr_str = (const char *) xmlGetProp(root_node, (const xmlChar *) "request_id");
+ if (!ast_strlen_zero(attr_str)) {
+ if (!(event_sub->request_id = ast_strdup(attr_str))) {
+ event_sub = xml_event_sub_destroy(event_sub);
+ return;
+ }
+ }
+
+ if (!(event_sub->sub = ast_event_subscribe_new(type, event_cb, session))) {
+ event_sub = xml_event_sub_destroy(event_sub);
+ return;
+ }
+
+ for (cur_node = root_node->children; cur_node; cur_node = cur_node->next) {
+ if (cur_node->type != XML_ELEMENT_NODE) {
+ ast_debug(1, "Came across something that wasn't a node, type '%d'\n", cur_node->type);
+ continue;
+ }
+
+ if (!strcasecmp((const char *) cur_node->name, "ie")) {
+ if (handle_subscription_ie(event_sub, cur_node)) {
+ event_sub = xml_event_sub_destroy(event_sub);
+ return;
+ }
+ } else {
+ ast_log(LOG_WARNING, "Came across unexpected node called '%s'\n", (const char *) cur_node->name);
+ }
+ }
+
+ if (ast_strlen_zero(event_sub->request_id)) {
+ fprintf(session->ser->f, "<subscription id=\"%u\"/>\n\n", event_sub->sub_id);
+ } else {
+ fprintf(session->ser->f, "<subscription id=\"%u\" request_id=\"%s\"/>\n\n",
+ event_sub->sub_id, event_sub->request_id);
+ }
+ fflush(session->ser->f);
+
+ ao2_lock(session);
+ ast_event_sub_activate(event_sub->sub);
+ event_sub->subscribed = 1;
+ AST_LIST_INSERT_TAIL(&session->event_subs, event_sub, entry);
+ ao2_unlock(session);
+}
+
+static void process_xml_request(struct xml_events_session *session, xmlDocPtr doc)
+{
+ xmlNode *cur_node;
+
+ for (cur_node = xmlDocGetRootElement(doc); cur_node; cur_node = cur_node->next) {
+ if (cur_node->type != XML_ELEMENT_NODE) {
+ ast_debug(1, "Came across something that wasn't a node, type '%d'\n", cur_node->type);
+ continue;
+ }
+
+ ast_debug(1, "node type: Element, name: %s\n", cur_node->name);
+
+ if (!strcasecmp((const char *) cur_node->name, "subscribe")) {
+ handle_subscribe(session, cur_node);
+ } else if (!strcasecmp((const char *) cur_node->name, "unsubscribe")) {
+ handle_unsubscribe(session, cur_node);
+ } else {
+ ast_log(LOG_WARNING, "Came across unexpected node called '%s'\n", (const char *) cur_node->name);
+ }
+ }
+}
+
static void *session_do(void *data)
{
struct xml_events_session *session;
- int flags;
if (!(session = ao2_alloc(sizeof(*session), xml_events_session_destructor))) {
return NULL;
@@ -274,19 +499,11 @@
session->ser = data;
- flags = fcntl(session->ser->fd, F_GETFL);
- flags |= O_NONBLOCK;
- fcntl(session->ser->fd, F_SETFL, flags);
-
- /* XXX temporary hack. Eventually add subscription support. */
- session->sub = ast_event_subscribe(AST_EVENT_ALL, event_cb, session, AST_EVENT_IE_END);
- if (!session->sub) {
- session = unref_session(session);
- return NULL;
- }
-
while (!session->stop) {
int res;
+ char buf[2048];
+ xmlParserCtxtPtr ctxt = NULL;
+ xmlDocPtr doc = NULL;
res = handle_events(session);
if (res < 0) {
@@ -307,20 +524,92 @@
continue;
}
- res = fread(buf, 1, sizeof(buf), session->ser->f);
- if (res < 1) {
- ast_debug(1, "fread() returned < 1, breaking out of session loop.\n");
+ for (;;) {
+ int errors;
+ size_t len;
+
+ buf[0] = '\0';
+
+ fgets(buf, sizeof(buf), session->ser->f);
+ if (feof(session->ser->f)) {
+ break;
+ }
+
+ len = strlen(buf);
+
+ if (len && buf[len - 1] == '\n') {
+ buf[--len] = '\0';
+ if (len && buf[len - 1] == '\r') {
+ buf[--len] = '\0';
+ }
+ }
+
+ if (ast_strlen_zero(buf)) {
+ /* End of request */
+ ast_debug(1, "End of XML request\n");
+
+ if (!ctxt) {
+ ast_debug(1, "XML request ended, but there is no XML parsing context to work with ...\n");
+ break;
+ }
+
+ ast_debug(1, "Finalizing parsing of XML request.\n");
+
+ finalize_parsing(ctxt);
+
+ if (!ctxt->wellFormed) {
+ ast_log(LOG_WARNING, "XML Request not properly formatted\n");
+ break;
+ }
+
+ ast_debug(1, "Processing received XML request.\n");
+
+ doc = ctxt->myDoc;
+ process_xml_request(session, doc);
+
+ break;
+ }
+
+ ast_debug(1, "Got line: %s\n", buf);
+
+ if (!ctxt) {
+ if (!(ctxt = xmlCreatePushParserCtxt(NULL, NULL, buf, len,
+ ast_inet_ntoa(session->ser->requestor.sin_addr)))) {
+ ast_log(LOG_WARNING, "Failed to create the XML parser context\n");
+ break;
+ }
+ ast_debug(1, "Created XML parser context\n");
+ continue;
+ }
+
+ if ((errors = xmlParseChunk(ctxt, buf, len, 0))) {
+ ast_debug(1, "Error(s) occurred when finalizing parsing: %d\n", errors);
+ break;
+ }
+ }
+
+ if (ctxt) {
+ ast_debug(1, "Destroying XML parser context.\n");
+ xmlFreeParserCtxt(ctxt);
+ ctxt = NULL;
+ }
+
+ if (doc) {
+ ast_debug(1, "Destroying XML document.\n");
+ xmlFreeDoc(doc);
+ doc = NULL;
+ }
+
+ if (feof(session->ser->f)) {
+ ast_debug(1, "Session EOF, tearing down\n");
break;
}
-
- /* XXX Eventually support subscriptions ... */
}
session = unref_session(session);
return NULL;
}
-
static void store_port(const char *val, struct sockaddr_in *sin)
{
@@ -440,6 +729,8 @@
static int load_module(void)
{
+ LIBXML_TEST_VERSION;
+
if (!(xml_events_sessions = ao2_container_alloc(NUM_SESSIONS_BUCKETS,
xml_events_session_hash, xml_events_session_cmp))) {
return AST_MODULE_LOAD_DECLINE;
More information about the asterisk-commits
mailing list