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