diff -ur --unidirectional-new-file original/cdr/.cdr_broadcast.moduleinfo work/cdr/.cdr_broadcast.moduleinfo
--- original/cdr/.cdr_broadcast.moduleinfo 1970-01-01 01:00:00.000000000 +0100
+++ work/cdr/.cdr_broadcast.moduleinfo 2009-05-12 18:34:27.000000000 +0200
@@ -0,0 +1,2 @@
+
+
diff -ur --unidirectional-new-file original/cdr/.moduleinfo work/cdr/.moduleinfo
--- original/cdr/.moduleinfo 1970-01-01 01:00:00.000000000 +0100
+++ work/cdr/.moduleinfo 2009-05-12 18:34:38.000000000 +0200
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+ unixodbc
+ ltdl
+
+
+ pgsql
+
+
+ radius
+
+
+ sqlite
+
+
+ freetds
+
+
diff -ur --unidirectional-new-file original/cdr/cdr_broadcast.c work/cdr/cdr_broadcast.c
--- original/cdr/cdr_broadcast.c 1970-01-01 01:00:00.000000000 +0100
+++ work/cdr/cdr_broadcast.c 2009-05-12 18:33:46.000000000 +0200
@@ -0,0 +1,264 @@
+/*
+ * 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); ast_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 ast_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);
+ ast_localtime(&(cdr->start), &tm, "GMT");
+ DATAPPEND(buffer, tm);
+ ast_localtime(&(cdr->answer), &tm, "GMT");
+ DATAPPEND(buffer, tm);
+ ast_localtime(&(cdr->end), &tm, "GMT");
+ 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;
+ struct ast_flags config_flags = { 0 };
+
+ cfg = ast_config_load(CDR_BROADCAST_CONFIG, config_flags);
+
+ if ((!cfg)||(cfg == CONFIG_STATUS_FILEINVALID)) {
+ 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 original/configs/cdr_broadcast.conf.sample work/configs/cdr_broadcast.conf.sample
--- original/configs/cdr_broadcast.conf.sample 1970-01-01 01:00:00.000000000 +0100
+++ work/configs/cdr_broadcast.conf.sample 2009-05-12 18:34:02.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