diff -ur --unidirectional-new-file asterisk-1.4.24.1/cdr/.cdr_broadcast.moduleinfo asterisk-1.4.24.1-new/cdr/.cdr_broadcast.moduleinfo
--- asterisk-1.4.24.1/cdr/.cdr_broadcast.moduleinfo 1970-01-01 01:00:00.000000000 +0100
+++ asterisk-1.4.24.1-new/cdr/.cdr_broadcast.moduleinfo 2009-05-12 18:12:48.000000000 +0200
@@ -0,0 +1,2 @@
+
+
diff -ur --unidirectional-new-file asterisk-1.4.24.1/cdr/.moduleinfo asterisk-1.4.24.1-new/cdr/.moduleinfo
--- asterisk-1.4.24.1/cdr/.moduleinfo 2009-04-02 19:44:23.000000000 +0200
+++ asterisk-1.4.24.1-new/cdr/.moduleinfo 2009-05-12 18:13:09.000000000 +0200
@@ -1,4 +1,6 @@
+
+
diff -ur --unidirectional-new-file asterisk-1.4.24.1/cdr/cdr_broadcast.c asterisk-1.4.24.1-new/cdr/cdr_broadcast.c
--- asterisk-1.4.24.1/cdr/cdr_broadcast.c 1970-01-01 01:00:00.000000000 +0100
+++ asterisk-1.4.24.1-new/cdr/cdr_broadcast.c 2009-05-12 18:13:22.000000000 +0200
@@ -0,0 +1,263 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Mark Spencer
+ *
+ * Includes code and algorithms from the Zapata library.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief UDP Event Broadcasting.
+ *
+ * \author Philipp Dunkel
+ *
+ * Uses cdr_broadcast.conf for configuration
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "--new--")
+
+#include "asterisk/manager.h"
+#include "asterisk/paths.h"
+#include "asterisk/module.h"
+#include "asterisk/cdr.h"
+#include "asterisk/config.h"
+#include "asterisk/lock.h"
+#include "asterisk/utils.h"
+#include "asterisk/threadstorage.h"
+#include "asterisk/strings.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+#define CDR_BROADCAST_FILE "cdr_broadcast.c"
+#define CDR_BROADCAST_CONFIG "cdr_broadcast.conf"
+#define CDR_BROADCAST_DESC "UDP Broadcasting of CDR and Manager Events"
+#define CDR_BROADCAST_LINELEN 1255
+
+#define DATE_FORMAT "%Y-%m-%d %T"
+#define STRPORT(str) str?htons(strtol(str,NULL,0)):0
+#define STRHOST(str) inet_addr(str?str:"127.0.0.1")
+#define SENDSTRING(sock, str) send(sock.socket, str, strlen(str)+1, 0)
+#define STRAPPEND(dst,src) strncat(dst, dst[0]?",\"":"\"",CDR_BROADCAST_LINELEN-strlen(dst)-1); strncat(dst,src?src:"",CDR_BROADCAST_LINELEN-strlen(dst)-1); strncat(dst,"\"", CDR_BROADCAST_LINELEN-strlen(dst)-1);
+#define INTAPPEND(dst,val) snprintf(&(dst[strlen(dst)]),CDR_BROADCAST_LINELEN-strlen(dst)-1,dst[0]?",\"%d\"":"\"%d\"",(int)val);
+#define DATAPPEND(dst,when) strncat(dst, dst[0]?",\"":"\"",CDR_BROADCAST_LINELEN-strlen(dst)-1); strftime(&(dst[strlen(dst)]), CDR_BROADCAST_LINELEN-strlen(dst)-1, DATE_FORMAT, &when); strncat(dst,"\"", CDR_BROADCAST_LINELEN-strlen(dst)-1);
+
+AST_MUTEX_DEFINE_STATIC(lock);
+
+static struct {
+ int enabled;
+ int multicast;
+ int socket;
+ struct sockaddr_in receiver;
+} global_evt_broadcast_socket;
+
+static struct {
+ int enabled;
+ int multicast;
+ int socket;
+ struct sockaddr_in receiver;
+} global_cdr_broadcast_socket;
+
+static struct manager_custom_hook global_evt_multicast_hook;
+
+static int evt_multicast(int category, const char* event, char * data) {
+ if (!global_evt_broadcast_socket.enabled) return 1;
+
+ ast_mutex_lock(&lock);
+ if (SENDSTRING(global_evt_broadcast_socket, data) < 0) {
+ ast_log(LOG_ERROR, "%d -> %s\n", errno, strerror(errno));
+ }
+ ast_mutex_unlock(&lock);
+
+ return 0;
+}
+
+static int cdr_multicast(struct ast_cdr *cdr) {
+ if (!global_cdr_broadcast_socket.enabled) return 1;
+
+ struct tm tm;
+ char buffer[CDR_BROADCAST_LINELEN];
+ buffer[0] = 0;
+
+ STRAPPEND(buffer, cdr->accountcode);
+ STRAPPEND(buffer, cdr->src);
+ STRAPPEND(buffer, cdr->dst);
+ STRAPPEND(buffer, cdr->dcontext);
+ STRAPPEND(buffer, cdr->clid);
+ STRAPPEND(buffer, cdr->channel);
+ STRAPPEND(buffer, cdr->dstchannel);
+ STRAPPEND(buffer, cdr->lastapp);
+ STRAPPEND(buffer, cdr->lastdata);
+ gmtime_r(&(cdr->start.tv_sec), &tm);
+ DATAPPEND(buffer, tm);
+ gmtime_r(&(cdr->answer.tv_sec), &tm);
+ DATAPPEND(buffer, tm);
+ gmtime_r(&(cdr->end.tv_sec), &tm);
+ DATAPPEND(buffer, tm);
+ INTAPPEND(buffer, cdr->duration);
+ INTAPPEND(buffer, cdr->billsec);
+ STRAPPEND(buffer, ast_cdr_disp2str(cdr->disposition));
+ STRAPPEND(buffer, ast_cdr_disp2str(cdr->amaflags));
+ STRAPPEND(buffer, cdr->uniqueid);
+ STRAPPEND(buffer, cdr->userfield);
+
+ ast_mutex_lock(&lock);
+ if (SENDSTRING(global_cdr_broadcast_socket, buffer) < 0) {
+ ast_log(LOG_ERROR, "%d -> %s\n", errno, strerror(errno));
+ } else {
+ ast_log(LOG_WARNING, "%s\n", buffer);
+ }
+ ast_mutex_unlock(&lock);
+
+ return 0;
+}
+
+static int load_config(int reload) {
+ char *cat = NULL;
+ struct ast_config *cfg;
+ struct ast_variable *var;
+
+ cfg = ast_config_load(CDR_BROADCAST_CONFIG);
+
+ if (!cfg) {
+ ast_log(LOG_ERROR, "Invalid config file\n");
+ return 1;
+ }
+
+ ast_mutex_lock(&lock);
+
+ while ((cat = ast_category_browse(cfg, cat))) {
+ if (!strcasecmp(cat,"events")) {
+ var = ast_variable_browse(cfg, cat);
+ while (var) {
+ if (var->value && !strcasecmp(var->name, "enabled")) {
+ global_evt_broadcast_socket.enabled = ((ast_true(var->value))?1:0);
+ } else if (var->value && !strcasecmp(var->name, "host")) {
+ global_evt_broadcast_socket.receiver.sin_addr.s_addr = STRHOST(var->value);
+ } else if (var->value && !strcasecmp(var->name, "port")) {
+ global_evt_broadcast_socket.receiver.sin_port = STRPORT(var->value);
+ }
+ var = var->next;
+ }
+ } else if (!strcasecmp(cat,"cdr")) {
+ var = ast_variable_browse(cfg, cat);
+ while (var) {
+ if (var->value && !strcasecmp(var->name, "enabled")) {
+ global_cdr_broadcast_socket.enabled = ((ast_true(var->value))?1:0);
+ } else if (var->value && !strcasecmp(var->name, "host")) {
+ global_cdr_broadcast_socket.receiver.sin_addr.s_addr = STRHOST(var->value);
+ } else if (var->value && !strcasecmp(var->name, "port")) {
+ global_cdr_broadcast_socket.receiver.sin_port = STRPORT(var->value);
+ }
+ var = var->next;
+ }
+ }
+ }
+ ast_mutex_unlock(&lock);
+
+ return 0;
+}
+
+static int unload_module(void) {
+ if (global_evt_broadcast_socket.enabled) {
+ ast_manager_unregister_hook(&global_evt_multicast_hook);
+ if (global_evt_broadcast_socket.socket > -1) close(global_evt_broadcast_socket.socket);
+ }
+ memset(&(global_evt_broadcast_socket.receiver), 0, sizeof(global_evt_broadcast_socket.receiver));
+ global_evt_broadcast_socket.socket = -1;
+ global_evt_broadcast_socket.enabled = 0;
+ global_evt_broadcast_socket.multicast = 0;
+ global_evt_broadcast_socket.receiver.sin_family = AF_INET;
+
+ if (global_cdr_broadcast_socket.enabled) {
+ ast_cdr_unregister(CDR_BROADCAST_FILE);
+ if (global_cdr_broadcast_socket.socket > -1) close(global_cdr_broadcast_socket.socket);
+ }
+ memset(&(global_cdr_broadcast_socket.receiver), 0, sizeof(global_cdr_broadcast_socket.receiver));
+ global_cdr_broadcast_socket.socket = -1;
+ global_cdr_broadcast_socket.enabled = 0;
+ global_cdr_broadcast_socket.multicast = 0;
+ global_cdr_broadcast_socket.receiver.sin_family = AF_INET;
+
+ return 0;
+}
+
+static int load_module(void) {
+ int optval = 1;
+ global_evt_broadcast_socket.enabled = 0;
+ global_cdr_broadcast_socket.enabled = 0;
+
+ if (unload_module()) return AST_MODULE_LOAD_DECLINE;
+
+ if (load_config(0)) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ if (global_evt_broadcast_socket.enabled) {
+ global_evt_multicast_hook.file = CDR_BROADCAST_FILE;
+ global_evt_multicast_hook.helper = evt_multicast;
+ global_evt_broadcast_socket.socket = socket(PF_INET, SOCK_DGRAM, 0);
+ if (global_evt_broadcast_socket.socket < 0) {
+ ast_log(LOG_WARNING, "Error Opening Socket: %s\n", strerror(errno));
+ global_evt_broadcast_socket.enabled = 0;
+ } else {
+ setsockopt(global_evt_broadcast_socket.socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);
+ setsockopt(global_evt_broadcast_socket.socket, SOL_SOCKET, SO_BROADCAST, &optval, sizeof optval);
+ if (connect(global_evt_broadcast_socket.socket,(struct sockaddr *)&(global_evt_broadcast_socket.receiver),sizeof(struct sockaddr_in))) {
+ ast_log(LOG_ERROR, "%d -> %s\n", errno, strerror(errno));
+ global_evt_broadcast_socket.enabled = 0;
+ } else {
+ ast_log(LOG_WARNING, "Connected to %s:%d\n", ast_inet_ntoa(global_evt_broadcast_socket.receiver.sin_addr), ntohs(global_evt_broadcast_socket.receiver.sin_port));
+ ast_manager_register_hook(&global_evt_multicast_hook);
+ }
+ }
+ }
+
+ if (global_cdr_broadcast_socket.enabled) {
+ global_cdr_broadcast_socket.socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (global_cdr_broadcast_socket.socket < 0) {
+ ast_log(LOG_WARNING, "Error Opening Socket: %s\n", strerror(errno));
+ global_cdr_broadcast_socket.enabled = 0;
+ } else {
+ if (global_cdr_broadcast_socket.multicast) {
+ setsockopt(global_cdr_broadcast_socket.socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);
+ setsockopt(global_cdr_broadcast_socket.socket, SOL_SOCKET, SO_BROADCAST, &optval, sizeof optval);
+ }
+ if (connect(global_cdr_broadcast_socket.socket,(struct sockaddr *)&(global_cdr_broadcast_socket.receiver),sizeof(struct sockaddr_in))) {
+ ast_log(LOG_ERROR, "%d -> %s\n", errno, strerror(errno));
+ global_cdr_broadcast_socket.enabled = 0;
+ } else {
+ ast_cdr_register(CDR_BROADCAST_FILE, CDR_BROADCAST_DESC, cdr_multicast);
+ }
+ }
+ }
+
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, CDR_BROADCAST_DESC,
+ .load = load_module,
+ .unload = unload_module,
+ .reload = load_module,
+);
diff -ur --unidirectional-new-file asterisk-1.4.24.1/configs/cdr_broadcast.conf.sample asterisk-1.4.24.1-new/configs/cdr_broadcast.conf.sample
--- asterisk-1.4.24.1/configs/cdr_broadcast.conf.sample 1970-01-01 01:00:00.000000000 +0100
+++ asterisk-1.4.24.1-new/configs/cdr_broadcast.conf.sample 2009-05-12 18:13:44.000000000 +0200
@@ -0,0 +1,16 @@
+;
+; Sample CDR-Multicast Configuration
+;
+[events]
+; Is the sending of Manager Events Enabled
+enabled=off
+; To which IP and Port are Manager Events sent
+host=225.0.1.1
+port=1811
+
+[cdr]
+; Is the sending of CDR Events Enabled
+enabled=off
+; To which IP and Port are CDR Events sent
+host=225.0.1.1
+port=1811
diff -ur --unidirectional-new-file asterisk-1.4.24.1/include/asterisk/manager.h asterisk-1.4.24.1-new/include/asterisk/manager.h
--- asterisk-1.4.24.1/include/asterisk/manager.h 2009-02-16 00:37:03.000000000 +0100
+++ asterisk-1.4.24.1-new/include/asterisk/manager.h 2009-05-12 18:23:35.000000000 +0200
@@ -26,6 +26,7 @@
#include
#include "asterisk/lock.h"
+#include "asterisk/linkedlists.h"
/*!
\file
@@ -81,6 +82,28 @@
struct manager_action *next;
};
+/*! \brief Manager Helper Function */
+typedef int (*manager_hook_t)(int, const char *, char *);
+
+struct manager_custom_hook {
+ /*! Identifier */
+ char *file;
+ /*! helper function */
+ manager_hook_t helper;
+ /*! Linked list information */
+ AST_RWLIST_ENTRY(manager_custom_hook) list;
+};
+
+/*! Add a custom hook to be called when an event is fired
+ \param hook struct manager_custom_hook object to add
+*/
+void ast_manager_register_hook(struct manager_custom_hook *hook);
+
+/*! Delete a custom hook to be called when an event is fired
+ \param hook struct manager_custom_hook object to delete
+*/
+void ast_manager_unregister_hook(struct manager_custom_hook *hook);
+
/* External routines may register/unregister manager callbacks this way */
#define ast_manager_register(a, b, c, d) ast_manager_register2(a, b, c, d, NULL)
diff -ur --unidirectional-new-file asterisk-1.4.24.1/main/manager.c asterisk-1.4.24.1-new/main/manager.c
--- asterisk-1.4.24.1/main/manager.c 2009-01-28 19:51:16.000000000 +0100
+++ asterisk-1.4.24.1-new/main/manager.c 2009-05-12 18:23:11.000000000 +0200
@@ -204,6 +204,26 @@
static struct manager_action *first_action;
AST_RWLOCK_DEFINE_STATIC(actionlock);
+static AST_RWLIST_HEAD_STATIC(manager_hooks, manager_custom_hook);
+
+/*! \brief Add a custom hook to be called when an event is fired */
+void ast_manager_register_hook(struct manager_custom_hook *hook)
+{
+ AST_RWLIST_WRLOCK(&manager_hooks);
+ AST_RWLIST_INSERT_TAIL(&manager_hooks, hook, list);
+ AST_RWLIST_UNLOCK(&manager_hooks);
+ return;
+}
+
+/*! \brief Delete a custom hook to be called when an event is fired */
+void ast_manager_unregister_hook(struct manager_custom_hook *hook)
+{
+ AST_RWLIST_WRLOCK(&manager_hooks);
+ AST_RWLIST_REMOVE(&manager_hooks, hook, list);
+ AST_RWLIST_UNLOCK(&manager_hooks);
+ return;
+}
+
/*! \brief Convert authority code to string with serveral options */
static char *authority_to_str(int authority, char *res, int reslen)
{
@@ -2509,6 +2529,7 @@
int manager_event(int category, const char *event, const char *fmt, ...)
{
struct mansession *s;
+ struct manager_custom_hook *hook;
char auth[80];
va_list ap;
struct timeval now;
@@ -2556,6 +2577,12 @@
}
AST_LIST_UNLOCK(&sessions);
+ AST_RWLIST_RDLOCK(&manager_hooks);
+ AST_RWLIST_TRAVERSE(&manager_hooks, hook, list) {
+ hook->helper(category, event, buf->str);
+ }
+ AST_RWLIST_UNLOCK(&manager_hooks);
+
return 0;
}