diff --git a/AUTHORS b/AUTHORS index 5ee32b293d..ff4417407a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -27,6 +27,7 @@ that much better: Stefan Knoblich - Various patches and support. Thanks. Justin Unger - Lots of help with patches and SIP testing. Thanks! Paul D. Tinsley - Various patches and support. + Ken Rice of Asteria Solutions Group, INC - xmlcdr, sofia improvements, load testing. A big THANK YOU goes to: diff --git a/src/mod/event_handlers/mod_cdr/Makefile b/src/mod/event_handlers/mod_cdr/Makefile index 2f94d31fbd..37e1c12eeb 100644 --- a/src/mod/event_handlers/mod_cdr/Makefile +++ b/src/mod/event_handlers/mod_cdr/Makefile @@ -3,7 +3,7 @@ CFLAGS += $(shell mysql_config --include) LDFLAGS += $(shell mysql_config --libs) CPPCC = g++ -OBJS=cdrcontainer.o basecdr.o baseregistry.o mysqlcdr.o pddcdr.o csvcdr.o +OBJS=cdrcontainer.o basecdr.o baseregistry.o mysqlcdr.o pddcdr.o csvcdr.o xmlcdr.o all: depends $(OBJS) $(MODNAME).$(DYNAMIC_LIB_EXTEN) diff --git a/src/mod/event_handlers/mod_cdr/README b/src/mod/event_handlers/mod_cdr/README index a7166e35ce..cc02b05c24 100644 --- a/src/mod/event_handlers/mod_cdr/README +++ b/src/mod/event_handlers/mod_cdr/README @@ -59,6 +59,21 @@ Configuration: Section: value is a comma separated list of supplemental channel variables to log. Can be a wildcard (*) (optional) value is 0 for no, 1 for yes, and determines whether or not to repeat any of the fixed channel variables as key / value pairs in the chanvars table. +Class: OdbcCDR, located in odbccdr.h and odbccdr.cpp + This class logs the call detail record to an ODBC database using prepared + statements. This class is similar to MysqlCDR in that the fixed channel variables are treated as additional columns on the main freeswitchcdr database table for improved normalization of the database. As such, you need to specify the format of each fixed channel variable as well. If you do not specify, it will default to a varchar column type, and will not execute if the table schema does not match. Therefore it is very important to make sure that any fixed channel variables you log exist as columns on the table. The supplemental channel variables are stored in a separate table using a key / value pair linking to the myuuid of the call. Recommended to use at least one other logger in conjuction with this one just to be on the safe side, as failover handling of errors to write to the db are not yet implemented, and therefore there is a risk of data loss if the database connection is lost entirely (it will be limited to only those records created at the time of the loss of connection) or some other fatal error is encountered. Additionally, since there is no uniform method to handling columns of type sequence/autoincrement/autonumber in the rdbms world, it should be noted that each row in the chanvars (supplemental channel variables) table will cost 36 bytes for the myuuid to be posted to it instead of 8 bytes for a bigint as in MysqlCDR. +Configuration: Section + - Not yet implemented, but meant for future use in ease of config + - The hostname or IP of the backend server + - The username used to authenticate to the backend server + - The password used to authenticate to the backend server + - The database to use for logging + - Optional: the name of the main logging table (defaults to freeswitchcdr) + - Optional: the name of the supplemental chanvars table (defaults to chanvars) + Is a comma separated list of key=type pairs. Types are x for decimal, s for string (varchar), d for double, i for integer, t for tiny. If no type is provided, it defaults that column to string (varchar). It cannot accept wildcards (*). (optional) + value is a comma separated list of supplemental channel variables to log. Can be a wildcard (*) (optional) + value is 0 for no, 1 for yes, and determines whether or not to repeat any of the fixed channel variables as key / value pairs in the chanvars table. + FAQ: Q: Why C++? @@ -70,6 +85,9 @@ A: There is a distinction so that a level of uniformity can be maintain on those Q: What would an example configuration look like? A: Here is an excerpt from the freeswitch XML configuration file: +Q: What happened to the ani2 field? +A: Oops, you caught us. The real name for is it aniii. You will need to update any database schemas or external handlers for this change. + diff --git a/src/mod/event_handlers/mod_cdr/schema.sql b/src/mod/event_handlers/mod_cdr/schema.sql index cd4f0afc31..5649ea03dc 100644 --- a/src/mod/event_handlers/mod_cdr/schema.sql +++ b/src/mod/event_handlers/mod_cdr/schema.sql @@ -8,7 +8,7 @@ create table freeswitchcdr ( src varchar(80) NOT NULL, dst varchar(80) NOT NULL, ani varchar(80) default "", - ani2 varchar(80) default "", + aniii varchar(80) default "", dialplan varchar(80) default "", myuuid char(36) NOT NULL, destuuid char(36) NOT NULL, @@ -19,13 +19,7 @@ create table freeswitchcdr ( billusec bigint default 0, disposition tinyint default 0, /* 0 = Busy or Unanswered, 1 = Answered */ hangupcause int default 0, - amaflags tinyint default 0, - /* - This section not needed, because it was an old asteriskism. A chan_var table is to replace it perhaps. - accountcode varchar(80) default "", - uniqueid varchar(32) default "", - userfield varchar(255) default "" - */ + amaflags tinyint default 0 ); create index myuuid_index on freeswitchcdr (myuuid); @@ -37,4 +31,4 @@ create table chanvars ( varvalue varchar(255) default "" ); -create index callid_index on chanvars(callid,varname); \ No newline at end of file +create index callid_index on chanvars(callid,varname); diff --git a/src/mod/event_handlers/mod_cdr/xmlcdr.cpp b/src/mod/event_handlers/mod_cdr/xmlcdr.cpp new file mode 100644 index 0000000000..684deebebf --- /dev/null +++ b/src/mod/event_handlers/mod_cdr/xmlcdr.cpp @@ -0,0 +1,221 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module + * Copyright 2006, Author: Yossi Neiman of Cartis Solutions, Inc. + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module + * + * The Initial Developer of the Original Code is + * Yossi Neiman + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Yossi Neiman + * Ken Rice of Asteria Solutions Group, INC + * + * Description: This C++ source file describes the XmlCDR class which handles formatting a CDR out to + * individual text files in a XML format. + * + * xmlcdr.cpp + * + */ + +#include +#include "xmlcdr.h" + +XmlCDR::XmlCDR() : BaseCDR() +{ + memset(formattedcallstartdate,0,100); + memset(formattedcallanswerdate,0,100); + memset(formattedcallenddate,0,100); +} + +XmlCDR::XmlCDR(switch_mod_cdr_newchannel_t *newchannel) : BaseCDR(newchannel) +{ + memset(formattedcallstartdate,0,100); + memset(formattedcallanswerdate,0,100); + memset(formattedcallenddate,0,100); + + if(newchannel != 0) + { + switch_time_exp_t tempcallstart, tempcallanswer, tempcallend; + memset(&tempcallstart,0,sizeof(tempcallstart)); + memset(&tempcallanswer,0,sizeof(tempcallanswer)); + memset(&tempcallend,0,sizeof(tempcallend)); + switch_time_exp_lt(&tempcallstart, callstartdate); + switch_time_exp_lt(&tempcallanswer, callanswerdate); + switch_time_exp_lt(&tempcallend, callenddate); + + // Format the times + size_t retsizecsd, retsizecad, retsizeced; //csd == callstartdate, cad == callanswerdate, ced == callenddate, ceff == callenddate_forfile + char format[] = "%Y-%m-%d-%H-%M-%S"; + switch_strftime(formattedcallstartdate,&retsizecsd,sizeof(formattedcallstartdate),format,&tempcallstart); + switch_strftime(formattedcallanswerdate,&retsizecad,sizeof(formattedcallanswerdate),format,&tempcallanswer); + switch_strftime(formattedcallenddate,&retsizeced,sizeof(formattedcallenddate),format,&tempcallend); + + std::ostringstream ostring; + ostring << (callenddate/1000000); + std::string callenddate_forfile = ostring.str(); + + outputfile_name = outputfile_path; + outputfile_name.append(SWITCH_PATH_SEPARATOR); + outputfile_name.append(callenddate_forfile); // Make sorting a bit easier, kinda like Maildir does + outputfile_name.append("."); + outputfile_name.append(myuuid); // The goal is to have a resulting filename of "/path/to/myuuid" + outputfile_name.append(".xml"); // .xml - "XML Data Dumper" + + outputfile.open(outputfile_name.c_str()); + + bool repeat = 1; + process_channel_variables(chanvars_supp_list,chanvars_fixed_list,newchannel->channel,repeat); + } +} + +XmlCDR::~XmlCDR() +{ + outputfile.close(); +} + +bool XmlCDR::activated=0; +bool XmlCDR::logchanvars=0; +bool XmlCDR::connectionstate=0; +std::string XmlCDR::outputfile_path; +std::list XmlCDR::chanvars_fixed_list; +std::list XmlCDR::chanvars_supp_list; + +void XmlCDR::connect(switch_xml_t& cfg, switch_xml_t& xml, switch_xml_t& settings, switch_xml_t& param) +{ + switch_console_printf(SWITCH_CHANNEL_LOG, "XmlCDR::connect() - Loading configuration file.\n"); + activated = 0; // Set it as inactive initially + connectionstate = 0; // Initialize it to false to show that we aren't yet connected. + + if ((settings = switch_xml_child(cfg, "xmlcdr"))) + { + int count_config_params = 0; // Need to make sure all params are set before we load + for (param = switch_xml_child(settings, "param"); param; param = param->next) + { + char *var = (char *) switch_xml_attr_soft(param, "name"); + char *val = (char *) switch_xml_attr_soft(param, "value"); + + if (!strcmp(var, "path")) + { + if(val != 0) + outputfile_path = val; + count_config_params++; + } + else if (!strcmp(var, "chanvars")) + { + if(val != 0) + { + std::string unparsed; + unparsed = val; + if(unparsed.size() > 0) + { + bool fixed = 0; + parse_channel_variables_xconfig(unparsed,chanvars_supp_list,fixed); + logchanvars=1; + } + } + } + else if (!strcmp(var, "chanvars_fixed")) + { + switch_console_printf(SWITCH_CHANNEL_LOG,"XmlCDR has no need for a fixed or supplemental list of channel variables due to the nature of the format. Please use the setting parameter of \"chanvars\" instead and try again.\n"); + } + else if (!strcmp(var, "chanvars_supp")) + { + switch_console_printf(SWITCH_CHANNEL_LOG,"XmlCDR has no need for a fixed or supplemental list of channel variables due to the nature of the format. Please use the setting parameter of \"chanvars\" instead and try again.\n"); + } + } + + if(count_config_params > 0) + activated = 1; + else + switch_console_printf(SWITCH_CHANNEL_LOG,"XmlCDR::connect(): You did not specify the minimum parameters for using this module. You must specify at least a path to have the records logged to.\n"); + } +} + +bool XmlCDR::process_record() +{ + bool retval = 0; + if(!outputfile) + switch_console_printf(SWITCH_CHANNEL_LOG, "XmlCDR::process_record(): Unable to open file %s to commit the call record to. Invalid path name, invalid permissions, or no space available?\n",outputfile_name.c_str()); + else + { + switch_console_printf(SWITCH_CHANNEL_LOG, "XmlCDR::process_record(): Preping the CDR to %s.\n",outputfile_name.c_str()); + // Format the call record and proceed from here... + outputfile << "" << std::endl; + outputfile << "" << std::endl; + outputfile << "\t" << std::endl; + outputfile << "\t" << std::endl; + outputfile << "\t" << std::endl; + outputfile << "\t" << std::endl; + outputfile << "\t" << std::endl; + outputfile << "\t" << std::endl; + outputfile << "\t" << std::endl; + outputfile << "\t" << std::endl; + outputfile << "\t" << std::endl; + outputfile << "\t" << std::endl; + outputfile << "\t" << std::endl; + outputfile << "\t" << std::endl; + outputfile << "\t" << std::endl; + outputfile << "\t" << std::endl; + outputfile << "\t" << std::endl; + outputfile << "\t" << std::endl; + outputfile << "\t" << std::endl; + outputfile << "\t" << std::endl; + outputfile << "\t" << std::endl; + outputfile << "\t" << std::endl; + outputfile << "\t" << std::endl; + outputfile << "\t" << std::endl; + + // Now to process chanvars + outputfile << "\t" << std::endl; + if(chanvars_supp.size() > 0 ) + { + std::map::iterator iItr,iEnd; + for(iItr = chanvars_supp.begin(), iEnd = chanvars_supp.end() ; iItr != iEnd; iItr++) + outputfile << "\t\tfirst << "\" data= \"" << iItr->second << "\" />" << std::endl; + } + outputfile << "\t" << std::endl << "" << std::endl << std::endl; + + switch_console_printf(SWITCH_CHANNEL_LOG, "XmlCDR::process_record(): Dumping the CDR to %s.\n",outputfile_name.c_str()); + retval = 1; + } + + return retval; +} + +bool XmlCDR::is_activated() +{ + return activated; +} + +void XmlCDR::tempdump_record() +{ + +} + +void XmlCDR::reread_tempdumped_records() +{ + +} + +void XmlCDR::disconnect() +{ + switch_console_printf(SWITCH_CHANNEL_LOG,"Shutting down XmlCDR... Done!"); +} + +AUTO_REGISTER_BASECDR(XmlCDR); diff --git a/src/mod/event_handlers/mod_cdr/xmlcdr.h b/src/mod/event_handlers/mod_cdr/xmlcdr.h new file mode 100644 index 0000000000..6daf87dd06 --- /dev/null +++ b/src/mod/event_handlers/mod_cdr/xmlcdr.h @@ -0,0 +1,72 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module + * Copyright 2006, Author: Yossi Neiman of Cartis Solutions, Inc. + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module + * + * The Initial Developer of the Original Code is + * Yossi Neiman + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Yossi Neiman + * Ken Rice, Asteria Solutions Group, Inc. + * + * Description: This C++ header file describes the XmlCDR class which handles formatting a CDR out to + * individual text files in a XML format. + * + * xmlcdr.h + * + */ + +#include "baseregistry.h" +#include +#include +#include +#include +#include + +#ifndef XMLCDR +#define XMLCDR + +class XmlCDR : public BaseCDR { + public: + XmlCDR(); + XmlCDR(switch_mod_cdr_newchannel_t *newchannel); + virtual ~XmlCDR(); + virtual bool process_record(); + virtual void connect(switch_xml_t& cfg, switch_xml_t& xml, switch_xml_t& settings, switch_xml_t& param); // connect and disconnect need to be static because we're persisting connections until shutdown + virtual void disconnect(); + virtual bool is_activated(); + virtual void tempdump_record(); + virtual void reread_tempdumped_records(); + + private: + static bool activated; // Is this module activated? + static bool connectionstate; // What is the status of the connection? + static bool logchanvars; + static std::string outputfile_path; // The directory we'll dump these into + static std::list chanvars_fixed_list; // Normally this would be used, but not in this class + static std::list chanvars_supp_list; // This will hold the list for all chanvars here + char formattedcallstartdate[100]; + char formattedcallanswerdate[100]; + char formattedcallenddate[100]; + std::string outputfile_name; + std::ofstream outputfile; +}; + +#endif